dbf-halloween2015

diff 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 diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/main.cc	Sun Nov 01 00:09:12 2015 +0200
     1.3 @@ -0,0 +1,409 @@
     1.4 +#include <stdio.h>
     1.5 +#include <stdlib.h>
     1.6 +#include <assert.h>
     1.7 +#include <vector>
     1.8 +#include "opengl.h"
     1.9 +#include <GL/glut.h>
    1.10 +#include "scene.h"
    1.11 +#include "meshgen.h"
    1.12 +#include "pnoise.h"
    1.13 +#include "image.h"
    1.14 +#include "rng.h"
    1.15 +#include "sdr.h"
    1.16 +#include "audio/audio.h"
    1.17 +#include "audio/ovstream.h"
    1.18 +#include "dsys/dsys.h"
    1.19 +
    1.20 +bool init();
    1.21 +void cleanup();
    1.22 +void display();
    1.23 +void idle();
    1.24 +void reshape(int x, int y);
    1.25 +void keyb(unsigned char key, int x, int y);
    1.26 +void mouse(int bn, int st, int x, int y);
    1.27 +void motion(int x, int y);
    1.28 +
    1.29 +float cam_theta, cam_phi = 25, cam_dist = 6;
    1.30 +Scene *scn;
    1.31 +bool wireframe;
    1.32 +int num_shells = 64;
    1.33 +float shell_scale = 1.015;
    1.34 +bool anim = true;
    1.35 +bool fullscr = true;
    1.36 +
    1.37 +static std::vector<Image*> images;
    1.38 +static Object *pkin_obj;
    1.39 +static Mesh *pkin_mesh;
    1.40 +static unsigned int pkin_tex;
    1.41 +
    1.42 +static unsigned int sdr_spot;
    1.43 +
    1.44 +static float ramp[3];
    1.45 +
    1.46 +
    1.47 +static OggVorbisStream *music;
    1.48 +static struct dsys_demo *demo;
    1.49 +
    1.50 +
    1.51 +int main(int argc, char **argv)
    1.52 +{
    1.53 +	glutInit(&argc, argv);
    1.54 +	glutInitWindowSize(1280, 720);
    1.55 +	glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
    1.56 +	glutCreateWindow("DBF Halloween 2015 compo entry");
    1.57 +
    1.58 +	if(argv[1]) {
    1.59 +		if(strcmp(argv[1], "-w") == 0 || strcmp(argv[1], "-windowed") == 0) {
    1.60 +			fullscr = false;
    1.61 +		} else {
    1.62 +			fprintf(stderr, "unrecognized argument: %s\nUse -w or -windowed to run in a window\n", argv[1]);
    1.63 +			return 1;
    1.64 +		}
    1.65 +	}
    1.66 +	if(fullscr) {
    1.67 +		glutFullScreen();
    1.68 +	}
    1.69 +
    1.70 +	glutDisplayFunc(display);
    1.71 +	glutIdleFunc(idle);
    1.72 +	glutReshapeFunc(reshape);
    1.73 +	glutKeyboardFunc(keyb);
    1.74 +	glutMouseFunc(mouse);
    1.75 +	glutMotionFunc(motion);
    1.76 +
    1.77 +	if(!init()) {
    1.78 +		return 1;
    1.79 +	}
    1.80 +	glutMainLoop();
    1.81 +	return 0;
    1.82 +}
    1.83 +
    1.84 +static float ground_func(float u, float v, void *cls)
    1.85 +{
    1.86 +	return fbm2(u * 3.0, v * 3.0, 2) * 0.8;
    1.87 +}
    1.88 +
    1.89 +static Vector2 pumpkin_func(float u, float v, void *cls)
    1.90 +{
    1.91 +	float theta = v * M_PI;
    1.92 +	float r = sin(theta) * 0.5 + 0.5;
    1.93 +
    1.94 +	// modulate a high-frequency short-amp wave along u to make the ribs(?)
    1.95 +	r += fabs(sin(u * M_PI * 12.0)) * 0.02;// + 1.0;
    1.96 +
    1.97 +	// throw some noise in there for good measure
    1.98 +	r += pnoise2(u * 16.0, v * 8.0, 16) * 0.05;// + 1.0;
    1.99 +
   1.100 +	float x = sin(theta) * r;
   1.101 +	float y = cos(theta) * r;
   1.102 +	return Vector2(x, y);
   1.103 +}
   1.104 +
   1.105 +#define CLAMP(x, a, b)	std::max<float>(std::min<float>(x, b), a)
   1.106 +
   1.107 +bool init()
   1.108 +{
   1.109 +	if(init_opengl() == -1) {
   1.110 +		return false;
   1.111 +	}
   1.112 +	Mesh::use_custom_sdr_attr = false;
   1.113 +
   1.114 +	glEnable(GL_DEPTH_TEST);
   1.115 +	glEnable(GL_CULL_FACE);
   1.116 +	glEnable(GL_LIGHTING);
   1.117 +	glEnable(GL_NORMALIZE);
   1.118 +
   1.119 +	if(!(demo = dsys_open("data/demo.script"))) {
   1.120 +		fprintf(stderr, "failed to load sequencing file\n");
   1.121 +		return false;
   1.122 +	}
   1.123 +	for(int i=0; i<3; i++) {
   1.124 +		char name[16];
   1.125 +		sprintf(name, "ramp%d", i);
   1.126 +		struct dsys_event *ev = dsys_event(demo, name);
   1.127 +		if(ev) {
   1.128 +			printf("found event: %s\n", name);
   1.129 +			dsys_event_link(ev, ramp + i);
   1.130 +		}
   1.131 +	}
   1.132 +
   1.133 +
   1.134 +	if(!(sdr_spot = create_program_load("sdr/default.v.glsl", "sdr/spot.p.glsl"))) {
   1.135 +		return false;
   1.136 +	}
   1.137 +
   1.138 +	Matrix4x4 xform;
   1.139 +
   1.140 +	scn = new Scene;
   1.141 +
   1.142 +	Light *lt = new Light;
   1.143 +	lt->pos = Vector3(-10, 10, 10);
   1.144 +	scn->add_light(lt);
   1.145 +
   1.146 +	// floor
   1.147 +	Mesh *mesh = new Mesh;
   1.148 +	gen_heightmap(mesh, 20, 20, 50, 50, ground_func);
   1.149 +	xform.set_rotation(Vector3(-M_PI / 2.0, 0, 0));
   1.150 +	mesh->apply_xform(xform);
   1.151 +
   1.152 +	Object *obj = new Object;
   1.153 +	obj->set_mesh(mesh);
   1.154 +	obj->xform().set_translation(Vector3(0, -0.9, 0));
   1.155 +	obj->mtl.diffuse = Vector3(0.7, 0.7, 0.7);
   1.156 +	obj->set_shader(sdr_spot);
   1.157 +	scn->add_object(obj);
   1.158 +
   1.159 +	Image *img = new Image;
   1.160 +	if(!img->load("data/grass02.jpg")) {
   1.161 +		return false;
   1.162 +	}
   1.163 +	images.push_back(img);
   1.164 +	obj->tex_xform().set_scaling(Vector3(5.0, 10.0, 1.0));
   1.165 +	obj->set_texture(img->texture());
   1.166 +
   1.167 +	// pumpkin texture
   1.168 +	img = new Image;
   1.169 +	if(!img->create(1024, 512)) {
   1.170 +		return false;
   1.171 +	}
   1.172 +	images.push_back(img);
   1.173 +
   1.174 +	static const Vector3 pkin_col = Vector3(0.824, 0.325, 0.063);
   1.175 +	unsigned char *pptr = img->pixels;
   1.176 +	for(int i=0; i<img->height; i++) {
   1.177 +		float v = (float)i / (float)img->height;
   1.178 +		for(int j=0; j<img->width; j++) {
   1.179 +			float u = (float)j / (float)img->width;
   1.180 +
   1.181 +			float val = pfbm2(u * 64.0, v * 32.0, 3, 128) * 0.1 + 1.0;
   1.182 +			val *= fabs(sin(u * M_PI * 12.0)) * 0.2 + 0.8;
   1.183 +			Vector3 col = pkin_col * val;
   1.184 +
   1.185 +			*pptr++ = (int)(CLAMP(col.x, 0.0, 1.0) * 255.0f);
   1.186 +			*pptr++ = (int)(CLAMP(col.y, 0.0, 1.0) * 255.0f);
   1.187 +			*pptr++ = (int)(CLAMP(col.z, 0.0, 1.0) * 255.0f);
   1.188 +			*pptr++ = 255;
   1.189 +		}
   1.190 +	}
   1.191 +
   1.192 +	// pumpkin
   1.193 +	pkin_mesh = new Mesh;
   1.194 +	gen_revol(pkin_mesh, 64, 20, pumpkin_func);
   1.195 +
   1.196 +	pkin_obj = new Object;
   1.197 +	pkin_obj->xform().set_rotation(Vector3(DEG_TO_RAD(-10), DEG_TO_RAD(90), 0));
   1.198 +	pkin_obj->set_mesh(pkin_mesh);
   1.199 +	pkin_obj->set_texture(img->texture());
   1.200 +	obj->set_shader(sdr_spot);
   1.201 +	scn->add_object(pkin_obj);
   1.202 +
   1.203 +	int num_pumpkins = 20;
   1.204 +	float dtheta = 1.0 / (float)num_pumpkins;
   1.205 +
   1.206 +	for(int i=0; i<num_pumpkins; i++) {
   1.207 +		float theta = (((float)i + rng_frand() * 0.5) * dtheta) * 2.0 * M_PI * 2.0;
   1.208 +		float r = 5.0 * (float)i / (float)num_pumpkins + 4.0;
   1.209 +
   1.210 +		float x = cos(theta) * r;
   1.211 +		float y = sin(theta) * r;
   1.212 +
   1.213 +		float tu = (x + 10.0) / 20.0;
   1.214 +		float tv = (10.0 - y) / 20.0;
   1.215 +		float h = ground_func(tu, tv, 0);
   1.216 +
   1.217 +		obj = new Object;
   1.218 +		obj->xform().translate(Vector3(x, h - 0.5, y));
   1.219 +		obj->xform().rotate(Vector3(DEG_TO_RAD(rng_frand() * 40.0 - 20.0), rng_frand() * M_PI * 2.0, 0));
   1.220 +		obj->xform().scale(Vector3(0.7, 0.7, 0.7));
   1.221 +		obj->set_mesh(pkin_mesh);
   1.222 +		obj->set_texture(img->texture());
   1.223 +		obj->set_shader(sdr_spot);
   1.224 +		scn->add_object(obj);
   1.225 +	}
   1.226 +
   1.227 +	// pumpkin glow mask
   1.228 +	img = new Image;
   1.229 +	if(!img->load("data/pumpkin_mask_blured.png")) {
   1.230 +		return false;
   1.231 +	}
   1.232 +	images.push_back(img);
   1.233 +	pkin_tex = img->texture();
   1.234 +
   1.235 +	if(!init_audio()) {
   1.236 +		fprintf(stderr, "failed to initialize audio\n");
   1.237 +		return false;
   1.238 +	}
   1.239 +	music = new OggVorbisStream;
   1.240 +	if(!music->open("data/welcome_to_horrorland.ogg")) {
   1.241 +		fprintf(stderr, "failed to open music\n");
   1.242 +		return false;
   1.243 +	}
   1.244 +	music->play(AUDIO_PLAYMODE_LOOP);
   1.245 +
   1.246 +	return true;
   1.247 +}
   1.248 +
   1.249 +void cleanup()
   1.250 +{
   1.251 +	music->stop();
   1.252 +	delete music;
   1.253 +	destroy_audio();
   1.254 +
   1.255 +	delete scn;
   1.256 +
   1.257 +	for(size_t i=0; i<images.size(); i++) {
   1.258 +		delete images[i];
   1.259 +	}
   1.260 +	images.clear();
   1.261 +}
   1.262 +
   1.263 +void display()
   1.264 +{
   1.265 +	unsigned int msec = glutGet(GLUT_ELAPSED_TIME);
   1.266 +	float sec = (float)msec / 1000.0;
   1.267 +
   1.268 +	dsys_update(demo, dsys_msec_to_dtime(msec));
   1.269 +	if(!dsys_is_running(demo)) {
   1.270 +		exit(0);
   1.271 +	}
   1.272 +
   1.273 +	float offs[3];
   1.274 +
   1.275 +	if(anim) {
   1.276 +		float t = sec * 0.5;
   1.277 +		cam_theta = cos(t) * 35.0;// + fbm1(t * 6.0, 1) * 2.0;
   1.278 +		cam_phi = sin(t * 2.0) * 10.0 + 25.0;// + fbm1(t * 8.0, 1) * 3.0;
   1.279 +
   1.280 +		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;
   1.281 +		//printf("ramps: %g %g %g, mag: %g\n", ramp[0], ramp[1], ramp[2], mag);
   1.282 +		for(int i=0; i<3; i++) {
   1.283 +			offs[i] = turbulence1(sec * 4.0 + i, 2) * mag;
   1.284 +		}
   1.285 +	}
   1.286 +
   1.287 +	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
   1.288 +
   1.289 +	glMatrixMode(GL_MODELVIEW);
   1.290 +	glLoadIdentity();
   1.291 +	glTranslatef(0, 0, -cam_dist);
   1.292 +	glRotatef(cam_phi, 1, 0, 0);
   1.293 +	glRotatef(cam_theta, 0, 1, 0);
   1.294 +	glTranslatef(offs[0], offs[1], offs[2]);
   1.295 +
   1.296 +	scn->draw();
   1.297 +
   1.298 +	glPushAttrib(GL_ENABLE_BIT | GL_LIGHTING_BIT);
   1.299 +	glDisable(GL_CULL_FACE);
   1.300 +
   1.301 +	glDepthMask(0);
   1.302 +	glEnable(GL_BLEND);
   1.303 +	glBlendFunc(GL_SRC_ALPHA, GL_ONE);
   1.304 +
   1.305 +	glBindTexture(GL_TEXTURE_2D, pkin_tex);
   1.306 +	glEnable(GL_TEXTURE_2D);
   1.307 +
   1.308 +	glMatrixMode(GL_MODELVIEW);
   1.309 +	glPushMatrix();
   1.310 +	glMultTransposeMatrixf(pkin_obj->xform()[0]);
   1.311 +
   1.312 +	num_shells = fbm1(sec * 2.0, 2) * 28.0 + 45;
   1.313 +
   1.314 +	for(int i=0; i<num_shells; i++) {
   1.315 +		float x = (float)i / (float)num_shells;
   1.316 +		float alpha = 0.025 / (x * x);
   1.317 +
   1.318 +		float black[] = {0, 0, 0, std::min(alpha, 1.0f) * 0.3f};
   1.319 +		float glow_col[] = {0.7, 0.5, 0.25, 1.0};
   1.320 +		glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, black);
   1.321 +		glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, black);
   1.322 +		glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, glow_col);
   1.323 +
   1.324 +		glScalef(shell_scale, shell_scale, shell_scale);
   1.325 +		pkin_mesh->draw();
   1.326 +	}
   1.327 +	glDepthMask(1);
   1.328 +
   1.329 +	glPopMatrix();
   1.330 +	glPopAttrib();
   1.331 +
   1.332 +
   1.333 +	glutSwapBuffers();
   1.334 +	assert(glGetError() == GL_NO_ERROR);
   1.335 +}
   1.336 +
   1.337 +void idle()
   1.338 +{
   1.339 +	glutPostRedisplay();
   1.340 +}
   1.341 +
   1.342 +void reshape(int x, int y)
   1.343 +{
   1.344 +	glViewport(0, 0, x, y);
   1.345 +
   1.346 +	glMatrixMode(GL_PROJECTION);
   1.347 +	glLoadIdentity();
   1.348 +	gluPerspective(50.0, (float)x / (float)y, 0.5, 500.0);
   1.349 +}
   1.350 +
   1.351 +void keyb(unsigned char key, int x, int y)
   1.352 +{
   1.353 +	switch(key) {
   1.354 +	case 27:
   1.355 +		exit(0);
   1.356 +
   1.357 +	case 'w':
   1.358 +		wireframe = !wireframe;
   1.359 +		break;
   1.360 +
   1.361 +	case 'f':
   1.362 +	case 'F':
   1.363 +		{
   1.364 +			static int prev_pos[2] = {50, 80};
   1.365 +
   1.366 +			fullscr = !fullscr;
   1.367 +			if(fullscr) {
   1.368 +				prev_pos[0] = glutGet(GLUT_WINDOW_X);
   1.369 +				prev_pos[1] = glutGet(GLUT_WINDOW_Y);
   1.370 +				glutFullScreen();
   1.371 +			} else {
   1.372 +				glutPositionWindow(prev_pos[0], prev_pos[1]);
   1.373 +			}
   1.374 +		}
   1.375 +		break;
   1.376 +	}
   1.377 +}
   1.378 +
   1.379 +static int prev_x, prev_y;
   1.380 +static bool bnstate[16];
   1.381 +
   1.382 +void mouse(int bn, int st, int x, int y)
   1.383 +{
   1.384 +	prev_x = x;
   1.385 +	prev_y = y;
   1.386 +	bnstate[bn - GLUT_LEFT_BUTTON] = st == GLUT_DOWN;
   1.387 +
   1.388 +	anim = !(st == GLUT_DOWN);
   1.389 +}
   1.390 +
   1.391 +void motion(int x, int y)
   1.392 +{
   1.393 +	int dx = x - prev_x;
   1.394 +	int dy = y - prev_y;
   1.395 +	prev_x = x;
   1.396 +	prev_y = y;
   1.397 +
   1.398 +	if(!dx && !dy) return;
   1.399 +
   1.400 +	if(bnstate[0]) {
   1.401 +		//anim = false;
   1.402 +		cam_theta += dx * 0.5;
   1.403 +		cam_phi += dy * 0.5;
   1.404 +		if(cam_phi < -90) cam_phi = -90;
   1.405 +		if(cam_phi > 90) cam_phi = 90;
   1.406 +	}
   1.407 +	if(bnstate[2]) {
   1.408 +		//anim = false;
   1.409 +		cam_dist += dy * 0.1;
   1.410 +		if(cam_dist < 0.0) cam_dist = 0.0;
   1.411 +	}
   1.412 +}