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