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
18 public class MaterialFlags { public bool doubleSided:1, translucent:1, tile:1, noFog:1, singleSideLight:1; };
19 public class Material : struct
42 public class PrimitiveGroup : struct
45 PrimitiveGroup prev, next;
46 PrimitiveGroupType type;
49 struct { union { uint16 * indices; uint * indices32; }; int nIndices; };
50 struct { int first, nVertices; };
57 public struct PrimitiveSingle
60 PrimitiveGroupType type;
63 struct { union { uint16 * indices; uint * indices32; }; int nIndices; };
64 struct { int first, nVertices; };
74 public class Mesh : struct
77 property Pointf * texCoords { get { return texCoords; } set { texCoords = value; } };
78 property int nVertices { get { return nVertices; } set { nVertices = value; } };
79 property Vector3Df * vertices { get { return vertices; } set { vertices = value; } };
80 property Vector3Df * normals { get { return normals; } set { normals = value; } };
81 property ColorRGBAf * colors { get { return colors; } set { colors = value; } };
82 property OldList groups { get { value = groups; } };
83 property MeshFeatures flags { get { return flags; } set { flags = value; } };
85 void Free(MeshFeatures what)
89 DisplaySystem displaySystem = this.displaySystem;
97 driver.FreeMesh(displaySystem, this);
98 for(;(group = groups.first);)
99 FreePrimitiveGroup(group);
101 for(c = 0; c<nPrimitives; c++)
103 if(primitives[c].data)
104 driver.FreeIndices(displaySystem, primitives[c].data);
110 this.displaySystem = null;
117 driver.FreeMesh(displaySystem, this);
122 bool Allocate(MeshFeatures what, int nVertices, DisplaySystem displaySystem)
125 if((!this.nVertices || this.nVertices == nVertices) && (!this.displaySystem || this.displaySystem == displaySystem))
128 this.nVertices = nVertices;
129 driver = displaySystem ? displaySystem.driver : (subclass(DisplayDriver))class(LFBDisplayDriver);
130 if(driver.AllocateMesh == DisplayDriver::AllocateMesh) driver = (subclass(DisplayDriver))class(LFBDisplayDriver);
131 if(driver.AllocateMesh(displaySystem, this))
138 this.displaySystem = displaySystem;
143 void Unlock(MeshFeatures flags)
146 driver.UnlockMesh(displaySystem, this, flags);
149 bool Lock(MeshFeatures flags)
154 if(driver.LockMesh(displaySystem, this, flags))
162 void FreePrimitiveGroup(PrimitiveGroup group)
167 driver.FreeIndices(displaySystem, group.data);
168 groups.Delete(group);
172 PrimitiveGroup AddPrimitiveGroup(PrimitiveGroupType flags, int nIndices)
174 PrimitiveGroup result = null;
175 PrimitiveGroup group { };
180 if(!(flags.vertexRange))
182 group.nIndices = nIndices;
185 group.data = driver.AllocateIndices(displaySystem, nIndices, flags.indices32bit);
188 if(LockPrimitiveGroup(group))
198 FreePrimitiveGroup(group);
203 bool LockPrimitiveGroup(PrimitiveGroup group)
209 group.indices = driver.LockIndices(displaySystem, group.data);
210 if(group.indices || group.type.vertexRange)
216 void UnlockPrimitiveGroup(PrimitiveGroup group)
218 if(this && group && group.data)
220 driver.UnlockIndices(displaySystem, group.data, group.type.indices32bit, group.nIndices);
221 //group.indices = null;
225 void FreePrimitive(PrimitiveSingle primitive)
227 if(this && primitive)
230 driver.FreeIndices(displaySystem, primitive.data);
231 primitive.data = null;
235 bool AllocatePrimitive(PrimitiveSingle primitive, PrimitiveGroupType flags, int nIndices)
238 if(this && primitive)
240 primitive.type = flags;
241 primitive.data = driver.AllocateIndices(displaySystem, nIndices, flags.indices32bit);
242 primitive.nIndices = nIndices;
245 if(LockPrimitive(primitive))
249 FreePrimitive(primitive);
254 void UnlockPrimitive(PrimitiveSingle primitive)
256 if(this && primitive)
258 driver.UnlockIndices(this.displaySystem, primitive.data, primitive.type.indices32bit, primitive.nIndices);
259 //primitive.indices = null;
263 bool LockPrimitive(PrimitiveSingle primitive)
266 if(this && primitive)
268 primitive.indices = driver.LockIndices(displaySystem, primitive.data);
269 if(primitive.indices)
275 void ComputeNormals(void)
278 int * numShared = new0 int[nVertices];
279 PrimitiveGroup group;
281 if(Allocate({ normals = true }, nVertices, displaySystem))
283 FillBytes(normals, 0, nVertices * sizeof(Vector3Df));
284 for(group = groups.first; group; group = group.next)
290 uint16 * indices16 = group.indices;
291 uint32 * indices32 = group.indices32;
292 bool i32bit = group.type.indices32bit;
294 if(group.type.primitiveType == triangles)
295 nIndex = nPoints = 3;
296 else if(group.type.primitiveType == quads)
297 nIndex = nPoints = 4;
298 else if(group.type.primitiveType == triFan || group.type.primitiveType == triStrip || group.type.primitiveType == quadStrip)
307 int nIndicesPerPrimitive;
308 if(group.type == Triangles)
309 nIndicesPerPrimitive = 3;
310 else if(group.type == Quads)
311 nIndicesPerPrimitive = 4;
315 for(c = offset; c<group.nIndices; c += nIndex)
319 Vector3Df planeNormal;
321 if(group.type.primitiveType == triFan)
323 plane.FromPointsf(vertices[group.indices[0]],
324 vertices[group.indices[c]],
325 vertices[group.indices[c-1]]);
326 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
328 normals[group.indices[0]].Add(normals[group.indices[0]], planeNormal);
329 numShared[group.indices[0]]++;
330 normals[group.indices[c-1]].Add(normals[group.indices[c-1]], planeNormal);
331 numShared[group.indices[c-1]]++;
332 normals[group.indices[c]].Add(normals[group.indices[c]], planeNormal);
333 numShared[group.indices[c]]++;
335 else if(group.type.primitiveType == triStrip || group.type.primitiveType == quadStrip)
337 plane.FromPointsf(vertices[group.indices[c-1-strip]],
338 vertices[group.indices[c-2+strip]],
339 vertices[group.indices[c]]);
340 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
342 normals[group.indices[c-1-strip]].Add(normals[group.indices[c-1-strip]], planeNormal);
343 numShared[group.indices[c-1-strip]]++;
344 normals[group.indices[c-2+strip]].Add(normals[group.indices[c-2+strip]], planeNormal);
345 numShared[group.indices[c-2+strip]]++;
346 normals[group.indices[c]].Add(normals[group.indices[c]], planeNormal);
347 numShared[group.indices[c]]++;
353 if(group.type.vertexRange)
355 plane.FromPointsf(vertices[c+2],
358 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
360 for(i = c; i<c+nIndex; i++)
362 normals[i].Add(normals[i], planeNormal);
368 plane.FromPointsf(vertices[i32bit ? indices32[c+2] : indices16[c+2]],
369 vertices[i32bit ? indices32[c+1] : indices16[c+1]],
370 vertices[i32bit ? indices32[c] : indices16[c]]);
371 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
373 for(i = c; i<c+nIndex; i++)
375 int index = i32bit ? indices32[i] : indices16[i];
376 normals[index].Add(normals[index], planeNormal);
383 // NOTE: Here we're currently making the assumption that the primitives are in indices mode (vertexRange = false)
384 for(c = 0; c<nPrimitives; c++)
387 PrimitiveSingle * primitive = &primitives[c];
390 Vector3Df planeNormal;
391 plane.FromPointsf(vertices[primitive->indices[2]],
392 vertices[primitive->indices[1]],
393 vertices[primitive->indices[0]]);
394 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
396 if(primitive->material.flags.doubleSided && plane.d < 0)
403 for(i = 0; i<primitive->nIndices; i++)
405 normals[primitive->indices[i]].Add(normals[primitive->indices[i]], planeNormal);
406 numShared[primitive->indices[i]] ++;
410 for(c = 0; c<nVertices; c++)
412 normals[c].Scale(normals[c], 1.0f / numShared[c]);
413 normals[c].Normalize(normals[c]);
416 Unlock({ normals = true });
421 void ApplyMaterial(Material material)
426 PrimitiveGroup group;
427 for(group = groups.first; group; group = group.next)
428 group.material = material;
429 for(c = 0; c<nPrimitives; c++)
430 primitives[c].material = material;
434 bool ApplyTranslucency(Object object)
439 PrimitiveGroup group, nextGroup;
442 // Merge non translucent primitives into groups
443 for(c = 0; c<nPrimitives; )
445 PrimitiveSingle * primitive = &primitives[c];
446 Material material = (primitive->material || !object) ? primitive->material : object.material;
447 if(!material || !(material.flags.translucent))
450 PrimitiveGroup group;
451 int nIndices = primitive->nIndices;
452 for(t = c+1; t<nPrimitives; t++)
454 PrimitiveSingle * prim = &primitives[t];
455 if(prim->type == primitive->type && prim->material == primitive->material)
456 nIndices += prim->nIndices;
458 group = AddPrimitiveGroup(primitive->type, nIndices);
462 group.material = material;
463 for(t = c; t<nPrimitives; t++)
465 primitive = &primitives[t];
466 if(group.type == primitive->type && group.material == primitive->material)
468 CopyBytesBy2(group.indices + nIndices,primitive->indices,primitive->nIndices);
469 nIndices +=primitive->nIndices;
470 CopyBytes(primitives + t, primitives + t + 1, (nPrimitives - t - 1) * sizeof(PrimitiveSingle));
475 UnlockPrimitiveGroup(group);
481 primitives = renew primitives PrimitiveSingle[this.nPrimitives];
483 // Split translucent groups into primitives
484 for(group = groups.first; group; group = nextGroup)
486 Material material = (group.material || !object) ? group.material : object.material;
488 nextGroup = group.next;
490 if(material && material.flags.translucent)
492 int nPrimitives = 0, c;
496 int groupCount = group.type.vertexRange ? group.nVertices : group.nIndices;
497 if(!groupCount) continue;
499 if(group.type.primitiveType == triangles)
500 nIndex = nPoints = 3;
501 else if(group.type.primitiveType == quads)
502 nIndex = nPoints = 4;
503 else if(group.type.primitiveType == triFan || group.type.primitiveType == triStrip)
512 nPrimitives += (groupCount - offset) / nIndex;
514 primitives = renew primitives PrimitiveSingle[this.nPrimitives + nPrimitives];
516 for(c = offset; c<groupCount; c+= nIndex)
518 PrimitiveSingle * primitive = &primitives[this.nPrimitives++];
520 if(AllocatePrimitive(primitive, group.type.primitiveType, nPoints))
522 if(group.type.vertexRange)
524 if(group.type.primitiveType == triangles || group.type.primitiveType == quads)
526 primitive->indices[0] = (uint16)(group.first + c);
527 primitive->indices[1] = (uint16)(group.first + c+1);
528 primitive->indices[2] = (uint16)(group.first + c+2);
530 if(group.type.primitiveType == quads)
531 primitive->indices[3] = (uint16)(group.first + c+3);
533 if(group.type.primitiveType == triFan)
535 primitive->indices[0] = (uint16)group.first;
536 primitive->indices[1] = (uint16)(group.first + c-1);
537 primitive->indices[2] = (uint16)(group.first + c);
539 else if(group.type.primitiveType == triStrip)
541 primitive->indices[0] = (uint16)(group.first + c-1-strip);
542 primitive->indices[1] = (uint16)(group.first + c-2+strip);
543 primitive->indices[2] = (uint16)(group.first + c);
549 if(group.type.primitiveType == triangles || group.type.primitiveType == quads)
550 CopyBytesBy2(primitive->indices, group.indices + c, nIndex);
552 if(group.type.primitiveType == triFan)
554 primitive->indices[0] = group.indices[0];
555 primitive->indices[1] = group.indices[c-1];
556 primitive->indices[2] = group.indices[c];
558 else if(group.type.primitiveType == triStrip)
560 primitive->indices[0] = group.indices[c-1-strip];
561 primitive->indices[1] = group.indices[c-2+strip];
562 primitive->indices[2] = group.indices[c];
566 primitive->material = group.material;
568 primitive->plane.FromPointsf(
569 vertices[primitive->indices[2]],
570 vertices[primitive->indices[1]],
571 vertices[primitive->indices[0]]);
573 primitive->middle.Add(vertices[primitive->indices[0]], vertices[primitive->indices[1]]);
574 primitive->middle.Add(primitive->middle, vertices[primitive->indices[2]]);
575 if(group.type == quads)
576 primitive->middle.Add(primitive->middle, vertices[primitive->indices[3]]);
577 primitive->middle.x /= nPoints;
578 primitive->middle.y /= nPoints;
579 primitive->middle.z /= nPoints;
581 UnlockPrimitive(primitive);
584 FreePrimitiveGroup(group);
590 object.flags.translucent = nPrimitives ? true : false;
597 void SetMinMaxRadius(void)
601 float xRadius, yRadius, zRadius;
603 min = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
604 max = {-MAXFLOAT,-MAXFLOAT,-MAXFLOAT };
606 for(c = 0; c<nVertices; c++)
608 float x = vertices[c].x, y = vertices[c].y, z = vertices[c].z;
609 if(x.isNan || y.isNan || z.isNan);
610 else if(x > 1E20 || x < -1E20 || y > 1E20 || y < -1E20 || z > 1E20 || z < -1E20);
613 min.x = Min(min.x, x);
614 min.y = Min(min.y, y);
615 min.z = Min(min.z, z);
616 max.x = Max(max.x, x);
617 max.y = Max(max.y, y);
618 max.z = Max(max.z, z);
621 xRadius = Max(max.x, -min.x);
622 yRadius = Max(max.y, -min.y);
623 zRadius = Max(max.z, -min.z);
625 radius = Max(xRadius, yRadius);
626 radius = Max(radius, zRadius);
629 void DoubleSided(bool flag)
633 PrimitiveGroup group;
635 for(group = groups.first; group; group = group.next)
639 group.material.flags.doubleSided = flag;
642 for(c = 0; c<nPrimitives; c++)
644 PrimitiveSingle * primitive = &primitives[c];
645 if(primitive->material)
647 primitive->material.flags.doubleSided = flag;
655 Vector3Df * vertices;
661 PrimitiveSingle * primitives;
666 DisplaySystem displaySystem;
667 subclass(DisplayDriver) driver;