namespace gfx3D; import "Display" public class MeshFeatures { public bool vertices:1, normals:1, texCoords1:1, texCoords2:1, doubleNormals:1, doubleVertices:1, colors:1, lightVectors:1, tangents:1; }; public class PrimitiveGroupType { public: RenderPrimitiveType primitiveType:8; bool vertexRange:1, indices32bit:1; }; public enum RenderPrimitiveType : PrimitiveGroupType { dot, // Point, lines, triangles, triStrip, triFan, quads, quadStrip, lineStrip /* , lineLoop, lineStrip, polygon */ }; public class MaterialFlags { public bool doubleSided:1, translucent:1, tile:1, noFog:1, singleSideLight:1, separateSpecular:1, cubeMap:1, noLighting:1; }; public class Material : struct { public: Material prev, next; char * name; float opacity; ColorRGB diffuse; ColorRGB ambient; ColorRGB specular; ColorRGB emissive; float power; Bitmap baseMap; Bitmap bumpMap; Bitmap specularMap; Bitmap reflectMap; CubeMap envMap; float reflectivity; float refractiveIndex; float refractiveIndexContainer; MaterialFlags flags; float uScale, vScale; Shader shader; void Free() { delete name; } }; public class PrimitiveGroup : struct { public: PrimitiveGroup prev, next; PrimitiveGroupType type; union { struct { union { uint16 * indices; uint * indices32; }; int nIndices; }; struct { int first, nVertices; }; }; Material material; private: void * data; }; /* public class PrimitiveGroupIndices16 : PrimitiveGroup { property Array indices { set { } } } public class PrimitiveGroupIndices32 : PrimitiveGroup { property Array indices { set { } } } public class PrimitiveGroupVertexRange : PrimitiveGroup { property int first { set { } } property int nVertices { set { } } } */ public struct PrimitiveSingle { public: PrimitiveGroupType type; union { struct { union { uint16 * indices; uint * indices32; }; int nIndices; }; struct { int first, nVertices; }; }; Material material; private: void * data; Vector3Df middle; Plane plane; }; public class Mesh : struct { public: property Pointf * texCoords { get { return texCoords; } set { texCoords = value; } }; property int nVertices { get { return nVertices; } set { nVertices = value; } }; property Vector3Df * vertices { get { return vertices; } set { vertices = value; } }; property Vector3Df * normals { get { return normals; } set { normals = value; } }; property Vector3Df * tangents { get { return tangents; } set { tangents = value; } }; property ColorRGBAf * colors { get { return colors; } set { colors = value; } }; property ColorRGB * lightVectors { get { return lightVectors; } set { lightVectors = value; } }; property OldList groups { get { value = groups; } }; property MeshFeatures flags { get { return flags; } set { flags = value; } }; void Free(MeshFeatures what) { if(this) { DisplaySystem displaySystem = this.displaySystem; PrimitiveGroup group; if(!what) { int c; flags = 0; if(driver) driver.FreeMesh(displaySystem, this); for(;(group = groups.first);) FreePrimitiveGroup(group); for(c = 0; cx - p0->x, p1->y - p0->y, p1->z - p0->z }; Vector3D v02 { p2->x - p0->x, p2->y - p0->y, p2->z - p0->z }; Pointf t01 { t1->x - t0->x, t1->y - t0->y }; Pointf t02 { t2->x - t0->x, t2->y - t0->y }; //if(Abs(t01.x) > 0.99) t01.x = 0; //if(Abs(t02.x) > 0.99) t02.x = 0; double f = w / (t01.x * t02.y - t02.x * t01.y); Vector3Df * tan1 = &tangents[index*2+0]; Vector3Df * tan2 = &tangents[index*2+1]; tan1->x += f * (v01.x * t02.y - v02.x * t01.y); tan1->y += f * (v01.y * t02.y - v02.y * t01.y); tan1->z += f * (v01.z * t02.y - v02.z * t01.y); tan2->x += f * (v02.x * t01.x - v01.x * t02.x); tan2->y += f * (v02.y * t01.x - v01.y * t02.x); tan2->z += f * (v02.z * t01.x - v01.z * t02.x); } } } } } } // NOTE: Here we're currently making the assumption that the primitives are in indices mode (vertexRange = false) for(c = 0; cindices[2]], vertices[primitive->indices[1]], vertices[primitive->indices[0]]); planeNormal = { (float) plane.normal.x, (float) plane.normal.y, (float) plane.normal.z }; if(primitive->material.flags.doubleSided && plane.d < 0) { planeNormal.x *= -1; planeNormal.y *= -1; planeNormal.z *= -1; } for(i = 0; inIndices; i++) { normals[primitive->indices[i]].Add(normals[primitive->indices[i]], planeNormal); numShared[primitive->indices[i]] ++; } } for(c = 0; cScale(n, s), n->Normalize(n); if(tangents) { Vector3Df * t1 = &tangents[2*c], * t2 = &tangents[2*c+1]; t1->Scale(t1, s), t1->Normalize(t1); t2->Scale(t2, s), t2->Normalize(t2); } } delete numShared; delete weightSum; Unlock({ normals = true, tangents = true }); } } void ApplyMaterial(Material material) { if(this) { int c; PrimitiveGroup group; for(group = groups.first; group; group = group.next) group.material = material; for(c = 0; cmaterial || !object) ? primitive->material : object.material; if(!material || !(material.flags.translucent)) { int t; PrimitiveGroup group; int nIndices = primitive->nIndices; for(t = c+1; ttype == primitive->type && prim->material == primitive->material) nIndices += prim->nIndices; } group = AddPrimitiveGroup(primitive->type, nIndices); if(group) { nIndices = 0; group.material = material; for(t = c; ttype && group.material == primitive->material) { CopyBytesBy2(group.indices + nIndices,primitive->indices,primitive->nIndices); nIndices +=primitive->nIndices; CopyBytes(primitives + t, primitives + t + 1, (nPrimitives - t - 1) * sizeof(PrimitiveSingle)); nPrimitives--; t--; } } UnlockPrimitiveGroup(group); } } else c++; } primitives = renew primitives PrimitiveSingle[this.nPrimitives]; // Split translucent groups into primitives for(group = groups.first; group; group = nextGroup) { Material material = (group.material || !object) ? group.material : object.material; nextGroup = group.next; if(material && material.flags.translucent) { int nPrimitives = 0, c; int offset = 0; int strip = 0; int nPoints, nIndex; int groupCount = group.type.vertexRange ? group.nVertices : group.nIndices; if(!groupCount) continue; if(group.type.primitiveType == triangles) nIndex = nPoints = 3; else if(group.type.primitiveType == quads) nIndex = nPoints = 4; else if(group.type.primitiveType == triFan || group.type.primitiveType == triStrip) { offset = 2; nIndex = 1; nPoints = 3; } else continue; nPrimitives += (groupCount - offset) / nIndex; primitives = renew primitives PrimitiveSingle[this.nPrimitives + nPrimitives]; for(c = offset; cindices[0] = (uint16)(group.first + c); primitive->indices[1] = (uint16)(group.first + c+1); primitive->indices[2] = (uint16)(group.first + c+2); } if(group.type.primitiveType == quads) primitive->indices[3] = (uint16)(group.first + c+3); if(group.type.primitiveType == triFan) { primitive->indices[0] = (uint16)group.first; primitive->indices[1] = (uint16)(group.first + c-1); primitive->indices[2] = (uint16)(group.first + c); } else if(group.type.primitiveType == triStrip) { primitive->indices[0] = (uint16)(group.first + c-1-strip); primitive->indices[1] = (uint16)(group.first + c-2+strip); primitive->indices[2] = (uint16)(group.first + c); strip ^= 1; } } else { if(group.type.primitiveType == triangles || group.type.primitiveType == quads) CopyBytesBy2(primitive->indices, group.indices + c, nIndex); if(group.type.primitiveType == triFan) { primitive->indices[0] = group.indices[0]; primitive->indices[1] = group.indices[c-1]; primitive->indices[2] = group.indices[c]; } else if(group.type.primitiveType == triStrip) { primitive->indices[0] = group.indices[c-1-strip]; primitive->indices[1] = group.indices[c-2+strip]; primitive->indices[2] = group.indices[c]; strip ^= 1; } } primitive->material = group.material; primitive->plane.FromPointsf( vertices[primitive->indices[2]], vertices[primitive->indices[1]], vertices[primitive->indices[0]]); primitive->middle.Add(vertices[primitive->indices[0]], vertices[primitive->indices[1]]); primitive->middle.Add(primitive->middle, vertices[primitive->indices[2]]); if(group.type == quads) primitive->middle.Add(primitive->middle, vertices[primitive->indices[3]]); primitive->middle.x /= nPoints; primitive->middle.y /= nPoints; primitive->middle.z /= nPoints; UnlockPrimitive(primitive); } } FreePrimitiveGroup(group); } } result = true; if(object) object.flags.translucent = nPrimitives ? true : false; } return result; } void * GetData() { return data; } private: void SetMinMaxRadius(void) { int c; float xRadius, yRadius, zRadius; min = { MAXFLOAT, MAXFLOAT, MAXFLOAT }; max = {-MAXFLOAT,-MAXFLOAT,-MAXFLOAT }; for(c = 0; c 1E20 || x < -1E20 || y > 1E20 || y < -1E20 || z > 1E20 || z < -1E20); else { min.x = Min(min.x, x); min.y = Min(min.y, y); min.z = Min(min.z, z); max.x = Max(max.x, x); max.y = Max(max.y, y); max.z = Max(max.z, z); } } xRadius = Max(max.x, -min.x); yRadius = Max(max.y, -min.y); zRadius = Max(max.z, -min.z); radius = Max(xRadius, yRadius); radius = Max(radius, zRadius); } void DoubleSided(bool flag) { if(this) { PrimitiveGroup group; int c; for(group = groups.first; group; group = group.next) { if(group.material) { group.material.flags.doubleSided = flag; } } for(c = 0; cmaterial) { primitive->material.flags.doubleSided = flag; } } } } MeshFeatures flags; int nVertices; Vector3Df * vertices; Vector3Df * normals; Vector3Df * tangents; Pointf * texCoords; ColorRGBAf * colors; ColorRGB * lightVectors; OldList groups; int nPrimitives; PrimitiveSingle * primitives; Vector3Df min, max; float radius; CubeMap normMap; // Private Data DisplaySystem displaySystem; subclass(DisplayDriver) driver; void * data; }; void computeNormalWeights(int n, Vector3Df * vertices, uint * indices, bool ix32Bit, int base, double * weights, Vector3D * edges, Vector3D * rEdges) { int i; for(i = 0; i < n; i++) { uint ix0 = i, ix1 = (i + 1) % n; Vector3Df * p0, *p1; if(indices) { if(ix32Bit) ix0 = indices[base+ix0], ix1 = indices[base+ix1]; else ix0 = ((uint16*)indices)[base+ix0], ix1 = ((uint16*)indices)[base+ix1]; } p0 = &vertices[ix0], p1 = &vertices[ix1]; edges[i] = { p1->x - p0->x, p1->y - p0->y, p1->z - p0->z }; edges[i].Normalize(edges[i]); rEdges[i].Scale(edges[i], -1); } for(i = 0; i < n; i++) weights[i] = acos(Min(1.0, Max(-1.0, edges[i].DotProduct(rEdges[i ? i-1 : n-1])))) / ((n-2) * Pi); }