5 public enum FrustumPlacement { outside, inside, intersecting };
7 public class ObjectFormat
9 class_data const char * extension;
10 class_property const char * extension
12 set { class_data(extension) = value; }
13 get { return class_data(extension); }
16 virtual bool ::Load(Object object, const char * fileName, DisplaySystem displaySystem);
19 // TODO: Review these:
20 public class ObjectFlags
23 bool root:1, viewSpace:1, ownMesh:1, translucent:1, flipWindings:1, keysLoaded:1, transform:1, mesh:1, light:1, camera:1, localMatrixSet:1;
24 bool computeLightVectors:1;
28 public struct Transform
31 Quaternion orientation;
35 /*static float ease(float t, float a, float b)
40 if (s == 0.0f) return t;
47 if (t < a) return (k/a)*t*t;
48 if (t < 1.0f - b) return k*(2.0f * t - a);
50 return 1.0f - (k/b)*t*t;
53 public enum FrameTrackType : uint16 { position = 1, rotation, scaling, fov, roll, colorChange, morph, hotSpot, fallOff, hide };
55 public class FrameTrackBits
61 public struct FrameKey
64 float tension, continuity, bias;
65 float easeFrom, easeTo;
69 Quaternion orientation;
79 enum SplinePart { splinePoint, splineA, splineB };
81 public class FrameTrack : struct
83 FrameTrack prev, next;
98 float GetFloat(SplinePart what, unsigned int n)
101 FrameKey *kn_1, *kn, *kn1;
108 if(what == splinePoint)
120 value *= 1.0f - kn->tension;
125 kn_1 = &keys[numKeys-2];
126 d1 = keys[numKeys-1].frame - kn_1->frame;
127 d2 = kn1->frame - kn->frame;
135 a1 = GetFloat(splineA, 1);
139 value *= 1.0f - kn->tension;
143 else if(n == numKeys-1)
151 value *= 1.0f - kn->tension;
157 d1 = kn->frame - kn_1->frame;
158 d2 = kn1->frame - keys[0].frame;
166 bn_1 = GetFloat(splineB, n-1);
170 value *= 1.0f - kn->tension;
178 d1 = kn->frame - kn_1->frame;
179 d2 = kn1->frame - kn->frame;
199 adjust = 0.5f + (1.0f - Abs(C))*(adjust - 0.5f);
202 part1 *= (1.0f + kn->bias)*(1.0f - C);
205 part2 *= (1.0f - kn->bias)*(1.0f + C);
207 value = part1 + part2;
208 value *= (1.0f - kn->tension)*adjust;
214 void GetVector(Vector3Df vector, SplinePart what, unsigned int n)
216 FrameKey *kn_1, *kn, *kn1;
217 Vector3Df *pn_1, *pn, *pn1;
223 if(what == splinePoint)
230 pn1 = &kn1->position;
234 vector.Subtract(pn1, pn);
235 vector.Scale(vector, 1.0f - kn->tension);
240 kn_1 = &keys[numKeys-2];
241 d1 = keys[numKeys-1].frame - kn_1->frame;
242 d2 = kn1->frame - kn->frame;
247 vector.Subtract(pn1, pn);
248 vector.Scale(vector, 1.5f);
250 GetVector(a1, splineA, 1);
253 vector.Subtract(vector, a1);
254 vector.Scale(vector, 1.0f - kn->tension);
258 else if(n == numKeys-1)
261 pn_1 = &kn_1->position;
265 vector.Subtract(pn, pn_1);
266 vector.Scale(vector, 1.0f - kn->tension);
272 d1 = kn->frame - kn_1->frame;
273 d2 = kn1->frame - keys[0].frame;
278 vector.Subtract(pn, pn_1);
279 vector.Scale(vector, 1.5f);
281 GetVector(&bn_1, splineB, n-1);
282 bn_1.Scale(bn_1, 0.5f);
284 vector.Subtract(vector, bn_1);
285 vector.Scale(vector, 1.0f - kn->tension);
293 d1 = kn->frame - kn_1->frame;
294 d2 = kn1->frame - kn->frame;
298 Vector3Df part1, part2;
300 pn_1 = &kn_1->position;
301 pn1 = &kn1->position;
314 adjust = 0.5f + (1.0f - Abs(C))*(adjust - 0.5f);
316 part1.Subtract(pn, pn_1);
317 part1.Scale(part1, (1.0f + kn->bias)*(1.0f - C));
319 part2.Subtract(pn1, pn);
320 part2.Scale(part2, (1.0f - kn->bias)*(1.0f + C));
322 vector.Add(part1, part2);
323 vector.Scale(vector, (1.0f - kn->tension)*adjust);
328 void GetQuaternion(Quaternion quat, SplinePart what, unsigned int n)
330 FrameKey *kn_1, *kn, *kn1;
331 Quaternion *qn_1, *qn, *qn1;
335 qn = &kn->orientation;
337 if (what == splinePoint)
345 if (!(type.loop) || numKeys <= 2)
347 qn1 = &kn1->orientation;
348 quat.Slerp(qn, qn1, (1.0f - kn->tension)*(1.0f + kn->continuity*kn->bias)/3.0f);
353 kn_1= &keys[numKeys-2];
354 d1 = keys[numKeys-1].frame - kn_1->frame;
355 d2 = kn1->frame - kn->frame;
358 else if (n == numKeys-1)
362 if (!(type.loop) || numKeys <= 2)
364 qn_1 = &kn_1->orientation;
365 quat.Slerp(qn, qn_1, (1.0f - kn->tension)*(1.0f - kn->continuity*kn->bias)/3.0f);
371 d1 = kn->frame - kn_1->frame;
372 d2 = kn1->frame - keys[0].frame;
379 d1 = kn->frame - kn_1->frame;
380 d2 = kn1->frame - kn->frame;
384 Quaternion g1, g2, tmp;
386 qn_1 = &kn_1->orientation;
387 qn1 = &kn1->orientation;
400 adjust = 0.5f + (1.0f - Abs(kn->continuity))*(adjust - 0.5f);
402 g1.Slerp(qn, qn_1,-(1.0f + kn->bias)/3.0f);
403 g2.Slerp(qn, qn1 , (1.0f - kn->bias)/3.0f);
404 tmp.Slerp(g1, g2, 0.5f + f*0.5f*kn->continuity);
405 quat.Slerp(qn, &tmp, f*(kn->tension - 1.0f)*adjust*2.0f);
410 void Interpolate(Vector3Df vector, Vector3Df prevVector, Vector3Df nextVector, int prev, int next, float t)
416 Vector3Df p1 = prevVector, p2 = nextVector;
419 GetVector(r1, splineB, prev);
420 GetVector(r2, splineA, next);
422 p1.Scale(p1, 2*t*t*t - 3*t*t + 1);
423 p2.Scale(p2,-2*t*t*t + 3*t*t);
425 r1.Scale(r1, t*t*t - 2*t*t + t);
426 r2.Scale(r2, t*t*t - t*t);
429 vector.Add(vector, r1);
430 vector.Add(vector, p2);
431 vector.Add(vector, r2);
435 void InterpolateQuat(Quaternion quat, Quaternion prevQuat, Quaternion nextQuat, int prev, int next, float t)
442 Quaternion q0, q1, q2;
444 GetQuaternion(b, splineB, prev);
445 GetQuaternion(a, splineA, next);
447 q0.Slerp(prevQuat, b, t);
449 q2.Slerp(a, nextQuat, t);
454 quat.Slerp(q0, q1, t);
458 float InterpolateFloat(float prevValue, float nextValue, int prev, int next, float t)
465 float p1 = prevValue, p2 = nextValue;
467 float r1 = GetFloat(splineB, prev);
468 float r2 = GetFloat(splineA, next);
470 p1 *= 2*t*t*t - 3*t*t + 1;
471 p2 *= -2*t*t*t + 3*t*t;
473 r1 *= t*t*t - 2*t*t + t;
476 value = p1 + r1 + p2 + r2;
482 static bool FindMaterialAndType(Mesh mesh, Material material, PrimitiveGroupType type)
484 PrimitiveGroup group;
485 for(group = mesh.groups.first; group; group = group.next)
486 if(group.material == material && group.type == type)
491 public class Object : struct
494 void SetMinMaxRadius(bool processMesh)
498 if(flags.mesh && mesh)
501 mesh.SetMinMaxRadius();
504 volume = (max.x >= min.x && max.y >= min.y && max.z >= min.z);
508 min = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
509 max = { -MAXFLOAT, -MAXFLOAT, -MAXFLOAT };
512 for(child = children.first; child; child = child.next)
514 child.SetMinMaxRadius(processMesh);
518 // Child Local + Child Object Transform
519 Vector3Df points[8] =
521 { child.min.x, child.min.y, child.min.z },
522 { child.min.x, child.min.y, child.max.z },
523 { child.min.x, child.max.y, child.min.z },
524 { child.min.x, child.max.y, child.max.z },
525 { child.max.x, child.min.y, child.min.z },
526 { child.max.x, child.min.y, child.max.z },
527 { child.max.x, child.max.y, child.min.z },
528 { child.max.x, child.max.y, child.max.z }
534 point.MultMatrix(points[c], child.localMatrix);
536 if(point.x < min.x) min.x = point.x;
537 if(point.y < min.y) min.y = point.y;
538 if(point.z < min.z) min.z = point.z;
540 if(point.x > max.x) max.x = point.x;
541 if(point.y > max.y) max.y = point.y;
542 if(point.z > max.z) max.z = point.z;
550 Vector3Df points[8] =
552 { min.x, min.y, min.z },
553 { min.x, min.y, max.z },
554 { min.x, max.y, min.z },
555 { min.x, max.y, max.z },
556 { max.x, min.y, min.z },
557 { max.x, min.y, max.z },
558 { max.x, max.y, min.z },
559 { max.x, max.y, max.z }
561 Vector3Df halfExtent;
562 Vector3D halfExtentd;
565 center.Add(min, max);
566 center.Scale(center, 0.5f);
567 halfExtent.Subtract(max, min);
568 halfExtent.Scale(halfExtent, 0.5f);
569 radius = halfExtent.length;
573 Vector3D min { MAXFLOAT, MAXFLOAT, MAXFLOAT };
574 Vector3D max { -MAXFLOAT, -MAXFLOAT, -MAXFLOAT };
579 point.MultMatrixf(points[c], matrix);
581 if(point.x < min.x) min.x = point.x;
582 if(point.y < min.y) min.y = point.y;
583 if(point.z < min.z) min.z = point.z;
585 if(point.x > max.x) max.x = point.x;
586 if(point.y > max.y) max.y = point.y;
587 if(point.z > max.z) max.z = point.z;
592 wcenter.Add(wmin, wmax);
593 wcenter.Scale(wcenter, 0.5f);
595 halfExtentd.Subtract(wmax, wmin);
596 halfExtentd.Scale(halfExtentd, 0.5);
597 wradius = halfExtentd.length;
601 void Duplicate(Object model)
607 name = CopyString(model.name);
609 flags.ownMesh = false;
610 flags.transform = false;
615 radius = model.radius;
617 if(parent && !flags.root)
618 matrix.Multiply(localMatrix, parent.matrix);
620 matrix = localMatrix;
622 for(modelChild = model.children.first; modelChild; modelChild = modelChild.next)
624 Object child { parent = this };
625 child.localMatrix = modelChild.localMatrix;
626 child.transform = modelChild.transform;
627 child.Duplicate(modelChild);
628 children.AddName(child);
633 void Free(DisplaySystem displaySystem)
639 while((child = children.first))
641 children.Remove(child);
642 child.Free(displaySystem);
644 // We did not do this before so as to keep transform on reloading for new DisplaySystem
645 // However since children are removed, it seems that purpose has been gone, we'd need
646 // a new mechanism to handle lost resources reloading...
649 if(flags.ownMesh && mesh)
651 DisplaySystem meshDisplaySystem = mesh.displaySystem;
653 if(meshDisplaySystem)
654 meshDisplaySystem.RemoveMesh(mesh);
658 tracks.Free(FrameTrack::Free);
664 bool Load(const char * fileName, const char * type, DisplaySystem displaySystem)
666 char ext[MAX_EXTENSION];
667 subclass(ObjectFormat) format;
671 if(!type && fileName)
672 type = strlwr(GetExtension(fileName, ext));
674 for(link = class(ObjectFormat).derivatives.first; link; link = link.next)
677 if(format.extension && !strcmp(format.extension, type))
680 if(!link) format = null;
684 if((format.Load(this, fileName, displaySystem)))
688 ErrorLogCode(GERR_LOAD_OBJECT_FAILED, fileName);*/
692 void FreeMesh(DisplaySystem displaySystem)
698 for(child = children.first; child; child = child.next)
699 child.FreeMesh(displaySystem);
703 Object Find(const char * name)
709 if(this.name && !strcmp(this.name, name))
713 for(child = children.first; child; child = child.next)
715 Object result = child.Find(name);
724 void Initialize(void)
728 transform.scaling = { 1, 1, 1 };
729 transform.orientation = { 1,0,0,0 };
731 flags.transform = true;
736 Mesh InitializeMesh(DisplaySystem displaySystem)
744 flags.ownMesh = true;
748 FillBytes(mesh, 0, sizeof(class Mesh));
749 displaySystem.AddMesh(mesh);
757 bool AddName(Object object, const char * name)
762 char * newName = CopyString(name);
763 object.name = newName;
764 result = children.AddName(object);
766 object.parent = this;
767 object.flags.transform = true;
772 // TODO: Add support to Merge Vertex Colors mesh feature
773 bool Merge(DisplaySystem displaySystem)
777 if(!children.first && (!this.flags.mesh || this.flags.ownMesh))
781 Object child, nextChild;
783 MeshFeatures flags = 0;
784 Mesh objectMesh = this.flags.mesh ? mesh : null;
785 bool freeMesh = this.flags.ownMesh;
787 // Count total number of vertices
790 flags |= objectMesh.flags;
791 nVertices += objectMesh.nVertices;
794 for(child = children.first; child; child = child.next)
796 child.Merge(displaySystem);
797 if(child.flags.mesh && child.mesh)
799 nVertices += child.mesh.nVertices;
800 flags |= child.mesh.flags;
801 this.flags.computeLightVectors |= child.flags.computeLightVectors;
808 if(this.flags.camera)
812 this.flags.ownMesh = true;
813 this.flags.mesh = true;
814 displaySystem.AddMesh(mesh);
816 if(mesh.Allocate(flags, nVertices, displaySystem))
820 int vertexOffset = 0;
821 PrimitiveGroup group = null;
828 for(c = 0; c<objectMesh.nVertices; c++)
830 mesh.vertices[nVertices] = objectMesh.vertices[c];
832 if(objectMesh.normals)
833 mesh.normals[nVertices] = objectMesh.normals[c];
834 if(objectMesh.texCoords)
835 mesh.texCoords[nVertices] = objectMesh.texCoords[c];
836 if(objectMesh.tangents)
838 mesh.tangents[2*nVertices+0] = objectMesh.tangents[2*c+0];
839 mesh.tangents[2*nVertices+1] = objectMesh.tangents[2*c+1];
846 for(child = children.first; child; child = child.next)
848 Matrix matrix, normalMatrix;
850 matrix = child.localMatrix;
853 matrix.Scale(child.transform.scaling.x, child.transform.scaling.y, child.transform.scaling.z);
854 matrix.Rotate(child.transform.orientation);
857 normalMatrix = matrix;
859 normalMatrix.m[3][0] = 0;
860 normalMatrix.m[3][1] = 0;
861 normalMatrix.m[3][2] = 0;
863 // matrix.Translate(child.transform.position.x, child.transform.position.y, child.transform.position.z);
865 if(child.flags.mesh && child.mesh)
867 for(c = 0; c < child.mesh.nVertices; c++)
869 mesh.vertices[nVertices].MultMatrix(child.mesh.vertices[c], matrix);
870 if(child.mesh.normals)
871 mesh.normals[nVertices].MultMatrix(child.mesh.normals[c], normalMatrix);
872 if(child.mesh.texCoords)
873 mesh.texCoords[nVertices] = child.mesh.texCoords[c];
874 if(child.mesh.tangents)
876 mesh.tangents[2*nVertices+0].MultMatrix(child.mesh.tangents[2*c+0], normalMatrix);
877 mesh.tangents[2*nVertices+1].MultMatrix(child.mesh.tangents[2*c+1], normalMatrix);
884 // Merge Indexed Primitive Groups
888 PrimitiveGroupType type = (PrimitiveGroupType)-1;
889 Material material = null;
890 bool foundGroup = false;
892 // Find first group type/material to process and determine how many indices are required
895 for(group = objectMesh.groups.first; group; group = group.next)
897 if(!foundGroup && !(group.type.vertexRange))
899 if(!FindMaterialAndType(mesh, group.material, group.type))
901 material = group.material;
903 nIndices += group.nIndices;
907 else if(material == group.material && type == group.type)
908 nIndices += group.nIndices;
912 for(child = children.first; child; child = child.next)
914 if(child.flags.mesh && child.mesh)
916 for(group = child.mesh.groups.first; group; group = group.next)
918 if(!foundGroup && !(group.type.vertexRange))
920 if(!FindMaterialAndType(mesh, group.material ? group.material : child.material, group.type))
922 material = group.material ? group.material : child.material;
924 nIndices += group.nIndices;
928 else if(material == (group.material ? group.material : child.material) && type == group.type)
929 nIndices += group.nIndices;
934 // Merge with all similar groups
937 PrimitiveGroup newGroup = mesh.AddPrimitiveGroup(type, nIndices);
940 newGroup.material = material;
947 for(group = objectMesh.groups.first; group; group = group.next)
949 if(newGroup.material == group.material && newGroup.type == group.type)
952 if(group.type.indices32bit)
953 for(c = 0; c<group.nIndices; c++)
954 newGroup.indices32[nIndices++] = group.indices32[c] + vertexOffset;
956 for(c = 0; c<group.nIndices; c++)
957 newGroup.indices[nIndices++] = (uint16)(group.indices[c] + vertexOffset);
960 vertexOffset += objectMesh.nVertices;
963 for(child = children.first; child; child = child.next)
965 if(child.flags.mesh && child.mesh)
967 for(group = child.mesh.groups.first; group; group = group.next)
969 if(newGroup.material == (group.material ? group.material : child.material) &&
970 newGroup.type == group.type)
973 if(group.type.indices32bit)
974 for(c = 0; c<group.nIndices; c++)
975 newGroup.indices32[nIndices++] = group.indices32[c] + vertexOffset;
977 for(c = 0; c<group.nIndices; c++)
978 newGroup.indices[nIndices++] = (uint16)(group.indices[c] + vertexOffset);
981 vertexOffset += child.mesh.nVertices;
984 mesh.UnlockPrimitiveGroup(newGroup);
991 // Merge Non-Indexed Primitive Groups
996 for(group = objectMesh.groups.first; group; group = group.next)
998 if(group.type.vertexRange)
1000 PrimitiveGroup newGroup = mesh.AddPrimitiveGroup(group.type, 0);
1003 newGroup.material = group.material;
1004 newGroup.nVertices = group.nVertices;
1005 newGroup.first = group.first + vertexOffset;
1009 vertexOffset += objectMesh.nVertices;
1012 for(child = children.first; child; child = child.next)
1014 if(child.flags.mesh && child.mesh)
1016 for(group = child.mesh.groups.first; group; group = group.next)
1018 if(group.type.vertexRange)
1020 PrimitiveGroup newGroup = mesh.AddPrimitiveGroup(group.type, 0);
1023 newGroup.material = group.material ? group.material : child.material;
1024 newGroup.nVertices = group.nVertices;
1025 newGroup.first = group.first + vertexOffset;
1029 vertexOffset += child.mesh.nVertices;
1035 nTriangles = objectMesh.nPrimitives;
1037 for(child = children.first; child; child = child.next)
1039 if(child.flags.mesh && child.mesh)
1040 nTriangles += child.mesh.nPrimitives;
1043 mesh.primitives = new PrimitiveSingle[nTriangles];
1044 mesh.nPrimitives = 0;
1048 for(c = 0; c<objectMesh.nPrimitives; c++)
1051 PrimitiveSingle * triangle = &mesh.primitives[mesh.nPrimitives++];
1052 PrimitiveSingle * src = &objectMesh.primitives[c];
1054 mesh.AllocatePrimitive(triangle, src->type, src->nIndices);
1055 triangle->material = src->material;
1056 triangle->middle = src->middle;
1057 triangle->plane = src->plane;
1060 //src->indices = null;
1063 if(triangle->type.indices32bit)
1064 for(i = 0; i<triangle->nIndices; i++)
1065 triangle->indices32[i] = src->indices32[i] + vertexOffset;
1067 for(i = 0; i<triangle->nIndices; i++)
1068 triangle->indices[i] = (uint16)(src->indices[i] + vertexOffset);
1069 mesh.UnlockPrimitive(triangle);
1071 vertexOffset += objectMesh.nVertices;
1074 for(child = children.first; child; child = child.next)
1076 if(child.flags.mesh && child.mesh)
1078 for(c = 0; c<child.mesh.nPrimitives; c++)
1081 PrimitiveSingle * triangle = &mesh.primitives[mesh.nPrimitives++];
1082 PrimitiveSingle * src = &child.mesh.primitives[c];
1084 mesh.AllocatePrimitive(triangle, src->type, src->nIndices);
1085 triangle->material = src->material ? src->material : child.material;
1086 triangle->middle = src->middle;
1087 triangle->plane = src->plane;
1090 //src->indices = null;
1093 if(triangle->type.indices32bit)
1095 for(i = 0; i<triangle->nIndices; i++)
1096 triangle->indices32[i] = src->indices32[i] + vertexOffset;
1100 for(i = 0; i<triangle->nIndices; i++)
1101 triangle->indices[i] = (uint16)(src->indices[i] + vertexOffset);
1103 mesh.UnlockPrimitive(triangle);
1105 vertexOffset += child.mesh.nVertices;
1110 for(child = children.first; child; child = nextChild)
1112 nextChild = child.next;
1113 children.Remove(child);
1114 child.Free(displaySystem);
1118 mesh.ApplyTranslucency(this);
1119 // this.flags.translucent = true;
1125 if(freeMesh && objectMesh)
1127 if(objectMesh.displaySystem)
1128 objectMesh.displaySystem.RemoveMesh(objectMesh);
1131 SetMinMaxRadius(true);
1136 void RotateEuler(Euler rotation, Euler min, Euler max)
1138 // WARNING: 'eulerOrientation' is only updated by this function
1139 Euler euler = eulerOrientation;//transform.orientation;
1140 euler.Add(euler, rotation);
1144 if(min.pitch && max.pitch)
1145 euler.pitch = Min(Max(euler.pitch, min.pitch), max.pitch);
1146 if(min.yaw && max.yaw)
1147 euler.yaw = Min(Max(euler.yaw, min.yaw), max.yaw);
1148 if(min.roll && max.roll)
1149 euler.roll = Min(Max(euler.roll, min.roll), max.roll);
1152 eulerOrientation = euler;
1153 transform.orientation = euler;
1157 void Move(Vector3D direction)
1162 matrix.RotationQuaternion(transform.orientation);
1163 offset.MultMatrix(direction, matrix);
1164 transform.position.Add(transform.position, offset);
1168 void UpdateTransform(void)
1170 SetTransformDirty();
1172 SetMinMaxRadius(false);
1175 void Animate(unsigned int frame)
1177 if(this && startFrame != endFrame)
1179 while(frame < startFrame) frame += (endFrame - startFrame + 1);
1180 while(frame > endFrame) frame -= (endFrame - startFrame + 1);
1185 SetMinMaxRadius(false);
1189 void DoubleSided(bool flag)
1194 mesh.DoubleSided(flag);
1195 for(child = children.first; child; child = child.next)
1196 child.DoubleSided(flag);
1200 bool IntersectsGroundPolygon(int count, Pointf * pointfs)
1202 bool result = false;
1206 double minX = wmin.x, maxX = wmax.x;
1207 double minY = wmin.z, maxY = wmax.z;
1208 double delta = (maxX - minX)/2;
1209 double x = (maxX + minX)/2, y = (maxY + minY)/2;
1211 for(c = 0; c<count; c++)
1215 p2 = &pointfs[(c == count-1) ? 0 : (c+1)];
1217 if( (p1->x < minX) && (p2->x < minX) )
1219 if((p1->y <= y) && (p2->y > y) )
1221 else if( (p1->y > y) && (p2->y <= y) )
1224 else if(!((p1->x > maxX && p2->x > maxX) || (p1->y < minY && p2->y < minY) || (p1->y > maxY && p2->y > maxY)))
1230 if (d < delta) return true;
1232 else if(p1->x == p2->x)
1236 if(d < delta) return true;
1237 else if(p1->x > x) ;
1238 else if( (p1->y <= y) && (p2->y > y) )
1240 else if( (p1->y > y) && (p2->y <= y) )
1251 d = a * x + b * y + (p2->x * p1->y) - (p2->y * p1->x);
1258 else if (d < b * delta)
1260 else if( ( (p1->y <= y) && (p2->y > y) ) || ( (p1->y > y) && (p2->y <= y) ) )
1264 xdy = (dx * (y - p1->y)) + (dy * p1->x);
1270 else if(xdy < x * dy)
1279 property Transform transform { set { transform = value; eulerOrientation = transform.orientation; } get { value = transform; } };
1280 property Material material { set { material = value; } get { return material; } };
1281 property Vector3Df max { get { value = max; } };
1282 property Vector3Df min { get { value = min; } };
1283 property Vector3Df center { get { value = center; } };
1284 property float radius { get { return radius; } };
1286 property Vector3D wmax { get { value = wmax; } };
1287 property Vector3D wmin { get { value = wmin; } };
1288 property Vector3D wcenter { get { value = wcenter; } };
1289 property double wradius { get { return wradius; } };
1291 property void * tag { set { tag = value; } get { return tag; } };
1292 property int frame { set { Animate(value); } get { return frame; } };
1293 property int startFrame { set { startFrame = value; } get { return startFrame; } };
1294 property int endFrame { set { endFrame = value; } get { return endFrame; } };
1296 property Mesh mesh { set { mesh = value; } get { return mesh; } };
1297 property Camera camera { get { return camera; } }; // Fix this with inheritance? camera inherit from Object?
1298 property Object firstChild { get { return children.first; } };
1299 property Object next { get { return next; } };
1300 property const char * name { get { return name; } };
1301 property Matrix matrix { get { value = matrix; } };
1302 property Object cameraTarget { set { cameraTarget = value; } get { return cameraTarget; } };
1303 property OldList * tracks { /* set { tracks = value; } */ get { return &tracks; } };
1304 property ObjectFlags flags { set { flags = value; } get { return flags; } };
1306 // TOFIX: 32-bit compiling with 64-bit SDK cannot access public members properly
1307 property Object parent { get { return parent; } }
1308 property uint numChildren { get { return children.count; } }
1310 property Matrix * localMatrixPtr { get { return &localMatrix; } }
1311 property Matrix * matrixPtr { get { return &matrix; } }
1316 children.offset = (uint)(uintptr)&((Object)0).prev;
1317 transform.scaling = { 1, 1, 1 };
1318 transform.orientation = { 1,0,0,0 };
1319 flags.transform = true;
1320 localMatrix.Identity();
1328 void SetTransformDirty()
1331 flags.transform = true;
1332 for(child = children.first; child; child = child.next)
1333 child.SetTransformDirty();
1336 void _UpdateTransform()
1342 // Cameras / Spot Lights must update their target first
1343 if(flags.camera && cameraTarget && cameraTarget.flags.transform)
1344 cameraTarget.UpdateTransform();
1345 else if(flags.light && light.flags.spot && light.target && light.target.flags.transform)
1346 light.target._UpdateTransform();
1348 if(flags.camera && cameraTarget)
1350 // Determine angle to look at target
1351 Vector3D position, direction;
1352 if(flags.root || !parent)
1353 position = transform.position;
1355 position.MultMatrix(transform.position, parent.matrix);
1357 direction.Subtract((Vector3D *)cameraTarget.matrix.m[3], position);
1358 transform.orientation.RotationDirection(direction);
1361 transform.orientation.RotateRoll(roll);
1364 if(flags.light && light.flags.spot)
1366 // Determine angle to look at target
1368 if(flags.root || !parent)
1369 position = transform.position;
1371 position.MultMatrix(transform.position, parent.matrix);
1375 light.direction.Subtract((Vector3D *) light.target.matrix.m[3], position);
1376 light.direction.Normalize(light.direction);
1380 if(!flags.localMatrixSet)
1382 localMatrix.Identity();
1383 localMatrix.Scale(transform.scaling.x, transform.scaling.y, transform.scaling.z);
1384 localMatrix.Rotate(transform.orientation);
1385 localMatrix.Translate(transform.position.x, transform.position.y, transform.position.z);
1388 // Compute transform (with ancestors)
1389 if(flags.root || !parent)
1390 matrix = localMatrix;
1392 matrix.Multiply(localMatrix, parent.matrix);
1394 flags.transform = false;
1396 for(child = children.first; child; child = child.next)
1398 if(child.flags.transform)
1399 child._UpdateTransform();
1404 void _Animate(unsigned int frame)
1409 for(track = tracks.first; track; track = track.next)
1415 unsigned int prev = 0, next = track.numKeys - 1;
1416 FrameKey * prevKey = &track.keys[prev], * nextKey = &track.keys[next];
1419 for(c = 0; c<track.numKeys; c++)
1421 FrameKey * key = track.keys + c;
1422 if(key->frame <= frame) { prevKey = key; prev = c; }
1423 if(key->frame >= frame) { nextKey = key; next = c; break; }
1426 if(nextKey->frame != prevKey->frame)
1427 t = ease((float) (frame - prevKey->frame) / (nextKey->frame - prevKey->frame), prevKey->easeFrom, nextKey->easeTo);
1429 switch(track.type.type)
1434 track.Interpolate(position, prevKey->position, nextKey->position, prev, next, t);
1435 transform.position = { (double)position.x, (double)position.y, (double)position.z };
1439 track.Interpolate(transform.scaling, prevKey->scaling, &nextKey->scaling, prev, next, t);
1442 track.InterpolateQuat(transform.orientation, prevKey->orientation, nextKey->orientation, prev, next, t);
1446 roll = track.InterpolateFloat(prevKey->roll, nextKey->roll, prev, next, t);
1450 camera.fov = track.InterpolateFloat(prevKey->fov, nextKey->fov, prev, next, t);
1452 double mm = (camera.fov - 5.05659508373109) / 1.13613250717301;
1453 camera.fov = 1248.58921609766 * pow(mm, -0.895625414990581);
1455 //camera.Setup(camera.width, camera.height, camera.origin);
1461 track.Interpolate((Vector3Df *)&light.diffuse,
1462 (Vector3Df *)&prevKey->color, (Vector3Df *)&nextKey->color, prev, next, t);
1463 light.specular = light.diffuse;
1468 light.fallOff = track.InterpolateFloat(prevKey->fallOff, nextKey->fallOff, prev, next, t);
1473 light.hotSpot = track.InterpolateFloat(prevKey->hotSpot, nextKey->hotSpot, prev, next, t);
1480 for(child = children.first; child; child = child.next)
1481 child._Animate(frame);
1483 flags.transform = true;
1487 FrustumPlacement InsideFrustum(Plane * planes)
1489 FrustumPlacement result = inside;
1492 // First test: Sphere
1493 for(p = 0; p<6; p++)
1495 Plane * plane = &planes[p];
1496 double dot = plane->normal.DotProduct(wcenter);
1497 double distance = dot + plane->d;
1498 if(distance < -wradius)
1503 if(Abs(distance) < wradius)
1504 result = intersecting;
1507 if(result == intersecting)
1509 // Second test: Bounding Box
1512 { wmin.x, wmin.y, wmin.z },
1513 { wmin.x, wmin.y, wmax.z },
1514 { wmin.x, wmax.y, wmin.z },
1515 { wmin.x, wmax.y, wmax.z },
1516 { wmax.x, wmin.y, wmin.z },
1517 { wmax.x, wmin.y, wmax.z },
1518 { wmax.x, wmax.y, wmin.z },
1519 { wmax.x, wmax.y, wmax.z }
1521 int numPlanesAllIn = 0;
1522 for(p = 0; p < 6; p++)
1524 Plane * plane = &planes[p];
1526 int numGoodPoints = 0;
1527 for(i = 0; i < 8; ++i)
1529 double dot = plane->normal.DotProduct(box[i]);
1530 double distance = dot + plane->d;
1539 if(numGoodPoints == 8)
1542 if(numPlanesAllIn == 6)
1556 unsigned startFrame, endFrame;
1560 public Transform transform;
1565 Vector3Df min, max, center;
1566 Vector3D wmin, wmax, wcenter;
1589 Object cameraTarget;
1594 public property Light light
1606 Euler eulerOrientation;