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
41 public class PrimitiveGroup : struct
44 PrimitiveGroup prev, next;
45 PrimitiveGroupType type;
48 struct { uint16 * indices; int nIndices; };
49 struct { int first, nVertices; };
56 public struct PrimitiveSingle
59 PrimitiveGroupType type;
62 struct { uint16 * indices; int nIndices; };
63 struct { int first, nVertices; };
73 public class Mesh : struct
76 property Pointf * texCoords { get { return texCoords; } set { texCoords = value; } };
77 property int nVertices { get { return nVertices; } set { nVertices = value; } };
78 property Vector3Df * vertices { get { return vertices; } set { vertices = value; } };
79 property Vector3Df * normals { get { return normals; } set { normals = value; } };
80 property ColorRGBAf * colors { get { return colors; } set { colors = value; } };
81 property OldList groups { get { value = groups; } };
82 property MeshFeatures flags { get { return flags; } set { flags = value; } };
84 void Free(MeshFeatures what)
88 DisplaySystem displaySystem = this.displaySystem;
96 driver.FreeMesh(displaySystem, this);
97 for(;(group = groups.first);)
98 FreePrimitiveGroup(group);
100 for(c = 0; c<nPrimitives; c++)
102 if(primitives[c].data)
103 driver.FreeIndices(displaySystem, primitives[c].data);
109 this.displaySystem = null;
116 driver.FreeMesh(displaySystem, this);
121 bool Allocate(MeshFeatures what, int nVertices, DisplaySystem displaySystem)
124 if((!nVertices || nVertices == nVertices) && (!this.displaySystem || this.displaySystem == displaySystem))
127 this.nVertices = nVertices;
128 driver = displaySystem ? displaySystem.driver : (subclass(DisplayDriver))class(LFBDisplayDriver);
129 if(driver.AllocateMesh == DisplayDriver::AllocateMesh) driver = (subclass(DisplayDriver))class(LFBDisplayDriver);
130 if(driver.AllocateMesh(displaySystem, this))
137 this.displaySystem = displaySystem;
142 void Unlock(MeshFeatures flags)
145 driver.UnlockMesh(displaySystem, this, flags);
148 bool Lock(MeshFeatures flags)
153 if(driver.LockMesh(displaySystem, this, flags))
161 void FreePrimitiveGroup(PrimitiveGroup group)
166 driver.FreeIndices(displaySystem, group.data);
167 groups.Delete(group);
171 PrimitiveGroup AddPrimitiveGroup(PrimitiveGroupType flags, int nIndices)
173 PrimitiveGroup result = null;
174 PrimitiveGroup group { };
179 if(!(flags.vertexRange))
181 group.nIndices = nIndices;
184 group.data = driver.AllocateIndices(displaySystem, nIndices, flags.indices32bit);
187 if(LockPrimitiveGroup(group))
197 FreePrimitiveGroup(group);
202 bool LockPrimitiveGroup(PrimitiveGroup group)
208 group.indices = driver.LockIndices(displaySystem, group.data);
209 if(group.indices || group.type.vertexRange)
215 void UnlockPrimitiveGroup(PrimitiveGroup group)
217 if(this && group && group.data)
219 driver.UnlockIndices(displaySystem, group.data, group.type.indices32bit, group.nIndices);
220 //group.indices = null;
224 void FreePrimitive(PrimitiveSingle primitive)
226 if(this && primitive)
229 driver.FreeIndices(displaySystem, primitive.data);
230 primitive.data = null;
234 bool AllocatePrimitive(PrimitiveSingle primitive, PrimitiveGroupType flags, int nIndices)
237 if(this && primitive)
239 primitive.type = flags;
240 primitive.data = driver.AllocateIndices(displaySystem, nIndices, flags.indices32bit);
241 primitive.nIndices = nIndices;
244 if(LockPrimitive(primitive))
248 FreePrimitive(primitive);
253 void UnlockPrimitive(PrimitiveSingle primitive)
255 if(this && primitive)
257 driver.UnlockIndices(this.displaySystem, primitive.data, primitive.type.indices32bit, primitive.nIndices);
258 //primitive.indices = null;
262 bool LockPrimitive(PrimitiveSingle primitive)
265 if(this && primitive)
267 primitive.indices = driver.LockIndices(displaySystem, primitive.data);
268 if(primitive.indices)
274 void ComputeNormals(void)
277 int * numShared = new0 int[nVertices];
278 PrimitiveGroup group;
280 if(Allocate({ normals = true }, nVertices, displaySystem))
282 FillBytes(normals, 0, nVertices * sizeof(Vector3Df));
283 for(group = groups.first; group; group = group.next)
285 int nPrimitives = 0, c;
289 uint16 * indices16 = group.indices;
290 uint32 * indices32 = group.indices;
291 bool i32bit = group.type.indices32bit;
293 if(group.type.primitiveType == triangles)
294 nIndex = nPoints = 3;
295 else if(group.type.primitiveType == quads)
296 nIndex = nPoints = 4;
297 else if(group.type.primitiveType == triFan || group.type.primitiveType == triStrip || group.type.primitiveType == quadStrip)
306 int nIndicesPerPrimitive;
307 if(group.type == Triangles)
308 nIndicesPerPrimitive = 3;
309 else if(group.type == Quads)
310 nIndicesPerPrimitive = 4;
314 for(c = offset; c<group.nIndices; c += nIndex)
318 Vector3Df planeNormal;
320 if(group.type.primitiveType == triFan)
322 plane.FromPointsf(vertices[group.indices[0]],
323 vertices[group.indices[c]],
324 vertices[group.indices[c-1]]);
325 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
327 normals[group.indices[0]].Add(normals[group.indices[0]], planeNormal);
328 numShared[group.indices[0]]++;
329 normals[group.indices[c-1]].Add(normals[group.indices[c-1]], planeNormal);
330 numShared[group.indices[c-1]]++;
331 normals[group.indices[c]].Add(normals[group.indices[c]], planeNormal);
332 numShared[group.indices[c]]++;
334 else if(group.type.primitiveType == triStrip || group.type.primitiveType == quadStrip)
336 plane.FromPointsf(vertices[group.indices[c-1-strip]],
337 vertices[group.indices[c-2+strip]],
338 vertices[group.indices[c]]);
339 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
341 normals[group.indices[c-1-strip]].Add(normals[group.indices[c-1-strip]], planeNormal);
342 numShared[group.indices[c-1-strip]]++;
343 normals[group.indices[c-2+strip]].Add(normals[group.indices[c-2+strip]], planeNormal);
344 numShared[group.indices[c-2+strip]]++;
345 normals[group.indices[c]].Add(normals[group.indices[c]], planeNormal);
346 numShared[group.indices[c]]++;
352 if(group.type.vertexRange)
354 plane.FromPointsf(vertices[c+2],
357 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
359 for(i = c; i<c+nIndex; i++)
361 normals[i].Add(normals[i], planeNormal);
367 plane.FromPointsf(vertices[i32bit ? indices32[c+2] : indices16[c+2]],
368 vertices[i32bit ? indices32[c+1] : indices16[c+1]],
369 vertices[i32bit ? indices32[c] : indices16[c]]);
370 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
372 for(i = c; i<c+nIndex; i++)
374 int index = i32bit ? indices32[i] : indices16[i];
375 normals[index].Add(normals[index], planeNormal);
382 // NOTE: Here we're currently making the assumption that the primitives are in indices mode (vertexRange = false)
383 for(c = 0; c<nPrimitives; c++)
386 PrimitiveSingle * primitive = &primitives[c];
389 Vector3Df planeNormal;
390 plane.FromPointsf(vertices[primitive->indices[2]],
391 vertices[primitive->indices[1]],
392 vertices[primitive->indices[0]]);
393 planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z };
395 if(primitive->material.flags.doubleSided && plane.d < 0)
402 for(i = 0; i<primitive->nIndices; i++)
404 normals[primitive->indices[i]].Add(normals[primitive->indices[i]], planeNormal);
405 numShared[primitive->indices[i]] ++;
409 for(c = 0; c<nVertices; c++)
411 normals[c].Scale(normals[c], 1.0f / numShared[c]);
412 normals[c].Normalize(normals[c]);
415 Unlock({ normals = true });
420 void ApplyMaterial(Material material)
425 PrimitiveGroup group;
426 for(group = groups.first; group; group = group.next)
427 group.material = material;
428 for(c = 0; c<nPrimitives; c++)
429 primitives[c].material = material;
433 bool ApplyTranslucency(Object object)
438 PrimitiveGroup group, nextGroup;
441 // Merge non translucent primitives into groups
442 for(c = 0; c<nPrimitives; )
444 PrimitiveSingle * primitive = &primitives[c];
445 Material material = (primitive->material || !object) ? primitive->material : object.material;
446 if(!material || !(material.flags.translucent))
449 PrimitiveGroup group;
450 int nIndices = primitive->nIndices;
451 for(t = c+1; t<nPrimitives; t++)
453 PrimitiveSingle * prim = &primitives[t];
454 if(prim->type == primitive->type && prim->material == primitive->material)
455 nIndices += prim->nIndices;
457 group = AddPrimitiveGroup(primitive->type, nIndices);
461 group.material = material;
462 for(t = c; t<nPrimitives; t++)
464 primitive = &primitives[t];
465 if(group.type == primitive->type && group.material == primitive->material)
467 CopyBytesBy2(group.indices + nIndices,primitive->indices,primitive->nIndices);
468 nIndices +=primitive->nIndices;
469 CopyBytes(primitives + t, primitives + t + 1, (nPrimitives - t - 1) * sizeof(PrimitiveSingle));
474 UnlockPrimitiveGroup(group);
480 primitives = renew primitives PrimitiveSingle[this.nPrimitives];
482 // Split translucent groups into primitives
483 for(group = groups.first; group; group = nextGroup)
485 Material material = (group.material || !object) ? group.material : object.material;
487 nextGroup = group.next;
489 if(material && material.flags.translucent)
491 int nPrimitives = 0, c;
495 int groupCount = group.type.vertexRange ? group.nVertices : group.nIndices;
496 if(!groupCount) continue;
498 if(group.type.primitiveType == triangles)
499 nIndex = nPoints = 3;
500 else if(group.type.primitiveType == quads)
501 nIndex = nPoints = 4;
502 else if(group.type.primitiveType == triFan || group.type.primitiveType == triStrip)
511 nPrimitives += (groupCount - offset) / nIndex;
513 primitives = renew primitives PrimitiveSingle[this.nPrimitives + nPrimitives];
515 for(c = offset; c<groupCount; c+= nIndex)
517 PrimitiveSingle * primitive = &primitives[this.nPrimitives++];
519 if(AllocatePrimitive(primitive, group.type.primitiveType, nPoints))
521 if(group.type.vertexRange)
523 if(group.type.primitiveType == triangles || group.type.primitiveType == quads)
525 primitive->indices[0] = (uint16)(group.first + c);
526 primitive->indices[1] = (uint16)(group.first + c+1);
527 primitive->indices[2] = (uint16)(group.first + c+2);
529 if(group.type.primitiveType == quads)
530 primitive->indices[3] = (uint16)(group.first + c+3);
532 if(group.type.primitiveType == triFan)
534 primitive->indices[0] = (uint16)group.first;
535 primitive->indices[1] = (uint16)(group.first + c-1);
536 primitive->indices[2] = (uint16)(group.first + c);
538 else if(group.type.primitiveType == triStrip)
540 primitive->indices[0] = (uint16)(group.first + c-1-strip);
541 primitive->indices[1] = (uint16)(group.first + c-2+strip);
542 primitive->indices[2] = (uint16)(group.first + c);
548 if(group.type.primitiveType == triangles || group.type.primitiveType == quads)
549 CopyBytesBy2(primitive->indices, group.indices + c, nIndex);
551 if(group.type.primitiveType == triFan)
553 primitive->indices[0] = group.indices[0];
554 primitive->indices[1] = group.indices[c-1];
555 primitive->indices[2] = group.indices[c];
557 else if(group.type.primitiveType == triStrip)
559 primitive->indices[0] = group.indices[c-1-strip];
560 primitive->indices[1] = group.indices[c-2+strip];
561 primitive->indices[2] = group.indices[c];
565 primitive->material = group.material;
567 primitive->plane.FromPointsf(
568 vertices[primitive->indices[2]],
569 vertices[primitive->indices[1]],
570 vertices[primitive->indices[0]]);
572 primitive->middle.Add(vertices[primitive->indices[0]], vertices[primitive->indices[1]]);
573 primitive->middle.Add(primitive->middle, vertices[primitive->indices[2]]);
574 if(group.type == quads)
575 primitive->middle.Add(primitive->middle, vertices[primitive->indices[3]]);
576 primitive->middle.x /= nPoints;
577 primitive->middle.y /= nPoints;
578 primitive->middle.z /= nPoints;
580 UnlockPrimitive(primitive);
583 FreePrimitiveGroup(group);
589 object.flags.translucent = nPrimitives ? true : false;
596 void SetMinMaxRadius(void)
600 float xRadius, yRadius, zRadius;
602 min = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
603 max = { MINFLOAT, MINFLOAT, MINFLOAT };
605 for(c = 0; c<nVertices; c++)
607 min.x = Min(min.x, vertices[c].x);
608 min.y = Min(min.y, vertices[c].y);
609 min.z = Min(min.z, vertices[c].z);
610 max.x = Max(max.x, vertices[c].x);
611 max.y = Max(max.y, vertices[c].y);
612 max.z = Max(max.z, vertices[c].z);
614 xRadius = Max(max.x, -min.x);
615 yRadius = Max(max.y, -min.y);
616 zRadius = Max(max.z, -min.z);
618 radius = Max(xRadius, yRadius);
619 radius = Max(radius, zRadius);
622 void DoubleSided(bool flag)
626 PrimitiveGroup group;
628 for(group = groups.first; group; group = group.next)
632 group.material.flags.doubleSided = flag;
635 for(c = 0; c<nPrimitives; c++)
637 PrimitiveSingle * primitive = &primitives[c];
638 if(primitive->material)
640 primitive->material.flags.doubleSided = flag;
648 Vector3Df * vertices;
654 PrimitiveSingle * primitives;
659 DisplaySystem displaySystem;
660 subclass(DisplayDriver) driver;