Tizen 2.1 base
[platform/upstream/libbullet.git] / Extras / CDTestFramework / Terrain.cpp
1 /*
2 CDTestFramework http://codercorner.com
3 Copyright (c) 2007-2008 Pierre Terdiman,  pierre@codercorner.com
4
5 This software is provided 'as-is', without any express or implied warranty.
6 In no event will the authors be held liable for any damages arising from the use of this software.
7 Permission is granted to anyone to use this software for any purpose, 
8 including commercial applications, and to alter it and redistribute it freely, 
9 subject to the following restrictions:
10
11 1. The origin of this software must not be misrepresented; you must not claim that you wrote the original software. If you use this software in a product, an acknowledgment in the product documentation would be appreciated but is not required.
12 2. Altered source versions must be plainly marked as such, and must not be misrepresented as being the original software.
13 3. This notice may not be removed or altered from any source distribution.
14 */
15 #include "stdafx.h"
16 #include "Terrain.h"
17
18 inline float NxAngle(const Point& v0, const Point& v1)
19         {
20         float cos = v0|v1;                                      // |v0|*|v1|*Cos(Angle)
21         float sin = (v0^v1).Magnitude();        // |v0|*|v1|*Sin(Angle)
22         return ::atan2(sin, cos);
23         }
24
25 static float computeAngle(const Point* verts, const udword* refs, udword vref)
26 {
27         udword e0=0,e2=0;
28         if(vref==refs[0])
29         {
30                 e0 = 2;
31                 e2 = 1;
32         }
33         else if(vref==refs[1])
34         {
35                 e0 = 2;
36                 e2 = 0;
37         }
38         else if(vref==refs[2])
39         {
40                 e0 = 0;
41                 e2 = 1;
42         }
43         else
44         {
45                 assert(0);
46         }
47         Point edge0 = verts[refs[e0]] - verts[vref];
48         Point edge1 = verts[refs[e2]] - verts[vref];
49
50         return NxAngle(edge0, edge1);
51 }
52 static bool buildSmoothNormals(
53         udword nbTris, udword nbVerts,
54         const Point* verts,
55         const udword* dFaces, const uword* wFaces,
56         Point* normals,
57         bool flip)
58         {
59         // Checkings
60         if(!verts || !normals || !nbTris || !nbVerts)   return false;
61
62         // Get correct destination buffers
63         // - if available, write directly to user-provided buffers
64         // - else get some ram and keep track of it
65         Point* FNormals = new Point[nbTris];
66         if(!FNormals) return false;
67
68         // Compute face normals
69         udword c = (flip!=0);
70         for(udword i=0;i<nbTris;i++)
71                 {
72                 udword Ref0 = dFaces ? dFaces[i*3+0]   : wFaces ? wFaces[i*3+0]   : 0;
73                 udword Ref1 = dFaces ? dFaces[i*3+1+c] : wFaces ? wFaces[i*3+1+c] : 1;
74                 udword Ref2 = dFaces ? dFaces[i*3+2-c] : wFaces ? wFaces[i*3+2-c] : 2;
75
76                 FNormals[i] = (verts[Ref2]-verts[Ref0])^(verts[Ref1] - verts[Ref0]);
77                 assert(!FNormals[i].IsZero());
78                 FNormals[i].Normalize();
79                 }
80
81         // Compute vertex normals
82         memset(normals, 0, nbVerts*sizeof(Point));
83
84         Point* TmpNormals = new Point[nbVerts];
85         memset(TmpNormals, 0, nbVerts*sizeof(Point));
86         for(udword i=0;i<nbTris;i++)
87                 {
88                 udword Ref[3];
89                 Ref[0] = dFaces ? dFaces[i*3+0] : wFaces ? wFaces[i*3+0] : 0;
90                 Ref[1] = dFaces ? dFaces[i*3+1] : wFaces ? wFaces[i*3+1] : 1;
91                 Ref[2] = dFaces ? dFaces[i*3+2] : wFaces ? wFaces[i*3+2] : 2;
92
93                 for(udword j=0;j<3;j++)
94                         {
95                         if(TmpNormals[Ref[j]].IsZero())
96                                 TmpNormals[Ref[j]] = FNormals[i];
97                         }
98                 }
99
100         for(udword i=0;i<nbTris;i++)
101                 {
102                 udword Ref[3];
103                 Ref[0] = dFaces ? dFaces[i*3+0] : wFaces ? wFaces[i*3+0] : 0;
104                 Ref[1] = dFaces ? dFaces[i*3+1] : wFaces ? wFaces[i*3+1] : 1;
105                 Ref[2] = dFaces ? dFaces[i*3+2] : wFaces ? wFaces[i*3+2] : 2;
106
107                 normals[Ref[0]] += FNormals[i] * computeAngle(verts, Ref, Ref[0]);
108                 normals[Ref[1]] += FNormals[i] * computeAngle(verts, Ref, Ref[1]);
109                 normals[Ref[2]] += FNormals[i] * computeAngle(verts, Ref, Ref[2]);
110                 }
111
112         // Normalize vertex normals
113         for(udword i=0;i<nbVerts;i++)
114                 {
115                 if(normals[i].IsZero())
116                         normals[i] = TmpNormals[i];
117                 assert(!normals[i].IsZero());
118                 normals[i].Normalize();
119                 }
120
121         DELETEARRAY(TmpNormals);
122         DELETEARRAY(FNormals);
123
124         return true;
125         }
126
127
128
129
130 #define ONE_OVER_RAND_MAX       (1.0f / float(RAND_MAX))
131 #define RAND_MAX_OVER_TWO   (RAND_MAX / 2 + 1)
132
133 TerrainData::TerrainData() :
134         size    (0),
135         nbVerts (0),
136         nbFaces (0),
137         offset  (0.0f),
138         width   (0.0f),
139         chaos   (0.0f),
140         verts   (NULL),
141         colors  (NULL),
142         normals (NULL),
143         faces   (NULL)
144 {
145 }
146
147 TerrainData::~TerrainData()
148 {
149         release();
150 }
151
152 void TerrainData::release()
153 {
154         DELETEARRAY(normals);
155         DELETEARRAY(faces);
156         DELETEARRAY(colors);
157         DELETEARRAY(verts);
158 }
159
160 void TerrainData::init(udword s, float o, float w, float c, bool flat, const Point* pos)
161         {
162         release();
163
164         size    = s;
165         offset  = o;
166         width   = w;
167         chaos   = c;
168         nbVerts = size*size;
169         nbFaces = (size-1)*(size-1)*2;
170
171         ////////
172
173         // Initialize terrain vertices
174         verts = new Point[nbVerts];
175         for(udword y=0;y<size;y++)
176                 {
177                 for(udword x=0;x<size;x++)
178                         {
179                         verts[x+y*size] = Point(float(x)-(float(size-1)*0.5f), 0.0f, float(y)-(float(size-1)*0.5f)) * width;
180                         }
181                 }
182
183         // Initialize terrain colors
184                 {
185                 colors = new Point[nbVerts];
186                 for(udword y=0;y<size;y++)
187                         {
188                         for(udword x=0;x<size;x++)
189                                 {
190                                 colors[x+y*size] = Point(0.5f, 0.4f, 0.2f);
191                                 }
192                         }
193                 }
194
195         // Initialize terrain faces
196         faces = new udword[nbFaces*3];
197         udword k = 0;
198         for(udword j=0;j<size-1;j++)
199                 {
200                 for(udword i=0;i<size-1;i++)
201                         {
202                         // Create first triangle
203                         faces[k++] = i   + j*size;
204                         faces[k++] = i   + (j+1)*size;
205                         faces[k++] = i+1 + (j+1)*size;
206
207                         // Create second triangle
208                         faces[k++] = i   + j*size;
209                         faces[k++] = i+1 + (j+1)*size;
210                         faces[k++] = i+1 + j*size;
211                         }
212                 }
213
214         struct Local
215                 {
216                 static void _Compute(bool* done, Point* field, udword x0, udword y0, udword currentSize, float value, udword initSize)
217                         {
218                         // Compute new size
219                         currentSize>>=1;
220                         if(!currentSize) return;
221
222                         // Compute new heights
223                         float v0 = (value * float(rand()-RAND_MAX_OVER_TWO) * ONE_OVER_RAND_MAX);
224                         float v1 = (value * float(rand()-RAND_MAX_OVER_TWO) * ONE_OVER_RAND_MAX);
225                         float v2 = (value * float(rand()-RAND_MAX_OVER_TWO) * ONE_OVER_RAND_MAX);
226                         float v3 = (value * float(rand()-RAND_MAX_OVER_TWO) * ONE_OVER_RAND_MAX);
227                         float v4 = (value * float(rand()-RAND_MAX_OVER_TWO) * ONE_OVER_RAND_MAX);
228
229                         udword x1 = (x0+currentSize)                            % initSize;
230                         udword x2 = (x0+currentSize+currentSize)        % initSize;
231                         udword y1 = (y0+currentSize)                            % initSize;
232                         udword y2 = (y0+currentSize+currentSize)        % initSize;
233
234                         if(!done[x1 + y0*initSize])     field[x1 + y0*initSize].y = v0 + 0.5f * (field[x0 + y0*initSize].y + field[x2 + y0*initSize].y);
235                         if(!done[x0 + y1*initSize])     field[x0 + y1*initSize].y = v1 + 0.5f * (field[x0 + y0*initSize].y + field[x0 + y2*initSize].y);
236                         if(!done[x2 + y1*initSize])     field[x2 + y1*initSize].y = v2 + 0.5f * (field[x2 + y0*initSize].y + field[x2 + y2*initSize].y);
237                         if(!done[x1 + y2*initSize])     field[x1 + y2*initSize].y = v3 + 0.5f * (field[x0 + y2*initSize].y + field[x2 + y2*initSize].y);
238                         if(!done[x1 + y1*initSize])     field[x1 + y1*initSize].y = v4 + 0.5f * (field[x0 + y1*initSize].y + field[x2 + y1*initSize].y);
239
240                         done[x1 + y0*initSize] = true;
241                         done[x0 + y1*initSize] = true;
242                         done[x2 + y1*initSize] = true;
243                         done[x1 + y2*initSize] = true;
244                         done[x1 + y1*initSize] = true;
245
246                         // Recurse through 4 corners
247                         value *= 0.5f;
248                         _Compute(done, field, x0,       y0,     currentSize, value, initSize);
249                         _Compute(done, field, x0,       y1,     currentSize, value, initSize);
250                         _Compute(done, field, x1,       y0,     currentSize, value, initSize);
251                         _Compute(done, field, x1,       y1,     currentSize, value, initSize);
252                         }
253                 };
254
255         // Fractalize
256         srand(42);
257         bool* done = new bool[nbVerts];
258         memset(done,0,nbVerts*sizeof(bool));
259         verts[0].y = 10.0f;
260         verts[size-1].y = 10.0f;
261         verts[size*(size-1)].y = 10.0f;
262         verts[nbVerts-1].y = 10.0f;
263         Local::_Compute(done, verts, 0, 0, size, chaos, size);
264         for(udword i=0;i<nbVerts;i++)   verts[i].y += offset;
265         delete[] done;
266         done=NULL;
267
268         // Create a flat area in our terrain
269         if(flat)
270                 {
271                 udword a = ((size)/2) - ((size)/8);
272                 udword b = ((size)/2) + ((size)/8);
273                 for(udword y=a;y<b;y++)
274                         {
275                         for(udword x=a;x<b;x++)
276                                 {
277                                 verts[x+y*size].y = 0.0f;
278                                 colors[x+y*size].x = 0.3f;
279                                 colors[x+y*size].y = 0.3f;
280                                 colors[x+y*size].z = 0.3f;
281                                 }
282                         }
283                 }
284
285         if(pos)
286                 {
287                 for(udword y=0;y<size;y++)
288                         for(udword x=0;x<size;x++)
289                                 verts[x+y*size] += *pos;
290                 }
291
292         // Build vertex normals
293         normals = new Point[nbVerts];
294         buildSmoothNormals(nbFaces, nbVerts, verts, faces, NULL, normals, true);
295         }
296
297 static void renderTerrain(const TerrainData& terrain, bool addWireframe)
298 {
299         float* pVertList = new float[terrain.nbFaces*3*3];
300         float* pNormList = new float[terrain.nbFaces*3*3];
301         float* pColorList = new float[terrain.nbFaces*4*3];
302
303         const udword* faces = terrain.faces;
304         const Point* colors = terrain.colors;
305         const Point* normals = terrain.normals;
306         const Point* verts = terrain.verts;
307
308         int vertIndex = 0;
309         int normIndex = 0;
310         int colorIndex = 0;
311         for(int i=0;i<(int)terrain.nbFaces;i++)
312         {
313                 for(int j=0;j<3;j++)
314                 {
315                         pVertList[vertIndex++] = verts[faces[i*3+j]].x;
316                         pVertList[vertIndex++] = verts[faces[i*3+j]].y;
317                         pVertList[vertIndex++] = verts[faces[i*3+j]].z;
318
319                         pNormList[normIndex++] = normals[faces[i*3+j]].x;
320                         pNormList[normIndex++] = normals[faces[i*3+j]].y;
321                         pNormList[normIndex++] = normals[faces[i*3+j]].z;
322
323                         pColorList[colorIndex++] = colors[faces[i*3+j]].x;
324                         pColorList[colorIndex++] = colors[faces[i*3+j]].y;
325                         pColorList[colorIndex++] = colors[faces[i*3+j]].z;
326                         pColorList[colorIndex++] = 1.0f;
327                 }
328         }
329
330     glEnableClientState(GL_VERTEX_ARRAY);
331         glVertexPointer(3,GL_FLOAT, 0, pVertList);
332     glEnableClientState(GL_NORMAL_ARRAY);
333         glNormalPointer(GL_FLOAT, 0, pNormList);
334     glColorPointer(4,GL_FLOAT, 0, pColorList);
335     glEnableClientState(GL_COLOR_ARRAY);
336     glDrawArrays(GL_TRIANGLES, 0, terrain.nbFaces*3);
337
338         if(addWireframe)
339         {
340                 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
341
342                 glVertexPointer(3,GL_FLOAT, 0, pVertList);
343                 glNormalPointer(GL_FLOAT, 0, pNormList);
344
345                 glDisableClientState(GL_COLOR_ARRAY);
346
347                 glLineWidth(2.0f);
348
349                 glColor4f(0.2f, 0.2f, 0.6f, 1.0f);
350                 glDrawArrays(GL_TRIANGLES, 0, terrain.nbFaces*3);
351
352                 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);      
353         }
354
355         glDisableClientState(GL_NORMAL_ARRAY);
356         glDisableClientState(GL_VERTEX_ARRAY);
357     glDisableClientState(GL_COLOR_ARRAY);
358
359         delete[] pVertList;
360         delete[] pNormList;
361         delete[] pColorList;
362 }
363
364 static void renderTerrainTriangles(const TerrainData& terrain, udword nbTriangles, const udword* indices)
365 {
366         float* pVertList = new float[nbTriangles*3*3];
367         float* pNormList = new float[nbTriangles*3*3];
368
369         const udword* faces = terrain.faces;
370         const Point* normals = terrain.normals;
371         const Point* verts = terrain.verts;
372
373         int vertIndex = 0;
374         int normIndex = 0;
375         for(int i=0;i<(int)nbTriangles;i++)
376         {
377                 udword index = *indices++;
378
379                 for(int j=0;j<3;j++)
380                 {
381                         pVertList[vertIndex++] = verts[faces[index*3+j]].x;
382                         pVertList[vertIndex++] = verts[faces[index*3+j]].y;
383                         pVertList[vertIndex++] = verts[faces[index*3+j]].z;
384
385                         pNormList[normIndex++] = normals[faces[index*3+j]].x;
386                         pNormList[normIndex++] = normals[faces[index*3+j]].y;
387                         pNormList[normIndex++] = normals[faces[index*3+j]].z;
388                 }
389         }
390
391     glEnableClientState(GL_VERTEX_ARRAY);
392         glVertexPointer(3,GL_FLOAT, 0, pVertList);
393     glEnableClientState(GL_NORMAL_ARRAY);
394         glNormalPointer(GL_FLOAT, 0, pNormList);
395         glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
396         glDrawArrays(GL_TRIANGLES, 0, nbTriangles*3);
397     glDisableClientState(GL_NORMAL_ARRAY);
398     glDisableClientState(GL_VERTEX_ARRAY);
399
400         delete[] pVertList;
401         delete[] pNormList;
402 }
403
404
405
406
407
408
409
410 static TerrainData* gTerrainData = NULL;
411 static Model* gOpcodeModel = null;
412 static MeshInterface gMeshInterface;
413
414 const Model* GetTerrainModel()
415 {
416         return gOpcodeModel;
417 }
418
419 void ReleaseTerrain()
420 {
421         DELETESINGLE(gOpcodeModel);
422         DELETESINGLE(gTerrainData);
423 }
424
425 void CreateTerrain()
426 {
427         /////////////
428         #define TERRAIN_SIZE    64
429         #define TERRAIN_CHAOS   30.0f
430
431         #define TERRAIN_OFFSET  -10.0f
432         #define TERRAIN_WIDTH   2.0f
433
434         ReleaseTerrain();
435
436         gTerrainData = new TerrainData;
437         gTerrainData->init(TERRAIN_SIZE, TERRAIN_OFFSET, TERRAIN_WIDTH, TERRAIN_CHAOS);
438
439         // Build OPCODE model
440
441         gMeshInterface.SetNbTriangles(gTerrainData->nbFaces);
442         gMeshInterface.SetNbVertices(gTerrainData->nbVerts);
443         gMeshInterface.SetPointers((const IndexedTriangle*)gTerrainData->faces, gTerrainData->verts);
444
445         OPCODECREATE Create;
446         Create.mIMesh                   = &gMeshInterface;
447         Create.mSettings.mLimit = 1;
448         Create.mSettings.mRules = SPLIT_SPLATTER_POINTS|SPLIT_GEOM_CENTER;
449         Create.mNoLeaf                  = true;
450         Create.mQuantized               = true;
451         Create.mKeepOriginal    = false;
452         Create.mCanRemap                = false;
453
454         gOpcodeModel = new Model;
455         if(!gOpcodeModel->Build(Create))
456         {
457         }
458 }
459
460 void RenderTerrain()
461 {
462         if(gTerrainData)
463                 renderTerrain(*gTerrainData, true);
464 }
465
466 void RenderTerrainTriangles(udword nbTriangles, const udword* indices)
467 {
468         if(gTerrainData)
469                 renderTerrainTriangles(*gTerrainData, nbTriangles, indices);
470 }