e7c304cc411d5a76f7fa22aa021c0571f165e987
[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, lightVectors:1, tangents: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    /* ,
19    lineLoop,
20    lineStrip,
21    polygon
22    */
23 };
24
25 public class MaterialFlags { public bool doubleSided:1, translucent:1, tile:1, noFog:1, singleSideLight:1, separateSpecular:1, cubeMap:1, noLighting:1; };
26 public class Material : struct
27 {
28 public:
29    Material prev, next;
30    char * name;
31    float opacity;
32    ColorRGB diffuse;
33    ColorRGB ambient;
34    ColorRGB specular;
35    ColorRGB emissive;
36    float power;
37    Bitmap baseMap;
38    Bitmap bumpMap;
39    Bitmap specularMap;
40    Bitmap reflectMap;
41    CubeMap envMap;
42    float reflectivity;
43    float refractiveIndex;
44    float refractiveIndexContainer;
45
46    MaterialFlags flags;
47    float uScale, vScale;
48    Shader shader;
49
50    void Free()
51    {
52       delete name;
53    }
54 };
55
56 public class PrimitiveGroup : struct
57 {
58 public:
59    PrimitiveGroup prev, next;
60    PrimitiveGroupType type;
61    union
62    {
63       struct { union { uint16 * indices; uint * indices32; }; int nIndices; };
64       struct { int first, nVertices; };
65    };
66    Material material;
67
68 private:
69    void * data;
70 };
71
72 /*
73 public class PrimitiveGroupIndices16 : PrimitiveGroup
74 {
75    property Array<uint16> indices
76    {
77       set { }
78    }
79 }
80
81 public class PrimitiveGroupIndices32 : PrimitiveGroup
82 {
83    property Array<uint> indices
84    {
85       set { }
86    }
87 }
88
89 public class PrimitiveGroupVertexRange : PrimitiveGroup
90 {
91    property int first { set { } }
92    property int nVertices { set { } }
93 }
94 */
95
96 public struct PrimitiveSingle
97 {
98 public:
99    PrimitiveGroupType type;
100    union
101    {
102       struct { union { uint16 * indices; uint * indices32; }; int nIndices; };
103       struct { int first, nVertices; };
104    };
105    Material material;
106
107 private:
108    void * data;
109    Vector3Df middle;
110    Plane plane;
111 };
112
113 public class Mesh : struct
114 {
115 public:
116    property Pointf * texCoords { get { return texCoords; } set { texCoords = value; } };
117    property int nVertices { get { return nVertices; } set { nVertices = value; } };
118    property Vector3Df * vertices { get { return vertices; } set { vertices = value; } };
119    property Vector3Df * normals { get { return normals; } set { normals = value; } };
120    property Vector3Df * tangents { get { return tangents; } set { tangents = value; } };
121    property ColorRGBAf * colors { get { return colors; } set { colors = value; } };
122    property ColorRGB * lightVectors { get { return lightVectors; } set { lightVectors = value; } };
123    property OldList groups { get { value = groups; } };
124    property MeshFeatures flags { get { return flags; } set { flags = value; } };
125
126    void Free(MeshFeatures what)
127    {
128       if(this)
129       {
130          DisplaySystem displaySystem = this.displaySystem;
131          PrimitiveGroup group;
132          if(!what)
133          {
134             int c;
135
136             flags = 0;
137             if(driver)
138                driver.FreeMesh(displaySystem, this);
139             for(;(group = groups.first);)
140                FreePrimitiveGroup(group);
141
142             for(c = 0; c<nPrimitives; c++)
143             {
144                if(primitives[c].data)
145                   driver.FreeIndices(displaySystem, primitives[c].data);
146             }
147
148             delete primitives;
149             nPrimitives = 0;
150             nVertices = 0;
151             this.displaySystem = null;
152             driver = null;
153          }
154          else
155          {
156             flags &= ~what;
157             if(driver)
158                driver.FreeMesh(displaySystem, this);
159          }
160       }
161    }
162
163    bool Allocate(MeshFeatures what, int nVertices, DisplaySystem displaySystem)
164    {
165       bool result = false;
166       if(!this.displaySystem || this.displaySystem == displaySystem)
167       {
168          driver = displaySystem ? displaySystem.driver : (subclass(DisplayDriver))class(LFBDisplayDriver);
169          if(driver.AllocateMesh == DisplayDriver::AllocateMesh) driver = (subclass(DisplayDriver))class(LFBDisplayDriver);
170          if(driver.AllocateMesh(displaySystem, this, what, nVertices))
171          {
172             flags |= what;
173             this.nVertices = nVertices;
174             if(Lock(what))
175                result = true;
176          }
177          if(!result)
178             Free(what);
179          this.displaySystem = displaySystem;
180       }
181       return result;
182    }
183
184    void Unlock(MeshFeatures flags)
185    {
186       if(this && driver)
187          driver.UnlockMesh(displaySystem, this, flags);
188    }
189
190    bool Lock(MeshFeatures flags)
191    {
192       bool result = false;
193       if(this && driver)
194       {
195          if(driver.LockMesh(displaySystem, this, flags))
196             result = true;
197          if(!result)
198             Unlock(flags);
199       }
200       return result;
201    }
202
203    void FreePrimitiveGroup(PrimitiveGroup group)
204    {
205       if(this && group)
206       {
207          if(group.data)
208             driver.FreeIndices(displaySystem, group.data);
209          groups.Delete(group);
210       }
211    }
212
213    PrimitiveGroup AddPrimitiveGroup(PrimitiveGroupType flags, int nIndices)
214    {
215       PrimitiveGroup result = null;
216       PrimitiveGroup group { };
217       if(group)
218       {
219          groups.Add(group);
220          group.type = flags;
221          if(!(flags.vertexRange))
222          {
223             group.nIndices = nIndices;
224             if(driver)
225             {
226                group.data = driver.AllocateIndices(displaySystem, nIndices, flags.indices32bit);
227                if(group.data)
228                {
229                   if(LockPrimitiveGroup(group))
230                      result = group;
231                }
232             }
233             else
234                result = group;
235          }
236          else
237             result = group;
238          if(!result)
239             FreePrimitiveGroup(group);
240       }
241       return result;
242    }
243
244    bool LockPrimitiveGroup(PrimitiveGroup group)
245    {
246       bool result = false;
247       if(this && group)
248       {
249          if(group.data)
250             group.indices = driver.LockIndices(displaySystem, group.data);
251          if(group.indices || group.type.vertexRange)
252             result = true;
253       }
254       return result;
255    }
256
257    void UnlockPrimitiveGroup(PrimitiveGroup group)
258    {
259       if(this && group && group.data)
260       {
261          driver.UnlockIndices(displaySystem, group.data, group.type.indices32bit, group.nIndices);
262          //group.indices = null;
263       }
264    }
265
266    void FreePrimitive(PrimitiveSingle primitive)
267    {
268       if(this && primitive)
269       {
270          if(primitive.data)
271             driver.FreeIndices(displaySystem, primitive.data);
272          primitive.data = null;
273       }
274    }
275
276    bool AllocatePrimitive(PrimitiveSingle primitive, PrimitiveGroupType flags, int nIndices)
277    {
278       bool result = false;
279       if(this && primitive)
280       {
281          primitive.type = flags;
282          primitive.data = driver.AllocateIndices(displaySystem, nIndices, flags.indices32bit);
283          primitive.nIndices = nIndices;
284          if(primitive.data)
285          {
286             if(LockPrimitive(primitive))
287                result = true;
288          }
289          if(!result)
290             FreePrimitive(primitive);
291       }
292       return result;
293    }
294
295    void UnlockPrimitive(PrimitiveSingle primitive)
296    {
297       if(this && primitive)
298       {
299          driver.UnlockIndices(this.displaySystem, primitive.data, primitive.type.indices32bit, primitive.nIndices);
300          //primitive.indices = null;
301       }
302    }
303
304    bool LockPrimitive(PrimitiveSingle primitive)
305    {
306       bool result = false;
307       if(this && primitive)
308       {
309          primitive.indices = driver.LockIndices(displaySystem, primitive.data);
310          if(primitive.indices)
311             result = true;
312       }
313       return result;
314    }
315
316    void ComputeNormals(void)
317    {
318       int c;
319       int * numShared = new0 int[nVertices];
320       double * weightSum = new0 double[nVertices];
321       PrimitiveGroup group;
322
323       if(Allocate({ normals = true, tangents = true }, nVertices, displaySystem))
324       {
325          Vector3Df * normals = this.normals;
326          Vector3Df * tangents = this.tangents;
327          Pointf * texCoords = this.texCoords;
328          FillBytes(normals, 0, nVertices * sizeof(Vector3Df));
329          FillBytes(tangents, 0, 2*nVertices * sizeof(Vector3Df));
330          for(group = groups.first; group; group = group.next)
331          {
332             int c;
333             int offset = 0;
334             int strip = 0;
335             int nPoints, nIndex;
336             uint16 * indices16 = group.indices;
337             uint32 * indices32 = group.indices32;
338             bool i32bit = group.type.indices32bit;
339
340             if(group.type.primitiveType == triangles)
341                nIndex = nPoints = 3;
342             else if(group.type.primitiveType == quads)
343                nIndex = nPoints = 4;
344             else if(group.type.primitiveType == triFan || group.type.primitiveType == triStrip || group.type.primitiveType == quadStrip)
345             {
346                offset = 2;
347                nIndex = 1;
348                nPoints = 3;
349             }
350             else
351                continue;
352             /*
353             int nIndicesPerPrimitive;
354             if(group.type == Triangles)
355                nIndicesPerPrimitive = 3;
356             else if(group.type == Quads)
357                nIndicesPerPrimitive = 4;
358             else
359                continue;
360             */
361             for(c = offset; c<group.nIndices; c += nIndex)
362             {
363                int i;
364                Plane plane;
365                Vector3Df planeNormal;
366
367                if(group.type.primitiveType == triFan)
368                {
369                   plane.FromPointsf(vertices[group.indices[0]],
370                                    vertices[group.indices[c]],
371                                    vertices[group.indices[c-1]]);
372                   planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
373
374                   normals[group.indices[0]].Add(normals[group.indices[0]], planeNormal);
375                   numShared[group.indices[0]]++;
376                   normals[group.indices[c-1]].Add(normals[group.indices[c-1]], planeNormal);
377                   numShared[group.indices[c-1]]++;
378                   normals[group.indices[c]].Add(normals[group.indices[c]], planeNormal);
379                   numShared[group.indices[c]]++;
380                }
381                else if(group.type.primitiveType == triStrip || group.type.primitiveType == quadStrip)
382                {
383                   plane.FromPointsf(vertices[group.indices[c-1-strip]],
384                                    vertices[group.indices[c-2+strip]],
385                                    vertices[group.indices[c]]);
386                   planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
387
388                   normals[group.indices[c-1-strip]].Add(normals[group.indices[c-1-strip]], planeNormal);
389                   numShared[group.indices[c-1-strip]]++;
390                   normals[group.indices[c-2+strip]].Add(normals[group.indices[c-2+strip]], planeNormal);
391                   numShared[group.indices[c-2+strip]]++;
392                   normals[group.indices[c]].Add(normals[group.indices[c]], planeNormal);
393                   numShared[group.indices[c]]++;
394
395                   strip ^= 1;
396                }
397                else
398                {
399                   if(group.type.vertexRange)
400                   {
401                      plane.FromPointsf(vertices[c+2],
402                                       vertices[c+1],
403                                       vertices[c]);
404                      planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
405
406                      for(i = c; i<c+nIndex; i++)
407                      {
408                         normals[i].Add(normals[i], planeNormal);
409                         numShared[i] ++;
410                      }
411                   }
412                   else
413                   {
414                      Vector3D edges[4], rEdges[4];
415                      double weights[4];
416                      computeNormalWeights(nIndex, vertices, indices32, i32bit, c, weights, edges, rEdges);
417
418                      plane.FromPointsf(vertices[i32bit ? indices32[c+2] : indices16[c+2]],
419                                        vertices[i32bit ? indices32[c+1] : indices16[c+1]],
420                                        vertices[i32bit ? indices32[c] :   indices16[c]]);
421                      planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
422
423                      for(i = c; i<c+nIndex; i++)
424                      {
425                         int index = i32bit ? indices32[i] : indices16[i];
426                         int v = i - c;
427                         double w = weights[v];
428                         //normals[index].Add(normals[index], planeNormal);
429                         normals[index].x += planeNormal.x * w;
430                         normals[index].y += planeNormal.y * w;
431                         normals[index].z += planeNormal.z * w;
432                         weightSum[index] += w;
433                         //numShared[index] ++;
434
435                         if(texCoords)
436                         {
437                            uint ix0 = index;
438                            uint prev = v ? i - 1 : c + nIndex-1;
439                            uint next = v < nIndex-1 ? i + 1 : c;
440                            uint ix1 = i32bit ? indices32[next] : indices16[next];
441                            uint ix2 = i32bit ? indices32[prev] : indices16[prev];
442                            Vector3Df * p0 = &vertices [ix0], * p1 = &vertices [ix1], * p2 = &vertices[ix2];
443                            Pointf    * t0 = &texCoords[ix0], * t1 = &texCoords[ix1], * t2 = &texCoords[ix2];
444                            Vector3D v01 { p1->x - p0->x, p1->y - p0->y, p1->z - p0->z };
445                            Vector3D v02 { p2->x - p0->x, p2->y - p0->y, p2->z - p0->z };
446                            Pointf t01 { t1->x - t0->x, t1->y - t0->y };
447                            Pointf t02 { t2->x - t0->x, t2->y - t0->y };
448                            //if(Abs(t01.x) > 0.99) t01.x = 0;
449                            //if(Abs(t02.x) > 0.99) t02.x = 0;
450
451                            double f = w / (t01.x * t02.y - t02.x * t01.y);
452                            Vector3Df * tan1 = &tangents[index*2+0];
453                            Vector3Df * tan2 = &tangents[index*2+1];
454
455                            tan1->x += f * (v01.x * t02.y - v02.x * t01.y);
456                            tan1->y += f * (v01.y * t02.y - v02.y * t01.y);
457                            tan1->z += f * (v01.z * t02.y - v02.z * t01.y);
458
459                            tan2->x += f * (v02.x * t01.x - v01.x * t02.x);
460                            tan2->y += f * (v02.y * t01.x - v01.y * t02.x);
461                            tan2->z += f * (v02.z * t01.x - v01.z * t02.x);
462                         }
463                      }
464                   }
465                }
466             }
467          }
468          // NOTE: Here we're currently making the assumption that the primitives are in indices mode (vertexRange = false)
469          for(c = 0; c<nPrimitives; c++)
470          {
471             int i;
472             PrimitiveSingle * primitive = &primitives[c];
473
474             Plane plane;
475             Vector3Df planeNormal;
476             plane.FromPointsf(vertices[primitive->indices[2]],
477                               vertices[primitive->indices[1]],
478                               vertices[primitive->indices[0]]);
479             planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
480
481             if(primitive->material.flags.doubleSided && plane.d < 0)
482             {
483                planeNormal.x *= -1;
484                planeNormal.y *= -1;
485                planeNormal.z *= -1;
486             }
487
488             for(i = 0; i<primitive->nIndices; i++)
489             {
490                normals[primitive->indices[i]].Add(normals[primitive->indices[i]], planeNormal);
491                numShared[primitive->indices[i]] ++;
492             }
493          }
494
495          for(c = 0; c<nVertices; c++)
496          {
497             float s = (float)(1.0 / weightSum[c]); // numShared[c]
498             Vector3Df * n = &normals[c], * t1 = &tangents[2*c], * t2 = &tangents[2*c+1];
499             n->Scale(n, s), n->Normalize(n);
500             t1->Scale(t1, s), t1->Normalize(t1);
501             t2->Scale(t2, s), t2->Normalize(t2);
502          }
503          delete numShared;
504          delete weightSum;
505          Unlock({ normals = true, tangents = true });
506       }
507    }
508
509
510    void ApplyMaterial(Material material)
511    {
512       if(this)
513       {
514          int c;
515          PrimitiveGroup group;
516          for(group = groups.first; group; group = group.next)
517             group.material = material;
518          for(c = 0; c<nPrimitives; c++)
519             primitives[c].material = material;
520       }
521    }
522
523    bool ApplyTranslucency(Object object)
524    {
525       bool result = false;
526       if(this)
527       {
528          PrimitiveGroup group, nextGroup;
529          int c;
530
531          // Merge non translucent primitives into groups
532          for(c = 0; c<nPrimitives; )
533          {
534             PrimitiveSingle * primitive = &primitives[c];
535             Material material = (primitive->material || !object) ? primitive->material : object.material;
536             if(!material || !(material.flags.translucent))
537             {
538                int t;
539                PrimitiveGroup group;
540                int nIndices = primitive->nIndices;
541                for(t = c+1; t<nPrimitives; t++)
542                {
543                   PrimitiveSingle * prim = &primitives[t];
544                   if(prim->type == primitive->type && prim->material == primitive->material)
545                      nIndices += prim->nIndices;
546                }
547                group = AddPrimitiveGroup(primitive->type, nIndices);
548                if(group)
549                {
550                   nIndices = 0;
551                   group.material = material;
552                   for(t = c; t<nPrimitives; t++)
553                   {
554                      primitive = &primitives[t];
555                      if(group.type == primitive->type && group.material == primitive->material)
556                      {
557                         CopyBytesBy2(group.indices + nIndices,primitive->indices,primitive->nIndices);
558                         nIndices +=primitive->nIndices;
559                         CopyBytes(primitives + t, primitives + t + 1, (nPrimitives - t - 1) * sizeof(PrimitiveSingle));
560                         nPrimitives--;
561                         t--;
562                      }
563                   }
564                   UnlockPrimitiveGroup(group);
565                }
566             }
567             else
568                c++;
569          }
570          primitives = renew primitives PrimitiveSingle[this.nPrimitives];
571
572          // Split translucent groups into primitives
573          for(group = groups.first; group; group = nextGroup)
574          {
575             Material material = (group.material || !object) ? group.material : object.material;
576
577             nextGroup = group.next;
578
579             if(material && material.flags.translucent)
580             {
581                int nPrimitives = 0, c;
582                int offset = 0;
583                int strip = 0;
584                int nPoints, nIndex;
585                int groupCount = group.type.vertexRange ? group.nVertices : group.nIndices;
586                if(!groupCount) continue;
587
588                if(group.type.primitiveType == triangles)
589                   nIndex = nPoints = 3;
590                else if(group.type.primitiveType == quads)
591                   nIndex = nPoints = 4;
592                else if(group.type.primitiveType == triFan || group.type.primitiveType == triStrip)
593                {
594                   offset = 2;
595                   nIndex = 1;
596                   nPoints = 3;
597                }
598                else
599                   continue;
600
601                nPrimitives += (groupCount - offset) / nIndex;
602
603                primitives = renew primitives PrimitiveSingle[this.nPrimitives + nPrimitives];
604
605                for(c = offset; c<groupCount; c+= nIndex)
606                {
607                   PrimitiveSingle * primitive = &primitives[this.nPrimitives++];
608
609                   if(AllocatePrimitive(primitive, group.type.primitiveType, nPoints))
610                   {
611                      if(group.type.vertexRange)
612                      {
613                         if(group.type.primitiveType == triangles || group.type.primitiveType == quads)
614                         {
615                            primitive->indices[0] = (uint16)(group.first + c);
616                            primitive->indices[1] = (uint16)(group.first + c+1);
617                            primitive->indices[2] = (uint16)(group.first + c+2);
618                         }
619                         if(group.type.primitiveType == quads)
620                            primitive->indices[3] = (uint16)(group.first + c+3);
621
622                         if(group.type.primitiveType == triFan)
623                         {
624                            primitive->indices[0] = (uint16)group.first;
625                            primitive->indices[1] = (uint16)(group.first + c-1);
626                            primitive->indices[2] = (uint16)(group.first + c);
627                         }
628                         else if(group.type.primitiveType == triStrip)
629                         {
630                            primitive->indices[0] = (uint16)(group.first + c-1-strip);
631                            primitive->indices[1] = (uint16)(group.first + c-2+strip);
632                            primitive->indices[2] = (uint16)(group.first + c);
633                            strip ^= 1;
634                         }
635                      }
636                      else
637                      {
638                         if(group.type.primitiveType == triangles || group.type.primitiveType == quads)
639                            CopyBytesBy2(primitive->indices, group.indices + c, nIndex);
640
641                         if(group.type.primitiveType == triFan)
642                         {
643                            primitive->indices[0] = group.indices[0];
644                            primitive->indices[1] = group.indices[c-1];
645                            primitive->indices[2] = group.indices[c];
646                         }
647                         else if(group.type.primitiveType == triStrip)
648                         {
649                            primitive->indices[0] = group.indices[c-1-strip];
650                            primitive->indices[1] = group.indices[c-2+strip];
651                            primitive->indices[2] = group.indices[c];
652                            strip ^= 1;
653                         }
654                      }
655                      primitive->material = group.material;
656
657                      primitive->plane.FromPointsf(
658                         vertices[primitive->indices[2]],
659                         vertices[primitive->indices[1]],
660                         vertices[primitive->indices[0]]);
661
662                      primitive->middle.Add(vertices[primitive->indices[0]], vertices[primitive->indices[1]]);
663                      primitive->middle.Add(primitive->middle, vertices[primitive->indices[2]]);
664                      if(group.type == quads)
665                         primitive->middle.Add(primitive->middle, vertices[primitive->indices[3]]);
666                      primitive->middle.x /= nPoints;
667                      primitive->middle.y /= nPoints;
668                      primitive->middle.z /= nPoints;
669
670                      UnlockPrimitive(primitive);
671                   }
672                }
673                FreePrimitiveGroup(group);
674             }
675          }
676          result = true;
677
678          if(object)
679             object.flags.translucent = nPrimitives ? true : false;
680       }
681       return result;
682    }
683
684    void * GetData()
685    {
686       return data;
687    }
688
689 private:
690
691    void SetMinMaxRadius(void)
692    {
693       int c;
694
695       float xRadius, yRadius, zRadius;
696
697       min = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
698       max = {-MAXFLOAT,-MAXFLOAT,-MAXFLOAT };
699
700       for(c = 0; c<nVertices; c++)
701       {
702          float x = vertices[c].x, y = vertices[c].y, z = vertices[c].z;
703          if(x.isNan || y.isNan || z.isNan);
704          else if(x > 1E20 || x < -1E20 || y > 1E20 || y < -1E20 || z > 1E20 || z < -1E20);
705          else
706          {
707             min.x = Min(min.x, x);
708             min.y = Min(min.y, y);
709             min.z = Min(min.z, z);
710             max.x = Max(max.x, x);
711             max.y = Max(max.y, y);
712             max.z = Max(max.z, z);
713          }
714       }
715       xRadius = Max(max.x, -min.x);
716       yRadius = Max(max.y, -min.y);
717       zRadius = Max(max.z, -min.z);
718
719       radius = Max(xRadius, yRadius);
720       radius = Max(radius, zRadius);
721    }
722
723    void DoubleSided(bool flag)
724    {
725       if(this)
726       {
727          PrimitiveGroup group;
728          int c;
729          for(group = groups.first; group; group = group.next)
730          {
731             if(group.material)
732             {
733                group.material.flags.doubleSided = flag;
734             }
735          }
736          for(c = 0; c<nPrimitives; c++)
737          {
738             PrimitiveSingle * primitive = &primitives[c];
739             if(primitive->material)
740             {
741                primitive->material.flags.doubleSided = flag;
742             }
743          }
744       }
745    }
746
747    MeshFeatures flags;
748    int nVertices;
749    Vector3Df * vertices;
750    Vector3Df * normals;
751    Vector3Df * tangents;
752    Pointf * texCoords;
753    ColorRGBAf * colors;
754    ColorRGB * lightVectors;
755    OldList groups;
756    int nPrimitives;
757    PrimitiveSingle * primitives;
758    Vector3Df min, max;
759    float radius;
760    CubeMap normMap;
761
762    // Private Data
763    DisplaySystem displaySystem;
764    subclass(DisplayDriver) driver;
765    void * data;
766 };
767
768 void computeNormalWeights(int n, Vector3Df * vertices, uint * indices, bool ix32Bit, int base, double * weights, Vector3D * edges, Vector3D * rEdges)
769 {
770    int i;
771    for(i = 0; i < n; i++)
772    {
773       uint ix0 = i, ix1 = (i + 1) % n;
774       Vector3Df * p0, *p1;
775       if(indices)
776       {
777          if(ix32Bit)
778             ix0 = indices[base+ix0], ix1 = indices[base+ix1];
779          else
780             ix0 = ((uint16*)indices)[base+ix0], ix1 = ((uint16*)indices)[base+ix1];
781       }
782       p0 = &vertices[ix0], p1 = &vertices[ix1];
783       edges[i] = { p1->x - p0->x, p1->y - p0->y, p1->z - p0->z };
784       edges[i].Normalize(edges[i]);
785       rEdges[i].Scale(edges[i], -1);
786    }
787    for(i = 0; i < n; i++)
788       weights[i] = acos(Min(1.0, Max(-1.0, edges[i].DotProduct(rEdges[i ? i-1 : n-1])))) / ((n-2) * Pi);
789 }