rev |
line source |
nuclear@0
|
1 #include <stdio.h>
|
nuclear@0
|
2 #include <stdlib.h>
|
nuclear@0
|
3 #include <assert.h>
|
nuclear@0
|
4 #include <vector>
|
nuclear@0
|
5 #include "opengl.h"
|
nuclear@0
|
6 #include <GL/glut.h>
|
nuclear@0
|
7 #include "scene.h"
|
nuclear@0
|
8 #include "meshgen.h"
|
nuclear@0
|
9 #include "pnoise.h"
|
nuclear@0
|
10 #include "image.h"
|
nuclear@0
|
11 #include "rng.h"
|
nuclear@0
|
12 #include "sdr.h"
|
nuclear@0
|
13 #include "audio/audio.h"
|
nuclear@0
|
14 #include "audio/ovstream.h"
|
nuclear@0
|
15 #include "dsys/dsys.h"
|
nuclear@0
|
16
|
nuclear@0
|
17 bool init();
|
nuclear@0
|
18 void cleanup();
|
nuclear@0
|
19 void display();
|
nuclear@0
|
20 void idle();
|
nuclear@0
|
21 void reshape(int x, int y);
|
nuclear@0
|
22 void keyb(unsigned char key, int x, int y);
|
nuclear@0
|
23 void mouse(int bn, int st, int x, int y);
|
nuclear@0
|
24 void motion(int x, int y);
|
nuclear@0
|
25
|
nuclear@0
|
26 float cam_theta, cam_phi = 25, cam_dist = 6;
|
nuclear@0
|
27 Scene *scn;
|
nuclear@0
|
28 bool wireframe;
|
nuclear@0
|
29 int num_shells = 64;
|
nuclear@0
|
30 float shell_scale = 1.015;
|
nuclear@0
|
31 bool anim = true;
|
nuclear@0
|
32 bool fullscr = true;
|
nuclear@0
|
33
|
nuclear@0
|
34 static std::vector<Image*> images;
|
nuclear@0
|
35 static Object *pkin_obj;
|
nuclear@0
|
36 static Mesh *pkin_mesh;
|
nuclear@0
|
37 static unsigned int pkin_tex;
|
nuclear@0
|
38
|
nuclear@0
|
39 static unsigned int sdr_spot;
|
nuclear@0
|
40
|
nuclear@0
|
41 static float ramp[3];
|
nuclear@0
|
42
|
nuclear@0
|
43
|
nuclear@0
|
44 static OggVorbisStream *music;
|
nuclear@0
|
45 static struct dsys_demo *demo;
|
nuclear@0
|
46
|
nuclear@0
|
47
|
nuclear@0
|
48 int main(int argc, char **argv)
|
nuclear@0
|
49 {
|
nuclear@0
|
50 glutInit(&argc, argv);
|
nuclear@0
|
51 glutInitWindowSize(1280, 720);
|
nuclear@0
|
52 glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
|
nuclear@0
|
53 glutCreateWindow("DBF Halloween 2015 compo entry");
|
nuclear@0
|
54
|
nuclear@0
|
55 if(argv[1]) {
|
nuclear@0
|
56 if(strcmp(argv[1], "-w") == 0 || strcmp(argv[1], "-windowed") == 0) {
|
nuclear@0
|
57 fullscr = false;
|
nuclear@0
|
58 } else {
|
nuclear@0
|
59 fprintf(stderr, "unrecognized argument: %s\nUse -w or -windowed to run in a window\n", argv[1]);
|
nuclear@0
|
60 return 1;
|
nuclear@0
|
61 }
|
nuclear@0
|
62 }
|
nuclear@0
|
63 if(fullscr) {
|
nuclear@0
|
64 glutFullScreen();
|
nuclear@0
|
65 }
|
nuclear@0
|
66
|
nuclear@0
|
67 glutDisplayFunc(display);
|
nuclear@0
|
68 glutIdleFunc(idle);
|
nuclear@0
|
69 glutReshapeFunc(reshape);
|
nuclear@0
|
70 glutKeyboardFunc(keyb);
|
nuclear@0
|
71 glutMouseFunc(mouse);
|
nuclear@0
|
72 glutMotionFunc(motion);
|
nuclear@0
|
73
|
nuclear@0
|
74 if(!init()) {
|
nuclear@0
|
75 return 1;
|
nuclear@0
|
76 }
|
nuclear@0
|
77 glutMainLoop();
|
nuclear@0
|
78 return 0;
|
nuclear@0
|
79 }
|
nuclear@0
|
80
|
nuclear@0
|
81 static float ground_func(float u, float v, void *cls)
|
nuclear@0
|
82 {
|
nuclear@0
|
83 return fbm2(u * 3.0, v * 3.0, 2) * 0.8;
|
nuclear@0
|
84 }
|
nuclear@0
|
85
|
nuclear@0
|
86 static Vector2 pumpkin_func(float u, float v, void *cls)
|
nuclear@0
|
87 {
|
nuclear@0
|
88 float theta = v * M_PI;
|
nuclear@0
|
89 float r = sin(theta) * 0.5 + 0.5;
|
nuclear@0
|
90
|
nuclear@0
|
91 // modulate a high-frequency short-amp wave along u to make the ribs(?)
|
nuclear@0
|
92 r += fabs(sin(u * M_PI * 12.0)) * 0.02;// + 1.0;
|
nuclear@0
|
93
|
nuclear@0
|
94 // throw some noise in there for good measure
|
nuclear@0
|
95 r += pnoise2(u * 16.0, v * 8.0, 16) * 0.05;// + 1.0;
|
nuclear@0
|
96
|
nuclear@0
|
97 float x = sin(theta) * r;
|
nuclear@0
|
98 float y = cos(theta) * r;
|
nuclear@0
|
99 return Vector2(x, y);
|
nuclear@0
|
100 }
|
nuclear@0
|
101
|
nuclear@0
|
102 #define CLAMP(x, a, b) std::max<float>(std::min<float>(x, b), a)
|
nuclear@0
|
103
|
nuclear@0
|
104 bool init()
|
nuclear@0
|
105 {
|
nuclear@0
|
106 if(init_opengl() == -1) {
|
nuclear@0
|
107 return false;
|
nuclear@0
|
108 }
|
nuclear@0
|
109 Mesh::use_custom_sdr_attr = false;
|
nuclear@0
|
110
|
nuclear@0
|
111 glEnable(GL_DEPTH_TEST);
|
nuclear@0
|
112 glEnable(GL_CULL_FACE);
|
nuclear@0
|
113 glEnable(GL_LIGHTING);
|
nuclear@0
|
114 glEnable(GL_NORMALIZE);
|
nuclear@0
|
115
|
nuclear@0
|
116 if(!(demo = dsys_open("data/demo.script"))) {
|
nuclear@0
|
117 fprintf(stderr, "failed to load sequencing file\n");
|
nuclear@0
|
118 return false;
|
nuclear@0
|
119 }
|
nuclear@0
|
120 for(int i=0; i<3; i++) {
|
nuclear@0
|
121 char name[16];
|
nuclear@0
|
122 sprintf(name, "ramp%d", i);
|
nuclear@0
|
123 struct dsys_event *ev = dsys_event(demo, name);
|
nuclear@0
|
124 if(ev) {
|
nuclear@0
|
125 printf("found event: %s\n", name);
|
nuclear@0
|
126 dsys_event_link(ev, ramp + i);
|
nuclear@0
|
127 }
|
nuclear@0
|
128 }
|
nuclear@0
|
129
|
nuclear@0
|
130
|
nuclear@0
|
131 if(!(sdr_spot = create_program_load("sdr/default.v.glsl", "sdr/spot.p.glsl"))) {
|
nuclear@0
|
132 return false;
|
nuclear@0
|
133 }
|
nuclear@0
|
134
|
nuclear@0
|
135 Matrix4x4 xform;
|
nuclear@0
|
136
|
nuclear@0
|
137 scn = new Scene;
|
nuclear@0
|
138
|
nuclear@0
|
139 Light *lt = new Light;
|
nuclear@0
|
140 lt->pos = Vector3(-10, 10, 10);
|
nuclear@0
|
141 scn->add_light(lt);
|
nuclear@0
|
142
|
nuclear@0
|
143 // floor
|
nuclear@0
|
144 Mesh *mesh = new Mesh;
|
nuclear@0
|
145 gen_heightmap(mesh, 20, 20, 50, 50, ground_func);
|
nuclear@0
|
146 xform.set_rotation(Vector3(-M_PI / 2.0, 0, 0));
|
nuclear@0
|
147 mesh->apply_xform(xform);
|
nuclear@0
|
148
|
nuclear@0
|
149 Object *obj = new Object;
|
nuclear@0
|
150 obj->set_mesh(mesh);
|
nuclear@0
|
151 obj->xform().set_translation(Vector3(0, -0.9, 0));
|
nuclear@0
|
152 obj->mtl.diffuse = Vector3(0.7, 0.7, 0.7);
|
nuclear@0
|
153 obj->set_shader(sdr_spot);
|
nuclear@0
|
154 scn->add_object(obj);
|
nuclear@0
|
155
|
nuclear@0
|
156 Image *img = new Image;
|
nuclear@0
|
157 if(!img->load("data/grass02.jpg")) {
|
nuclear@0
|
158 return false;
|
nuclear@0
|
159 }
|
nuclear@0
|
160 images.push_back(img);
|
nuclear@0
|
161 obj->tex_xform().set_scaling(Vector3(5.0, 10.0, 1.0));
|
nuclear@0
|
162 obj->set_texture(img->texture());
|
nuclear@0
|
163
|
nuclear@0
|
164 // pumpkin texture
|
nuclear@0
|
165 img = new Image;
|
nuclear@0
|
166 if(!img->create(1024, 512)) {
|
nuclear@0
|
167 return false;
|
nuclear@0
|
168 }
|
nuclear@0
|
169 images.push_back(img);
|
nuclear@0
|
170
|
nuclear@0
|
171 static const Vector3 pkin_col = Vector3(0.824, 0.325, 0.063);
|
nuclear@0
|
172 unsigned char *pptr = img->pixels;
|
nuclear@0
|
173 for(int i=0; i<img->height; i++) {
|
nuclear@0
|
174 float v = (float)i / (float)img->height;
|
nuclear@0
|
175 for(int j=0; j<img->width; j++) {
|
nuclear@0
|
176 float u = (float)j / (float)img->width;
|
nuclear@0
|
177
|
nuclear@0
|
178 float val = pfbm2(u * 64.0, v * 32.0, 3, 128) * 0.1 + 1.0;
|
nuclear@0
|
179 val *= fabs(sin(u * M_PI * 12.0)) * 0.2 + 0.8;
|
nuclear@0
|
180 Vector3 col = pkin_col * val;
|
nuclear@0
|
181
|
nuclear@0
|
182 *pptr++ = (int)(CLAMP(col.x, 0.0, 1.0) * 255.0f);
|
nuclear@0
|
183 *pptr++ = (int)(CLAMP(col.y, 0.0, 1.0) * 255.0f);
|
nuclear@0
|
184 *pptr++ = (int)(CLAMP(col.z, 0.0, 1.0) * 255.0f);
|
nuclear@0
|
185 *pptr++ = 255;
|
nuclear@0
|
186 }
|
nuclear@0
|
187 }
|
nuclear@0
|
188
|
nuclear@0
|
189 // pumpkin
|
nuclear@0
|
190 pkin_mesh = new Mesh;
|
nuclear@0
|
191 gen_revol(pkin_mesh, 64, 20, pumpkin_func);
|
nuclear@0
|
192
|
nuclear@0
|
193 pkin_obj = new Object;
|
nuclear@0
|
194 pkin_obj->xform().set_rotation(Vector3(DEG_TO_RAD(-10), DEG_TO_RAD(90), 0));
|
nuclear@0
|
195 pkin_obj->set_mesh(pkin_mesh);
|
nuclear@0
|
196 pkin_obj->set_texture(img->texture());
|
nuclear@0
|
197 obj->set_shader(sdr_spot);
|
nuclear@0
|
198 scn->add_object(pkin_obj);
|
nuclear@0
|
199
|
nuclear@0
|
200 int num_pumpkins = 20;
|
nuclear@0
|
201 float dtheta = 1.0 / (float)num_pumpkins;
|
nuclear@0
|
202
|
nuclear@0
|
203 for(int i=0; i<num_pumpkins; i++) {
|
nuclear@0
|
204 float theta = (((float)i + rng_frand() * 0.5) * dtheta) * 2.0 * M_PI * 2.0;
|
nuclear@0
|
205 float r = 5.0 * (float)i / (float)num_pumpkins + 4.0;
|
nuclear@0
|
206
|
nuclear@0
|
207 float x = cos(theta) * r;
|
nuclear@0
|
208 float y = sin(theta) * r;
|
nuclear@0
|
209
|
nuclear@0
|
210 float tu = (x + 10.0) / 20.0;
|
nuclear@0
|
211 float tv = (10.0 - y) / 20.0;
|
nuclear@0
|
212 float h = ground_func(tu, tv, 0);
|
nuclear@0
|
213
|
nuclear@0
|
214 obj = new Object;
|
nuclear@0
|
215 obj->xform().translate(Vector3(x, h - 0.5, y));
|
nuclear@0
|
216 obj->xform().rotate(Vector3(DEG_TO_RAD(rng_frand() * 40.0 - 20.0), rng_frand() * M_PI * 2.0, 0));
|
nuclear@0
|
217 obj->xform().scale(Vector3(0.7, 0.7, 0.7));
|
nuclear@0
|
218 obj->set_mesh(pkin_mesh);
|
nuclear@0
|
219 obj->set_texture(img->texture());
|
nuclear@0
|
220 obj->set_shader(sdr_spot);
|
nuclear@0
|
221 scn->add_object(obj);
|
nuclear@0
|
222 }
|
nuclear@0
|
223
|
nuclear@0
|
224 // pumpkin glow mask
|
nuclear@0
|
225 img = new Image;
|
nuclear@0
|
226 if(!img->load("data/pumpkin_mask_blured.png")) {
|
nuclear@0
|
227 return false;
|
nuclear@0
|
228 }
|
nuclear@0
|
229 images.push_back(img);
|
nuclear@0
|
230 pkin_tex = img->texture();
|
nuclear@0
|
231
|
nuclear@0
|
232 if(!init_audio()) {
|
nuclear@0
|
233 fprintf(stderr, "failed to initialize audio\n");
|
nuclear@0
|
234 return false;
|
nuclear@0
|
235 }
|
nuclear@0
|
236 music = new OggVorbisStream;
|
nuclear@0
|
237 if(!music->open("data/welcome_to_horrorland.ogg")) {
|
nuclear@0
|
238 fprintf(stderr, "failed to open music\n");
|
nuclear@0
|
239 return false;
|
nuclear@0
|
240 }
|
nuclear@0
|
241 music->play(AUDIO_PLAYMODE_LOOP);
|
nuclear@0
|
242
|
nuclear@0
|
243 return true;
|
nuclear@0
|
244 }
|
nuclear@0
|
245
|
nuclear@0
|
246 void cleanup()
|
nuclear@0
|
247 {
|
nuclear@0
|
248 music->stop();
|
nuclear@0
|
249 delete music;
|
nuclear@0
|
250 destroy_audio();
|
nuclear@0
|
251
|
nuclear@0
|
252 delete scn;
|
nuclear@0
|
253
|
nuclear@0
|
254 for(size_t i=0; i<images.size(); i++) {
|
nuclear@0
|
255 delete images[i];
|
nuclear@0
|
256 }
|
nuclear@0
|
257 images.clear();
|
nuclear@0
|
258 }
|
nuclear@0
|
259
|
nuclear@0
|
260 void display()
|
nuclear@0
|
261 {
|
nuclear@0
|
262 unsigned int msec = glutGet(GLUT_ELAPSED_TIME);
|
nuclear@0
|
263 float sec = (float)msec / 1000.0;
|
nuclear@0
|
264
|
nuclear@0
|
265 dsys_update(demo, dsys_msec_to_dtime(msec));
|
nuclear@0
|
266 if(!dsys_is_running(demo)) {
|
nuclear@0
|
267 exit(0);
|
nuclear@0
|
268 }
|
nuclear@0
|
269
|
nuclear@0
|
270 float offs[3];
|
nuclear@0
|
271
|
nuclear@0
|
272 if(anim) {
|
nuclear@0
|
273 float t = sec * 0.5;
|
nuclear@0
|
274 cam_theta = cos(t) * 35.0;// + fbm1(t * 6.0, 1) * 2.0;
|
nuclear@0
|
275 cam_phi = sin(t * 2.0) * 10.0 + 25.0;// + fbm1(t * 8.0, 1) * 3.0;
|
nuclear@0
|
276
|
nuclear@0
|
277 float mag = std::max(fmod(ramp[0], 1.0), std::max(fmod(ramp[1], 1.0), fmod(ramp[2], 1.0))) * 0.8 + 0.15;
|
nuclear@0
|
278 //printf("ramps: %g %g %g, mag: %g\n", ramp[0], ramp[1], ramp[2], mag);
|
nuclear@0
|
279 for(int i=0; i<3; i++) {
|
nuclear@0
|
280 offs[i] = turbulence1(sec * 4.0 + i, 2) * mag;
|
nuclear@0
|
281 }
|
nuclear@0
|
282 }
|
nuclear@0
|
283
|
nuclear@0
|
284 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
nuclear@0
|
285
|
nuclear@0
|
286 glMatrixMode(GL_MODELVIEW);
|
nuclear@0
|
287 glLoadIdentity();
|
nuclear@0
|
288 glTranslatef(0, 0, -cam_dist);
|
nuclear@0
|
289 glRotatef(cam_phi, 1, 0, 0);
|
nuclear@0
|
290 glRotatef(cam_theta, 0, 1, 0);
|
nuclear@0
|
291 glTranslatef(offs[0], offs[1], offs[2]);
|
nuclear@0
|
292
|
nuclear@0
|
293 scn->draw();
|
nuclear@0
|
294
|
nuclear@0
|
295 glPushAttrib(GL_ENABLE_BIT | GL_LIGHTING_BIT);
|
nuclear@0
|
296 glDisable(GL_CULL_FACE);
|
nuclear@0
|
297
|
nuclear@0
|
298 glDepthMask(0);
|
nuclear@0
|
299 glEnable(GL_BLEND);
|
nuclear@0
|
300 glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
nuclear@0
|
301
|
nuclear@0
|
302 glBindTexture(GL_TEXTURE_2D, pkin_tex);
|
nuclear@0
|
303 glEnable(GL_TEXTURE_2D);
|
nuclear@0
|
304
|
nuclear@0
|
305 glMatrixMode(GL_MODELVIEW);
|
nuclear@0
|
306 glPushMatrix();
|
nuclear@0
|
307 glMultTransposeMatrixf(pkin_obj->xform()[0]);
|
nuclear@0
|
308
|
nuclear@0
|
309 num_shells = fbm1(sec * 2.0, 2) * 28.0 + 45;
|
nuclear@0
|
310
|
nuclear@0
|
311 for(int i=0; i<num_shells; i++) {
|
nuclear@0
|
312 float x = (float)i / (float)num_shells;
|
nuclear@0
|
313 float alpha = 0.025 / (x * x);
|
nuclear@0
|
314
|
nuclear@0
|
315 float black[] = {0, 0, 0, std::min(alpha, 1.0f) * 0.3f};
|
nuclear@0
|
316 float glow_col[] = {0.7, 0.5, 0.25, 1.0};
|
nuclear@0
|
317 glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, black);
|
nuclear@0
|
318 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black);
|
nuclear@0
|
319 glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, glow_col);
|
nuclear@0
|
320
|
nuclear@0
|
321 glScalef(shell_scale, shell_scale, shell_scale);
|
nuclear@0
|
322 pkin_mesh->draw();
|
nuclear@0
|
323 }
|
nuclear@0
|
324 glDepthMask(1);
|
nuclear@0
|
325
|
nuclear@0
|
326 glPopMatrix();
|
nuclear@0
|
327 glPopAttrib();
|
nuclear@0
|
328
|
nuclear@0
|
329
|
nuclear@0
|
330 glutSwapBuffers();
|
nuclear@0
|
331 assert(glGetError() == GL_NO_ERROR);
|
nuclear@0
|
332 }
|
nuclear@0
|
333
|
nuclear@0
|
334 void idle()
|
nuclear@0
|
335 {
|
nuclear@0
|
336 glutPostRedisplay();
|
nuclear@0
|
337 }
|
nuclear@0
|
338
|
nuclear@0
|
339 void reshape(int x, int y)
|
nuclear@0
|
340 {
|
nuclear@0
|
341 glViewport(0, 0, x, y);
|
nuclear@0
|
342
|
nuclear@0
|
343 glMatrixMode(GL_PROJECTION);
|
nuclear@0
|
344 glLoadIdentity();
|
nuclear@0
|
345 gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0);
|
nuclear@0
|
346 }
|
nuclear@0
|
347
|
nuclear@0
|
348 void keyb(unsigned char key, int x, int y)
|
nuclear@0
|
349 {
|
nuclear@0
|
350 switch(key) {
|
nuclear@0
|
351 case 27:
|
nuclear@0
|
352 exit(0);
|
nuclear@0
|
353
|
nuclear@0
|
354 case 'w':
|
nuclear@0
|
355 wireframe = !wireframe;
|
nuclear@0
|
356 break;
|
nuclear@0
|
357
|
nuclear@0
|
358 case 'f':
|
nuclear@0
|
359 case 'F':
|
nuclear@0
|
360 {
|
nuclear@0
|
361 static int prev_pos[2] = {50, 80};
|
nuclear@0
|
362
|
nuclear@0
|
363 fullscr = !fullscr;
|
nuclear@0
|
364 if(fullscr) {
|
nuclear@0
|
365 prev_pos[0] = glutGet(GLUT_WINDOW_X);
|
nuclear@0
|
366 prev_pos[1] = glutGet(GLUT_WINDOW_Y);
|
nuclear@0
|
367 glutFullScreen();
|
nuclear@0
|
368 } else {
|
nuclear@0
|
369 glutPositionWindow(prev_pos[0], prev_pos[1]);
|
nuclear@0
|
370 }
|
nuclear@0
|
371 }
|
nuclear@0
|
372 break;
|
nuclear@0
|
373 }
|
nuclear@0
|
374 }
|
nuclear@0
|
375
|
nuclear@0
|
376 static int prev_x, prev_y;
|
nuclear@0
|
377 static bool bnstate[16];
|
nuclear@0
|
378
|
nuclear@0
|
379 void mouse(int bn, int st, int x, int y)
|
nuclear@0
|
380 {
|
nuclear@0
|
381 prev_x = x;
|
nuclear@0
|
382 prev_y = y;
|
nuclear@0
|
383 bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN;
|
nuclear@0
|
384
|
nuclear@0
|
385 anim = !(st == GLUT_DOWN);
|
nuclear@0
|
386 }
|
nuclear@0
|
387
|
nuclear@0
|
388 void motion(int x, int y)
|
nuclear@0
|
389 {
|
nuclear@0
|
390 int dx = x - prev_x;
|
nuclear@0
|
391 int dy = y - prev_y;
|
nuclear@0
|
392 prev_x = x;
|
nuclear@0
|
393 prev_y = y;
|
nuclear@0
|
394
|
nuclear@0
|
395 if(!dx && !dy) return;
|
nuclear@0
|
396
|
nuclear@0
|
397 if(bnstate[0]) {
|
nuclear@0
|
398 //anim = false;
|
nuclear@0
|
399 cam_theta += dx * 0.5;
|
nuclear@0
|
400 cam_phi += dy * 0.5;
|
nuclear@0
|
401 if(cam_phi < -90) cam_phi = -90;
|
nuclear@0
|
402 if(cam_phi > 90) cam_phi = 90;
|
nuclear@0
|
403 }
|
nuclear@0
|
404 if(bnstate[2]) {
|
nuclear@0
|
405 //anim = false;
|
nuclear@0
|
406 cam_dist += dy * 0.1;
|
nuclear@0
|
407 if(cam_dist < 0.0) cam_dist = 0.0;
|
nuclear@0
|
408 }
|
nuclear@0
|
409 }
|