cleaned all trailing white space from source files.
[sdk] / ecere / src / gfx / 3D / Mesh.ec
1 namespace gfx3D;
2
3 import "Display"
4
5 public class MeshFeatures { public bool vertices:1, normals:1, texCoords1:1, texCoords2:1, doubleNormals:1, doubleVertices:1, colors:1; };
6 public class PrimitiveGroupType { public: RenderPrimitiveType primitiveType:8; bool vertexRange:1, indices32bit:1; };
7 public enum RenderPrimitiveType : PrimitiveGroupType
8 {
9    dot, // Point,
10    lines,
11    triangles,
12    triStrip,
13    triFan,
14    quads,
15    quadStrip,
16    lineStrip
17 };
18 public class MaterialFlags { public bool doubleSided:1, translucent:1, tile:1, noFog:1, singleSideLight:1; };
19 public class Material : struct
20 {
21 public:
22    Material prev, next;
23    char * name;
24    float opacity;
25    ColorRGB diffuse;
26    ColorRGB ambient;
27    ColorRGB specular;
28    ColorRGB emissive;
29    float power;
30    Bitmap baseMap;
31    Bitmap bumpMap;
32    Bitmap envMap;
33    MaterialFlags flags;
34
35    void Free()
36    {
37       delete name;
38    }
39 };
40
41 public class PrimitiveGroup : struct
42 {
43 public:
44    PrimitiveGroup prev, next;
45    PrimitiveGroupType type;
46    union
47    {
48       struct { uint16 * indices; int nIndices; };
49       struct { int first, nVertices; };
50    };
51    Material material;
52 private:
53    void * data;
54 };
55
56 public struct PrimitiveSingle
57 {
58 public:
59    PrimitiveGroupType type;
60    union
61    {
62       struct { uint16 * indices; int nIndices; };
63       struct { int first, nVertices; };
64    };
65    Material material;
66
67 private:
68    void * data;
69    Vector3Df middle;
70    Plane plane;
71 };
72
73 public class Mesh : struct
74 {
75 public:
76    property Pointf * texCoords { get { return texCoords; } set { texCoords = value; } };
77    property int nVertices { get { return nVertices; } set { nVertices = value; } };
78    property Vector3Df * vertices { get { return vertices; } set { vertices = value; } };
79    property Vector3Df * normals { get { return normals; } set { normals = value; } };
80    property ColorRGBAf * colors { get { return colors; } set { colors = value; } };
81    property OldList groups { get { value = groups; } };
82    property MeshFeatures flags { get { return flags; } set { flags = value; } };
83
84    void Free(MeshFeatures what)
85    {
86       if(this)
87       {
88          DisplaySystem displaySystem = this.displaySystem;
89          PrimitiveGroup group;
90          if(!what)
91          {
92             int c;
93
94             flags = 0;
95             if(driver)
96                driver.FreeMesh(displaySystem, this);
97             for(;(group = groups.first);)
98                FreePrimitiveGroup(group);
99
100             for(c = 0; c<nPrimitives; c++)
101             {
102                if(primitives[c].data)
103                   driver.FreeIndices(displaySystem, primitives[c].data);
104             }
105
106             delete primitives;
107             nPrimitives = 0;
108             nVertices = 0;
109             this.displaySystem = null;
110             driver = null;
111          }
112          else
113          {
114             flags &= ~what;
115             if(driver)
116                driver.FreeMesh(displaySystem, this);
117          }
118       }
119    }
120
121    bool Allocate(MeshFeatures what, int nVertices, DisplaySystem displaySystem)
122    {
123       bool result = false;
124       if((!nVertices || nVertices == nVertices) && (!this.displaySystem || this.displaySystem == displaySystem))
125       {
126          flags |= what;
127          this.nVertices = nVertices;
128          driver = displaySystem ? displaySystem.driver : (subclass(DisplayDriver))class(LFBDisplayDriver);
129          if(driver.AllocateMesh == DisplayDriver::AllocateMesh) driver = (subclass(DisplayDriver))class(LFBDisplayDriver);
130          if(driver.AllocateMesh(displaySystem, this))
131          {
132             if(Lock(what))
133                result = true;
134          }
135          if(!result)
136             Free(what);
137          this.displaySystem = displaySystem;
138       }
139       return result;
140    }
141
142    void Unlock(MeshFeatures flags)
143    {
144       if(this && driver)
145          driver.UnlockMesh(displaySystem, this, flags);
146    }
147
148    bool Lock(MeshFeatures flags)
149    {
150       bool result = false;
151       if(this && driver)
152       {
153          if(driver.LockMesh(displaySystem, this, flags))
154             result = true;
155          if(!result)
156             Unlock(flags);
157       }
158       return result;
159    }
160
161    void FreePrimitiveGroup(PrimitiveGroup group)
162    {
163       if(this && group)
164       {
165          if(group.data)
166             driver.FreeIndices(displaySystem, group.data);
167          groups.Delete(group);
168       }
169    }
170
171    PrimitiveGroup AddPrimitiveGroup(PrimitiveGroupType flags, int nIndices)
172    {
173       PrimitiveGroup result = null;
174       PrimitiveGroup group { };
175       if(group)
176       {
177          groups.Add(group);
178          group.type = flags;
179          if(!(flags.vertexRange))
180          {
181             group.nIndices = nIndices;
182             if(driver)
183             {
184                group.data = driver.AllocateIndices(displaySystem, nIndices, flags.indices32bit);
185                if(group.data)
186                {
187                   if(LockPrimitiveGroup(group))
188                      result = group;
189                }
190             }
191             else
192                result = group;
193          }
194          else
195             result = group;
196          if(!result)
197             FreePrimitiveGroup(group);
198       }
199       return result;
200    }
201
202    bool LockPrimitiveGroup(PrimitiveGroup group)
203    {
204       bool result = false;
205       if(this && group)
206       {
207          if(group.data)
208             group.indices = driver.LockIndices(displaySystem, group.data);
209          if(group.indices || group.type.vertexRange)
210             result = true;
211       }
212       return result;
213    }
214
215    void UnlockPrimitiveGroup(PrimitiveGroup group)
216    {
217       if(this && group && group.data)
218       {
219          driver.UnlockIndices(displaySystem, group.data, group.type.indices32bit, group.nIndices);
220          //group.indices = null;
221       }
222    }
223
224    void FreePrimitive(PrimitiveSingle primitive)
225    {
226       if(this && primitive)
227       {
228          if(primitive.data)
229             driver.FreeIndices(displaySystem, primitive.data);
230          primitive.data = null;
231       }
232    }
233
234    bool AllocatePrimitive(PrimitiveSingle primitive, PrimitiveGroupType flags, int nIndices)
235    {
236       bool result = false;
237       if(this && primitive)
238       {
239          primitive.type = flags;
240          primitive.data = driver.AllocateIndices(displaySystem, nIndices, flags.indices32bit);
241          primitive.nIndices = nIndices;
242          if(primitive.data)
243          {
244             if(LockPrimitive(primitive))
245                result = true;
246          }
247          if(!result)
248             FreePrimitive(primitive);
249       }
250       return result;
251    }
252
253    void UnlockPrimitive(PrimitiveSingle primitive)
254    {
255       if(this && primitive)
256       {
257          driver.UnlockIndices(this.displaySystem, primitive.data, primitive.type.indices32bit, primitive.nIndices);
258          //primitive.indices = null;
259       }
260    }
261
262    bool LockPrimitive(PrimitiveSingle primitive)
263    {
264       bool result = false;
265       if(this && primitive)
266       {
267          primitive.indices = driver.LockIndices(displaySystem, primitive.data);
268          if(primitive.indices)
269             result = true;
270       }
271       return result;
272    }
273
274    void ComputeNormals(void)
275    {
276       int c;
277       int * numShared = new0 int[nVertices];
278       PrimitiveGroup group;
279
280       if(Allocate({ normals = true }, nVertices, displaySystem))
281       {
282          FillBytes(normals, 0, nVertices * sizeof(Vector3Df));
283          for(group = groups.first; group; group = group.next)
284          {
285             int nPrimitives = 0, c;
286             int offset = 0;
287             int strip = 0;
288             int nPoints, nIndex;
289             uint16 * indices16 = group.indices;
290             uint32 * indices32 = group.indices;
291             bool i32bit = group.type.indices32bit;
292
293             if(group.type.primitiveType == triangles)
294                nIndex = nPoints = 3;
295             else if(group.type.primitiveType == quads)
296                nIndex = nPoints = 4;
297             else if(group.type.primitiveType == triFan || group.type.primitiveType == triStrip || group.type.primitiveType == quadStrip)
298             {
299                offset = 2;
300                nIndex = 1;
301                nPoints = 3;
302             }
303             else
304                continue;
305             /*
306             int nIndicesPerPrimitive;
307             if(group.type == Triangles)
308                nIndicesPerPrimitive = 3;
309             else if(group.type == Quads)
310                nIndicesPerPrimitive = 4;
311             else
312                continue;
313             */
314             for(c = offset; c<group.nIndices; c += nIndex)
315             {
316                int i;
317                Plane plane;
318                Vector3Df planeNormal;
319
320                if(group.type.primitiveType == triFan)
321                {
322                   plane.FromPointsf(vertices[group.indices[0]],
323                                    vertices[group.indices[c]],
324                                    vertices[group.indices[c-1]]);
325                   planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
326
327                   normals[group.indices[0]].Add(normals[group.indices[0]], planeNormal);
328                   numShared[group.indices[0]]++;
329                   normals[group.indices[c-1]].Add(normals[group.indices[c-1]], planeNormal);
330                   numShared[group.indices[c-1]]++;
331                   normals[group.indices[c]].Add(normals[group.indices[c]], planeNormal);
332                   numShared[group.indices[c]]++;
333                }
334                else if(group.type.primitiveType == triStrip || group.type.primitiveType == quadStrip)
335                {
336                   plane.FromPointsf(vertices[group.indices[c-1-strip]],
337                                    vertices[group.indices[c-2+strip]],
338                                    vertices[group.indices[c]]);
339                   planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
340
341                   normals[group.indices[c-1-strip]].Add(normals[group.indices[c-1-strip]], planeNormal);
342                   numShared[group.indices[c-1-strip]]++;
343                   normals[group.indices[c-2+strip]].Add(normals[group.indices[c-2+strip]], planeNormal);
344                   numShared[group.indices[c-2+strip]]++;
345                   normals[group.indices[c]].Add(normals[group.indices[c]], planeNormal);
346                   numShared[group.indices[c]]++;
347
348                   strip ^= 1;
349                }
350                else
351                {
352                   if(group.type.vertexRange)
353                   {
354                      plane.FromPointsf(vertices[c+2],
355                                       vertices[c+1],
356                                       vertices[c]);
357                      planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
358
359                      for(i = c; i<c+nIndex; i++)
360                      {
361                         normals[i].Add(normals[i], planeNormal);
362                         numShared[i] ++;
363                      }
364                   }
365                   else
366                   {
367                      plane.FromPointsf(vertices[i32bit ? indices32[c+2] : indices16[c+2]],
368                                       vertices[i32bit ? indices32[c+1] : indices16[c+1]],
369                                       vertices[i32bit ? indices32[c] : indices16[c]]);
370                      planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
371
372                      for(i = c; i<c+nIndex; i++)
373                      {
374                         int index = i32bit ? indices32[i] : indices16[i];
375                         normals[index].Add(normals[index], planeNormal);
376                         numShared[index] ++;
377                      }
378                   }
379                }
380             }
381          }
382          // NOTE: Here we're currently making the assumption that the primitives are in indices mode (vertexRange = false)
383          for(c = 0; c<nPrimitives; c++)
384          {
385             int i;
386             PrimitiveSingle * primitive = &primitives[c];
387
388             Plane plane;
389             Vector3Df planeNormal;
390             plane.FromPointsf(vertices[primitive->indices[2]],
391                              vertices[primitive->indices[1]],
392                              vertices[primitive->indices[0]]);
393             planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
394
395             if(primitive->material.flags.doubleSided && plane.d < 0)
396             {
397                planeNormal.x *= -1;
398                planeNormal.y *= -1;
399                planeNormal.z *= -1;
400             }
401
402             for(i = 0; i<primitive->nIndices; i++)
403             {
404                normals[primitive->indices[i]].Add(normals[primitive->indices[i]], planeNormal);
405                numShared[primitive->indices[i]] ++;
406             }
407          }
408
409          for(c = 0; c<nVertices; c++)
410          {
411             normals[c].Scale(normals[c], 1.0f / numShared[c]);
412             normals[c].Normalize(normals[c]);
413          }
414          delete numShared;
415          Unlock({ normals = true });
416       }
417    }
418
419
420    void ApplyMaterial(Material material)
421    {
422       if(this)
423       {
424          int c;
425          PrimitiveGroup group;
426          for(group = groups.first; group; group = group.next)
427             group.material = material;
428          for(c = 0; c<nPrimitives; c++)
429             primitives[c].material = material;
430       }
431    }
432
433    bool ApplyTranslucency(Object object)
434    {
435       bool result = false;
436       if(this)
437       {
438          PrimitiveGroup group, nextGroup;
439          int c;
440
441          // Merge non translucent primitives into groups
442          for(c = 0; c<nPrimitives; )
443          {
444             PrimitiveSingle * primitive = &primitives[c];
445             Material material = (primitive->material || !object) ? primitive->material : object.material;
446             if(!material || !(material.flags.translucent))
447             {
448                int t;
449                PrimitiveGroup group;
450                int nIndices = primitive->nIndices;
451                for(t = c+1; t<nPrimitives; t++)
452                {
453                   PrimitiveSingle * prim = &primitives[t];
454                   if(prim->type == primitive->type && prim->material == primitive->material)
455                      nIndices += prim->nIndices;
456                }
457                group = AddPrimitiveGroup(primitive->type, nIndices);
458                if(group)
459                {
460                   nIndices = 0;
461                   group.material = material;
462                   for(t = c; t<nPrimitives; t++)
463                   {
464                      primitive = &primitives[t];
465                      if(group.type == primitive->type && group.material == primitive->material)
466                      {
467                         CopyBytesBy2(group.indices + nIndices,primitive->indices,primitive->nIndices);
468                         nIndices +=primitive->nIndices;
469                         CopyBytes(primitives + t, primitives + t + 1, (nPrimitives - t - 1) * sizeof(PrimitiveSingle));
470                         nPrimitives--;
471                         t--;
472                      }
473                   }
474                   UnlockPrimitiveGroup(group);
475                }
476             }
477             else
478                c++;
479          }
480          primitives = renew primitives PrimitiveSingle[this.nPrimitives];
481
482          // Split translucent groups into primitives
483          for(group = groups.first; group; group = nextGroup)
484          {
485             Material material = (group.material || !object) ? group.material : object.material;
486
487             nextGroup = group.next;
488
489             if(material && material.flags.translucent)
490             {
491                int nPrimitives = 0, c;
492                int offset = 0;
493                int strip = 0;
494                int nPoints, nIndex;
495                int groupCount = group.type.vertexRange ? group.nVertices : group.nIndices;
496                if(!groupCount) continue;
497
498                if(group.type.primitiveType == triangles)
499                   nIndex = nPoints = 3;
500                else if(group.type.primitiveType == quads)
501                   nIndex = nPoints = 4;
502                else if(group.type.primitiveType == triFan || group.type.primitiveType == triStrip)
503                {
504                   offset = 2;
505                   nIndex = 1;
506                   nPoints = 3;
507                }
508                else
509                   continue;
510
511                nPrimitives += (groupCount - offset) / nIndex;
512
513                primitives = renew primitives PrimitiveSingle[this.nPrimitives + nPrimitives];
514
515                for(c = offset; c<groupCount; c+= nIndex)
516                {
517                   PrimitiveSingle * primitive = &primitives[this.nPrimitives++];
518
519                   if(AllocatePrimitive(primitive, group.type.primitiveType, nPoints))
520                   {
521                      if(group.type.vertexRange)
522                      {
523                         if(group.type.primitiveType == triangles || group.type.primitiveType == quads)
524                         {
525                            primitive->indices[0] = (uint16)(group.first + c);
526                            primitive->indices[1] = (uint16)(group.first + c+1);
527                            primitive->indices[2] = (uint16)(group.first + c+2);
528                         }
529                         if(group.type.primitiveType == quads)
530                            primitive->indices[3] = (uint16)(group.first + c+3);
531
532                         if(group.type.primitiveType == triFan)
533                         {
534                            primitive->indices[0] = (uint16)group.first;
535                            primitive->indices[1] = (uint16)(group.first + c-1);
536                            primitive->indices[2] = (uint16)(group.first + c);
537                         }
538                         else if(group.type.primitiveType == triStrip)
539                         {
540                            primitive->indices[0] = (uint16)(group.first + c-1-strip);
541                            primitive->indices[1] = (uint16)(group.first + c-2+strip);
542                            primitive->indices[2] = (uint16)(group.first + c);
543                            strip ^= 1;
544                         }
545                      }
546                      else
547                      {
548                         if(group.type.primitiveType == triangles || group.type.primitiveType == quads)
549                            CopyBytesBy2(primitive->indices, group.indices + c, nIndex);
550
551                         if(group.type.primitiveType == triFan)
552                         {
553                            primitive->indices[0] = group.indices[0];
554                            primitive->indices[1] = group.indices[c-1];
555                            primitive->indices[2] = group.indices[c];
556                         }
557                         else if(group.type.primitiveType == triStrip)
558                         {
559                            primitive->indices[0] = group.indices[c-1-strip];
560                            primitive->indices[1] = group.indices[c-2+strip];
561                            primitive->indices[2] = group.indices[c];
562                            strip ^= 1;
563                         }
564                      }
565                      primitive->material = group.material;
566
567                      primitive->plane.FromPointsf(
568                         vertices[primitive->indices[2]],
569                         vertices[primitive->indices[1]],
570                         vertices[primitive->indices[0]]);
571
572                      primitive->middle.Add(vertices[primitive->indices[0]], vertices[primitive->indices[1]]);
573                      primitive->middle.Add(primitive->middle, vertices[primitive->indices[2]]);
574                      if(group.type == quads)
575                         primitive->middle.Add(primitive->middle, vertices[primitive->indices[3]]);
576                      primitive->middle.x /= nPoints;
577                      primitive->middle.y /= nPoints;
578                      primitive->middle.z /= nPoints;
579
580                      UnlockPrimitive(primitive);
581                   }
582                }
583                FreePrimitiveGroup(group);
584             }
585          }
586          result = true;
587
588          if(object)
589             object.flags.translucent = nPrimitives ? true : false;
590       }
591       return result;
592    }
593
594 private:
595
596    void SetMinMaxRadius(void)
597    {
598       int c;
599
600       float xRadius, yRadius, zRadius;
601
602       min = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
603       max = { MINFLOAT, MINFLOAT, MINFLOAT };
604
605       for(c = 0; c<nVertices; c++)
606       {
607          min.x = Min(min.x, vertices[c].x);
608          min.y = Min(min.y, vertices[c].y);
609          min.z = Min(min.z, vertices[c].z);
610          max.x = Max(max.x, vertices[c].x);
611          max.y = Max(max.y, vertices[c].y);
612          max.z = Max(max.z, vertices[c].z);
613       }
614       xRadius = Max(max.x, -min.x);
615       yRadius = Max(max.y, -min.y);
616       zRadius = Max(max.z, -min.z);
617
618       radius = Max(xRadius, yRadius);
619       radius = Max(radius, zRadius);
620    }
621
622    void DoubleSided(bool flag)
623    {
624       if(this)
625       {
626          PrimitiveGroup group;
627          int c;
628          for(group = groups.first; group; group = group.next)
629          {
630             if(group.material)
631             {
632                group.material.flags.doubleSided = flag;
633             }
634          }
635          for(c = 0; c<nPrimitives; c++)
636          {
637             PrimitiveSingle * primitive = &primitives[c];
638             if(primitive->material)
639             {
640                primitive->material.flags.doubleSided = flag;
641             }
642          }
643       }
644    }
645
646    MeshFeatures flags;
647    int nVertices;
648    Vector3Df * vertices;
649    Vector3Df * normals;
650    Pointf * texCoords;
651    ColorRGBAf * colors;
652    OldList groups;
653    int nPrimitives;
654    PrimitiveSingle * primitives;
655    Vector3Df min, max;
656    float radius;
657
658    // Private Data
659    DisplaySystem displaySystem;
660    subclass(DisplayDriver) driver;
661    void * data;
662 };