dbf-halloween2015

view src/main.cc @ 2:5ae5fd3626fa

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