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 }
|