dbf-halloween2015

view src/main.cc @ 3:c37fe5d8a4ed

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