ecere/gfx/3D: Updates to Direct3D driver to not crash on bump maps / cube maps
[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 = texCoords != null }, 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          if(tangents)
330             FillBytes(tangents, 0, 2*nVertices * sizeof(Vector3Df));
331          for(group = groups.first; group; group = group.next)
332          {
333             int c;
334             int offset = 0;
335             int strip = 0;
336             int nPoints, nIndex;
337             uint16 * indices16 = group.indices;
338             uint32 * indices32 = group.indices32;
339             bool i32bit = group.type.indices32bit;
340
341             if(group.type.primitiveType == triangles)
342                nIndex = nPoints = 3;
343             else if(group.type.primitiveType == quads)
344                nIndex = nPoints = 4;
345             else if(group.type.primitiveType == triFan || group.type.primitiveType == triStrip || group.type.primitiveType == quadStrip)
346             {
347                offset = 2;
348                nIndex = 1;
349                nPoints = 3;
350             }
351             else
352                continue;
353             /*
354             int nIndicesPerPrimitive;
355             if(group.type == Triangles)
356                nIndicesPerPrimitive = 3;
357             else if(group.type == Quads)
358                nIndicesPerPrimitive = 4;
359             else
360                continue;
361             */
362             for(c = offset; c<group.nIndices; c += nIndex)
363             {
364                int i;
365                Plane plane;
366                Vector3Df planeNormal;
367
368                if(group.type.primitiveType == triFan)
369                {
370                   plane.FromPointsf(vertices[group.indices[0]],
371                                    vertices[group.indices[c]],
372                                    vertices[group.indices[c-1]]);
373                   planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
374
375                   normals[group.indices[0]].Add(normals[group.indices[0]], planeNormal);
376                   numShared[group.indices[0]]++;
377                   normals[group.indices[c-1]].Add(normals[group.indices[c-1]], planeNormal);
378                   numShared[group.indices[c-1]]++;
379                   normals[group.indices[c]].Add(normals[group.indices[c]], planeNormal);
380                   numShared[group.indices[c]]++;
381                }
382                else if(group.type.primitiveType == triStrip || group.type.primitiveType == quadStrip)
383                {
384                   plane.FromPointsf(vertices[group.indices[c-1-strip]],
385                                    vertices[group.indices[c-2+strip]],
386                                    vertices[group.indices[c]]);
387                   planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
388
389                   normals[group.indices[c-1-strip]].Add(normals[group.indices[c-1-strip]], planeNormal);
390                   numShared[group.indices[c-1-strip]]++;
391                   normals[group.indices[c-2+strip]].Add(normals[group.indices[c-2+strip]], planeNormal);
392                   numShared[group.indices[c-2+strip]]++;
393                   normals[group.indices[c]].Add(normals[group.indices[c]], planeNormal);
394                   numShared[group.indices[c]]++;
395
396                   strip ^= 1;
397                }
398                else
399                {
400                   if(group.type.vertexRange)
401                   {
402                      plane.FromPointsf(vertices[c+2],
403                                       vertices[c+1],
404                                       vertices[c]);
405                      planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
406
407                      for(i = c; i<c+nIndex; i++)
408                      {
409                         normals[i].Add(normals[i], planeNormal);
410                         numShared[i] ++;
411                      }
412                   }
413                   else
414                   {
415                      Vector3D edges[4], rEdges[4];
416                      double weights[4];
417                      computeNormalWeights(nIndex, vertices, indices32, i32bit, c, weights, edges, rEdges);
418
419                      plane.FromPointsf(vertices[i32bit ? indices32[c+2] : indices16[c+2]],
420                                        vertices[i32bit ? indices32[c+1] : indices16[c+1]],
421                                        vertices[i32bit ? indices32[c] :   indices16[c]]);
422                      planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
423
424                      for(i = c; i<c+nIndex; i++)
425                      {
426                         int index = i32bit ? indices32[i] : indices16[i];
427                         int v = i - c;
428                         double w = weights[v];
429                         //normals[index].Add(normals[index], planeNormal);
430                         normals[index].x += planeNormal.x * w;
431                         normals[index].y += planeNormal.y * w;
432                         normals[index].z += planeNormal.z * w;
433                         weightSum[index] += w;
434                         //numShared[index] ++;
435
436                         if(tangents)
437                         {
438                            uint ix0 = index;
439                            uint prev = v ? i - 1 : c + nIndex-1;
440                            uint next = v < nIndex-1 ? i + 1 : c;
441                            uint ix1 = i32bit ? indices32[next] : indices16[next];
442                            uint ix2 = i32bit ? indices32[prev] : indices16[prev];
443                            Vector3Df * p0 = &vertices [ix0], * p1 = &vertices [ix1], * p2 = &vertices[ix2];
444                            Pointf    * t0 = &texCoords[ix0], * t1 = &texCoords[ix1], * t2 = &texCoords[ix2];
445                            Vector3D v01 { p1->x - p0->x, p1->y - p0->y, p1->z - p0->z };
446                            Vector3D v02 { p2->x - p0->x, p2->y - p0->y, p2->z - p0->z };
447                            Pointf t01 { t1->x - t0->x, t1->y - t0->y };
448                            Pointf t02 { t2->x - t0->x, t2->y - t0->y };
449                            //if(Abs(t01.x) > 0.99) t01.x = 0;
450                            //if(Abs(t02.x) > 0.99) t02.x = 0;
451
452                            double f = w / (t01.x * t02.y - t02.x * t01.y);
453                            Vector3Df * tan1 = &tangents[index*2+0];
454                            Vector3Df * tan2 = &tangents[index*2+1];
455
456                            tan1->x += f * (v01.x * t02.y - v02.x * t01.y);
457                            tan1->y += f * (v01.y * t02.y - v02.y * t01.y);
458                            tan1->z += f * (v01.z * t02.y - v02.z * t01.y);
459
460                            tan2->x += f * (v02.x * t01.x - v01.x * t02.x);
461                            tan2->y += f * (v02.y * t01.x - v01.y * t02.x);
462                            tan2->z += f * (v02.z * t01.x - v01.z * t02.x);
463                         }
464                      }
465                   }
466                }
467             }
468          }
469          // NOTE: Here we're currently making the assumption that the primitives are in indices mode (vertexRange = false)
470          for(c = 0; c<nPrimitives; c++)
471          {
472             int i;
473             PrimitiveSingle * primitive = &primitives[c];
474
475             Plane plane;
476             Vector3Df planeNormal;
477             plane.FromPointsf(vertices[primitive->indices[2]],
478                               vertices[primitive->indices[1]],
479                               vertices[primitive->indices[0]]);
480             planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
481
482             if(primitive->material.flags.doubleSided && plane.d < 0)
483             {
484                planeNormal.x *= -1;
485                planeNormal.y *= -1;
486                planeNormal.z *= -1;
487             }
488
489             for(i = 0; i<primitive->nIndices; i++)
490             {
491                normals[primitive->indices[i]].Add(normals[primitive->indices[i]], planeNormal);
492                numShared[primitive->indices[i]] ++;
493             }
494          }
495
496          for(c = 0; c<nVertices; c++)
497          {
498             float s = (float)(1.0 / weightSum[c]); // numShared[c]
499             Vector3Df * n = &normals[c];
500             n->Scale(n, s), n->Normalize(n);
501             if(tangents)
502             {
503                Vector3Df * t1 = &tangents[2*c], * t2 = &tangents[2*c+1];
504                t1->Scale(t1, s), t1->Normalize(t1);
505                t2->Scale(t2, s), t2->Normalize(t2);
506             }
507          }
508          delete numShared;
509          delete weightSum;
510          Unlock({ normals = true, tangents = true });
511       }
512    }
513
514
515    void ApplyMaterial(Material material)
516    {
517       if(this)
518       {
519          int c;
520          PrimitiveGroup group;
521          for(group = groups.first; group; group = group.next)
522             group.material = material;
523          for(c = 0; c<nPrimitives; c++)
524             primitives[c].material = material;
525       }
526    }
527
528    bool ApplyTranslucency(Object object)
529    {
530       bool result = false;
531       if(this)
532       {
533          PrimitiveGroup group, nextGroup;
534          int c;
535
536          // Merge non translucent primitives into groups
537          for(c = 0; c<nPrimitives; )
538          {
539             PrimitiveSingle * primitive = &primitives[c];
540             Material material = (primitive->material || !object) ? primitive->material : object.material;
541             if(!material || !(material.flags.translucent))
542             {
543                int t;
544                PrimitiveGroup group;
545                int nIndices = primitive->nIndices;
546                for(t = c+1; t<nPrimitives; t++)
547                {
548                   PrimitiveSingle * prim = &primitives[t];
549                   if(prim->type == primitive->type && prim->material == primitive->material)
550                      nIndices += prim->nIndices;
551                }
552                group = AddPrimitiveGroup(primitive->type, nIndices);
553                if(group)
554                {
555                   nIndices = 0;
556                   group.material = material;
557                   for(t = c; t<nPrimitives; t++)
558                   {
559                      primitive = &primitives[t];
560                      if(group.type == primitive->type && group.material == primitive->material)
561                      {
562                         CopyBytesBy2(group.indices + nIndices,primitive->indices,primitive->nIndices);
563                         nIndices +=primitive->nIndices;
564                         CopyBytes(primitives + t, primitives + t + 1, (nPrimitives - t - 1) * sizeof(PrimitiveSingle));
565                         nPrimitives--;
566                         t--;
567                      }
568                   }
569                   UnlockPrimitiveGroup(group);
570                }
571             }
572             else
573                c++;
574          }
575          primitives = renew primitives PrimitiveSingle[this.nPrimitives];
576
577          // Split translucent groups into primitives
578          for(group = groups.first; group; group = nextGroup)
579          {
580             Material material = (group.material || !object) ? group.material : object.material;
581
582             nextGroup = group.next;
583
584             if(material && material.flags.translucent)
585             {
586                int nPrimitives = 0, c;
587                int offset = 0;
588                int strip = 0;
589                int nPoints, nIndex;
590                int groupCount = group.type.vertexRange ? group.nVertices : group.nIndices;
591                if(!groupCount) continue;
592
593                if(group.type.primitiveType == triangles)
594                   nIndex = nPoints = 3;
595                else if(group.type.primitiveType == quads)
596                   nIndex = nPoints = 4;
597                else if(group.type.primitiveType == triFan || group.type.primitiveType == triStrip)
598                {
599                   offset = 2;
600                   nIndex = 1;
601                   nPoints = 3;
602                }
603                else
604                   continue;
605
606                nPrimitives += (groupCount - offset) / nIndex;
607
608                primitives = renew primitives PrimitiveSingle[this.nPrimitives + nPrimitives];
609
610                for(c = offset; c<groupCount; c+= nIndex)
611                {
612                   PrimitiveSingle * primitive = &primitives[this.nPrimitives++];
613
614                   if(AllocatePrimitive(primitive, group.type.primitiveType, nPoints))
615                   {
616                      if(group.type.vertexRange)
617                      {
618                         if(group.type.primitiveType == triangles || group.type.primitiveType == quads)
619                         {
620                            primitive->indices[0] = (uint16)(group.first + c);
621                            primitive->indices[1] = (uint16)(group.first + c+1);
622                            primitive->indices[2] = (uint16)(group.first + c+2);
623                         }
624                         if(group.type.primitiveType == quads)
625                            primitive->indices[3] = (uint16)(group.first + c+3);
626
627                         if(group.type.primitiveType == triFan)
628                         {
629                            primitive->indices[0] = (uint16)group.first;
630                            primitive->indices[1] = (uint16)(group.first + c-1);
631                            primitive->indices[2] = (uint16)(group.first + c);
632                         }
633                         else if(group.type.primitiveType == triStrip)
634                         {
635                            primitive->indices[0] = (uint16)(group.first + c-1-strip);
636                            primitive->indices[1] = (uint16)(group.first + c-2+strip);
637                            primitive->indices[2] = (uint16)(group.first + c);
638                            strip ^= 1;
639                         }
640                      }
641                      else
642                      {
643                         if(group.type.primitiveType == triangles || group.type.primitiveType == quads)
644                            CopyBytesBy2(primitive->indices, group.indices + c, nIndex);
645
646                         if(group.type.primitiveType == triFan)
647                         {
648                            primitive->indices[0] = group.indices[0];
649                            primitive->indices[1] = group.indices[c-1];
650                            primitive->indices[2] = group.indices[c];
651                         }
652                         else if(group.type.primitiveType == triStrip)
653                         {
654                            primitive->indices[0] = group.indices[c-1-strip];
655                            primitive->indices[1] = group.indices[c-2+strip];
656                            primitive->indices[2] = group.indices[c];
657                            strip ^= 1;
658                         }
659                      }
660                      primitive->material = group.material;
661
662                      primitive->plane.FromPointsf(
663                         vertices[primitive->indices[2]],
664                         vertices[primitive->indices[1]],
665                         vertices[primitive->indices[0]]);
666
667                      primitive->middle.Add(vertices[primitive->indices[0]], vertices[primitive->indices[1]]);
668                      primitive->middle.Add(primitive->middle, vertices[primitive->indices[2]]);
669                      if(group.type == quads)
670                         primitive->middle.Add(primitive->middle, vertices[primitive->indices[3]]);
671                      primitive->middle.x /= nPoints;
672                      primitive->middle.y /= nPoints;
673                      primitive->middle.z /= nPoints;
674
675                      UnlockPrimitive(primitive);
676                   }
677                }
678                FreePrimitiveGroup(group);
679             }
680          }
681          result = true;
682
683          if(object)
684             object.flags.translucent = nPrimitives ? true : false;
685       }
686       return result;
687    }
688
689    void * GetData()
690    {
691       return data;
692    }
693
694 private:
695
696    void SetMinMaxRadius(void)
697    {
698       int c;
699
700       float xRadius, yRadius, zRadius;
701
702       min = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
703       max = {-MAXFLOAT,-MAXFLOAT,-MAXFLOAT };
704
705       for(c = 0; c<nVertices; c++)
706       {
707          float x = vertices[c].x, y = vertices[c].y, z = vertices[c].z;
708          if(x.isNan || y.isNan || z.isNan);
709          else if(x > 1E20 || x < -1E20 || y > 1E20 || y < -1E20 || z > 1E20 || z < -1E20);
710          else
711          {
712             min.x = Min(min.x, x);
713             min.y = Min(min.y, y);
714             min.z = Min(min.z, z);
715             max.x = Max(max.x, x);
716             max.y = Max(max.y, y);
717             max.z = Max(max.z, z);
718          }
719       }
720       xRadius = Max(max.x, -min.x);
721       yRadius = Max(max.y, -min.y);
722       zRadius = Max(max.z, -min.z);
723
724       radius = Max(xRadius, yRadius);
725       radius = Max(radius, zRadius);
726    }
727
728    void DoubleSided(bool flag)
729    {
730       if(this)
731       {
732          PrimitiveGroup group;
733          int c;
734          for(group = groups.first; group; group = group.next)
735          {
736             if(group.material)
737             {
738                group.material.flags.doubleSided = flag;
739             }
740          }
741          for(c = 0; c<nPrimitives; c++)
742          {
743             PrimitiveSingle * primitive = &primitives[c];
744             if(primitive->material)
745             {
746                primitive->material.flags.doubleSided = flag;
747             }
748          }
749       }
750    }
751
752    MeshFeatures flags;
753    int nVertices;
754    Vector3Df * vertices;
755    Vector3Df * normals;
756    Vector3Df * tangents;
757    Pointf * texCoords;
758    ColorRGBAf * colors;
759    ColorRGB * lightVectors;
760    OldList groups;
761    int nPrimitives;
762    PrimitiveSingle * primitives;
763    Vector3Df min, max;
764    float radius;
765    CubeMap normMap;
766
767    // Private Data
768    DisplaySystem displaySystem;
769    subclass(DisplayDriver) driver;
770    void * data;
771 };
772
773 void computeNormalWeights(int n, Vector3Df * vertices, uint * indices, bool ix32Bit, int base, double * weights, Vector3D * edges, Vector3D * rEdges)
774 {
775    int i;
776    for(i = 0; i < n; i++)
777    {
778       uint ix0 = i, ix1 = (i + 1) % n;
779       Vector3Df * p0, *p1;
780       if(indices)
781       {
782          if(ix32Bit)
783             ix0 = indices[base+ix0], ix1 = indices[base+ix1];
784          else
785             ix0 = ((uint16*)indices)[base+ix0], ix1 = ((uint16*)indices)[base+ix1];
786       }
787       p0 = &vertices[ix0], p1 = &vertices[ix1];
788       edges[i] = { p1->x - p0->x, p1->y - p0->y, p1->z - p0->z };
789       edges[i].Normalize(edges[i]);
790       rEdges[i].Scale(edges[i], -1);
791    }
792    for(i = 0; i < n; i++)
793       weights[i] = acos(Min(1.0, Max(-1.0, edges[i].DotProduct(rEdges[i ? i-1 : n-1])))) / ((n-2) * Pi);
794 }