cubemapper

view src/app.cc @ 5:614295b72341

minor fixes, and redundant code removal
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 30 Jul 2017 16:16:57 +0300
parents 2bfafdced01a
children
line source
1 /*
2 Cubemapper - a program for converting panoramic images into cubemaps
3 Copyright (C) 2017 John Tsiombikas <nuclear@member.fsf.org>
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <math.h>
22 #include <assert.h>
23 #include <imago2.h>
24 #include "app.h"
25 #include "opengl.h"
26 #include "texture.h"
27 #include "mesh.h"
28 #include "meshgen.h"
30 static void draw_equilateral();
31 static void draw_cubemap();
32 static bool parse_args(int argc, char **argv);
34 static const char *img_fname, *img_suffix;
35 static float cam_theta, cam_phi;
37 static Texture *tex;
38 static Mesh *mesh;
40 static int win_width, win_height;
41 static int show_cubemap;
43 static unsigned int fbo;
44 static unsigned int cube_tex;
45 static int cube_size;
48 bool app_init(int argc, char **argv)
49 {
50 if(!parse_args(argc, argv)) {
51 return false;
52 }
53 if(!img_fname) {
54 fprintf(stderr, "please specify an equilateral panoramic image\n");
55 return false;
56 }
58 if(!init_opengl()) {
59 return false;
60 }
62 glEnable(GL_MULTISAMPLE);
64 Mesh::use_custom_sdr_attr = false;
65 mesh = new Mesh;
66 gen_sphere(mesh, 1.0, 80, 40);
67 mesh->flip();
68 Mat4 xform;
69 xform.rotation_y(-M_PI / 2.0); // rotate the sphere to face the "front" part of the image
70 mesh->apply_xform(xform, xform);
72 xform.scaling(-1, 1, 1); // flip horizontal texcoord since we're inside the sphere
73 mesh->texcoord_apply_xform(xform);
75 tex = new Texture;
76 if(!tex->load(img_fname)) {
77 return false;
78 }
79 printf("loaded image: %dx%d\n", tex->get_width(), tex->get_height());
81 if(!(img_suffix = strrchr(img_fname, '.'))) {
82 img_suffix = ".jpg";
83 }
85 // create cubemap
86 cube_size = tex->get_height();
87 glGenTextures(1, &cube_tex);
88 glBindTexture(GL_TEXTURE_CUBE_MAP, cube_tex);
89 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
90 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
91 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
92 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
93 glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
95 for(int i=0; i<6; i++) {
96 glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB16F, cube_size, cube_size,
97 0, GL_RGB, GL_FLOAT, 0);
98 }
101 // create fbo
102 glGenFramebuffers(1, &fbo);
104 // tex-gen for cubemap visualization
105 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
106 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
107 glTexGeni(GL_R, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR);
108 float planes[][4] = {{1, 0, 0, 0}, {0, 1, 0, 0}, {0, 0, 1, 0}};
109 glTexGenfv(GL_S, GL_OBJECT_PLANE, planes[0]);
110 glTexGenfv(GL_T, GL_OBJECT_PLANE, planes[1]);
111 glTexGenfv(GL_R, GL_OBJECT_PLANE, planes[2]);
112 return true;
113 }
115 void app_cleanup()
116 {
117 delete mesh;
118 delete tex;
119 }
121 void app_draw()
122 {
123 glClear(GL_COLOR_BUFFER_BIT);
125 Mat4 view_matrix;
126 view_matrix.pre_rotate_x(deg_to_rad(cam_phi));
127 view_matrix.pre_rotate_y(deg_to_rad(cam_theta));
129 glMatrixMode(GL_MODELVIEW);
130 glLoadMatrixf(view_matrix[0]);
132 if(show_cubemap) {
133 draw_cubemap();
135 glColor3f(0, 0, 0);
136 app_print_text(10, 10, "cubemap");
137 glColor3f(0, 0.8, 1);
138 app_print_text(8, 13, "cubemap");
139 } else {
140 draw_equilateral();
142 glColor3f(0, 0, 0);
143 app_print_text(10, 10, "equilateral");
144 glColor3f(1, 0.8, 0);
145 app_print_text(8, 13, "equilateral");
146 }
147 glColor3f(1, 1, 1);
149 app_swap_buffers();
150 assert(glGetError() == GL_NO_ERROR);
151 }
153 void render_cubemap()
154 {
155 printf("rendering cubemap %dx%d\n", cube_size, cube_size);
157 float *pixels = new float[cube_size * cube_size * 3];
159 glViewport(0, 0, cube_size, cube_size);
161 Mat4 viewmat[6];
162 viewmat[0].rotation_y(deg_to_rad(90)); // +X
163 viewmat[1].rotation_y(deg_to_rad(-90)); // -X
164 viewmat[2].rotation_x(deg_to_rad(90)); // +Y
165 viewmat[2].rotate_y(deg_to_rad(180));
166 viewmat[3].rotation_x(deg_to_rad(-90)); // -Y
167 viewmat[3].rotate_y(deg_to_rad(180));
168 viewmat[4].rotation_y(deg_to_rad(180)); // +Z
170 // this must coincide with the order of GL_TEXTURE_CUBE_MAP_* values
171 static const char *fname_pattern[] = {
172 "cubemap_px%s",
173 "cubemap_nx%s",
174 "cubemap_py%s",
175 "cubemap_ny%s",
176 "cubemap_pz%s",
177 "cubemap_nz%s"
178 };
179 static char fname[64];
181 glMatrixMode(GL_PROJECTION);
182 glPushMatrix();
183 glLoadIdentity();
184 gluPerspective(90, 1.0, 0.5, 500.0);
185 glScalef(-1, -1, 1);
187 glBindFramebuffer(GL_FRAMEBUFFER, fbo);
189 for(int i=0; i<6; i++) {
190 glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0,
191 GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, cube_tex, 0);
193 glClear(GL_COLOR_BUFFER_BIT);
195 glMatrixMode(GL_MODELVIEW);
196 glLoadMatrixf(viewmat[i][0]);
198 draw_equilateral();
200 glGetTexImage(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, GL_RGB, GL_FLOAT, pixels);
202 sprintf(fname, fname_pattern[i], img_suffix);
203 if(img_save_pixels(fname, pixels, cube_size, cube_size, IMG_FMT_RGBF) == -1) {
204 fprintf(stderr, "failed to save %dx%d image: %s\n", cube_size, cube_size, fname);
205 }
206 }
208 glBindFramebuffer(GL_FRAMEBUFFER, 0);
209 glViewport(0, 0, win_width, win_height);
211 glMatrixMode(GL_PROJECTION);
212 glPopMatrix();
214 delete [] pixels;
216 glBindTexture(GL_TEXTURE_CUBE_MAP, cube_tex);
217 glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
218 }
220 static void draw_equilateral()
221 {
222 tex->bind();
223 glEnable(GL_TEXTURE_2D);
224 mesh->draw();
225 glDisable(GL_TEXTURE_2D);
226 }
228 static void draw_cubemap()
229 {
230 glPushAttrib(GL_ENABLE_BIT);
232 glBindTexture(GL_TEXTURE_CUBE_MAP, cube_tex);
233 glEnable(GL_TEXTURE_CUBE_MAP);
234 glEnable(GL_TEXTURE_GEN_S);
235 glEnable(GL_TEXTURE_GEN_T);
236 glEnable(GL_TEXTURE_GEN_R);
238 mesh->draw();
240 glPopAttrib();
241 }
243 void app_reshape(int x, int y)
244 {
245 glViewport(0, 0, x, y);
247 glMatrixMode(GL_PROJECTION);
248 glLoadIdentity();
249 gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0);
251 win_width = x;
252 win_height = y;
253 }
255 void app_keyboard(int key, bool press)
256 {
257 if(press) {
258 switch(key) {
259 case 27:
260 app_quit();
261 break;
263 case ' ':
264 show_cubemap = !show_cubemap;
265 app_redisplay();
266 break;
268 case 'c':
269 render_cubemap();
270 show_cubemap = 1;
271 app_redisplay();
272 break;
273 }
274 }
275 }
277 static float prev_x, prev_y;
278 static bool bnstate[16];
280 void app_mouse_button(int bn, bool press, int x, int y)
281 {
282 if(bn < (int)(sizeof bnstate / sizeof *bnstate)) {
283 bnstate[bn] = press;
284 }
285 prev_x = x;
286 prev_y = y;
287 }
289 void app_mouse_motion(int x, int y)
290 {
291 float dx = x - prev_x;
292 float dy = y - prev_y;
293 prev_x = x;
294 prev_y = y;
296 if(!dx && !dy) return;
298 if(bnstate[0]) {
299 cam_theta += dx * 0.5;
300 cam_phi += dy * 0.5;
302 if(cam_phi < -90) cam_phi = -90;
303 if(cam_phi > 90) cam_phi = 90;
304 app_redisplay();
305 }
306 }
308 static bool parse_args(int argc, char **argv)
309 {
310 for(int i=1; i<argc; i++) {
311 if(argv[i][0] == '-') {
312 fprintf(stderr, "invalid option: %s\n", argv[i]);
313 return false;
314 } else {
315 if(img_fname) {
316 fprintf(stderr, "unexpected option: %s\n", argv[i]);
317 return false;
318 }
319 img_fname = argv[i];
320 }
321 }
323 return true;
324 }