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
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
43 float refractiveIndex;
44 float refractiveIndexContainer;
56 public class PrimitiveGroup : struct
59 PrimitiveGroup prev, next;
60 PrimitiveGroupType type;
63 struct { union { uint16 * indices; uint * indices32; }; int nIndices; };
64 struct { int first, nVertices; };
73 public class PrimitiveGroupIndices16 : PrimitiveGroup
75 property Array<uint16> indices
81 public class PrimitiveGroupIndices32 : PrimitiveGroup
83 property Array<uint> indices
89 public class PrimitiveGroupVertexRange : PrimitiveGroup
91 property int first { set { } }
92 property int nVertices { set { } }
96 public struct PrimitiveSingle
99 PrimitiveGroupType type;
102 struct { union { uint16 * indices; uint * indices32; }; int nIndices; };
103 struct { int first, nVertices; };
113 public class Mesh : struct
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; } };
126 void Free(MeshFeatures what)
130 DisplaySystem displaySystem = this.displaySystem;
131 PrimitiveGroup group;
138 driver.FreeMesh(displaySystem, this);
139 for(;(group = groups.first);)
140 FreePrimitiveGroup(group);
142 for(c = 0; c<nPrimitives; c++)
144 if(primitives[c].data)
145 driver.FreeIndices(displaySystem, primitives[c].data);
151 this.displaySystem = null;
158 driver.FreeMesh(displaySystem, this);
163 bool Allocate(MeshFeatures what, int nVertices, DisplaySystem displaySystem)
166 if(!this.displaySystem || this.displaySystem == displaySystem)
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))
173 this.nVertices = nVertices;
179 this.displaySystem = displaySystem;
184 void Unlock(MeshFeatures flags)
187 driver.UnlockMesh(displaySystem, this, flags);
190 bool Lock(MeshFeatures flags)
195 if(driver.LockMesh(displaySystem, this, flags))
203 void FreePrimitiveGroup(PrimitiveGroup group)
208 driver.FreeIndices(displaySystem, group.data);
209 groups.Delete(group);
213 PrimitiveGroup AddPrimitiveGroup(PrimitiveGroupType flags, int nIndices)
215 PrimitiveGroup result = null;
216 PrimitiveGroup group { };
221 if(!(flags.vertexRange))
223 group.nIndices = nIndices;
226 group.data = driver.AllocateIndices(displaySystem, nIndices, flags.indices32bit);
229 if(LockPrimitiveGroup(group))
239 FreePrimitiveGroup(group);
244 bool LockPrimitiveGroup(PrimitiveGroup group)
250 group.indices = driver.LockIndices(displaySystem, group.data);
251 if(group.indices || group.type.vertexRange)
257 void UnlockPrimitiveGroup(PrimitiveGroup group)
259 if(this && group && group.data)
261 driver.UnlockIndices(displaySystem, group.data, group.type.indices32bit, group.nIndices);
262 //group.indices = null;
266 void FreePrimitive(PrimitiveSingle primitive)
268 if(this && primitive)
271 driver.FreeIndices(displaySystem, primitive.data);
272 primitive.data = null;
276 bool AllocatePrimitive(PrimitiveSingle primitive, PrimitiveGroupType flags, int nIndices)
279 if(this && primitive)
281 primitive.type = flags;
282 primitive.data = driver.AllocateIndices(displaySystem, nIndices, flags.indices32bit);
283 primitive.nIndices = nIndices;
286 if(LockPrimitive(primitive))
290 FreePrimitive(primitive);
295 void UnlockPrimitive(PrimitiveSingle primitive)
297 if(this && primitive)
299 driver.UnlockIndices(this.displaySystem, primitive.data, primitive.type.indices32bit, primitive.nIndices);
300 //primitive.indices = null;
304 bool LockPrimitive(PrimitiveSingle primitive)
307 if(this && primitive)
309 primitive.indices = driver.LockIndices(displaySystem, primitive.data);
310 if(primitive.indices)
316 void ComputeNormals(void)
319 int * numShared = new0 int[nVertices];
320 double * weightSum = new0 double[nVertices];
321 PrimitiveGroup group;
323 if(Allocate({ normals = true, tangents = true }, nVertices, displaySystem))
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)
336 uint16 * indices16 = group.indices;
337 uint32 * indices32 = group.indices32;
338 bool i32bit = group.type.indices32bit;
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)
353 int nIndicesPerPrimitive;
354 if(group.type == Triangles)
355 nIndicesPerPrimitive = 3;
356 else if(group.type == Quads)
357 nIndicesPerPrimitive = 4;
361 for(c = offset; c<group.nIndices; c += nIndex)
365 Vector3Df planeNormal;
367 if(group.type.primitiveType == triFan)
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 };
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]]++;
381 else if(group.type.primitiveType == triStrip || group.type.primitiveType == quadStrip)
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 };
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]]++;
399 if(group.type.vertexRange)
401 plane.FromPointsf(vertices[c+2],
404 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
406 for(i = c; i<c+nIndex; i++)
408 normals[i].Add(normals[i], planeNormal);
414 Vector3D edges[4], rEdges[4];
416 computeNormalWeights(nIndex, vertices, indices32, i32bit, c, weights, edges, rEdges);
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 };
423 for(i = c; i<c+nIndex; i++)
425 int index = i32bit ? indices32[i] : indices16[i];
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] ++;
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;
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];
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);
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);
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++)
472 PrimitiveSingle * primitive = &primitives[c];
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 };
481 if(primitive->material.flags.doubleSided && plane.d < 0)
488 for(i = 0; i<primitive->nIndices; i++)
490 normals[primitive->indices[i]].Add(normals[primitive->indices[i]], planeNormal);
491 numShared[primitive->indices[i]] ++;
495 for(c = 0; c<nVertices; c++)
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);
505 Unlock({ normals = true, tangents = true });
510 void ApplyMaterial(Material material)
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;
523 bool ApplyTranslucency(Object object)
528 PrimitiveGroup group, nextGroup;
531 // Merge non translucent primitives into groups
532 for(c = 0; c<nPrimitives; )
534 PrimitiveSingle * primitive = &primitives[c];
535 Material material = (primitive->material || !object) ? primitive->material : object.material;
536 if(!material || !(material.flags.translucent))
539 PrimitiveGroup group;
540 int nIndices = primitive->nIndices;
541 for(t = c+1; t<nPrimitives; t++)
543 PrimitiveSingle * prim = &primitives[t];
544 if(prim->type == primitive->type && prim->material == primitive->material)
545 nIndices += prim->nIndices;
547 group = AddPrimitiveGroup(primitive->type, nIndices);
551 group.material = material;
552 for(t = c; t<nPrimitives; t++)
554 primitive = &primitives[t];
555 if(group.type == primitive->type && group.material == primitive->material)
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));
564 UnlockPrimitiveGroup(group);
570 primitives = renew primitives PrimitiveSingle[this.nPrimitives];
572 // Split translucent groups into primitives
573 for(group = groups.first; group; group = nextGroup)
575 Material material = (group.material || !object) ? group.material : object.material;
577 nextGroup = group.next;
579 if(material && material.flags.translucent)
581 int nPrimitives = 0, c;
585 int groupCount = group.type.vertexRange ? group.nVertices : group.nIndices;
586 if(!groupCount) continue;
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)
601 nPrimitives += (groupCount - offset) / nIndex;
603 primitives = renew primitives PrimitiveSingle[this.nPrimitives + nPrimitives];
605 for(c = offset; c<groupCount; c+= nIndex)
607 PrimitiveSingle * primitive = &primitives[this.nPrimitives++];
609 if(AllocatePrimitive(primitive, group.type.primitiveType, nPoints))
611 if(group.type.vertexRange)
613 if(group.type.primitiveType == triangles || group.type.primitiveType == quads)
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);
619 if(group.type.primitiveType == quads)
620 primitive->indices[3] = (uint16)(group.first + c+3);
622 if(group.type.primitiveType == triFan)
624 primitive->indices[0] = (uint16)group.first;
625 primitive->indices[1] = (uint16)(group.first + c-1);
626 primitive->indices[2] = (uint16)(group.first + c);
628 else if(group.type.primitiveType == triStrip)
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);
638 if(group.type.primitiveType == triangles || group.type.primitiveType == quads)
639 CopyBytesBy2(primitive->indices, group.indices + c, nIndex);
641 if(group.type.primitiveType == triFan)
643 primitive->indices[0] = group.indices[0];
644 primitive->indices[1] = group.indices[c-1];
645 primitive->indices[2] = group.indices[c];
647 else if(group.type.primitiveType == triStrip)
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];
655 primitive->material = group.material;
657 primitive->plane.FromPointsf(
658 vertices[primitive->indices[2]],
659 vertices[primitive->indices[1]],
660 vertices[primitive->indices[0]]);
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;
670 UnlockPrimitive(primitive);
673 FreePrimitiveGroup(group);
679 object.flags.translucent = nPrimitives ? true : false;
691 void SetMinMaxRadius(void)
695 float xRadius, yRadius, zRadius;
697 min = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
698 max = {-MAXFLOAT,-MAXFLOAT,-MAXFLOAT };
700 for(c = 0; c<nVertices; c++)
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);
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);
715 xRadius = Max(max.x, -min.x);
716 yRadius = Max(max.y, -min.y);
717 zRadius = Max(max.z, -min.z);
719 radius = Max(xRadius, yRadius);
720 radius = Max(radius, zRadius);
723 void DoubleSided(bool flag)
727 PrimitiveGroup group;
729 for(group = groups.first; group; group = group.next)
733 group.material.flags.doubleSided = flag;
736 for(c = 0; c<nPrimitives; c++)
738 PrimitiveSingle * primitive = &primitives[c];
739 if(primitive->material)
741 primitive->material.flags.doubleSided = flag;
749 Vector3Df * vertices;
751 Vector3Df * tangents;
754 ColorRGB * lightVectors;
757 PrimitiveSingle * primitives;
763 DisplaySystem displaySystem;
764 subclass(DisplayDriver) driver;
768 void computeNormalWeights(int n, Vector3Df * vertices, uint * indices, bool ix32Bit, int base, double * weights, Vector3D * edges, Vector3D * rEdges)
771 for(i = 0; i < n; i++)
773 uint ix0 = i, ix1 = (i + 1) % n;
778 ix0 = indices[base+ix0], ix1 = indices[base+ix1];
780 ix0 = ((uint16*)indices)[base+ix0], ix1 = ((uint16*)indices)[base+ix1];
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);
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);