compiler/libec: (#205) Fixed integer promotions to follow the C standard (6.3.1.1)
[sdk] / samples / 3D / terrainCameraDemo / dna.ec
1 /****************************************************************************
2    ECERE Runtime Library
3
4    Copyright (c) 2001 Jerome Jacovella-St-Louis
5    All Rights Reserved.
6
7    dna.ec - DNA 3D Model
8 ****************************************************************************/
9 public import "ecere"
10
11 bool CreateCylinder(Mesh mesh, int radius, int height, int steps, DisplaySystem displaySystem)
12 {
13    bool result = false;
14    if(mesh)
15       if(mesh.Allocate({ vertices = true, normals = true, texCoords1 = true }, steps * 2, displaySystem))
16       {
17          PrimitiveGroup group = mesh.AddPrimitiveGroup({ triStrip, true }, 0);
18          if(group)
19          {
20             int c;
21             Vector3Df *pVertices, *pNormals;
22             Pointf *pTexCoords;
23
24             pVertices  = mesh.vertices;
25             pNormals   = mesh.normals;
26             pTexCoords = mesh.texCoords;
27
28             group.first = 0;
29             group.nVertices = steps * 2;
30
31             for(c = 0; c<steps; c++)
32             {
33                int index;
34                Radians theta = (2 * Pi * c) / (steps - 1);
35
36                index = 2 * c + 1;
37                pVertices[index].x = (float)sin(theta) * radius;
38                pVertices[index].y = -height/2;
39                pVertices[index].z = (float)cos(theta) * radius;
40
41                pNormals[index].x = (float)sin(theta);
42                pNormals[index].y = 0;
43                pNormals[index].z = (float)cos(theta);
44
45 /*
46                index = 2 * c + 1;
47                pVertices[index].x = (float)cos(theta) * radius;
48                pVertices[index].y = -height/2;
49                pVertices[index].z = (float)sin(theta) * radius;
50
51                pNormals[index].x = (float)cos(theta);
52                pNormals[index].y = 0;
53                pNormals[index].z = (float)sin(theta);
54 */
55                pTexCoords[index].x = ((float) c) / (steps - 1);
56                pTexCoords[index].y = 1;
57
58
59                index = 2 * c;
60                pVertices[index].x = (float)sin(theta) * radius;
61                pVertices[index].y = height/2;
62                pVertices[index].z = (float)cos(theta) * radius;
63
64                pNormals[index].x = (float)sin(theta);
65                pNormals[index].y = 0;
66                pNormals[index].z = (float)cos(theta);
67 /*
68                index = 2 * c;
69                pVertices[index].x = (float)cos(theta) * radius;
70                pVertices[index].y = height/2;
71                pVertices[index].z = (float)sin(theta) * radius;
72
73                pNormals[index].x = (float)cos(theta);
74                pNormals[index].y = 0;
75                pNormals[index].z = (float)sin(theta);
76 */
77                pTexCoords[index].x = ((float) c) / (steps - 1);
78                pTexCoords[index].y = 0;
79             }
80             result = true;
81          }
82          mesh.Unlock(0);
83       }
84    return result;
85 }
86
87
88 public class DNABox : Mesh
89 {
90    int width, height, depth;
91 public:
92    bool Create(DisplaySystem displaySystem)
93    {
94       bool result = false;
95       if(Allocate({ vertices = true, texCoords1 = true }, 24, displaySystem))
96       {
97          PrimitiveGroup group;
98          Vector3Df vertices[24] =
99          {
100             { -(float)width/2,-(float)height/2,-(float)depth/2 },
101             {  (float)width/2,-(float)height/2,-(float)depth/2 },
102             {  (float)width/2, (float)height/2,-(float)depth/2 },
103             { -(float)width/2, (float)height/2,-(float)depth/2 },
104             { -(float)width/2,-(float)height/2, (float)depth/2 },
105             {  (float)width/2,-(float)height/2, (float)depth/2 },
106             {  (float)width/2, (float)height/2, (float)depth/2 },
107             { -(float)width/2, (float)height/2, (float)depth/2 },
108
109             { -(float)width/2,-(float)height/2,-(float)depth/2 },
110             {  (float)width/2,-(float)height/2,-(float)depth/2 },
111             {  (float)width/2, (float)height/2,-(float)depth/2 },
112             { -(float)width/2, (float)height/2,-(float)depth/2 },
113             { -(float)width/2,-(float)height/2, (float)depth/2 },
114             {  (float)width/2,-(float)height/2, (float)depth/2 },
115             {  (float)width/2, (float)height/2, (float)depth/2 },
116             { -(float)width/2, (float)height/2, (float)depth/2 },
117
118             { -(float)width/2,-(float)height/2,-(float)depth/2 },
119             {  (float)width/2,-(float)height/2,-(float)depth/2 },
120             {  (float)width/2, (float)height/2,-(float)depth/2 },
121             { -(float)width/2, (float)height/2,-(float)depth/2 },
122             { -(float)width/2,-(float)height/2, (float)depth/2 },
123             {  (float)width/2,-(float)height/2, (float)depth/2 },
124             {  (float)width/2, (float)height/2, (float)depth/2 },
125             { -(float)width/2, (float)height/2, (float)depth/2 }
126          };
127          Pointf texCoords[24] =
128          {
129             { 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1 },
130             { 1, 0 }, { 0, 0 }, { 0, 1 }, { 1, 1 },
131             { 1, 0 }, { 0, 0 }, { 0, 1 }, { 1, 1 },
132             { 0, 0 }, { 1, 0 }, { 1, 1 }, { 0, 1 },
133             { 0, 1 }, { 1, 1 }, { 1, 1 }, { 0, 1 },
134             { 0, 0 }, { 1, 0 }, { 1, 0 }, { 0, 0 }
135          };
136          uint16 indices[36] =
137          {
138             // up, front, down, back, right, left
139             21,20,16, 17,21,16,
140             3,2,1, 0,3,1,
141             18,19,23, 22,18,23,
142             6,7,4, 5,6,4,
143             10,14,13, 9,10,13,
144             15,11,8, 12,15,8
145          };
146
147          memcpy(this.vertices, vertices, sizeof(vertices));
148          memcpy(this.texCoords, texCoords, sizeof(texCoords));
149
150          group = AddPrimitiveGroup(triangles, 36);
151          if(group)
152          {
153             memcpy(group.indices, indices, sizeof(indices));
154
155             ComputeNormals();
156
157             result = true;
158
159             UnlockPrimitiveGroup(group);
160          }
161          Unlock(0);
162       }
163       return result;
164    }
165 }
166
167 public class DNAHelix : Mesh
168 {
169    int start;
170    int height;
171    float numCurves;
172    int curveSegments;
173    int radius;
174    int width;
175
176 public:
177    bool Create(DisplaySystem displaySystem)
178    {
179       bool result = false;
180       PrimitiveGroup group;
181       uint16 num = (uint16)(curveSegments*numCurves);
182       int vertexCount = (num+1)*4;
183
184       if(Allocate({ vertices = true, texCoords1 = true }, vertexCount, displaySystem))
185       {
186          uint16 v;
187          Radians angle;
188          int segment;
189          uint16 startv;
190          float x,y;
191          int polygonCount = ((num*4)+2);
192
193          //Define Vertices
194          for(v=0, segment=0; segment<num+1; segment++)
195          {
196             angle=segment*2*Pi/curveSegments+start;
197             x=(float)(cos(angle)*(radius-width/4));
198             y=(float)(sin(angle)*(radius-width/4));
199
200             texCoords[v].x = (float)segment / (num + 1) * 16;
201             texCoords[v].y = 0;
202             vertices[v++] = { -x,-(float)height/2+segment*(float)height/num, y };
203             texCoords[v].x = (float)segment / (num + 1) * 16;
204             texCoords[v].y = 0.25f;
205             vertices[v++] = { -x,-(float)height/2+segment*(float)height/num+width, y };
206          }
207          startv=v;
208          for(segment=0; segment<num+1; segment++)
209          {
210             angle=segment*2*Pi/curveSegments+start;
211             x=(float)(cos(angle)*(radius+width/4));
212             y=(float)(sin(angle)*(radius+width/4));
213
214             texCoords[v].x = (float)segment / (num + 1) * 16;
215             texCoords[v].y = 0.75f;
216             vertices[v++] = { -x,-(float)height/2+segment*(float)height/num, y };
217             texCoords[v].x = (float)segment / (num + 1) * 16;
218             texCoords[v].y = 0.50f;
219             vertices[v++] = { -x,-(float)height/2+segment*(float)height/num+width, y };
220          }
221
222          group = AddPrimitiveGroup(triangles, polygonCount * 6);
223          if(group)
224          {
225             int index = 0;
226             uint16 p;
227
228             //Define Polygons
229             for(p=0; p<num; p++)
230             {
231                group.indices[index++] = p*2+1;
232                group.indices[index++] = p*2+3;
233                group.indices[index++] = p*2+2;
234                group.indices[index++] = p*2+2;
235                group.indices[index++] = p*2;
236                group.indices[index++] = p*2+1;
237
238                group.indices[index++] = p*2+startv;
239                group.indices[index++] = p*2+2+startv;
240                group.indices[index++] = p*2+3+startv;
241                group.indices[index++] = p*2+3+startv;
242                group.indices[index++] = p*2+1+startv;
243                group.indices[index++] = p*2+startv;
244
245                group.indices[index++] = p*2+startv+1;
246                group.indices[index++] = p*2+startv+3;
247                group.indices[index++] = p*2+3;
248                group.indices[index++] = p*2+3;
249                group.indices[index++] = p*2+1;
250                group.indices[index++] = p*2+startv+1;
251
252                group.indices[index++] = p*2;
253                group.indices[index++] = p*2+2;
254                group.indices[index++] = p*2+startv+2;
255                group.indices[index++] = p*2+startv+2;
256                group.indices[index++] = p*2+startv;
257                group.indices[index++] = p*2;
258             }
259
260             // Ends
261             group.indices[index++] = startv;
262             group.indices[index++] = startv+1;
263             group.indices[index++] = 1;
264             group.indices[index++] = 1;
265             group.indices[index++] = 0;
266             group.indices[index++] = startv;
267
268             group.indices[index++] = 2*num;
269             group.indices[index++] = 2*num+1;
270             group.indices[index++] = 2*num+startv+1;
271             group.indices[index++] = 2*num+startv+1;
272             group.indices[index++] = 2*num+startv;
273             group.indices[index++] = 2*num;
274
275             ComputeNormals();
276             result = true;
277
278             UnlockPrimitiveGroup(group);
279          }
280          Unlock(0);
281       }
282       return result;
283    }
284 }
285
286 static const char * names[7] = { "Adenine", "Cytosine", "Guanine", "Thymine", "Phosphate", "Desoxyribose", "Hydrogene" };
287
288 public class DNAModel : Object
289 {
290    int numBases;
291    int space;
292    Degrees rotation;
293    int helixCurveSegments;
294    int helixWidth;
295    int hydrogenWidth;
296    int baseWidth;
297    int baseHeight;
298    int baseDepth;
299    int desoxyriboseWidth;
300    const char * textureFile;
301
302 public:
303    bool Create(DisplaySystem displaySystem)
304    {
305       bool result = false;
306       if(this)
307       {
308          InitializeMesh(displaySystem);
309
310          if(mesh)
311          {
312             int c;
313             Bitmap map { };
314             Object phosphate, hydrogen;
315             Material material;
316             DNABox box { width = baseWidth, height = baseHeight, depth = baseDepth };
317             // TOFX: Warning this didn't do what I expected: (Neither did a watch on 'rotation'!)
318             //DNAHelix helix { start = 0, height = (numBases-1)*space, numCurves = (float)(numBases * rotation / 360), curveSegments = helixCurveSegments,
319             DNAHelix helix { start = 0, height = (numBases-1)*space, numCurves = (float)(numBases * (double)rotation / 360), curveSegments = helixCurveSegments,
320                radius = hydrogenWidth + baseWidth + desoxyriboseWidth, width = helixWidth };
321
322             map.Load(textureFile ? textureFile : ":texture1.pcx", null, null);
323
324             for(c = 0; c < 7; c++)
325             {
326                material = { name = CopyString(names[c]) };
327                displaySystem.AddMaterial(material);
328                if(material)
329                {
330                   material.diffuse = material.ambient = white;
331                   material.opacity = 1;
332                   if(map)
333                   {
334                      material.baseMap = displaySystem.GetTexture(names[c]);
335                      if(!material.baseMap)
336                      {
337                         material.baseMap = Bitmap { };
338                         material.baseMap.Allocate(null, 64, 64, 0, map.pixelFormat, true);
339                         if(map.pixelFormat == pixelFormat8)
340                            CopyBytesBy4(material.baseMap.palette, map.palette, 256);
341                         material.baseMap.Grab(map, 0, c*material.baseMap.height);
342                         material.baseMap.MakeMipMaps(displaySystem);
343                         displaySystem.AddTexture(names[c], material.baseMap);
344                      }
345                   }
346                   if(!strcmp(names[c], "Phosphate"))
347                      material.flags.tile = true;
348                }
349             }
350             if(map)
351                delete map;
352
353             //*******************  Base Meshes *******************
354             box.Create(null);
355             helix.Create(null);
356             helix.ApplyMaterial(displaySystem.GetMaterial("Phosphate"));
357
358             //*******************  PHOSPHATE     *******************
359             phosphate = { mesh = helix }; AddName(phosphate, "Phosphate01");
360             phosphate = { mesh = helix }; AddName(phosphate, "Phosphate02");
361             phosphate.transform.orientation = Euler { yaw = 180 };
362
363             //*******************  HYDROGENE     *******************
364             hydrogen = { }; AddName(hydrogen, "Hydrogene");
365             hydrogen.InitializeMesh(null);
366             CreateCylinder(hydrogen.mesh, hydrogenWidth/2, numBases*space, 50, null);
367             material = displaySystem.GetMaterial("Hydrogene");
368             material.flags.doubleSided = true;
369             hydrogen.mesh.ApplyMaterial(material);
370             //******************************************************
371
372             RandomSeed(0x1234);
373
374             for(c=0; c<numBases; c++)
375             {
376                Object base, desoxyribose;
377                char name[20];
378                Vector3D pos;
379
380                // Pick texture
381                int b1 = GetRandom(0,3);
382                int b2 = 3-b1;
383                Quaternion angle { 1,0,0,0 };
384                Vector3D position;
385                Matrix matrix;
386
387                // Change Rotation
388                angle.Yaw(-rotation*c);
389                matrix.RotationQuaternion(angle);
390
391                position = { (baseWidth+hydrogenWidth)/2.0f,-numBases*space/2.0f+space/2.0f+c*space,0 };
392
393                //*******************  BASES         *******************
394                sprintf(name, "Base%02d", c*2);
395                base = { }; AddName(base, name);
396                base.flags = { mesh = true };
397                base.mesh = box;
398                base.transform.orientation = angle;
399                base.transform.scaling = { 1,1,1 };
400                base.matrix.Identity();
401                pos.MultMatrix(position, matrix); base.transform.position = pos;
402                base.UpdateTransform();
403                base.material = displaySystem.GetMaterial(names[b1]);
404
405                sprintf(name, "Base%02d", c*2+1);
406                base = { }; AddName(base, name);
407                base.flags = { mesh = true };
408                base.mesh = box;
409                base.transform.orientation = angle;
410                base.transform.scaling = { 1,1,1 };
411                base.matrix.Identity();
412                position.x = -(baseWidth+hydrogenWidth)/2.0f;
413                base.UpdateTransform();
414                pos.MultMatrix(position, matrix); base.transform.position = pos;
415                base.material = displaySystem.GetMaterial(names[b2]);
416
417                //*******************  DESOXYRIBOSE  *******************
418                sprintf(name, "Desoxyribose%02d", c*2);
419                desoxyribose = { }; AddName(desoxyribose, name);
420                desoxyribose.mesh = box;
421                desoxyribose.transform.orientation = angle;
422                desoxyribose.transform.scaling = { (float)desoxyriboseWidth / baseWidth, 1,1 };
423                position.x = baseWidth+(desoxyriboseWidth+hydrogenWidth)/2.0f;
424                pos.MultMatrix(position, matrix); desoxyribose.transform.position = pos;
425                desoxyribose.material = displaySystem.GetMaterial("Desoxyribose");
426
427                sprintf(name, "Desoxyribose%02d", c*2+1);
428                desoxyribose = { }; AddName(desoxyribose, name);
429                desoxyribose.mesh = box;
430                desoxyribose.transform.orientation = angle;
431                desoxyribose.transform.scaling = { (float)desoxyriboseWidth / baseWidth, 1,1 };
432                position.x = -baseWidth-(desoxyriboseWidth+hydrogenWidth)/2.0f;
433                pos.MultMatrix(position, matrix); desoxyribose.transform.position = pos;
434                desoxyribose.material = displaySystem.GetMaterial("Desoxyribose");
435             }
436             transform.scaling = { 1,1,1 };
437             transform.orientation = { 1, 0,0,0 };
438             UpdateTransform();
439
440             if(Merge(displaySystem))
441                result = true;
442             UpdateTransform();
443             SetMinMaxRadius(true);
444
445             delete box;
446             delete helix;
447          }
448       }
449       return result;
450    }
451 }