cubemapper
diff src/app.cc @ 0:8fc9e1d3aad2
initial commit
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 27 Jul 2017 20:36:12 +0300 |
parents | |
children | d7a29cb7ac8d |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/src/app.cc Thu Jul 27 20:36:12 2017 +0300 1.3 @@ -0,0 +1,243 @@ 1.4 +#include <stdio.h> 1.5 +#include <stdlib.h> 1.6 +#include <string.h> 1.7 +#include <math.h> 1.8 +#include <assert.h> 1.9 +#include <imago2.h> 1.10 +#include "app.h" 1.11 +#include "opengl.h" 1.12 +#include "texture.h" 1.13 +#include "mesh.h" 1.14 +#include "meshgen.h" 1.15 + 1.16 +static void draw_scene(); // both near and infinite parts 1.17 +static void draw_scene_near(); // near scene: regular objects affected by parallax shift and translation 1.18 +// infinity scene: objects conceptually at infinity, not affected by parallax shift and translation 1.19 +static void draw_scene_inf(); 1.20 +static bool parse_args(int argc, char **argv); 1.21 + 1.22 +static const char *img_fname; 1.23 +static float cam_theta, cam_phi; 1.24 + 1.25 +static Texture *pano_tex; 1.26 +static Mesh *pano_mesh; 1.27 + 1.28 +static int win_width, win_height; 1.29 + 1.30 + 1.31 +bool app_init(int argc, char **argv) 1.32 +{ 1.33 + if(!parse_args(argc, argv)) { 1.34 + return false; 1.35 + } 1.36 + if(!img_fname) { 1.37 + fprintf(stderr, "please specify an equilateral panoramic image\n"); 1.38 + return false; 1.39 + } 1.40 + 1.41 + if(!init_opengl()) { 1.42 + return false; 1.43 + } 1.44 + 1.45 + glEnable(GL_CULL_FACE); 1.46 + 1.47 + if(GLEW_ARB_framebuffer_sRGB) { 1.48 + glGetError(); // discard previous errors 1.49 + glEnable(GL_FRAMEBUFFER_SRGB); 1.50 + if(glGetError() != GL_NO_ERROR) { 1.51 + fprintf(stderr, "failed to enable sRGB framebuffer\n"); 1.52 + } 1.53 + } 1.54 + 1.55 + Mesh::use_custom_sdr_attr = false; 1.56 + pano_mesh = new Mesh; 1.57 + gen_sphere(pano_mesh, 1.0, 80, 40); 1.58 + pano_mesh->flip(); 1.59 + Mat4 xform; 1.60 + xform.rotation_y(-M_PI / 2.0); // rotate the sphere to face the "front" part of the image 1.61 + pano_mesh->apply_xform(xform, xform); 1.62 + 1.63 + xform.scaling(-1, 1, 1); // flip horizontal texcoord since we're inside the sphere 1.64 + pano_mesh->texcoord_apply_xform(xform); 1.65 + 1.66 + pano_tex = new Texture; 1.67 + if(!pano_tex->load(img_fname)) { 1.68 + return false; 1.69 + } 1.70 + return true; 1.71 +} 1.72 + 1.73 +void app_cleanup() 1.74 +{ 1.75 + delete pano_mesh; 1.76 + delete pano_tex; 1.77 +} 1.78 + 1.79 +void app_draw() 1.80 +{ 1.81 + glClear(GL_COLOR_BUFFER_BIT); 1.82 + 1.83 + Mat4 view_matrix; 1.84 + view_matrix.pre_rotate_x(deg_to_rad(cam_phi)); 1.85 + view_matrix.pre_rotate_y(deg_to_rad(cam_theta)); 1.86 + 1.87 + glMatrixMode(GL_MODELVIEW); 1.88 + glLoadMatrixf(view_matrix[0]); 1.89 + 1.90 + draw_scene(); 1.91 + 1.92 + app_swap_buffers(); 1.93 + assert(glGetError() == GL_NO_ERROR); 1.94 +} 1.95 + 1.96 +void render_cubemap() 1.97 +{ 1.98 + int fbsize = win_width < win_height ? win_width : win_height; 1.99 + float *pixels = new float[fbsize * fbsize * 3]; 1.100 + 1.101 + glViewport(0, 0, fbsize, fbsize); 1.102 + 1.103 + Mat4 viewmat[6]; 1.104 + viewmat[0].rotation_y(deg_to_rad(90)); // +X 1.105 + viewmat[1].rotation_x(deg_to_rad(-90)); // +Y 1.106 + viewmat[2].rotation_y(deg_to_rad(180)); // +Z 1.107 + viewmat[3].rotation_y(deg_to_rad(-90)); // -X 1.108 + viewmat[4].rotation_x(deg_to_rad(90)); // -Y 1.109 + 1.110 + static const char *fname[] = { 1.111 + "cubemap_px.jpg", 1.112 + "cubemap_py.jpg", 1.113 + "cubemap_pz.jpg", 1.114 + "cubemap_nx.jpg", 1.115 + "cubemap_ny.jpg", 1.116 + "cubemap_nz.jpg" 1.117 + }; 1.118 + 1.119 + glMatrixMode(GL_PROJECTION); 1.120 + glLoadIdentity(); 1.121 + gluPerspective(45, 1.0, 0.5, 500.0); 1.122 + 1.123 + for(int i=0; i<6; i++) { 1.124 + glClear(GL_COLOR_BUFFER_BIT); 1.125 + 1.126 + glMatrixMode(GL_MODELVIEW); 1.127 + glLoadMatrixf(viewmat[i][0]); 1.128 + 1.129 + draw_scene(); 1.130 + 1.131 + glReadPixels(0, 0, fbsize, fbsize, GL_RGB, GL_FLOAT, pixels); 1.132 + if(img_save_pixels(fname[i], pixels, fbsize, fbsize, IMG_FMT_RGBF) == -1) { 1.133 + fprintf(stderr, "failed to save %dx%d image: %s\n", fbsize, fbsize, fname[i]); 1.134 + break; 1.135 + } 1.136 + } 1.137 + 1.138 + glViewport(0, 0, win_width, win_height); 1.139 + 1.140 + delete [] pixels; 1.141 +} 1.142 + 1.143 +// both near and infinite parts (see below) 1.144 +static void draw_scene() 1.145 +{ 1.146 + draw_scene_inf(); 1.147 + draw_scene_near(); 1.148 +} 1.149 + 1.150 +// infinity scene: objects conceptually at infinity, not affected by parallax shift and translation 1.151 +static void draw_scene_inf() 1.152 +{ 1.153 + pano_tex->bind(); 1.154 + glEnable(GL_TEXTURE_2D); 1.155 + pano_mesh->draw(); 1.156 + glDisable(GL_TEXTURE_2D); 1.157 +} 1.158 + 1.159 +// near scene: regular objects affected by parallax shift and translation 1.160 +static void draw_scene_near() 1.161 +{ 1.162 +} 1.163 + 1.164 +void app_reshape(int x, int y) 1.165 +{ 1.166 + glViewport(0, 0, x, y); 1.167 + 1.168 + glMatrixMode(GL_PROJECTION); 1.169 + glLoadIdentity(); 1.170 + gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0); 1.171 + 1.172 + win_width = x; 1.173 + win_height = y; 1.174 +} 1.175 + 1.176 +void app_keyboard(int key, bool press) 1.177 +{ 1.178 + if(press) { 1.179 + switch(key) { 1.180 + case 27: 1.181 + app_quit(); 1.182 + break; 1.183 + 1.184 + case 's': 1.185 + printf("rendering cubemap\n"); 1.186 + render_cubemap(); 1.187 + break; 1.188 + } 1.189 + } 1.190 +} 1.191 + 1.192 +static float prev_x, prev_y; 1.193 +static bool bnstate[16]; 1.194 + 1.195 +void app_mouse_button(int bn, bool press, int x, int y) 1.196 +{ 1.197 + if(bn < (int)(sizeof bnstate / sizeof *bnstate)) { 1.198 + bnstate[bn] = press; 1.199 + } 1.200 + prev_x = x; 1.201 + prev_y = y; 1.202 +} 1.203 + 1.204 +void app_mouse_motion(int x, int y) 1.205 +{ 1.206 + float dx = x - prev_x; 1.207 + float dy = y - prev_y; 1.208 + prev_x = x; 1.209 + prev_y = y; 1.210 + 1.211 + if(!dx && !dy) return; 1.212 + 1.213 + if(bnstate[0]) { 1.214 + cam_theta += dx * 0.5; 1.215 + cam_phi += dy * 0.5; 1.216 + 1.217 + if(cam_phi < -90) cam_phi = -90; 1.218 + if(cam_phi > 90) cam_phi = 90; 1.219 + app_redisplay(); 1.220 + } 1.221 +} 1.222 + 1.223 +static bool parse_args(int argc, char **argv) 1.224 +{ 1.225 + for(int i=1; i<argc; i++) { 1.226 + if(argv[i][0] == '-') { 1.227 + /* 1.228 + } else if(strcmp(argv[i], "-help") == 0) { 1.229 + printf("usage: %s [options]\noptions:\n", argv[0]); 1.230 + printf(" -help: print usage information and exit\n"); 1.231 + exit(0); 1.232 + } else {*/ 1.233 + fprintf(stderr, "invalid option: %s\n", argv[i]); 1.234 + return false; 1.235 + //} 1.236 + } else { 1.237 + if(img_fname) { 1.238 + fprintf(stderr, "unexpected option: %s\n", argv[i]); 1.239 + return false; 1.240 + } 1.241 + img_fname = argv[i]; 1.242 + } 1.243 + } 1.244 + 1.245 + return true; 1.246 +}