cubemapper

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