dbf-halloween2015

view src/main.cc @ 0:50683c78264e

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