cubemapper

annotate src/app.cc @ 1:d7a29cb7ac8d

resize to the final cubemap face size
author John Tsiombikas <nuclear@member.fsf.org>
date Fri, 28 Jul 2017 07:44:35 +0300
parents 8fc9e1d3aad2
children e308561f9889
rev   line source
nuclear@0 1 #include <stdio.h>
nuclear@0 2 #include <stdlib.h>
nuclear@0 3 #include <string.h>
nuclear@0 4 #include <math.h>
nuclear@0 5 #include <assert.h>
nuclear@0 6 #include <imago2.h>
nuclear@0 7 #include "app.h"
nuclear@0 8 #include "opengl.h"
nuclear@0 9 #include "texture.h"
nuclear@0 10 #include "mesh.h"
nuclear@0 11 #include "meshgen.h"
nuclear@0 12
nuclear@0 13 static void draw_scene(); // both near and infinite parts
nuclear@0 14 static void draw_scene_near(); // near scene: regular objects affected by parallax shift and translation
nuclear@0 15 // infinity scene: objects conceptually at infinity, not affected by parallax shift and translation
nuclear@0 16 static void draw_scene_inf();
nuclear@0 17 static bool parse_args(int argc, char **argv);
nuclear@0 18
nuclear@1 19 static void flip_image(float *pixels, int xsz, int ysz);
nuclear@1 20
nuclear@0 21 static const char *img_fname;
nuclear@0 22 static float cam_theta, cam_phi;
nuclear@0 23
nuclear@0 24 static Texture *pano_tex;
nuclear@0 25 static Mesh *pano_mesh;
nuclear@0 26
nuclear@0 27 static int win_width, win_height;
nuclear@0 28
nuclear@0 29
nuclear@0 30 bool app_init(int argc, char **argv)
nuclear@0 31 {
nuclear@0 32 if(!parse_args(argc, argv)) {
nuclear@0 33 return false;
nuclear@0 34 }
nuclear@0 35 if(!img_fname) {
nuclear@0 36 fprintf(stderr, "please specify an equilateral panoramic image\n");
nuclear@0 37 return false;
nuclear@0 38 }
nuclear@0 39
nuclear@0 40 if(!init_opengl()) {
nuclear@0 41 return false;
nuclear@0 42 }
nuclear@0 43
nuclear@0 44 glEnable(GL_CULL_FACE);
nuclear@0 45
nuclear@0 46 if(GLEW_ARB_framebuffer_sRGB) {
nuclear@0 47 glGetError(); // discard previous errors
nuclear@0 48 glEnable(GL_FRAMEBUFFER_SRGB);
nuclear@0 49 if(glGetError() != GL_NO_ERROR) {
nuclear@0 50 fprintf(stderr, "failed to enable sRGB framebuffer\n");
nuclear@0 51 }
nuclear@0 52 }
nuclear@0 53
nuclear@0 54 Mesh::use_custom_sdr_attr = false;
nuclear@0 55 pano_mesh = new Mesh;
nuclear@0 56 gen_sphere(pano_mesh, 1.0, 80, 40);
nuclear@0 57 pano_mesh->flip();
nuclear@0 58 Mat4 xform;
nuclear@0 59 xform.rotation_y(-M_PI / 2.0); // rotate the sphere to face the "front" part of the image
nuclear@0 60 pano_mesh->apply_xform(xform, xform);
nuclear@0 61
nuclear@0 62 xform.scaling(-1, 1, 1); // flip horizontal texcoord since we're inside the sphere
nuclear@0 63 pano_mesh->texcoord_apply_xform(xform);
nuclear@0 64
nuclear@0 65 pano_tex = new Texture;
nuclear@0 66 if(!pano_tex->load(img_fname)) {
nuclear@0 67 return false;
nuclear@0 68 }
nuclear@1 69 printf("loaded image: %dx%d\n", pano_tex->get_width(), pano_tex->get_height());
nuclear@0 70 return true;
nuclear@0 71 }
nuclear@0 72
nuclear@0 73 void app_cleanup()
nuclear@0 74 {
nuclear@0 75 delete pano_mesh;
nuclear@0 76 delete pano_tex;
nuclear@0 77 }
nuclear@0 78
nuclear@0 79 void app_draw()
nuclear@0 80 {
nuclear@0 81 glClear(GL_COLOR_BUFFER_BIT);
nuclear@0 82
nuclear@0 83 Mat4 view_matrix;
nuclear@0 84 view_matrix.pre_rotate_x(deg_to_rad(cam_phi));
nuclear@0 85 view_matrix.pre_rotate_y(deg_to_rad(cam_theta));
nuclear@0 86
nuclear@0 87 glMatrixMode(GL_MODELVIEW);
nuclear@0 88 glLoadMatrixf(view_matrix[0]);
nuclear@0 89
nuclear@0 90 draw_scene();
nuclear@0 91
nuclear@0 92 app_swap_buffers();
nuclear@0 93 assert(glGetError() == GL_NO_ERROR);
nuclear@0 94 }
nuclear@0 95
nuclear@0 96 void render_cubemap()
nuclear@0 97 {
nuclear@0 98 int fbsize = win_width < win_height ? win_width : win_height;
nuclear@0 99 float *pixels = new float[fbsize * fbsize * 3];
nuclear@0 100
nuclear@0 101 glViewport(0, 0, fbsize, fbsize);
nuclear@0 102
nuclear@0 103 Mat4 viewmat[6];
nuclear@0 104 viewmat[0].rotation_y(deg_to_rad(90)); // +X
nuclear@0 105 viewmat[1].rotation_x(deg_to_rad(-90)); // +Y
nuclear@0 106 viewmat[2].rotation_y(deg_to_rad(180)); // +Z
nuclear@0 107 viewmat[3].rotation_y(deg_to_rad(-90)); // -X
nuclear@0 108 viewmat[4].rotation_x(deg_to_rad(90)); // -Y
nuclear@0 109
nuclear@0 110 static const char *fname[] = {
nuclear@0 111 "cubemap_px.jpg",
nuclear@0 112 "cubemap_py.jpg",
nuclear@0 113 "cubemap_pz.jpg",
nuclear@0 114 "cubemap_nx.jpg",
nuclear@0 115 "cubemap_ny.jpg",
nuclear@0 116 "cubemap_nz.jpg"
nuclear@0 117 };
nuclear@0 118
nuclear@0 119 glMatrixMode(GL_PROJECTION);
nuclear@0 120 glLoadIdentity();
nuclear@0 121 gluPerspective(45, 1.0, 0.5, 500.0);
nuclear@0 122
nuclear@0 123 for(int i=0; i<6; i++) {
nuclear@0 124 glClear(GL_COLOR_BUFFER_BIT);
nuclear@0 125
nuclear@0 126 glMatrixMode(GL_MODELVIEW);
nuclear@0 127 glLoadMatrixf(viewmat[i][0]);
nuclear@0 128
nuclear@0 129 draw_scene();
nuclear@0 130
nuclear@0 131 glReadPixels(0, 0, fbsize, fbsize, GL_RGB, GL_FLOAT, pixels);
nuclear@1 132 flip_image(pixels, fbsize, fbsize);
nuclear@1 133
nuclear@0 134 if(img_save_pixels(fname[i], pixels, fbsize, fbsize, IMG_FMT_RGBF) == -1) {
nuclear@0 135 fprintf(stderr, "failed to save %dx%d image: %s\n", fbsize, fbsize, fname[i]);
nuclear@0 136 break;
nuclear@0 137 }
nuclear@0 138 }
nuclear@0 139
nuclear@0 140 glViewport(0, 0, win_width, win_height);
nuclear@0 141
nuclear@0 142 delete [] pixels;
nuclear@0 143 }
nuclear@0 144
nuclear@0 145 // both near and infinite parts (see below)
nuclear@0 146 static void draw_scene()
nuclear@0 147 {
nuclear@0 148 draw_scene_inf();
nuclear@0 149 draw_scene_near();
nuclear@0 150 }
nuclear@0 151
nuclear@0 152 // infinity scene: objects conceptually at infinity, not affected by parallax shift and translation
nuclear@0 153 static void draw_scene_inf()
nuclear@0 154 {
nuclear@0 155 pano_tex->bind();
nuclear@0 156 glEnable(GL_TEXTURE_2D);
nuclear@0 157 pano_mesh->draw();
nuclear@0 158 glDisable(GL_TEXTURE_2D);
nuclear@0 159 }
nuclear@0 160
nuclear@0 161 // near scene: regular objects affected by parallax shift and translation
nuclear@0 162 static void draw_scene_near()
nuclear@0 163 {
nuclear@0 164 }
nuclear@0 165
nuclear@0 166 void app_reshape(int x, int y)
nuclear@0 167 {
nuclear@0 168 glViewport(0, 0, x, y);
nuclear@0 169
nuclear@0 170 glMatrixMode(GL_PROJECTION);
nuclear@0 171 glLoadIdentity();
nuclear@0 172 gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0);
nuclear@0 173
nuclear@0 174 win_width = x;
nuclear@0 175 win_height = y;
nuclear@0 176 }
nuclear@0 177
nuclear@0 178 void app_keyboard(int key, bool press)
nuclear@0 179 {
nuclear@1 180 int cubemap_size;
nuclear@1 181
nuclear@0 182 if(press) {
nuclear@0 183 switch(key) {
nuclear@0 184 case 27:
nuclear@0 185 app_quit();
nuclear@0 186 break;
nuclear@0 187
nuclear@1 188 case ' ':
nuclear@1 189 cubemap_size = pano_tex->get_width() / 4;
nuclear@1 190 app_resize(cubemap_size, cubemap_size);
nuclear@1 191 break;
nuclear@1 192
nuclear@0 193 case 's':
nuclear@0 194 printf("rendering cubemap\n");
nuclear@0 195 render_cubemap();
nuclear@0 196 break;
nuclear@0 197 }
nuclear@0 198 }
nuclear@0 199 }
nuclear@0 200
nuclear@0 201 static float prev_x, prev_y;
nuclear@0 202 static bool bnstate[16];
nuclear@0 203
nuclear@0 204 void app_mouse_button(int bn, bool press, int x, int y)
nuclear@0 205 {
nuclear@0 206 if(bn < (int)(sizeof bnstate / sizeof *bnstate)) {
nuclear@0 207 bnstate[bn] = press;
nuclear@0 208 }
nuclear@0 209 prev_x = x;
nuclear@0 210 prev_y = y;
nuclear@0 211 }
nuclear@0 212
nuclear@0 213 void app_mouse_motion(int x, int y)
nuclear@0 214 {
nuclear@0 215 float dx = x - prev_x;
nuclear@0 216 float dy = y - prev_y;
nuclear@0 217 prev_x = x;
nuclear@0 218 prev_y = y;
nuclear@0 219
nuclear@0 220 if(!dx && !dy) return;
nuclear@0 221
nuclear@0 222 if(bnstate[0]) {
nuclear@0 223 cam_theta += dx * 0.5;
nuclear@0 224 cam_phi += dy * 0.5;
nuclear@0 225
nuclear@0 226 if(cam_phi < -90) cam_phi = -90;
nuclear@0 227 if(cam_phi > 90) cam_phi = 90;
nuclear@0 228 app_redisplay();
nuclear@0 229 }
nuclear@0 230 }
nuclear@0 231
nuclear@0 232 static bool parse_args(int argc, char **argv)
nuclear@0 233 {
nuclear@0 234 for(int i=1; i<argc; i++) {
nuclear@0 235 if(argv[i][0] == '-') {
nuclear@0 236 /*
nuclear@0 237 } else if(strcmp(argv[i], "-help") == 0) {
nuclear@0 238 printf("usage: %s [options]\noptions:\n", argv[0]);
nuclear@0 239 printf(" -help: print usage information and exit\n");
nuclear@0 240 exit(0);
nuclear@0 241 } else {*/
nuclear@0 242 fprintf(stderr, "invalid option: %s\n", argv[i]);
nuclear@0 243 return false;
nuclear@0 244 //}
nuclear@0 245 } else {
nuclear@0 246 if(img_fname) {
nuclear@0 247 fprintf(stderr, "unexpected option: %s\n", argv[i]);
nuclear@0 248 return false;
nuclear@0 249 }
nuclear@0 250 img_fname = argv[i];
nuclear@0 251 }
nuclear@0 252 }
nuclear@0 253
nuclear@0 254 return true;
nuclear@0 255 }
nuclear@1 256
nuclear@1 257 static void flip_image(float *pixels, int xsz, int ysz)
nuclear@1 258 {
nuclear@1 259 float *top_ptr = pixels;
nuclear@1 260 float *bot_ptr = pixels + xsz * (ysz - 1) * 3;
nuclear@1 261 float *line = new float[xsz * 3];
nuclear@1 262 int scansz = xsz * 3 * sizeof(float);
nuclear@1 263
nuclear@1 264 for(int i=0; i<ysz / 2; i++) {
nuclear@1 265 memcpy(line, top_ptr, scansz);
nuclear@1 266 memcpy(top_ptr, bot_ptr, scansz);
nuclear@1 267 memcpy(bot_ptr, line, scansz);
nuclear@1 268 top_ptr += xsz * 3;
nuclear@1 269 bot_ptr -= xsz * 3;
nuclear@1 270 }
nuclear@1 271
nuclear@1 272 delete [] line;
nuclear@1 273 }