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 = texCoords != null }, nVertices, displaySystem))
325 Vector3Df * normals = this.normals;
326 Vector3Df * tangents = this.tangents;
327 Pointf * texCoords = this.texCoords;
328 FillBytes(normals, 0, nVertices * sizeof(Vector3Df));
330 FillBytes(tangents, 0, 2*nVertices * sizeof(Vector3Df));
331 for(group = groups.first; group; group = group.next)
337 uint16 * indices16 = group.indices;
338 uint32 * indices32 = group.indices32;
339 bool i32bit = group.type.indices32bit;
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)
354 int nIndicesPerPrimitive;
355 if(group.type == Triangles)
356 nIndicesPerPrimitive = 3;
357 else if(group.type == Quads)
358 nIndicesPerPrimitive = 4;
362 for(c = offset; c<group.nIndices; c += nIndex)
366 Vector3Df planeNormal;
368 if(group.type.primitiveType == triFan)
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 };
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]]++;
382 else if(group.type.primitiveType == triStrip || group.type.primitiveType == quadStrip)
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 };
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]]++;
400 if(group.type.vertexRange)
402 plane.FromPointsf(vertices[c+2],
405 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
407 for(i = c; i<c+nIndex; i++)
409 normals[i].Add(normals[i], planeNormal);
415 Vector3D edges[4], rEdges[4];
417 computeNormalWeights(nIndex, vertices, indices32, i32bit, c, weights, edges, rEdges);
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 };
424 for(i = c; i<c+nIndex; i++)
426 int index = i32bit ? indices32[i] : indices16[i];
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] ++;
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;
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];
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);
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);
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++)
473 PrimitiveSingle * primitive = &primitives[c];
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 };
482 if(primitive->material.flags.doubleSided && plane.d < 0)
489 for(i = 0; i<primitive->nIndices; i++)
491 normals[primitive->indices[i]].Add(normals[primitive->indices[i]], planeNormal);
492 numShared[primitive->indices[i]] ++;
496 for(c = 0; c<nVertices; c++)
498 float s = (float)(1.0 / weightSum[c]); // numShared[c]
499 Vector3Df * n = &normals[c];
500 n->Scale(n, s), n->Normalize(n);
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);
510 Unlock({ normals = true, tangents = true });
515 void ApplyMaterial(Material material)
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;
528 bool ApplyTranslucency(Object object)
533 PrimitiveGroup group, nextGroup;
536 // Merge non translucent primitives into groups
537 for(c = 0; c<nPrimitives; )
539 PrimitiveSingle * primitive = &primitives[c];
540 Material material = (primitive->material || !object) ? primitive->material : object.material;
541 if(!material || !(material.flags.translucent))
544 PrimitiveGroup group;
545 int nIndices = primitive->nIndices;
546 for(t = c+1; t<nPrimitives; t++)
548 PrimitiveSingle * prim = &primitives[t];
549 if(prim->type == primitive->type && prim->material == primitive->material)
550 nIndices += prim->nIndices;
552 group = AddPrimitiveGroup(primitive->type, nIndices);
556 group.material = material;
557 for(t = c; t<nPrimitives; t++)
559 primitive = &primitives[t];
560 if(group.type == primitive->type && group.material == primitive->material)
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));
569 UnlockPrimitiveGroup(group);
575 primitives = renew primitives PrimitiveSingle[this.nPrimitives];
577 // Split translucent groups into primitives
578 for(group = groups.first; group; group = nextGroup)
580 Material material = (group.material || !object) ? group.material : object.material;
582 nextGroup = group.next;
584 if(material && material.flags.translucent)
586 int nPrimitives = 0, c;
590 int groupCount = group.type.vertexRange ? group.nVertices : group.nIndices;
591 if(!groupCount) continue;
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)
606 nPrimitives += (groupCount - offset) / nIndex;
608 primitives = renew primitives PrimitiveSingle[this.nPrimitives + nPrimitives];
610 for(c = offset; c<groupCount; c+= nIndex)
612 PrimitiveSingle * primitive = &primitives[this.nPrimitives++];
614 if(AllocatePrimitive(primitive, group.type.primitiveType, nPoints))
616 if(group.type.vertexRange)
618 if(group.type.primitiveType == triangles || group.type.primitiveType == quads)
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);
624 if(group.type.primitiveType == quads)
625 primitive->indices[3] = (uint16)(group.first + c+3);
627 if(group.type.primitiveType == triFan)
629 primitive->indices[0] = (uint16)group.first;
630 primitive->indices[1] = (uint16)(group.first + c-1);
631 primitive->indices[2] = (uint16)(group.first + c);
633 else if(group.type.primitiveType == triStrip)
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);
643 if(group.type.primitiveType == triangles || group.type.primitiveType == quads)
644 CopyBytesBy2(primitive->indices, group.indices + c, nIndex);
646 if(group.type.primitiveType == triFan)
648 primitive->indices[0] = group.indices[0];
649 primitive->indices[1] = group.indices[c-1];
650 primitive->indices[2] = group.indices[c];
652 else if(group.type.primitiveType == triStrip)
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];
660 primitive->material = group.material;
662 primitive->plane.FromPointsf(
663 vertices[primitive->indices[2]],
664 vertices[primitive->indices[1]],
665 vertices[primitive->indices[0]]);
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;
675 UnlockPrimitive(primitive);
678 FreePrimitiveGroup(group);
684 object.flags.translucent = nPrimitives ? true : false;
696 void SetMinMaxRadius(void)
700 float xRadius, yRadius, zRadius;
702 min = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
703 max = {-MAXFLOAT,-MAXFLOAT,-MAXFLOAT };
705 for(c = 0; c<nVertices; c++)
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);
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);
720 xRadius = Max(max.x, -min.x);
721 yRadius = Max(max.y, -min.y);
722 zRadius = Max(max.z, -min.z);
724 radius = Max(xRadius, yRadius);
725 radius = Max(radius, zRadius);
728 void DoubleSided(bool flag)
732 PrimitiveGroup group;
734 for(group = groups.first; group; group = group.next)
738 group.material.flags.doubleSided = flag;
741 for(c = 0; c<nPrimitives; c++)
743 PrimitiveSingle * primitive = &primitives[c];
744 if(primitive->material)
746 primitive->material.flags.doubleSided = flag;
754 Vector3Df * vertices;
756 Vector3Df * tangents;
759 ColorRGB * lightVectors;
762 PrimitiveSingle * primitives;
768 DisplaySystem displaySystem;
769 subclass(DisplayDriver) driver;
773 void computeNormalWeights(int n, Vector3Df * vertices, uint * indices, bool ix32Bit, int base, double * weights, Vector3D * edges, Vector3D * rEdges)
776 for(i = 0; i < n; i++)
778 uint ix0 = i, ix1 = (i + 1) % n;
783 ix0 = indices[base+ix0], ix1 = indices[base+ix1];
785 ix0 = ((uint16*)indices)[base+ix0], ix1 = ((uint16*)indices)[base+ix1];
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);
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);