cubemapper

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