nuclear@2: /* nuclear@2: Stereoscopic tunnel for iOS. nuclear@6: Copyright (C) 2011-2015 John Tsiombikas nuclear@2: nuclear@2: This program is free software: you can redistribute it and/or modify nuclear@2: it under the terms of the GNU General Public License as published by nuclear@2: the Free Software Foundation, either version 3 of the License, or nuclear@2: (at your option) any later version. nuclear@2: nuclear@2: This program is distributed in the hope that it will be useful, nuclear@2: but WITHOUT ANY WARRANTY; without even the implied warranty of nuclear@2: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the nuclear@2: GNU General Public License for more details. nuclear@2: nuclear@2: You should have received a copy of the GNU General Public License nuclear@2: along with this program. If not, see . nuclear@2: */ nuclear@2: nuclear@2: nuclear@2: #include nuclear@2: #include nuclear@2: #include nuclear@2: #include nuclear@2: #include "opengl.h" nuclear@2: #include "istereo.h" nuclear@2: #include "sanegl.h" nuclear@2: #include "sdr.h" nuclear@2: #include "respath.h" nuclear@2: #include "tex.h" nuclear@2: #include "cam.h" nuclear@2: #include "vmath.h" nuclear@2: #include "config.h" nuclear@6: #include "ui.h" nuclear@7: #include "drawtext.h" nuclear@2: nuclear@2: static void render(float t); nuclear@2: static void draw_tunnel(float t); nuclear@2: static void tunnel_vertex(float u, float v, float du, float dv, int tang_loc, float t); nuclear@2: static vec3_t calc_text_pos(float sec); nuclear@2: static void draw_text(float idx, vec3_t tpos, float alpha); nuclear@2: static void worm(float t, float z, float *tx, float *ty); nuclear@2: static unsigned int get_shader_program(const char *vfile, const char *pfile); nuclear@2: static float get_sec(void); nuclear@2: nuclear@7: unsigned int prog, prog_simple, prog_tunnel, prog_text, prog_color, prog_ui, prog_font; nuclear@2: unsigned int tex, tex_stones, tex_normal, tex_text; nuclear@7: struct dtx_font *font; nuclear@2: nuclear@2: int view_xsz, view_ysz; nuclear@2: nuclear@2: int stereo = 0; nuclear@2: int use_bump = 0; nuclear@6: int show_opt = 1; nuclear@2: nuclear@2: /* construction parameters */ nuclear@2: int sides = 24; nuclear@2: int segm = 20; nuclear@2: float tunnel_speed = 0.75; nuclear@2: float ring_height = 0.5; nuclear@2: float text_period = 13.0; nuclear@2: float text_speed = 2.2; nuclear@2: nuclear@2: float split = 0.5275; nuclear@2: nuclear@2: int init(void) nuclear@2: { nuclear@2: add_resource_path("sdr"); nuclear@2: add_resource_path("data"); nuclear@2: nuclear@2: if(!(prog_simple = get_shader_program("test.v.glsl", "test.p.glsl"))) { nuclear@2: return -1; nuclear@2: } nuclear@2: if(!(prog_tunnel = get_shader_program("tunnel.v.glsl", "tunnel.p.glsl"))) { nuclear@2: return -1; nuclear@2: } nuclear@2: if(!(prog_text = get_shader_program("text.v.glsl", "text.p.glsl"))) { nuclear@2: return -1; nuclear@2: } nuclear@6: if(!(prog_color = get_shader_program("color.v.glsl", "color.p.glsl"))) { nuclear@6: return -1; nuclear@6: } nuclear@6: if(!(prog_ui = get_shader_program("ui.v.glsl", "ui.p.glsl"))) { nuclear@6: return -1; nuclear@6: } nuclear@7: if(!(prog_font = get_shader_program("ui.v.glsl", "font.p.glsl"))) { nuclear@7: return -1; nuclear@7: } nuclear@2: nuclear@2: if(!(tex = load_texture(find_resource("tiles.jpg", 0, 0)))) { nuclear@2: return -1; nuclear@2: } nuclear@2: if(!(tex_stones = load_texture(find_resource("stonewall.jpg", 0, 0)))) { nuclear@2: return -1; nuclear@2: } nuclear@2: if(!(tex_normal = load_texture(find_resource("stonewall_normal.jpg", 0, 0)))) { nuclear@2: return -1; nuclear@2: } nuclear@2: if(!(tex_text = load_texture(find_resource("text.png", 0, 0)))) { nuclear@2: return -1; nuclear@2: } nuclear@2: nuclear@7: if(!(font = dtx_open_font_glyphmap(find_resource("linux-libertine_s24.glyphmap", 0, 0)))) { nuclear@7: fprintf(stderr, "failed to load font\n"); nuclear@7: return -1; nuclear@7: } nuclear@7: dtx_vertex_attribs(get_attrib_loc(prog_ui, "attr_vertex"), get_attrib_loc(prog_ui, "attr_texcoord")); nuclear@7: dtx_use_font(font, 24); nuclear@7: nuclear@2: glEnable(GL_DEPTH_TEST); nuclear@2: glEnable(GL_CULL_FACE); nuclear@2: nuclear@6: if(ui_init() == -1) { nuclear@6: return -1; nuclear@6: } nuclear@6: nuclear@2: cam_fov(42.5); nuclear@2: cam_clip(0.5, 250.0); nuclear@2: nuclear@2: return 0; nuclear@2: } nuclear@2: nuclear@2: void cleanup(void) nuclear@2: { nuclear@6: ui_shutdown(); nuclear@6: free_program(prog_simple); nuclear@6: free_program(prog_tunnel); nuclear@6: free_program(prog_color); nuclear@6: free_program(prog_ui); nuclear@7: free_program(prog_font); nuclear@7: dtx_close_font(font); nuclear@2: } nuclear@2: nuclear@2: void redraw(void) nuclear@2: { nuclear@2: float pan_x, pan_y, z; nuclear@2: float tsec = get_sec(); nuclear@2: nuclear@2: z = ring_height * segm; nuclear@2: worm(tsec, z, &pan_x, &pan_y); nuclear@2: nuclear@2: if(use_bump) { nuclear@2: glClearColor(0.01, 0.01, 0.01, 1.0); nuclear@2: tunnel_speed = 0.5; nuclear@2: } else { nuclear@2: glClearColor(0.6, 0.6, 0.6, 1.0); nuclear@2: tunnel_speed = 0.75; nuclear@2: } nuclear@2: glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); nuclear@2: nuclear@2: if(stereo) { nuclear@4: int split_pt = (int)((float)view_xsz * split); nuclear@2: nuclear@2: /* right eye */ nuclear@4: glViewport(0, 0, split_pt, view_ysz); nuclear@4: cam_aspect((float)split_pt / (float)view_ysz); nuclear@2: nuclear@2: gl_matrix_mode(GL_PROJECTION); nuclear@2: gl_load_identity(); nuclear@2: cam_stereo_proj_matrix(CAM_RIGHT); nuclear@4: //gl_rotatef(-90, 0, 0, 1); nuclear@2: nuclear@2: gl_matrix_mode(GL_MODELVIEW); nuclear@2: gl_load_identity(); nuclear@2: cam_stereo_view_matrix(CAM_RIGHT); nuclear@2: gl_translatef(-pan_x, -pan_y, -1.1 * ring_height * segm); nuclear@2: nuclear@2: render(tsec); nuclear@2: nuclear@2: /* left eye */ nuclear@4: glViewport(split_pt, 0, view_xsz - split_pt, view_ysz); nuclear@4: cam_aspect((float)(view_xsz - split_pt) / (float)view_ysz); nuclear@2: nuclear@2: gl_matrix_mode(GL_PROJECTION); nuclear@2: gl_load_identity(); nuclear@2: cam_stereo_proj_matrix(CAM_LEFT); nuclear@4: //gl_rotatef(-90, 0, 0, 1); nuclear@2: nuclear@2: gl_matrix_mode(GL_MODELVIEW); nuclear@2: gl_load_identity(); nuclear@2: cam_stereo_view_matrix(CAM_LEFT); nuclear@2: gl_translatef(-pan_x, -pan_y, -1.1 * ring_height * segm); nuclear@2: nuclear@2: render(tsec); nuclear@2: } else { nuclear@2: glViewport(0, 0, view_xsz, view_ysz); nuclear@2: cam_aspect((float)view_xsz / (float)view_ysz); nuclear@2: nuclear@2: gl_matrix_mode(GL_PROJECTION); nuclear@2: gl_load_identity(); nuclear@4: //gl_rotatef(-90, 0, 0, 1); nuclear@2: cam_proj_matrix(); nuclear@2: nuclear@2: gl_matrix_mode(GL_MODELVIEW); nuclear@2: gl_load_identity(); nuclear@2: cam_view_matrix(); nuclear@2: gl_translatef(-pan_x, -pan_y, -1.1 * ring_height * segm); nuclear@2: nuclear@2: render(tsec); nuclear@2: } nuclear@2: nuclear@7: /* TEST */ nuclear@7: /*bind_program(prog_ui); nuclear@7: nuclear@7: gl_matrix_mode(GL_PROJECTION); nuclear@7: gl_load_identity(); nuclear@7: gl_ortho(0, view_xsz, 0, view_ysz, -1, 1); nuclear@7: gl_matrix_mode(GL_MODELVIEW); nuclear@7: gl_load_identity(); nuclear@7: gl_apply_xform(prog_ui); nuclear@7: nuclear@7: glDisable(GL_DEPTH_TEST); nuclear@7: dtx_printf("hello world\n"); nuclear@7: glEnable(GL_DEPTH_TEST);*/ nuclear@7: nuclear@2: assert(glGetError() == GL_NO_ERROR); nuclear@2: } nuclear@2: nuclear@2: static void render(float t) nuclear@2: { nuclear@2: int i; nuclear@2: float text_line; nuclear@2: nuclear@2: draw_tunnel(t); nuclear@2: nuclear@2: if(use_bump) { nuclear@2: glDepthMask(0); nuclear@2: text_line = floor((text_speed * t) / text_period); nuclear@2: for(i=0; i<8; i++) { nuclear@2: vec3_t tpos = calc_text_pos(t - (float)i * 0.011); nuclear@2: draw_text(text_line, tpos, 1.5 / (float)i); nuclear@2: } nuclear@2: glDepthMask(1); nuclear@2: } nuclear@6: nuclear@6: if(show_opt) { nuclear@6: ui_draw(); nuclear@6: } nuclear@2: } nuclear@2: nuclear@2: static void draw_tunnel(float t) nuclear@2: { nuclear@2: static const float uoffs[] = {0.0, 0.0, 1.0, 1.0}; nuclear@2: static const float voffs[] = {0.0, 1.0, 1.0, 0.0}; nuclear@2: int i, j, k, tang_loc = -1; nuclear@2: float du, dv; nuclear@2: nuclear@2: prog = use_bump ? prog_tunnel : prog_simple; nuclear@2: nuclear@2: bind_program(prog); nuclear@2: set_uniform_float(prog, "t", t); nuclear@2: nuclear@2: if(use_bump) { nuclear@2: vec3_t ltpos = calc_text_pos(t); nuclear@2: nuclear@2: bind_texture(tex_normal, 1); nuclear@2: set_uniform_int(prog, "tex_norm", 1); nuclear@2: bind_texture(tex_stones, 0); nuclear@2: set_uniform_int(prog, "tex", 0); nuclear@2: nuclear@2: set_uniform_float4(prog, "light_pos", ltpos.x, ltpos.y, ltpos.z, 1.0); nuclear@2: tang_loc = get_attrib_loc(prog, "attr_tangent"); nuclear@2: } else { nuclear@2: bind_texture(tex, 0); nuclear@2: set_uniform_int(prog, "tex", 0); nuclear@2: } nuclear@2: nuclear@2: gl_matrix_mode(GL_TEXTURE); nuclear@2: gl_load_identity(); nuclear@2: gl_translatef(0, -fmod(t * tunnel_speed, 1.0), 0); nuclear@2: nuclear@2: gl_begin(GL_QUADS); nuclear@2: gl_color3f(1.0, 1.0, 1.0); nuclear@2: nuclear@2: du = 1.0 / sides; nuclear@2: dv = 1.0 / segm; nuclear@2: nuclear@2: for(i=0; i 1.0 ? 1.0 : alpha); nuclear@2: nuclear@2: gl_texcoord2f(0, 1); nuclear@2: gl_vertex3f(-1, -0.2, 0); nuclear@2: nuclear@2: gl_texcoord2f(1, 1); nuclear@2: gl_vertex3f(1, -0.2, 0); nuclear@2: nuclear@2: gl_texcoord2f(1, 0); nuclear@2: gl_vertex3f(1, 0.2, 0); nuclear@2: nuclear@2: gl_texcoord2f(0, 0); nuclear@2: gl_vertex3f(-1, 0.2, 0); nuclear@2: gl_end(); nuclear@2: nuclear@2: bind_texture(0, 0); nuclear@2: glDisable(GL_BLEND); nuclear@2: nuclear@2: gl_pop_matrix(); nuclear@2: } nuclear@2: nuclear@2: nuclear@2: static void worm(float t, float z, float *tx, float *ty) nuclear@2: { nuclear@2: float x, y; nuclear@2: x = sin(t) + cos(t + z) + sin(t * 2.0 + z) / 2.0; nuclear@2: y = cos(t) + sin(t + z) + cos(t * 2.0 + z) / 2.0; nuclear@2: nuclear@2: *tx = x * 0.5; nuclear@2: *ty = y * 0.5; nuclear@2: } nuclear@2: nuclear@2: nuclear@2: void reshape(int x, int y) nuclear@2: { nuclear@2: glViewport(0, 0, x, y); nuclear@2: nuclear@4: float aspect = (float)x / (float)y; nuclear@4: float maxfov = 40.0; nuclear@4: float vfov = aspect > 1.0 ? maxfov / aspect : maxfov; nuclear@4: nuclear@4: cam_fov(vfov); nuclear@4: nuclear@2: gl_matrix_mode(GL_PROJECTION); nuclear@2: gl_load_identity(); nuclear@4: glu_perspective(vfov, aspect, 0.5, 500.0); nuclear@2: nuclear@2: view_xsz = x; nuclear@2: view_ysz = y; nuclear@6: nuclear@6: ui_reshape(x, y); nuclear@6: } nuclear@6: nuclear@6: void mouse_button(int bn, int press, int x, int y) nuclear@6: { nuclear@6: if(show_opt) { nuclear@6: ui_button(bn, press, x, y); nuclear@6: } nuclear@6: } nuclear@6: nuclear@6: void mouse_motion(int x, int y) nuclear@6: { nuclear@6: if(show_opt) { nuclear@6: ui_motion(x, y); nuclear@6: } nuclear@2: } nuclear@2: nuclear@2: static unsigned int get_shader_program(const char *vfile, const char *pfile) nuclear@2: { nuclear@2: unsigned int prog, vs, ps; nuclear@2: nuclear@2: if(!(vs = get_vertex_shader(find_resource(vfile, 0, 0)))) { nuclear@2: return 0; nuclear@2: } nuclear@2: if(!(ps = get_pixel_shader(find_resource(pfile, 0, 0)))) { nuclear@2: return 0; nuclear@2: } nuclear@2: nuclear@2: if(!(prog = create_program_link(vs, ps))) { nuclear@2: return 0; nuclear@2: } nuclear@2: return prog; nuclear@2: } nuclear@2: nuclear@2: nuclear@2: #ifdef IPHONE nuclear@2: #include nuclear@2: nuclear@2: static float get_sec(void) nuclear@2: { nuclear@2: static float first; nuclear@2: static int init; nuclear@2: nuclear@2: if(!init) { nuclear@2: init = 1; nuclear@2: first = CACurrentMediaTime(); nuclear@2: return 0.0f; nuclear@2: } nuclear@2: return CACurrentMediaTime() - first; nuclear@2: } nuclear@2: nuclear@2: #else nuclear@2: nuclear@2: static float get_sec(void) nuclear@2: { nuclear@2: return (float)glutGet(GLUT_ELAPSED_TIME) / 1000.0f; nuclear@2: } nuclear@2: #endif