7 public class MeshFeatures { public bool vertices:1, normals:1, texCoords1:1, texCoords2:1, doubleNormals:1, doubleVertices:1, colors:1; };
8 public class PrimitiveGroupType { public: RenderPrimitiveType primitiveType:8; bool vertexRange:1, indices32bit:1; };
9 public enum RenderPrimitiveType : PrimitiveGroupType
20 public class MaterialFlags { public bool doubleSided:1, translucent:1, tile:1, noFog:1, singleSideLight:1; };
21 public class Material : struct
44 public class PrimitiveGroup : struct
47 PrimitiveGroup prev, next;
48 PrimitiveGroupType type;
51 struct { uint16 * indices; int nIndices; };
52 struct { int first, nVertices; };
59 public struct PrimitiveSingle
62 PrimitiveGroupType type;
65 struct { uint16 * indices; int nIndices; };
66 struct { int first, nVertices; };
76 public class Mesh : struct
79 property Pointf * texCoords { get { return texCoords; } set { texCoords = value; } };
80 property int nVertices { get { return nVertices; } set { nVertices = value; } };
81 property Vector3Df * vertices { get { return vertices; } set { vertices = value; } };
82 property Vector3Df * normals { get { return normals; } set { normals = value; } };
83 property ColorRGBAf * colors { get { return colors; } set { colors = value; } };
84 property OldList groups { get { value = groups; } };
85 property MeshFeatures flags { get { return flags; } set { flags = value; } };
87 void Free(MeshFeatures what)
91 DisplaySystem displaySystem = this.displaySystem;
99 driver.FreeMesh(displaySystem, this);
100 for(;(group = groups.first);)
101 FreePrimitiveGroup(group);
103 for(c = 0; c<nPrimitives; c++)
105 if(primitives[c].data)
106 driver.FreeIndices(displaySystem, primitives[c].data);
112 this.displaySystem = null;
119 driver.FreeMesh(displaySystem, this);
124 bool Allocate(MeshFeatures what, int nVertices, DisplaySystem displaySystem)
127 if((!nVertices || nVertices == nVertices) && (!this.displaySystem || this.displaySystem == displaySystem))
130 this.nVertices = nVertices;
131 driver = displaySystem ? displaySystem.driver : (subclass(DisplayDriver))class(LFBDisplayDriver);
132 if(driver.AllocateMesh == DisplayDriver::AllocateMesh) driver = (subclass(DisplayDriver))class(LFBDisplayDriver);
133 if(driver.AllocateMesh(displaySystem, this))
140 this.displaySystem = displaySystem;
145 void Unlock(MeshFeatures flags)
148 driver.UnlockMesh(displaySystem, this, flags);
151 bool Lock(MeshFeatures flags)
156 if(driver.LockMesh(displaySystem, this, flags))
164 void FreePrimitiveGroup(PrimitiveGroup group)
169 driver.FreeIndices(displaySystem, group.data);
170 groups.Delete(group);
174 PrimitiveGroup AddPrimitiveGroup(PrimitiveGroupType flags, int nIndices)
176 PrimitiveGroup result = null;
177 PrimitiveGroup group { };
182 if(!(flags.vertexRange))
184 group.nIndices = nIndices;
187 group.data = driver.AllocateIndices(displaySystem, nIndices, flags.indices32bit);
190 if(LockPrimitiveGroup(group))
200 FreePrimitiveGroup(group);
205 bool LockPrimitiveGroup(PrimitiveGroup group)
211 group.indices = driver.LockIndices(displaySystem, group.data);
212 if(group.indices || group.type.vertexRange)
218 void UnlockPrimitiveGroup(PrimitiveGroup group)
220 if(this && group && group.data)
222 driver.UnlockIndices(displaySystem, group.data, group.type.indices32bit, group.nIndices);
223 //group.indices = null;
227 void FreePrimitive(PrimitiveSingle primitive)
229 if(this && primitive)
232 driver.FreeIndices(displaySystem, primitive.data);
233 primitive.data = null;
237 bool AllocatePrimitive(PrimitiveSingle primitive, PrimitiveGroupType flags, int nIndices)
240 if(this && primitive)
242 primitive.type = flags;
243 primitive.data = driver.AllocateIndices(displaySystem, nIndices, flags.indices32bit);
244 primitive.nIndices = nIndices;
247 if(LockPrimitive(primitive))
251 FreePrimitive(primitive);
256 void UnlockPrimitive(PrimitiveSingle primitive)
258 if(this && primitive)
260 driver.UnlockIndices(this.displaySystem, primitive.data, primitive.type.indices32bit, primitive.nIndices);
261 //primitive.indices = null;
265 bool LockPrimitive(PrimitiveSingle primitive)
268 if(this && primitive)
270 primitive.indices = driver.LockIndices(displaySystem, primitive.data);
271 if(primitive.indices)
277 void ComputeNormals(void)
280 int * numShared = new0 int[nVertices];
281 PrimitiveGroup group;
283 if(Allocate({ normals = true }, nVertices, displaySystem))
285 FillBytes(normals, 0, nVertices * sizeof(Vector3Df));
286 for(group = groups.first; group; group = group.next)
288 int nPrimitives = 0, c;
292 uint16 * indices16 = group.indices;
293 uint32 * indices32 = group.indices;
294 bool i32bit = group.type.indices32bit;
296 if(group.type.primitiveType == triangles)
297 nIndex = nPoints = 3;
298 else if(group.type.primitiveType == quads)
299 nIndex = nPoints = 4;
300 else if(group.type.primitiveType == triFan || group.type.primitiveType == triStrip || group.type.primitiveType == quadStrip)
309 int nIndicesPerPrimitive;
310 if(group.type == Triangles)
311 nIndicesPerPrimitive = 3;
312 else if(group.type == Quads)
313 nIndicesPerPrimitive = 4;
317 for(c = offset; c<group.nIndices; c += nIndex)
321 Vector3Df planeNormal;
323 if(group.type.primitiveType == triFan)
325 plane.FromPointsf(vertices[group.indices[0]],
326 vertices[group.indices[c]],
327 vertices[group.indices[c-1]]);
328 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
330 normals[group.indices[0]].Add(normals[group.indices[0]], planeNormal);
331 numShared[group.indices[0]]++;
332 normals[group.indices[c-1]].Add(normals[group.indices[c-1]], planeNormal);
333 numShared[group.indices[c-1]]++;
334 normals[group.indices[c]].Add(normals[group.indices[c]], planeNormal);
335 numShared[group.indices[c]]++;
337 else if(group.type.primitiveType == triStrip || group.type.primitiveType == quadStrip)
339 plane.FromPointsf(vertices[group.indices[c-1-strip]],
340 vertices[group.indices[c-2+strip]],
341 vertices[group.indices[c]]);
342 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
344 normals[group.indices[c-1-strip]].Add(normals[group.indices[c-1-strip]], planeNormal);
345 numShared[group.indices[c-1-strip]]++;
346 normals[group.indices[c-2+strip]].Add(normals[group.indices[c-2+strip]], planeNormal);
347 numShared[group.indices[c-2+strip]]++;
348 normals[group.indices[c]].Add(normals[group.indices[c]], planeNormal);
349 numShared[group.indices[c]]++;
355 if(group.type.vertexRange)
357 plane.FromPointsf(vertices[c+2],
360 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
362 for(i = c; i<c+nIndex; i++)
364 normals[i].Add(normals[i], planeNormal);
370 plane.FromPointsf(vertices[i32bit ? indices32[c+2] : indices16[c+2]],
371 vertices[i32bit ? indices32[c+1] : indices16[c+1]],
372 vertices[i32bit ? indices32[c] : indices16[c]]);
373 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
375 for(i = c; i<c+nIndex; i++)
377 int index = i32bit ? indices32[i] : indices16[i];
378 normals[index].Add(normals[index], planeNormal);
385 // NOTE: Here we're currently making the assumption that the primitives are in indices mode (vertexRange = false)
386 for(c = 0; c<nPrimitives; c++)
389 PrimitiveSingle * primitive = &primitives[c];
392 Vector3Df planeNormal;
393 plane.FromPointsf(vertices[primitive->indices[2]],
394 vertices[primitive->indices[1]],
395 vertices[primitive->indices[0]]);
396 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
398 if(primitive->material.flags.doubleSided && plane.d < 0)
405 for(i = 0; i<primitive->nIndices; i++)
407 normals[primitive->indices[i]].Add(normals[primitive->indices[i]], planeNormal);
408 numShared[primitive->indices[i]] ++;
412 for(c = 0; c<nVertices; c++)
414 normals[c].Scale(normals[c], 1.0f / numShared[c]);
415 normals[c].Normalize(normals[c]);
418 Unlock({ normals = true });
423 void ApplyMaterial(Material material)
428 PrimitiveGroup group;
429 for(group = groups.first; group; group = group.next)
430 group.material = material;
431 for(c = 0; c<nPrimitives; c++)
432 primitives[c].material = material;
436 bool ApplyTranslucency(Object object)
441 PrimitiveGroup group, nextGroup;
444 // Merge non translucent primitives into groups
445 for(c = 0; c<nPrimitives; )
447 PrimitiveSingle * primitive = &primitives[c];
448 Material material = (primitive->material || !object) ? primitive->material : object.material;
449 if(!material || !(material.flags.translucent))
452 PrimitiveGroup group;
453 int nIndices = primitive->nIndices;
454 for(t = c+1; t<nPrimitives; t++)
456 PrimitiveSingle * prim = &primitives[t];
457 if(prim->type == primitive->type && prim->material == primitive->material)
458 nIndices += prim->nIndices;
460 group = AddPrimitiveGroup(primitive->type, nIndices);
464 group.material = material;
465 for(t = c; t<nPrimitives; t++)
467 primitive = &primitives[t];
468 if(group.type == primitive->type && group.material == primitive->material)
470 CopyBytesBy2(group.indices + nIndices,primitive->indices,primitive->nIndices);
471 nIndices +=primitive->nIndices;
472 CopyBytes(primitives + t, primitives + t + 1, (nPrimitives - t - 1) * sizeof(PrimitiveSingle));
477 UnlockPrimitiveGroup(group);
483 primitives = renew primitives PrimitiveSingle[this.nPrimitives];
485 // Split translucent groups into primitives
486 for(group = groups.first; group; group = nextGroup)
488 Material material = (group.material || !object) ? group.material : object.material;
490 nextGroup = group.next;
492 if(material && material.flags.translucent)
494 int nPrimitives = 0, c;
498 int groupCount = group.type.vertexRange ? group.nVertices : group.nIndices;
499 if(!groupCount) continue;
501 if(group.type.primitiveType == triangles)
502 nIndex = nPoints = 3;
503 else if(group.type.primitiveType == quads)
504 nIndex = nPoints = 4;
505 else if(group.type.primitiveType == triFan || group.type.primitiveType == triStrip)
514 nPrimitives += (groupCount - offset) / nIndex;
516 primitives = renew primitives PrimitiveSingle[this.nPrimitives + nPrimitives];
518 for(c = offset; c<groupCount; c+= nIndex)
520 PrimitiveSingle * primitive = &primitives[this.nPrimitives++];
522 if(AllocatePrimitive(primitive, group.type.primitiveType, nPoints))
524 if(group.type.vertexRange)
526 if(group.type.primitiveType == triangles || group.type.primitiveType == quads)
528 primitive->indices[0] = (uint16)(group.first + c);
529 primitive->indices[1] = (uint16)(group.first + c+1);
530 primitive->indices[2] = (uint16)(group.first + c+2);
532 if(group.type.primitiveType == quads)
533 primitive->indices[3] = (uint16)(group.first + c+3);
535 if(group.type.primitiveType == triFan)
537 primitive->indices[0] = (uint16)group.first;
538 primitive->indices[1] = (uint16)(group.first + c-1);
539 primitive->indices[2] = (uint16)(group.first + c);
541 else if(group.type.primitiveType == triStrip)
543 primitive->indices[0] = (uint16)(group.first + c-1-strip);
544 primitive->indices[1] = (uint16)(group.first + c-2+strip);
545 primitive->indices[2] = (uint16)(group.first + c);
551 if(group.type.primitiveType == triangles || group.type.primitiveType == quads)
552 CopyBytesBy2(primitive->indices, group.indices + c, nIndex);
554 if(group.type.primitiveType == triFan)
556 primitive->indices[0] = group.indices[0];
557 primitive->indices[1] = group.indices[c-1];
558 primitive->indices[2] = group.indices[c];
560 else if(group.type.primitiveType == triStrip)
562 primitive->indices[0] = group.indices[c-1-strip];
563 primitive->indices[1] = group.indices[c-2+strip];
564 primitive->indices[2] = group.indices[c];
568 primitive->material = group.material;
570 primitive->plane.FromPointsf(
571 vertices[primitive->indices[2]],
572 vertices[primitive->indices[1]],
573 vertices[primitive->indices[0]]);
575 primitive->middle.Add(vertices[primitive->indices[0]], vertices[primitive->indices[1]]);
576 primitive->middle.Add(primitive->middle, vertices[primitive->indices[2]]);
577 if(group.type == quads)
578 primitive->middle.Add(primitive->middle, vertices[primitive->indices[3]]);
579 primitive->middle.x /= nPoints;
580 primitive->middle.y /= nPoints;
581 primitive->middle.z /= nPoints;
583 UnlockPrimitive(primitive);
586 FreePrimitiveGroup(group);
592 object.flags.translucent = nPrimitives ? true : false;
599 void SetMinMaxRadius(void)
603 float xRadius, yRadius, zRadius;
605 min = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
606 max = {-MAXFLOAT,-MAXFLOAT,-MAXFLOAT };
608 for(c = 0; c<nVertices; c++)
610 float x = vertices[c].x, y = vertices[c].y, z = vertices[c].z;
611 if(isnan(x) || isnan(y) || isnan(z));
612 else if(x > 1E20 || x < -1E20 || y > 1E20 || y < -1E20 || z > 1E20 || z < -1E20);
615 min.x = Min(min.x, x);
616 min.y = Min(min.y, y);
617 min.z = Min(min.z, z);
618 max.x = Max(max.x, x);
619 max.y = Max(max.y, y);
620 max.z = Max(max.z, z);
623 xRadius = Max(max.x, -min.x);
624 yRadius = Max(max.y, -min.y);
625 zRadius = Max(max.z, -min.z);
627 radius = Max(xRadius, yRadius);
628 radius = Max(radius, zRadius);
631 void DoubleSided(bool flag)
635 PrimitiveGroup group;
637 for(group = groups.first; group; group = group.next)
641 group.material.flags.doubleSided = flag;
644 for(c = 0; c<nPrimitives; c++)
646 PrimitiveSingle * primitive = &primitives[c];
647 if(primitive->material)
649 primitive->material.flags.doubleSided = flag;
657 Vector3Df * vertices;
663 PrimitiveSingle * primitives;
668 DisplaySystem displaySystem;
669 subclass(DisplayDriver) driver;