cubemapper

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