nuclear@0: #include nuclear@0: #include nuclear@0: #include nuclear@11: #include nuclear@0: #include "opengl.h" nuclear@0: #include "game.h" nuclear@7: #include "camera.h" nuclear@10: #include "sdr.h" nuclear@11: #include "sanegl.h" nuclear@17: #include "texture.h" nuclear@7: nuclear@17: static void draw_quad(float hsz, float vsz, unsigned int sdr); nuclear@0: nuclear@0: static int win_width, win_height; nuclear@9: static float win_aspect; nuclear@9: static int video_width, video_height; nuclear@9: static float video_aspect; nuclear@17: static unsigned int sdrprog, sdrprog_test; nuclear@17: static int uloc_tex, uloc_test_tex; nuclear@17: static struct texture *test_tex; nuclear@17: nuclear@17: enum { ATTR_VERTEX, ATTR_TEXCOORD }; nuclear@10: nuclear@10: static const char *vsdr_source = nuclear@11: "attribute vec4 attr_vertex, attr_texcoord;\n" nuclear@11: "uniform mat4 matrix_modelview, matrix_projection, matrix_texture;\n" nuclear@10: "varying vec4 tex_coords;\n" nuclear@10: "void main()\n" nuclear@10: "{\n" nuclear@11: "\tmat4 mvp = matrix_projection * matrix_modelview;\n" nuclear@11: "\tgl_Position = mvp * attr_vertex;\n" nuclear@11: "\ttex_coords = matrix_texture * attr_texcoord;\n" nuclear@10: "}\n"; nuclear@10: nuclear@17: static const char *psdr_cam_source = nuclear@10: "#extension GL_OES_EGL_image_external : require\n" nuclear@11: "precision mediump float;\n" nuclear@10: "uniform samplerExternalOES tex;\n" nuclear@10: "varying vec4 tex_coords;\n" nuclear@10: "void main()\n" nuclear@10: "{\n" nuclear@10: "\tvec4 texel = texture2D(tex, tex_coords.xy);\n" nuclear@10: "\tgl_FragColor = vec4(texel.xyz, 1.0);\n" nuclear@10: "}\n"; nuclear@0: nuclear@17: static const char *psdr_tex_source = nuclear@17: "precision mediump float;\n" nuclear@17: "uniform sampler2D tex;\n" nuclear@17: "varying vec4 tex_coords;\n" nuclear@17: "void main()\n" nuclear@17: "{\n" nuclear@17: "\tvec4 texel = texture2D(tex, tex_coords.xy);\n" nuclear@17: "\tgl_FragColor = texel;\n" nuclear@17: "}\n"; nuclear@0: nuclear@20: extern "C" int game_init(void) nuclear@0: { nuclear@17: unsigned int vsdr, psdr_cam, psdr_tex; nuclear@10: nuclear@17: //glEnable(GL_DEPTH_TEST); nuclear@0: glEnable(GL_CULL_FACE); nuclear@0: nuclear@0: glClearColor(0.4, 0.4, 0.4, 1); nuclear@8: nuclear@10: if(!(vsdr = create_vertex_shader(vsdr_source))) nuclear@10: return -1; nuclear@11: assert(glGetError() == GL_NO_ERROR); nuclear@17: if(!(psdr_cam = create_pixel_shader(psdr_cam_source))) nuclear@10: return -1; nuclear@11: assert(glGetError() == GL_NO_ERROR); nuclear@17: if(!(psdr_tex = create_pixel_shader(psdr_tex_source))) nuclear@17: return -1; nuclear@17: assert(glGetError() == GL_NO_ERROR); nuclear@17: if(!(sdrprog = create_program_link(vsdr, psdr_cam, 0))) { nuclear@10: fprintf(stderr, "failed to create shader program\n"); nuclear@10: return -1; nuclear@10: } nuclear@17: if(!(sdrprog_test = create_program_link(vsdr, psdr_tex, 0))) { nuclear@17: fprintf(stderr, "failed to create test shader program\n"); nuclear@17: return -1; nuclear@17: } nuclear@17: nuclear@10: glUseProgram(sdrprog); nuclear@17: glBindAttribLocation(sdrprog, ATTR_VERTEX, "attr_vertex"); nuclear@17: glBindAttribLocation(sdrprog, ATTR_TEXCOORD, "attr_texcoord"); nuclear@11: uloc_tex = glGetUniformLocation(sdrprog, "tex"); nuclear@17: glLinkProgram(sdrprog); nuclear@17: nuclear@17: glUseProgram(sdrprog_test); nuclear@17: glBindAttribLocation(sdrprog_test, ATTR_VERTEX, "attr_vertex"); nuclear@17: glBindAttribLocation(sdrprog_test, ATTR_TEXCOORD, "attr_texcoord"); nuclear@17: uloc_test_tex = glGetUniformLocation(sdrprog_test, "tex"); nuclear@17: glLinkProgram(sdrprog_test); nuclear@17: nuclear@17: if(!(test_tex = get_texture("data/opengl.png"))) { nuclear@17: return -1; nuclear@17: } nuclear@10: nuclear@8: cam_start_video(); nuclear@9: cam_video_size(&video_width, &video_height); nuclear@9: if(video_height) { nuclear@9: video_aspect = (float)video_width / (float)video_height; nuclear@9: } else { nuclear@9: video_aspect = 1.0; nuclear@9: } nuclear@9: nuclear@9: printf("started video %dx%d (aspect: %g)\n", video_width, video_height, video_aspect); nuclear@0: return 0; nuclear@0: } nuclear@0: nuclear@20: extern "C" void game_shutdown(void) nuclear@0: { nuclear@8: cam_shutdown(); nuclear@10: free_program(sdrprog); nuclear@0: } nuclear@0: nuclear@20: extern "C" void game_display(unsigned long msec) nuclear@0: { nuclear@9: unsigned int tex; nuclear@9: const float *tex_matrix; nuclear@9: float xscale, yscale; nuclear@9: nuclear@8: cam_update(); nuclear@9: tex = cam_texture(); nuclear@9: tex_matrix = cam_texture_matrix(); nuclear@7: nuclear@4: //float tsec = (float)msec / 1000.0f; nuclear@0: nuclear@0: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); nuclear@0: nuclear@11: gl_matrix_mode(GL_MODELVIEW); nuclear@11: gl_load_identity(); nuclear@11: gl_matrix_mode(GL_TEXTURE); nuclear@11: gl_load_matrixf(tex_matrix); nuclear@11: nuclear@10: glUseProgram(sdrprog); nuclear@10: glBindTexture(GL_TEXTURE_EXTERNAL_OES, tex); nuclear@11: if(uloc_tex >= 0) { nuclear@11: glUniform1i(uloc_tex, 0); nuclear@11: } nuclear@7: nuclear@9: if(video_aspect > win_aspect) { nuclear@9: xscale = 1.0; nuclear@9: yscale = 1.0 / video_aspect; nuclear@9: } else { nuclear@9: xscale = video_aspect; nuclear@9: yscale = 1.0; nuclear@9: } nuclear@17: draw_quad(xscale, yscale, sdrprog); nuclear@17: nuclear@17: gl_matrix_mode(GL_TEXTURE); nuclear@17: gl_load_identity(); nuclear@17: gl_translatef(0, 1, 0); nuclear@17: gl_scalef(1, -1, 1); nuclear@17: gl_matrix_mode(GL_MODELVIEW); nuclear@17: gl_load_identity(); nuclear@17: gl_scalef((float)test_tex->width / (float)test_tex->height, 1, 1); nuclear@17: nuclear@17: glUseProgram(sdrprog_test); nuclear@17: glBindTexture(GL_TEXTURE_2D, test_tex->texid); nuclear@17: if(uloc_test_tex >= 0) { nuclear@17: glUniform1i(uloc_test_tex, 0); nuclear@17: } nuclear@17: nuclear@17: glEnable(GL_BLEND); nuclear@17: glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); nuclear@17: nuclear@17: draw_quad(0.5, 0.5, sdrprog_test); nuclear@17: nuclear@17: glDisable(GL_BLEND); nuclear@7: } nuclear@7: nuclear@17: static void draw_quad(float hsz, float vsz, unsigned int sdr) nuclear@7: { nuclear@7: static const float varr[] = {-1, -1, 1, -1, 1, 1, -1, 1}; nuclear@9: static const float tcarr[] = {0, 0, 1, 0, 1, 1, 0, 1}; nuclear@7: nuclear@11: gl_matrix_mode(GL_MODELVIEW); nuclear@11: gl_push_matrix(); nuclear@11: gl_scalef(hsz, vsz, 1); nuclear@11: nuclear@17: gl_apply_xform(sdr); nuclear@7: nuclear@17: glEnableVertexAttribArray(ATTR_VERTEX); nuclear@17: glEnableVertexAttribArray(ATTR_TEXCOORD); nuclear@17: glVertexAttribPointer(ATTR_VERTEX, 2, GL_FLOAT, 0, 0, varr); nuclear@17: glVertexAttribPointer(ATTR_TEXCOORD, 2, GL_FLOAT, 0, 0, tcarr); nuclear@7: nuclear@8: glDrawArrays(GL_TRIANGLE_FAN, 0, 4); nuclear@7: nuclear@17: glDisableVertexAttribArray(ATTR_VERTEX); nuclear@17: glDisableVertexAttribArray(ATTR_TEXCOORD); nuclear@11: nuclear@11: gl_pop_matrix(); nuclear@0: } nuclear@0: nuclear@20: extern "C" void game_reshape(int x, int y) nuclear@0: { nuclear@0: win_width = x; nuclear@0: win_height = y; nuclear@9: win_aspect = y ? (float)x / (float)y : 1.0; nuclear@0: glViewport(0, 0, x, y); nuclear@0: nuclear@11: gl_matrix_mode(GL_PROJECTION); nuclear@11: gl_load_identity(); nuclear@11: gl_scalef((float)win_height / (float)win_width, 1, 1); nuclear@0: } nuclear@0: nuclear@20: extern "C" void game_keyboard(int key, int pressed) nuclear@0: { nuclear@0: if(!pressed) return; nuclear@0: nuclear@0: switch(key) { nuclear@0: case 27: nuclear@0: exit(0); nuclear@0: nuclear@0: default: nuclear@0: break; nuclear@0: } nuclear@0: } nuclear@0: nuclear@0: #define MAX_TOUCH_IDS 16 nuclear@0: static struct { nuclear@0: int bnstate[8]; nuclear@0: int prev_x, prev_y; nuclear@0: } mstate[MAX_TOUCH_IDS]; nuclear@0: nuclear@20: extern "C" void game_mouse_button(int id, int bn, int pressed, int x, int y) nuclear@0: { nuclear@0: if(id >= MAX_TOUCH_IDS) return; nuclear@0: nuclear@0: mstate[id].prev_x = x; nuclear@0: mstate[id].prev_y = y; nuclear@0: mstate[id].bnstate[bn] = pressed; nuclear@0: } nuclear@0: nuclear@20: extern "C" void game_mouse_motion(int id, int x, int y) nuclear@0: { nuclear@0: /* nuclear@0: int dx, dy, cx, cy; nuclear@0: nuclear@0: if(id >= MAX_TOUCH_IDS) return; nuclear@0: nuclear@0: cx = win_width / 2; nuclear@0: cy = win_height / 2; nuclear@0: nuclear@0: dx = x - mstate[id].prev_x; nuclear@0: dy = y - mstate[id].prev_y; nuclear@0: mstate[id].prev_x = x; nuclear@0: mstate[id].prev_y = y; nuclear@0: nuclear@0: if(!dx && !dy) return; nuclear@0: nuclear@0: if(mouselook || mstate[id].bnstate[0]) { nuclear@0: player_turn(&player, dx * 0.5, dy * 0.5); nuclear@0: } nuclear@0: if(mstate[id].bnstate[2]) { nuclear@0: dbg_cam_dist += 0.1 * dy; nuclear@0: if(dbg_cam_dist < 0.0) dbg_cam_dist = 0.0; nuclear@0: } nuclear@0: nuclear@0: if(mouselook) { nuclear@0: warping_mouse = 1; nuclear@0: set_mouse_pos(cx, cy); nuclear@0: mstate[id].prev_x = cx; nuclear@0: mstate[id].prev_y = cy; nuclear@0: } nuclear@0: */ nuclear@0: } nuclear@0: