5 public class MeshFeatures { public bool vertices:1, normals:1, texCoords1:1, texCoords2:1, doubleNormals:1, doubleVertices:1, colors:1; };
6 public class PrimitiveGroupType { public: RenderPrimitiveType primitiveType:8; bool vertexRange:1, indices32bit:1; };
7 public enum RenderPrimitiveType : PrimitiveGroupType
25 public class MaterialFlags { public bool doubleSided:1, translucent:1, tile:1, noFog:1, singleSideLight:1; };
26 public class Material : struct
49 public class PrimitiveGroup : struct
52 PrimitiveGroup prev, next;
53 PrimitiveGroupType type;
56 struct { union { uint16 * indices; uint * indices32; }; int nIndices; };
57 struct { int first, nVertices; };
66 public class PrimitiveGroupIndices16 : PrimitiveGroup
68 property Array<uint16> indices
74 public class PrimitiveGroupIndices32 : PrimitiveGroup
76 property Array<uint> indices
82 public class PrimitiveGroupVertexRange : PrimitiveGroup
84 property int first { set { } }
85 property int nVertices { set { } }
89 public struct PrimitiveSingle
92 PrimitiveGroupType type;
95 struct { union { uint16 * indices; uint * indices32; }; int nIndices; };
96 struct { int first, nVertices; };
106 public class Mesh : struct
109 property Pointf * texCoords { get { return texCoords; } set { texCoords = value; } };
110 property int nVertices { get { return nVertices; } set { nVertices = value; } };
111 property Vector3Df * vertices { get { return vertices; } set { vertices = value; } };
112 property Vector3Df * normals { get { return normals; } set { normals = value; } };
113 property ColorRGBAf * colors { get { return colors; } set { colors = value; } };
114 property OldList groups { get { value = groups; } };
115 property MeshFeatures flags { get { return flags; } set { flags = value; } };
117 void Free(MeshFeatures what)
121 DisplaySystem displaySystem = this.displaySystem;
122 PrimitiveGroup group;
129 driver.FreeMesh(displaySystem, this);
130 for(;(group = groups.first);)
131 FreePrimitiveGroup(group);
133 for(c = 0; c<nPrimitives; c++)
135 if(primitives[c].data)
136 driver.FreeIndices(displaySystem, primitives[c].data);
142 this.displaySystem = null;
149 driver.FreeMesh(displaySystem, this);
154 bool Allocate(MeshFeatures what, int nVertices, DisplaySystem displaySystem)
157 if(!this.displaySystem || this.displaySystem == displaySystem)
159 driver = displaySystem ? displaySystem.driver : (subclass(DisplayDriver))class(LFBDisplayDriver);
160 if(driver.AllocateMesh == DisplayDriver::AllocateMesh) driver = (subclass(DisplayDriver))class(LFBDisplayDriver);
161 if(driver.AllocateMesh(displaySystem, this, what, nVertices))
164 this.nVertices = nVertices;
170 this.displaySystem = displaySystem;
175 void Unlock(MeshFeatures flags)
178 driver.UnlockMesh(displaySystem, this, flags);
181 bool Lock(MeshFeatures flags)
186 if(driver.LockMesh(displaySystem, this, flags))
194 void FreePrimitiveGroup(PrimitiveGroup group)
199 driver.FreeIndices(displaySystem, group.data);
200 groups.Delete(group);
204 PrimitiveGroup AddPrimitiveGroup(PrimitiveGroupType flags, int nIndices)
206 PrimitiveGroup result = null;
207 PrimitiveGroup group { };
212 if(!(flags.vertexRange))
214 group.nIndices = nIndices;
217 group.data = driver.AllocateIndices(displaySystem, nIndices, flags.indices32bit);
220 if(LockPrimitiveGroup(group))
230 FreePrimitiveGroup(group);
235 bool LockPrimitiveGroup(PrimitiveGroup group)
241 group.indices = driver.LockIndices(displaySystem, group.data);
242 if(group.indices || group.type.vertexRange)
248 void UnlockPrimitiveGroup(PrimitiveGroup group)
250 if(this && group && group.data)
252 driver.UnlockIndices(displaySystem, group.data, group.type.indices32bit, group.nIndices);
253 //group.indices = null;
257 void FreePrimitive(PrimitiveSingle primitive)
259 if(this && primitive)
262 driver.FreeIndices(displaySystem, primitive.data);
263 primitive.data = null;
267 bool AllocatePrimitive(PrimitiveSingle primitive, PrimitiveGroupType flags, int nIndices)
270 if(this && primitive)
272 primitive.type = flags;
273 primitive.data = driver.AllocateIndices(displaySystem, nIndices, flags.indices32bit);
274 primitive.nIndices = nIndices;
277 if(LockPrimitive(primitive))
281 FreePrimitive(primitive);
286 void UnlockPrimitive(PrimitiveSingle primitive)
288 if(this && primitive)
290 driver.UnlockIndices(this.displaySystem, primitive.data, primitive.type.indices32bit, primitive.nIndices);
291 //primitive.indices = null;
295 bool LockPrimitive(PrimitiveSingle primitive)
298 if(this && primitive)
300 primitive.indices = driver.LockIndices(displaySystem, primitive.data);
301 if(primitive.indices)
307 void ComputeNormals(void)
310 int * numShared = new0 int[nVertices];
311 PrimitiveGroup group;
313 if(Allocate({ normals = true }, nVertices, displaySystem))
315 FillBytes(normals, 0, nVertices * sizeof(Vector3Df));
316 for(group = groups.first; group; group = group.next)
322 uint16 * indices16 = group.indices;
323 uint32 * indices32 = group.indices32;
324 bool i32bit = group.type.indices32bit;
326 if(group.type.primitiveType == triangles)
327 nIndex = nPoints = 3;
328 else if(group.type.primitiveType == quads)
329 nIndex = nPoints = 4;
330 else if(group.type.primitiveType == triFan || group.type.primitiveType == triStrip || group.type.primitiveType == quadStrip)
339 int nIndicesPerPrimitive;
340 if(group.type == Triangles)
341 nIndicesPerPrimitive = 3;
342 else if(group.type == Quads)
343 nIndicesPerPrimitive = 4;
347 for(c = offset; c<group.nIndices; c += nIndex)
351 Vector3Df planeNormal;
353 if(group.type.primitiveType == triFan)
355 plane.FromPointsf(vertices[group.indices[0]],
356 vertices[group.indices[c]],
357 vertices[group.indices[c-1]]);
358 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
360 normals[group.indices[0]].Add(normals[group.indices[0]], planeNormal);
361 numShared[group.indices[0]]++;
362 normals[group.indices[c-1]].Add(normals[group.indices[c-1]], planeNormal);
363 numShared[group.indices[c-1]]++;
364 normals[group.indices[c]].Add(normals[group.indices[c]], planeNormal);
365 numShared[group.indices[c]]++;
367 else if(group.type.primitiveType == triStrip || group.type.primitiveType == quadStrip)
369 plane.FromPointsf(vertices[group.indices[c-1-strip]],
370 vertices[group.indices[c-2+strip]],
371 vertices[group.indices[c]]);
372 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
374 normals[group.indices[c-1-strip]].Add(normals[group.indices[c-1-strip]], planeNormal);
375 numShared[group.indices[c-1-strip]]++;
376 normals[group.indices[c-2+strip]].Add(normals[group.indices[c-2+strip]], planeNormal);
377 numShared[group.indices[c-2+strip]]++;
378 normals[group.indices[c]].Add(normals[group.indices[c]], planeNormal);
379 numShared[group.indices[c]]++;
385 if(group.type.vertexRange)
387 plane.FromPointsf(vertices[c+2],
390 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
392 for(i = c; i<c+nIndex; i++)
394 normals[i].Add(normals[i], planeNormal);
400 plane.FromPointsf(vertices[i32bit ? indices32[c+2] : indices16[c+2]],
401 vertices[i32bit ? indices32[c+1] : indices16[c+1]],
402 vertices[i32bit ? indices32[c] : indices16[c]]);
403 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
405 for(i = c; i<c+nIndex; i++)
407 int index = i32bit ? indices32[i] : indices16[i];
408 normals[index].Add(normals[index], planeNormal);
415 // NOTE: Here we're currently making the assumption that the primitives are in indices mode (vertexRange = false)
416 for(c = 0; c<nPrimitives; c++)
419 PrimitiveSingle * primitive = &primitives[c];
422 Vector3Df planeNormal;
423 plane.FromPointsf(vertices[primitive->indices[2]],
424 vertices[primitive->indices[1]],
425 vertices[primitive->indices[0]]);
426 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
428 if(primitive->material.flags.doubleSided && plane.d < 0)
435 for(i = 0; i<primitive->nIndices; i++)
437 normals[primitive->indices[i]].Add(normals[primitive->indices[i]], planeNormal);
438 numShared[primitive->indices[i]] ++;
442 for(c = 0; c<nVertices; c++)
444 normals[c].Scale(normals[c], 1.0f / numShared[c]);
445 normals[c].Normalize(normals[c]);
448 Unlock({ normals = true });
453 void ApplyMaterial(Material material)
458 PrimitiveGroup group;
459 for(group = groups.first; group; group = group.next)
460 group.material = material;
461 for(c = 0; c<nPrimitives; c++)
462 primitives[c].material = material;
466 bool ApplyTranslucency(Object object)
471 PrimitiveGroup group, nextGroup;
474 // Merge non translucent primitives into groups
475 for(c = 0; c<nPrimitives; )
477 PrimitiveSingle * primitive = &primitives[c];
478 Material material = (primitive->material || !object) ? primitive->material : object.material;
479 if(!material || !(material.flags.translucent))
482 PrimitiveGroup group;
483 int nIndices = primitive->nIndices;
484 for(t = c+1; t<nPrimitives; t++)
486 PrimitiveSingle * prim = &primitives[t];
487 if(prim->type == primitive->type && prim->material == primitive->material)
488 nIndices += prim->nIndices;
490 group = AddPrimitiveGroup(primitive->type, nIndices);
494 group.material = material;
495 for(t = c; t<nPrimitives; t++)
497 primitive = &primitives[t];
498 if(group.type == primitive->type && group.material == primitive->material)
500 CopyBytesBy2(group.indices + nIndices,primitive->indices,primitive->nIndices);
501 nIndices +=primitive->nIndices;
502 CopyBytes(primitives + t, primitives + t + 1, (nPrimitives - t - 1) * sizeof(PrimitiveSingle));
507 UnlockPrimitiveGroup(group);
513 primitives = renew primitives PrimitiveSingle[this.nPrimitives];
515 // Split translucent groups into primitives
516 for(group = groups.first; group; group = nextGroup)
518 Material material = (group.material || !object) ? group.material : object.material;
520 nextGroup = group.next;
522 if(material && material.flags.translucent)
524 int nPrimitives = 0, c;
528 int groupCount = group.type.vertexRange ? group.nVertices : group.nIndices;
529 if(!groupCount) continue;
531 if(group.type.primitiveType == triangles)
532 nIndex = nPoints = 3;
533 else if(group.type.primitiveType == quads)
534 nIndex = nPoints = 4;
535 else if(group.type.primitiveType == triFan || group.type.primitiveType == triStrip)
544 nPrimitives += (groupCount - offset) / nIndex;
546 primitives = renew primitives PrimitiveSingle[this.nPrimitives + nPrimitives];
548 for(c = offset; c<groupCount; c+= nIndex)
550 PrimitiveSingle * primitive = &primitives[this.nPrimitives++];
552 if(AllocatePrimitive(primitive, group.type.primitiveType, nPoints))
554 if(group.type.vertexRange)
556 if(group.type.primitiveType == triangles || group.type.primitiveType == quads)
558 primitive->indices[0] = (uint16)(group.first + c);
559 primitive->indices[1] = (uint16)(group.first + c+1);
560 primitive->indices[2] = (uint16)(group.first + c+2);
562 if(group.type.primitiveType == quads)
563 primitive->indices[3] = (uint16)(group.first + c+3);
565 if(group.type.primitiveType == triFan)
567 primitive->indices[0] = (uint16)group.first;
568 primitive->indices[1] = (uint16)(group.first + c-1);
569 primitive->indices[2] = (uint16)(group.first + c);
571 else if(group.type.primitiveType == triStrip)
573 primitive->indices[0] = (uint16)(group.first + c-1-strip);
574 primitive->indices[1] = (uint16)(group.first + c-2+strip);
575 primitive->indices[2] = (uint16)(group.first + c);
581 if(group.type.primitiveType == triangles || group.type.primitiveType == quads)
582 CopyBytesBy2(primitive->indices, group.indices + c, nIndex);
584 if(group.type.primitiveType == triFan)
586 primitive->indices[0] = group.indices[0];
587 primitive->indices[1] = group.indices[c-1];
588 primitive->indices[2] = group.indices[c];
590 else if(group.type.primitiveType == triStrip)
592 primitive->indices[0] = group.indices[c-1-strip];
593 primitive->indices[1] = group.indices[c-2+strip];
594 primitive->indices[2] = group.indices[c];
598 primitive->material = group.material;
600 primitive->plane.FromPointsf(
601 vertices[primitive->indices[2]],
602 vertices[primitive->indices[1]],
603 vertices[primitive->indices[0]]);
605 primitive->middle.Add(vertices[primitive->indices[0]], vertices[primitive->indices[1]]);
606 primitive->middle.Add(primitive->middle, vertices[primitive->indices[2]]);
607 if(group.type == quads)
608 primitive->middle.Add(primitive->middle, vertices[primitive->indices[3]]);
609 primitive->middle.x /= nPoints;
610 primitive->middle.y /= nPoints;
611 primitive->middle.z /= nPoints;
613 UnlockPrimitive(primitive);
616 FreePrimitiveGroup(group);
622 object.flags.translucent = nPrimitives ? true : false;
634 void SetMinMaxRadius(void)
638 float xRadius, yRadius, zRadius;
640 min = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
641 max = {-MAXFLOAT,-MAXFLOAT,-MAXFLOAT };
643 for(c = 0; c<nVertices; c++)
645 float x = vertices[c].x, y = vertices[c].y, z = vertices[c].z;
646 if(x.isNan || y.isNan || z.isNan);
647 else if(x > 1E20 || x < -1E20 || y > 1E20 || y < -1E20 || z > 1E20 || z < -1E20);
650 min.x = Min(min.x, x);
651 min.y = Min(min.y, y);
652 min.z = Min(min.z, z);
653 max.x = Max(max.x, x);
654 max.y = Max(max.y, y);
655 max.z = Max(max.z, z);
658 xRadius = Max(max.x, -min.x);
659 yRadius = Max(max.y, -min.y);
660 zRadius = Max(max.z, -min.z);
662 radius = Max(xRadius, yRadius);
663 radius = Max(radius, zRadius);
666 void DoubleSided(bool flag)
670 PrimitiveGroup group;
672 for(group = groups.first; group; group = group.next)
676 group.material.flags.doubleSided = flag;
679 for(c = 0; c<nPrimitives; c++)
681 PrimitiveSingle * primitive = &primitives[c];
682 if(primitive->material)
684 primitive->material.flags.doubleSided = flag;
692 Vector3Df * vertices;
698 PrimitiveSingle * primitives;
703 DisplaySystem displaySystem;
704 subclass(DisplayDriver) driver;