dc184217c6ccfad42060809b20b21ebf1f90dc89
[sdk] / samples / 3D / terrainCameraDemo / demo.ec
1 /****************************************************************************
2    Ecere 3D Engine Demonstration
3
4    Copyright (c) 2001-2010 Jerome Jacovella-St-Louis
5    All Rights Reserved.
6
7    demo.ec - Main Module
8 ****************************************************************************/
9 import "ecere"
10 import "dna"
11 import "terrain"
12
13 define BACKGROUND = white;
14 define speed = 200;
15
16 // --- Terrain Data Loading ---
17 static Elevation heightMap[1025 * 1025];
18
19 #define ALTITUDE_FACTOR 1
20 #define ALTITUDE_OFFSET 0 // -5000
21
22 #define EARTH_RADIUS 6367000
23
24 #define CELL_LAT_POINTS  1201
25 #define CELL_LON_POINTS  1201
26
27 #define RESOLUTION_LAT  (EARTH_RADIUS * ((Pi / 180) / (CELL_LAT_POINTS - 1)))
28 #define RESOLUTION_LON(LATITUDE)  (EARTH_RADIUS * ((float)sin(LATITUDE) * ((Pi / 180) / (CELL_LON_POINTS - 1))))
29
30 /*
31 struct ElevationColor
32 {
33    int altitude;
34    ColorAlpha color;
35 };
36
37 static Array<ElevationColor> colorMap
38 { [
39    {  0, Color { 0, 0, 0 } },
40    {  1100, Color { 28, 24, 101 } },
41    {   1200, Color { 17, 138, 150 } },
42    {   1300, Color { 0,75,0 } },
43    {  1500, Color { 244,244,144 } },
44    {  2000, Color { 79, 45, 8 } },
45    {  2300, Color { 129, 65, 58 } },
46    {  2600, Color { 185, 185, 185 } },
47    {  3000, Color { 255, 255, 255 } }
48 ] };
49
50 static void OutputTexture(String fileName)
51 {
52    Bitmap bitmap { };
53    if(bitmap.Allocate(null, 1025, 1025, 0, pixelFormat888, false))
54    {
55       ColorAlpha * picture = (ColorAlpha *)bitmap.picture;
56       int y, x;
57
58       Array<ColorAlpha> colorTable { size = 65536 };
59       int altitude;
60       ElevationColor * curKey = colorMap.array, * nextKey = colorMap.array;
61       int keyNum = 0, nextKeyNum = 0;
62
63       for(altitude = -32768; altitude<32768; altitude++)
64       {
65          int a = 255;
66          Color color;
67          while(altitude > nextKey->altitude)
68          {
69             curKey = nextKey; keyNum = nextKeyNum;
70             if(keyNum < colorMap.count - 1)
71             {
72                nextKey = curKey + 1;
73                nextKeyNum = keyNum + 1;
74             }
75             else
76                break;
77          }
78
79          if(nextKey->altitude != curKey->altitude)
80          {
81             float scale = (float) (altitude - curKey->altitude) / (nextKey->altitude - curKey->altitude);
82             Color cColor = curKey->color, nColor = nextKey->color;
83             int cr = cColor.r, cg = cColor.g, cb = cColor.b;
84             int nr = nColor.r, ng = nColor.g, nb = nColor.b;
85             int r = (int)(cr + (nr - cr) * scale);
86             int g = (int)(cg + (ng - cg) * scale);
87             int b = (int)(cb + (nb - cb) * scale);
88             r = Max(Min(r, 255),0);
89             g = Max(Min(g, 255),0);
90             b = Max(Min(b, 255),0);
91             color = { (byte)r, (byte)g, (byte)b };
92          }
93          else
94             color = curKey->color;
95          colorTable[altitude + 32768] = { 255, color };
96       }
97
98       for(y = 0; y < bitmap.height; y++)
99          for(x = 0; x < bitmap.width; x++)
100             picture[y * bitmap.width + x] = colorTable[heightMap[y * 1025 + x] + 32768];
101
102       delete colorTable;
103       bitmap.Save(fileName, null, null);
104    }
105    delete bitmap;
106 }
107 */
108
109 static bool LoadTerrain(Terrain terrain, char * fileName, Angle lat)
110 {
111    bool result = false;
112    File f = FileOpen(fileName, read);
113    if(f)
114    {
115       int y;
116       float resLon = (float)RESOLUTION_LON(lat);
117       for(y = 0; y<1025; y++)
118       {
119          int x;
120          byte buffer[1201 * 2];
121          if(f.Read(buffer, sizeof(uint16), 1201) < 1201)
122             break;
123          for(x = 0; x<1025; x++)
124          {
125             unsigned char b0 = buffer[2*x], b1 = buffer[2*x+1];
126             short value = (short)((((int)b0 << 8) | b1) - ((b0 & 0x80) ? 0x10000 : 0));
127             if(value > 20000) value = -32768;
128             heightMap[y*1025+x] = value * ALTITUDE_FACTOR + ALTITUDE_OFFSET;
129          }
130       }
131
132       // OutputTexture("res/texture.png");
133
134       if(terrain.Create(heightMap, 16, 1025, 2, resLon, RESOLUTION_LAT, 512,512))
135          result = true;
136       delete f;
137    }
138    return result;
139 }
140
141 class Scene : Window
142 {
143    bool filled;
144
145    Camera camera
146    {
147       //type = attached;
148       type = attachedQuaternion;
149       position = { 0, 0, -10 };
150       orientation = Euler { 180, 30, 0 };
151       zMax = 340000;
152    };
153    Light light;
154    Terrain terrain { };
155    Bitmap textures[16];
156    //Bitmap detail { };
157    Object player { };
158    SkyBox sky { size = { 100, 100, 100 }, folder = ":skycube", extension = "jpg" };
159    DNAModel dna
160    {
161       numBases = 24;
162       space = 60;
163       rotation = 22.5; //Pi/8;
164       helixCurveSegments = 48;
165       helixWidth = 50;
166       hydrogenWidth = 40;
167       baseWidth = 180;
168       baseHeight = 40;
169       baseDepth = 40;
170       desoxyriboseWidth = 40;
171       textureFile = ":texture1.pcx";
172    };
173    /*
174    Cube dna
175    {
176       size = { 100, 100, 100 };
177    };*/
178
179    Object water { };
180    Material groundMaterial;
181    TerrainMesh terrainMesh { terrain = terrain };
182    float fogDensity;
183    float detailBias;
184    float zMax;
185    double lastTime;
186    FPS frameRate;
187    int frame;
188    Point lastMousePosition, newMousePosition;
189    bool leftDown, rightDown;
190    bool acquiredInput;
191
192    borderStyle = sizable;
193    hasMaximize = true;
194    hasMinimize = true;
195    hasClose = true;
196
197    text = "3D Camera & Terrain Demo";
198    size = { 640, 480 };
199
200    Scene()
201    {
202       // Load terrain from SRTM data ( 3 arc seconds data from http://www.viewfinderpanoramas.org/ , L12 Cell)
203       LoadTerrain(terrain, ":N45W110.hgt", Degrees { 45 });
204
205       frame = 0;
206       fogDensity = 0.0001f;
207       detailBias = 400;//1000;
208       //detailBias = 0;
209       //zMax = 100000; //340000;
210       zMax = 340000;
211       filled = true;
212       newMousePosition = lastMousePosition = { MAXINT, MAXINT };
213    }
214
215    Timer timer
216    {
217       this, delay = 0.01;
218
219       bool DelayExpired()
220       {
221          Elevation height;
222          int x, y;
223          MouseButtons b;
224          static bool firstTime = true;
225          double currentTime = GetTime();
226          double diffTime = currentTime - lastTime;
227          lastTime = currentTime;
228
229          if(dna)
230          {
231             Quaternion orientation = dna.transform.orientation;
232             orientation.RotateYawPitch(Degrees { (float)30*diffTime }, 0);
233             dna.transform.orientation = orientation;
234             dna.UpdateTransform();
235          }
236
237          //light.orientation.RotatePitch(Radians { 0.02f });
238
239          if(acquiredInput)
240             ((GuiApplication)__thisModule).GetMouseState(&b, &x, &y);
241          else
242          {
243             if(lastMousePosition.x != MAXINT)
244             {
245                x = newMousePosition.x - lastMousePosition.x;
246                y = newMousePosition.y - lastMousePosition.y;
247                lastMousePosition = newMousePosition;
248             }
249             else
250             {
251                x = y = 0;
252             }
253             b = 0;
254             if(leftDown)  b.left = true;
255             if(rightDown) b.right = true;
256          }
257
258          if(player)
259          {
260             player.Animate(frame);
261             frame ++;
262             if(frame == 100) frame = 0;
263
264             //player.RotateEuler({ Radians { -x / 60.0f }, Radians { -y / 60.0f } }, { pitch = -90 }, { pitch = 90 });
265             //player.RotateEuler({ roll = Radians { x / 60.0f }, pitch = Radians { y / 60.0f } }, null, null);
266             //player.Rotate({ roll = Radians { x / 60.0f }, pitch = Radians { y / 60.0f } });
267             {
268                Quaternion a = player.transform.orientation;
269                a.RotateRoll(Radians { x / 60.0f });
270                a.RotatePitch(Radians { y / 60.0f });
271                player.transform.orientation = a;
272                player.UpdateTransform();
273             }
274
275             if(b.right)
276                player.Move({ 0, 0,-(float)diffTime * (camera.type == attachedQuaternion ? 10 : 1) * speed });
277             else if(b.left)
278                player.Move({ 0, 0, (float)diffTime * (camera.type == attachedQuaternion ? 10 : 1) * speed });
279
280             height = (int)-terrain.GetElevation(
281                (float)player.transform.position.x,
282                (float)player.transform.position.z);
283
284             if((float)player.transform.position.y > height - 100)
285             {
286                player.transform.position.y = height - 100.0f;
287                player.UpdateTransform();
288             }
289          }
290
291          if(firstTime || x || y || b)
292          {
293             firstTime = false;
294             camera.Slerp(0.2f);
295          }
296
297          if(camera.Update())
298          {
299             display.Lock(false);
300             terrainMesh.OptimizeMesh(camera, detailBias, zMax);
301             display.Unlock();
302          }
303
304          Update(null);
305          return true;
306       }
307    };
308
309    void OnPosition(int x, int y, int w, int h)
310    {
311       camera.Setup(w, h, null);
312       camera.Update(); // This wasn't necessary before!
313       display.Lock(false);
314       terrainMesh.OptimizeMesh(camera, detailBias, zMax);
315       display.Unlock();
316    }
317
318    bool OnPostCreate()
319    {
320       timer.Start();
321       acquiredInput = AcquireInput(true);
322       return true;
323    }
324
325    bool OnMouseOver(int x, int y, Modifiers mods)
326    {
327       lastMousePosition = { x, y };
328       newMousePosition = { x, y };
329       return true;
330    }
331
332    bool OnMouseLeave(Modifiers mods)
333    {
334       lastMousePosition = { MAXINT, MAXINT };
335       newMousePosition = { MAXINT, MAXINT };
336       return true;
337    }
338
339    bool OnMouseMove(int x, int y, Modifiers mods)
340    {
341       newMousePosition = { x, y };
342       return true;
343    }
344
345    bool OnLeftButtonDown(int x, int y, Modifiers mods)
346    {
347       leftDown = true;
348       Capture();
349       return true;
350    }
351
352    bool OnLeftButtonUp(int x, int y, Modifiers mods)
353    {
354       if(leftDown && !rightDown)
355          ReleaseCapture();
356       leftDown = false;
357       return true;
358    }
359
360    bool OnRightButtonDown(int x, int y, Modifiers mods)
361    {
362       rightDown = true;
363       Capture();
364       return true;
365    }
366    bool OnRightButtonUp(int x, int y, Modifiers mods)
367    {
368       if(rightDown && !leftDown)
369          ReleaseCapture();
370       rightDown = false;
371       return true;
372    }
373
374    bool OnLoadGraphics()
375    {
376       Bitmap map { };
377
378       light.ambient = { 0.2f, 0.2f, 0.2f };
379       light.diffuse = light.specular = white;
380       light.orientation = { 1,0,0,0 };
381       light.orientation.RotatePitch(30);
382
383       if(map.Load(":texture.png", null, null))
384       {
385          int c;
386          int across = 4;
387          map.Convert(null, pixelFormat888, null);
388          map.SmoothEdges(256);
389          for(c = 0; c < across * across; c++)
390          {
391             textures[c] = { };
392             textures[c].Allocate(null, 256, 256, 0, map.pixelFormat, true);
393             if(map.pixelFormat == pixelFormat8)
394                memcpy(textures[c].palette, map.palette, 256*4);
395             textures[c].Grab(map,
396                      (c % across) * textures[c].width,
397                      (c / across) * textures[c].height);
398             textures[c].MakeMipMaps(displaySystem);
399          }
400       }
401       delete map;
402
403       player.Load(":aircraft/aircraft.3DS", null, displaySystem);
404
405       camera.target = player;
406
407       dna.Create(displaySystem);
408
409       if(dna)
410          dna.transform.position.y = -2200;
411       dna.UpdateTransform();
412
413       if(player)
414       {
415          player.transform.position.y = -2200;
416          player.transform.position.x = 1000;
417          player.transform.orientation = Euler { yaw = 230 };
418       }
419
420       /*detail.Load(":detail.pcx", null, displaySystem);
421       displaySystem.AddTexture("DetailTexture", detail);*/
422
423       sky.InitializeMesh(displaySystem);
424       sky.Create(displaySystem);
425
426       terrainMesh.CreateMesh(terrain, 8192*16, 1024, 1024, false, false, displaySystem);
427       lastTime = GetTime();
428
429       frameRate.Start();
430       return true;
431    }
432
433    void OnUnloadGraphics()
434    {
435       int c;
436       for(c = 0; c<16; c++)
437          delete textures[c];
438       terrainMesh.FreeMesh();
439    }
440
441    void OnRedraw(Surface surface)
442    {
443       surface.SetBackground(BACKGROUND);
444
445       surface.Clear(depthBuffer);
446
447       display.SetCamera(surface, camera);
448
449       display.SetLight(0, light);
450       display.fogColor = BACKGROUND;
451       display.fogDensity = fogDensity;
452       //display.fogDensity = 0.0000000001f;
453
454       sky.Render(camera, display);
455
456       if(!filled) display.fillMode = wireframe;
457       terrainMesh.RenderMesh(display, null, textures);
458       if(!filled) display.fillMode = solid;
459
460       display.DrawObject(dna);
461       display.DrawObject(player);
462
463       display.SetCamera(surface, null);
464
465       surface.SetForeground(black);
466       //surface.WriteTextf(10,10, "Detail: %.0f, ZMax: %.02f, FPS: %.02f", detailBias, zMax, frameRate.fps);
467
468       frameRate.Step();
469    }
470
471    bool OnKeyDown(Key key, unichar ch)
472    {
473       switch(key)
474       {
475          case escape:
476             Destroy(0);
477             return false;
478          case w: filled = false; break;
479          case f: filled = true; break;
480          case u:
481             AcquireInput(false);
482             acquiredInput = false;
483             GetMousePosition(&lastMousePosition.x, &lastMousePosition.y);
484             break;
485          case a:
486             acquiredInput = AcquireInput(true);
487             break;
488          case k0:
489             camera.type = fixed;
490             camera.position = camera.cPosition;
491             camera.orientation = camera.cOrientation;
492             break;
493          case k1:
494             /*camera.type = attached;
495             camera.position = { 0, 0, -30 };
496             camera.Slerp(0.1f);
497             */
498             camera.type = attachedQuaternion;
499             camera.position = { 0, 0, -10 };
500             camera.orientation = Euler { 180, 30, 0 };
501             camera.Slerp(0.2f);
502             break;
503          case k2:
504             camera.type = lookAt;
505             camera.position = camera.cPosition; //{ 1000, -3000, 0 };
506             camera.position.z -= 5;
507             camera.orientation = { 1,0,0,0 };
508             camera.Slerp(0.1f);
509             break;
510       }
511       return true;
512    }
513
514    bool OnKeyHit(Key key, unichar ch)
515    {
516       float detailBias = this.detailBias;
517       float zMax = this.zMax;
518       switch(key)
519       {
520          case pageUp: detailBias++; break;
521          case pageDown: detailBias--; break;
522          case home: zMax *= 0.9f; break;
523          case end: zMax /= 0.9f; break;
524          case keyPadPlus: camera.position.z /= 0.9f; break;
525          case keyPadMinus: camera.position.z *= 0.9f; break;
526          case f7: camera.RotateYaw(-0.02f, 0, 0); break;
527          case f8: camera.RotateYaw(0.02f, 0, 0);  break;
528          case f9: camera.RotatePitch(-0.02f, 0, 0); break;
529          case f10:camera.RotatePitch( 0.02f, 0, 0); break;
530       }
531       if(this.detailBias != detailBias || this.zMax != zMax)
532       {
533          this.detailBias = Max(0, detailBias);
534          this.zMax = Min(zMax, 340000);
535          display.Lock(false);
536          terrainMesh.OptimizeMesh(camera, this.detailBias, this.zMax);
537          display.Unlock();
538       }
539       return true;
540    }
541 }
542
543 class CameraDemoApp : GuiApplication
544 {
545    driver = "OpenGL";
546    timerResolution = 60;
547 }
548
549 Scene scene { };