fixed multiple insertions of the same texture
[summerhack] / src / parts / temple.cpp
1 #include <cassert>
2 #include "temple.hpp"
3 #include "common/err_msg.h"
4
5 static void make_skycube(Scene *scene);
6 static void make_temple(Scene *scene);
7 static bool make_pillars(Scene *scene);
8 static void make_blobs(Scene *scene);
9
10 static void move_blobs(scalar_t t);
11 static scalar_t eval_func(const Vector3 &vec, scalar_t t);
12 static Vector3 eval_normals(const Vector3 &vec, scalar_t t);
13
14 static const int pillar_udiv = 16;
15
16 ParticleSysParams *pp[4];
17
18 Texture *greets;
19
20 #define BLOB_COUNT      4
21 static scalar_t bint[BLOB_COUNT] = {30, 28, 24, 15};
22 static Vector3 pos[BLOB_COUNT];
23 static ScalarField *sfield;
24 static Object *blob;
25
26 #define BLOBS
27 #define TEMPLE
28 #define EXIBITS
29
30 #define ANIM
31
32 TemplePart::TemplePart() : ScenePart("temple", new Scene) {
33 #ifdef ANIM
34         TargetCamera *cam = new TargetCamera(Vector3(0, 52, 0), Vector3(0, 50, 0));
35 #else
36         TargetCamera *cam = new TargetCamera(Vector3(0, 60, -160), Vector3(0, 50, 0));
37 #endif
38         cam->set_fov(DEG_TO_RAD(50));
39         scene->add_camera(cam);
40
41         PointLight *lt;
42         
43         lt = new PointLight(Vector3(-200, 250, -400));
44         lt->set_intensity(0.9);
45         scene->add_light(lt);
46
47         lt = new PointLight(Vector3(200, 20, 0));
48         lt->set_intensity(0.6);
49         scene->add_light(lt);
50
51         lt = new PointLight(Vector3(20, 500, -400));
52         lt->set_intensity(0.5);
53         scene->add_light(lt);
54
55         scene->set_ambient_light(0.1);
56
57         make_skycube(scene);
58 #ifdef TEMPLE
59         make_temple(scene);
60 #endif
61 #ifdef EXIBITS
62         make_pillars(scene);
63 #endif
64 #ifdef BLOBS
65         make_blobs(scene);
66 #endif
67         
68         MotionController ctrl;
69
70 #ifdef ANIM
71         ctrl = MotionController(CTRL_COS, TIME_FREE);
72         ctrl.set_sin_func(0.58, 250);
73         ctrl.set_control_axis(CTRL_X);
74         cam->add_controller(ctrl, CTRL_TRANSLATION);
75
76         ctrl = MotionController(CTRL_SIN, TIME_FREE);
77         ctrl.set_sin_func(1.17, 125);
78         ctrl.set_control_axis(CTRL_X);
79         cam->add_controller(ctrl, CTRL_TRANSLATION);
80
81         ctrl = MotionController(CTRL_SIN, TIME_FREE);
82         ctrl.set_sin_func(0.49, 220);
83         ctrl.set_control_axis(CTRL_Z);
84         cam->add_controller(ctrl, CTRL_TRANSLATION);
85
86         ctrl = MotionController(CTRL_COS, TIME_FREE);
87         ctrl.set_sin_func(0.99, 105);
88         ctrl.set_control_axis(CTRL_Z);
89         cam->add_controller(ctrl, CTRL_TRANSLATION);
90
91         ctrl = MotionController(CTRL_SIN, TIME_FREE);
92         ctrl.set_sin_func(0.45, 50);
93         ctrl.set_control_axis(CTRL_Y);
94         cam->add_controller(ctrl, CTRL_TRANSLATION);
95 #endif
96
97         greets = get_texture("data/img/greets.png");
98
99         scene->set_background(0.5);
100
101         // in order to precalculate the cubemaps...
102         scene->render(0);
103
104         //scene->render_sequence(0, 15000, 25);
105         //exit(0);
106 }
107
108 TemplePart::~TemplePart() {}
109
110 static void make_skycube(Scene *scene) {
111         const float size = 5000;
112         Object *face[6];
113         Texture *tex[6];
114
115         face[0] = new ObjPlane(Vector3(0, -1, 0), Vector2(size, size), 0);
116         face[0]->translate(Vector3(0, size / 2, 0));
117         tex[0] = get_texture("data/img/py.jpg");
118         
119         face[1] = new ObjPlane(Vector3(0, 1, 0), Vector2(size, size), 0);
120         face[1]->translate(Vector3(0, -size / 2, 0));
121         tex[1] = get_texture("data/img/ny.jpg");
122
123         face[2] = new ObjPlane(Vector3(0, 0, -1), Vector2(size, size), 0);
124         face[2]->translate(Vector3(0, 0, size / 2));
125         tex[2] = get_texture("data/img/pz.jpg");
126         
127         face[3] = new ObjPlane(Vector3(0, 0, 1), Vector2(size, size), 0);
128         face[3]->translate(Vector3(0, 0, -size / 2));
129         tex[3] = get_texture("data/img/nz.jpg");
130
131         face[4] = new ObjPlane(Vector3(-1, 0, 0), Vector2(size, size), 0);
132         face[4]->translate(Vector3(size / 2, 0, 0));
133         tex[4] = get_texture("data/img/px.jpg");
134         
135         face[5] = new ObjPlane(Vector3(1, 0, 0), Vector2(size, size), 0);
136         face[5]->translate(Vector3(-size / 2, 0, 0));
137         tex[5] = get_texture("data/img/nx.jpg");
138
139         for(int i=0; i<6; i++) {
140                 Material *mat = face[i]->get_material_ptr();
141                 mat->emissive_color = 1.0;
142                 mat->set_texture(tex[i], TEXTYPE_DIFFUSE);
143                 face[i]->set_texture_addressing(TEXADDR_CLAMP);
144                 scene->add_object(face[i]);
145         }
146 }
147
148 void make_temple(Scene *scene) {
149         const Vector3 pillar_body[] = {
150                 Vector3(8, 4, 0),
151                 Vector3(12, 40, 0),
152                 Vector3(11, 70, 0),
153                 Vector3(4, 106, 0)
154         };
155
156         const Vector3 pillar_pos[] = {
157                 Vector3(-50, 0, -50),
158                 Vector3(-50, 0, 50),
159                 Vector3(50, 0, 50),
160                 Vector3(50, 0, -50)
161         };
162
163
164         TriMesh pillar_mesh;
165         create_revolution(&pillar_mesh, pillar_body, 4, pillar_udiv, 10);
166
167         Material pillar_mat;
168         pillar_mat.specular_color = 1.0;
169         pillar_mat.specular_power = 70.0;
170         pillar_mat.set_texture(get_texture("data/img/benedeti.jpg"), TEXTYPE_DIFFUSE);
171
172         for(int i=0; i<4; i++) {
173                 Object *obj = new Object;
174                 obj->get_mesh() = pillar_mesh;
175                 obj->set_position(pillar_pos[i]);
176                 *obj->get_material_ptr() = pillar_mat;
177                 scene->add_object(obj);
178
179                 obj = new ObjCylinder(13.0, 5.0, true, pillar_udiv);
180                 obj->set_position(pillar_pos[i] + Vector3(0, 6, 0));
181                 *obj->get_material_ptr() = pillar_mat;
182                 scene->add_object(obj);
183                 
184                 obj = new ObjCylinder(16.0, 5.0, true, pillar_udiv);
185                 obj->set_position(pillar_pos[i] + Vector3(0, 2, 0));
186                 *obj->get_material_ptr() = pillar_mat;
187                 scene->add_object(obj);
188
189                 obj = new ObjTorus(2.0, 5.0);
190                 obj->set_position(pillar_pos[i] + Vector3(0, 102, 0));
191                 *obj->get_material_ptr() = pillar_mat;
192                 scene->add_object(obj);
193
194                 obj = new ObjTorus(2.0, 7);
195                 obj->set_position(pillar_pos[i] + Vector3(0, 105, 0));
196                 *obj->get_material_ptr() = pillar_mat;
197                 scene->add_object(obj);
198         }
199
200
201         // floor
202         Object *obj = new ObjCylinder(95.0, 5, true, 25);
203         obj->set_position(Vector3(0, -2.5, 0));
204         obj->get_material_ptr()->set_texture(get_texture("data/img/brick1_base1.jpg"), TEXTYPE_DIFFUSE);
205         scene->add_object(obj);
206
207         obj = new ObjCylinder(103.0, 5, true, 25);
208         obj->set_position(Vector3(0, -7.5, 0));
209         obj->get_material_ptr()->set_texture(get_texture("data/img/brick1_base1.jpg"), TEXTYPE_DIFFUSE);
210         scene->add_object(obj);
211
212         // ceiling
213         const Vector3 ceil[] = {
214                 Vector3(90, 0, 0),
215                 Vector3(92, 4, 0),
216                 Vector3(98, 14, 0),
217                 Vector3(95, 20, 0),
218                 Vector3(60, 40, 0),
219                 Vector3(20, 60, 0),
220                 Vector3(18, 64, 0),
221                 Vector3(23, 66, 0),
222                 Vector3(26, 67, 0),
223                 Vector3(25, 70, 0),
224                 Vector3(10, 78, 0),
225                 Vector3(4, 84, 0),
226                 Vector3(2, 90, 0),
227                 Vector3(0.1, 100, 0)
228         };
229
230         obj = new Object;
231         create_revolution(obj->get_mesh_ptr(), ceil, 14, 24, 28);
232         obj->set_pivot(Vector3(0, 40, 0));
233         obj->set_position(Vector3(0, 110, 0));
234         obj->calculate_normals();
235
236         Texture *cubemap = new Texture(64, 64, TEX_CUBE);
237         add_texture(cubemap);
238
239         Material *mat = obj->get_material_ptr();
240         mat->diffuse_color = mat->ambient_color = int_color(239, 190, 37) * 0.8;
241         mat->specular_color = int_color(255, 198, 43);
242         mat->specular_power = 40.0;
243         mat->set_texture(get_texture("data/img/brick1_base1.jpg"), TEXTYPE_DIFFUSE);
244         mat->set_texture(cubemap, TEXTYPE_ENVMAP);
245         mat->auto_refl = false;
246         mat->env_intensity = 0.3;
247         scene->add_object(obj);
248
249         obj = new ObjCylinder(94, 5, true, 25);
250         obj->set_position(Vector3(0, 107.5, 0));
251         *obj->get_material_ptr() = *mat;
252         scene->add_object(obj);
253
254         // sting
255         const Vector3 sting[] = {
256                 Vector3(12, 0, 0),
257                 Vector3(9, 4, 0),
258                 Vector3(5, 6, 0),
259                 Vector3(2, 10, 0),
260                 Vector3(0.01, 34, 0)
261         };
262
263         cubemap = new Texture(16, 16, TEX_CUBE);
264         add_texture(cubemap);
265
266         obj = new Object;
267         create_revolution(obj->get_mesh_ptr(), sting, 5, 10, 10);
268         obj->set_pivot(Vector3(0, 5, 0));
269         mat = obj->get_material_ptr();
270         mat->diffuse_color = mat->ambient_color = 0.1;
271         mat->specular_color = 1.0;
272         mat->specular_power = 80.0;
273         mat->set_texture(cubemap, TEXTYPE_ENVMAP);
274         mat->auto_refl = false;
275         scene->add_object(obj);
276
277
278         // floor-floor
279         obj = new ObjPlane(Vector3(0, 1, 0), Vector2(1200, 1200), 6);
280         obj->set_position(Vector3(0, -10, 0));
281         mat = obj->get_material_ptr();
282         mat->set_texture(get_texture("data/img/mud.jpg"), TEXTYPE_DIFFUSE);
283         mat->tmat[TEXTYPE_DIFFUSE].set_scaling(Vector3(4.0, 4.0, 4.0));
284         scene->add_object(obj);
285 }
286
287 static bool make_pillars(Scene *scene) {
288         static const Vector3 ppos[] = {
289                 Vector3(-150, -7.5, 0),
290                 Vector3(0, -7.5, 150),
291                 Vector3(150, -7.5, 0),
292                 Vector3(0, -7.5, -150)
293         };
294
295         static const char *label_tex[] = {
296                 "data/img/label_dolphin.png",
297                 "data/img/label_duck.png",
298                 "data/img/label_face.png",
299                 "data/img/label_teapot.png",
300                 0
301         };
302         
303         Curve *curve = load_curve("data/pillar.curve");
304
305         for(int i=0; i<4; i++) {
306                 char name[128];
307                 sprintf(name, "pillar%02d", i);
308                 
309                 Object *obj = new Object;
310                 obj->name = name;
311                 Material *mat = obj->get_material_ptr();
312                 create_revolution(obj->get_mesh_ptr(), *curve, pillar_udiv, 10);
313                 obj->set_scaling(Vector3(2.3, 1.8, 2.3));
314                 obj->apply_xform();
315                 obj->normalize_normals();
316                 obj->set_position(ppos[i]);
317
318                 mat->specular_color = 1.0;
319                 mat->specular_power = 70.0;
320                 mat->set_texture(get_texture("data/img/benedeti.jpg"), TEXTYPE_DIFFUSE);
321                 scene->add_object(obj);
322
323                 obj = new ObjCylinder(14.0, 3.0);
324                 obj->set_position(ppos[i]);
325                 mat = obj->get_material_ptr();
326                 mat->specular_color = 1.0;
327                 mat->specular_power = 70.0;
328                 mat->set_texture(get_texture("data/img/benedeti.jpg"), TEXTYPE_DIFFUSE);
329                 scene->add_object(obj);
330
331
332                 Texture *cubemap = new Texture(64, 64, TEX_CUBE);
333                 add_texture(cubemap);
334                 
335                 // put exibit
336                 switch(i) {
337                 case 1:
338                         {
339                                 Scene *scene = load_scene("data/geom/duck.3ds");
340                                 if(!scene) {
341                                         error("failed to load duck.3ds");
342                                         return false;
343                                 }
344                                 obj = scene->get_object("Object03");
345                                 assert(obj);
346                                 scene->remove_object(obj);
347                                 delete scene;
348
349                                 obj->set_scaling(Vector3(0.009, 0.009, 0.009));
350                                 obj->set_auto_normalize(true);
351                         
352                                 obj->set_position(ppos[i] + Vector3(0, 50, 0));
353                                 obj->set_rotation(Vector3(0, quarter_pi, 0));
354                         }
355                         break;
356
357                 case 2:
358                         {
359                                 Scene *scene = load_scene("data/geom/chrmface.3ds");
360                                 if(!scene) {
361                                         error("failed to load chrmface.3ds");
362                                         return false;
363                                 }
364                                 obj = scene->get_object("0main01");
365                                 assert(obj);
366                                 scene->remove_object(obj);
367                                 delete scene;
368
369                                 obj->set_scaling(Vector3(0.2, 0.2, 0.2));
370                                 obj->set_auto_normalize(true);
371
372                                 obj->set_position(ppos[i] + Vector3(4, 58, 0));                         
373                                 obj->set_rotation(Vector3(0, half_pi, 0));
374
375                                 obj->get_material_ptr()->two_sided = true;
376                         }
377                         break;
378
379                 case 0:
380                         {
381                                 Scene *scene = load_scene("data/geom/dolphin.3ds");
382                                 if(!scene) {
383                                         error("failed to load dolphin.3ds");
384                                         return false;
385                                 }
386                                 obj = scene->get_object("Loft01");
387                                 assert(obj);
388                                 scene->remove_object(obj);
389                                 delete scene;
390
391                                 obj->set_scaling(Vector3(0.14, 0.14, 0.14));
392                                 obj->set_auto_normalize(true);
393
394                                 obj->set_position(ppos[i] + Vector3(0, 48, 0));
395                                 obj->set_rotation(Vector3(half_pi, half_pi, 0));
396                         }
397                         break;
398                 
399                 case 3:
400                 default:
401                         obj = new ObjTeapot(6.0);
402                         obj->set_position(ppos[i] + Vector3(0, 43.7, 0));
403                         break;
404                 }
405
406                 mat = obj->get_material_ptr();
407                 mat->diffuse_color = mat->ambient_color = 0.1;
408                 mat->specular_color = 1.0;
409                 mat->specular_power = 80.0;
410                 mat->set_texture(cubemap, TEXTYPE_ENVMAP);
411                 mat->auto_refl = false;
412                 
413                 MotionController ctrl(CTRL_SIN, TIME_FREE);
414                 ctrl.set_control_axis(CTRL_Y);
415                 ctrl.set_sin_func(frand(0.5) + 2.3, 3.0, frand(pi));
416                 obj->add_controller(ctrl, CTRL_TRANSLATION);
417                 obj->translate(Vector3(0, 3.0, 0));
418                 scene->add_object(obj);
419
420                 ParticleSystem *label = new ParticleSystem("data/exibit.psys");
421                 pp[i] = label->get_params();
422                 pp[i]->halo = get_texture(label_tex[i]);
423                 label->set_position(ppos[i] + Vector3(0, 80, 0));
424                 scene->add_particle_sys(label);
425
426                 ParticleSystem *trail = new ParticleSystem("data/test2.psys");
427                 trail->set_position(ppos[i] + Vector3(0, 50, 0));
428
429                 ctrl = MotionController(CTRL_SIN, TIME_FREE);
430                 ctrl.set_control_axis(CTRL_X);
431                 ctrl.set_sin_func(5.0, 30.0, (float)i * half_pi);
432                 trail->add_controller(ctrl, CTRL_TRANSLATION);
433
434                 ctrl = MotionController(CTRL_COS, TIME_FREE);
435                 ctrl.set_control_axis(CTRL_Z);
436                 ctrl.set_sin_func(5.0, 30.0, (float)i * half_pi);
437                 trail->add_controller(ctrl, CTRL_TRANSLATION);
438
439                 ctrl = MotionController(CTRL_SIN, TIME_FREE);
440                 ctrl.set_control_axis(CTRL_Y);
441                 ctrl.set_sin_func(1.8, 25.0, (float)i * half_pi);
442                 trail->add_controller(ctrl, CTRL_TRANSLATION);
443                 
444                 scene->add_particle_sys(trail);
445         }
446
447         delete curve;
448         return true;
449 }
450
451 #define MIN(a, b)       ((a) < (b) ? (a) : (b))
452 #define MAX(a, b)       ((a) > (b) ? (a) : (b))
453
454 void TemplePart::draw_part() {
455         static const float greets_time = 18.0;
456         float t = (float)time / 1000.0f;
457
458 #ifdef EXIBITS
459         float yoffs = MIN(150.0, t * 25.0);
460         for(int i=0; i<4; i++) {
461                 pp[i]->spawn_offset = FuzzyVec3(0.0, yoffs, 0.0);
462         }
463 #endif
464
465 #ifdef BLOBS
466         move_blobs(t);
467         sfield->triangulate(blob->get_mesh_ptr(), 1.0, t, true);
468 #endif
469
470         scene->render(time);
471
472         if(t > greets_time) {
473                 t *= 1.8;
474
475                 float a2 = sin(t);
476         a2 = a2 > 0 ? -a2 : a2;
477         a2 += 1.0f;
478         a2 *= frand(0.8) + 0.2;
479
480         float a1 = a2;//(cos(t)+1)/2;
481         a1 *= (sin(t / 2.0) > 0) ? 1.0 : 0.0;     // modulate with step func
482         a1 *= sin(t / 2.0);
483
484                 Color col(1.0, 1.0, 1.0, MAX(a2, a1) + 0.4);
485         
486                 set_matrix(XFORM_TEXTURE, Matrix4x4::identity_matrix);
487                 load_xform_matrices();
488
489                 for(int i=0; i<10; i++) {
490                         set_alpha_blending(true);
491                         set_blend_func(BLEND_SRC_ALPHA, BLEND_ONE);
492                         float off = (float)i * 0.0025;
493                         col.a *= 0.8;
494                         dsys::overlay(greets, Vector2(-off, -off), Vector2(1 + off, 1 + off), col, 0, false);
495                         set_alpha_blending(false);
496                 }
497         }
498 }
499
500 static void move_blobs(scalar_t t) {
501         Vector3 offs = Vector3(0, 2.75 * cos(t*1.5) + 2.25, 0);
502         pos[0] = offs + Vector3(sin(t), cos(t), 0) * 8.0;
503         pos[1] = offs + Vector3(sin(t*2) + cos(t*4)/2, sin(t*1.5), cos(t)) * 8.0;
504         pos[2] = offs + Vector3(cos(t*1.8)/2 + sin(t)/4, cos(t*2) + sin(t), sin(t*1.3)) * 8.0;
505         pos[3] = offs + Vector3(sin(t*1.2)/3 + cos(t*1.8)/3.5, sin(cos(t*2) + t)*1.5, cos(t*2.0)/2) * 7.0;
506
507         //cyl = Vector2(cos(t), sin(t*2.0)) * 8.0;
508 }
509
510 static scalar_t eval_func(const Vector3 &vec, scalar_t t) {
511         scalar_t val = 0.0;
512         for(int i=0; i<BLOB_COUNT; i++) {
513                 val += (bint[i] * 0.75) / (vec - pos[i]).length_sq();
514         }
515
516         return val;
517 }
518
519 //#define NORMAL_GRAD
520 static Vector3 eval_normals(const Vector3 &vec, scalar_t t) {
521 #ifdef NORMAL_GRAD
522         const scalar_t diff = 0.1;
523
524         Vector3 grad;
525         grad.x = eval_func(vec + Vector3(diff, 0, 0), t) - eval_func(vec + Vector3(-diff, 0, 0), t);
526         grad.y = eval_func(vec + Vector3(0, diff, 0), t) - eval_func(vec + Vector3(0, -diff, 0), t);
527         grad.z = eval_func(vec + Vector3(0, 0, diff), t) - eval_func(vec + Vector3(0, 0, -diff), t);
528
529         return -grad.normalized();
530 #else
531         Vector3 normal(0, 0, 0);
532         for(int i=0; i<BLOB_COUNT; i++) {
533                 scalar_t len_sq = (vec - pos[i]).length_sq();
534                 scalar_t len_quad = len_sq * len_sq;
535                 normal += (vec - pos[i]) * 2.0 * bint[i] / len_quad;
536         }
537
538         return normal.normalized();
539 #endif
540 }
541
542
543 static void make_blobs(Scene *scene) {
544         // scalar field
545         const int grid = 23;
546         const scalar_t field_size = 40.0;
547         const scalar_t hsz = field_size / 2.0;
548
549         sfield = new ScalarField(grid, Vector3(-hsz, -hsz, -hsz), Vector3(hsz, hsz, hsz));
550         sfield->set_evaluator(eval_func);
551         sfield->set_normal_evaluator(eval_normals);
552         
553         // rendering details
554         Texture *cubemap = new Texture(64, 64, TEX_CUBE);
555         add_texture(cubemap);
556
557         blob = new Object;
558         blob->name = "blob";
559         blob->set_dynamic(true);
560         blob->set_position(Vector3(0, 50, 0));
561         blob->set_scaling(Vector3(2.8, 2.6, 2.8));
562         blob->set_auto_normalize(true);
563
564         Material *mat = blob->get_material_ptr();
565         mat->ambient_color = mat->diffuse_color = Color(0.7, 0.4, 0.2) * 0.4;
566         mat->specular_color = Color(0.9, 0.7, 0.6);
567         mat->specular_power = 60.0;
568         mat->set_texture(cubemap, TEXTYPE_ENVMAP);
569         mat->env_intensity = 0.6;
570         mat->auto_refl = false;
571         mat->two_sided = true;
572
573         scene->add_object(blob);
574 }