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;
27 public struct Transform
30 Quaternion orientation;
34 /*static float ease(float t, float a, float b)
39 if (s == 0.0f) return t;
46 if (t < a) return (k/a)*t*t;
47 if (t < 1.0f - b) return k*(2.0f * t - a);
49 return 1.0f - (k/b)*t*t;
52 public enum FrameTrackType : uint16 { position = 1, rotation, scaling, fov, roll, colorChange, morph, hotSpot, fallOff, hide };
54 public class FrameTrackBits
60 public struct FrameKey
63 float tension, continuity, bias;
64 float easeFrom, easeTo;
68 Quaternion orientation;
78 enum SplinePart { splinePoint, splineA, splineB };
80 public class FrameTrack : struct
82 FrameTrack prev, next;
97 float GetFloat(SplinePart what, unsigned int n)
100 FrameKey *kn_1, *kn, *kn1;
107 if(what == splinePoint)
119 value *= 1.0f - kn->tension;
124 kn_1 = &keys[numKeys-2];
125 d1 = keys[numKeys-1].frame - kn_1->frame;
126 d2 = kn1->frame - kn->frame;
134 a1 = GetFloat(splineA, 1);
138 value *= 1.0f - kn->tension;
142 else if(n == numKeys-1)
150 value *= 1.0f - kn->tension;
156 d1 = kn->frame - kn_1->frame;
157 d2 = kn1->frame - keys[0].frame;
165 bn_1 = GetFloat(splineB, n-1);
169 value *= 1.0f - kn->tension;
177 d1 = kn->frame - kn_1->frame;
178 d2 = kn1->frame - kn->frame;
198 adjust = 0.5f + (1.0f - Abs(C))*(adjust - 0.5f);
201 part1 *= (1.0f + kn->bias)*(1.0f - C);
204 part2 *= (1.0f - kn->bias)*(1.0f + C);
206 value = part1 + part2;
207 value *= (1.0f - kn->tension)*adjust;
213 void GetVector(Vector3Df vector, SplinePart what, unsigned int n)
215 FrameKey *kn_1, *kn, *kn1;
216 Vector3Df *pn_1, *pn, *pn1;
222 if(what == splinePoint)
229 pn1 = &kn1->position;
233 vector.Subtract(pn1, pn);
234 vector.Scale(vector, 1.0f - kn->tension);
239 kn_1 = &keys[numKeys-2];
240 d1 = keys[numKeys-1].frame - kn_1->frame;
241 d2 = kn1->frame - kn->frame;
246 vector.Subtract(pn1, pn);
247 vector.Scale(vector, 1.5f);
249 GetVector(a1, splineA, 1);
252 vector.Subtract(vector, a1);
253 vector.Scale(vector, 1.0f - kn->tension);
257 else if(n == numKeys-1)
260 pn_1 = &kn_1->position;
264 vector.Subtract(pn, pn_1);
265 vector.Scale(vector, 1.0f - kn->tension);
271 d1 = kn->frame - kn_1->frame;
272 d2 = kn1->frame - keys[0].frame;
277 vector.Subtract(pn, pn_1);
278 vector.Scale(vector, 1.5f);
280 GetVector(&bn_1, splineB, n-1);
281 bn_1.Scale(bn_1, 0.5f);
283 vector.Subtract(vector, bn_1);
284 vector.Scale(vector, 1.0f - kn->tension);
292 d1 = kn->frame - kn_1->frame;
293 d2 = kn1->frame - kn->frame;
297 Vector3Df part1, part2;
299 pn_1 = &kn_1->position;
300 pn1 = &kn1->position;
313 adjust = 0.5f + (1.0f - Abs(C))*(adjust - 0.5f);
315 part1.Subtract(pn, pn_1);
316 part1.Scale(part1, (1.0f + kn->bias)*(1.0f - C));
318 part2.Subtract(pn1, pn);
319 part2.Scale(part2, (1.0f - kn->bias)*(1.0f + C));
321 vector.Add(part1, part2);
322 vector.Scale(vector, (1.0f - kn->tension)*adjust);
327 void GetQuaternion(Quaternion quat, SplinePart what, unsigned int n)
329 FrameKey *kn_1, *kn, *kn1;
330 Quaternion *qn_1, *qn, *qn1;
334 qn = &kn->orientation;
336 if (what == splinePoint)
344 if (!(type.loop) || numKeys <= 2)
346 qn1 = &kn1->orientation;
347 quat.Slerp(qn, qn1, (1.0f - kn->tension)*(1.0f + kn->continuity*kn->bias)/3.0f);
352 kn_1= &keys[numKeys-2];
353 d1 = keys[numKeys-1].frame - kn_1->frame;
354 d2 = kn1->frame - kn->frame;
357 else if (n == numKeys-1)
361 if (!(type.loop) || numKeys <= 2)
363 qn_1 = &kn_1->orientation;
364 quat.Slerp(qn, qn_1, (1.0f - kn->tension)*(1.0f - kn->continuity*kn->bias)/3.0f);
370 d1 = kn->frame - kn_1->frame;
371 d2 = kn1->frame - keys[0].frame;
378 d1 = kn->frame - kn_1->frame;
379 d2 = kn1->frame - kn->frame;
383 Quaternion g1, g2, tmp;
385 qn_1 = &kn_1->orientation;
386 qn1 = &kn1->orientation;
399 adjust = 0.5f + (1.0f - Abs(kn->continuity))*(adjust - 0.5f);
401 g1.Slerp(qn, qn_1,-(1.0f + kn->bias)/3.0f);
402 g2.Slerp(qn, qn1 , (1.0f - kn->bias)/3.0f);
403 tmp.Slerp(g1, g2, 0.5f + f*0.5f*kn->continuity);
404 quat.Slerp(qn, &tmp, f*(kn->tension - 1.0f)*adjust*2.0f);
409 void Interpolate(Vector3Df vector, Vector3Df prevVector, Vector3Df nextVector, int prev, int next, float t)
415 Vector3Df p1 = prevVector, p2 = nextVector;
418 GetVector(r1, splineB, prev);
419 GetVector(r2, splineA, next);
421 p1.Scale(p1, 2*t*t*t - 3*t*t + 1);
422 p2.Scale(p2,-2*t*t*t + 3*t*t);
424 r1.Scale(r1, t*t*t - 2*t*t + t);
425 r2.Scale(r2, t*t*t - t*t);
428 vector.Add(vector, r1);
429 vector.Add(vector, p2);
430 vector.Add(vector, r2);
434 void InterpolateQuat(Quaternion quat, Quaternion prevQuat, Quaternion nextQuat, int prev, int next, float t)
441 Quaternion q0, q1, q2;
443 GetQuaternion(b, splineB, prev);
444 GetQuaternion(a, splineA, next);
446 q0.Slerp(prevQuat, b, t);
448 q2.Slerp(a, nextQuat, t);
453 quat.Slerp(q0, q1, t);
457 float InterpolateFloat(float prevValue, float nextValue, int prev, int next, float t)
464 float p1 = prevValue, p2 = nextValue;
466 float r1 = GetFloat(splineB, prev);
467 float r2 = GetFloat(splineA, next);
469 p1 *= 2*t*t*t - 3*t*t + 1;
470 p2 *= -2*t*t*t + 3*t*t;
472 r1 *= t*t*t - 2*t*t + t;
475 value = p1 + r1 + p2 + r2;
481 static bool FindMaterialAndType(Mesh mesh, Material material, PrimitiveGroupType type)
483 PrimitiveGroup group;
484 for(group = mesh.groups.first; group; group = group.next)
485 if(group.material == material && group.type == type)
490 public class Object : struct
493 void SetMinMaxRadius(bool processMesh)
497 if(flags.mesh && mesh)
500 mesh.SetMinMaxRadius();
503 volume = (max.x >= min.x && max.y >= min.y && max.z >= min.z);
507 min = { MAXFLOAT, MAXFLOAT, MAXFLOAT };
508 max = { -MAXFLOAT, -MAXFLOAT, -MAXFLOAT };
511 for(child = children.first; child; child = child.next)
513 child.SetMinMaxRadius(processMesh);
517 // Child Local + Child Object Transform
518 Vector3Df points[8] =
520 { child.min.x, child.min.y, child.min.z },
521 { child.min.x, child.min.y, child.max.z },
522 { child.min.x, child.max.y, child.min.z },
523 { child.min.x, child.max.y, child.max.z },
524 { child.max.x, child.min.y, child.min.z },
525 { child.max.x, child.min.y, child.max.z },
526 { child.max.x, child.max.y, child.min.z },
527 { child.max.x, child.max.y, child.max.z }
533 point.MultMatrix(points[c], child.localMatrix);
535 if(point.x < min.x) min.x = point.x;
536 if(point.y < min.y) min.y = point.y;
537 if(point.z < min.z) min.z = point.z;
539 if(point.x > max.x) max.x = point.x;
540 if(point.y > max.y) max.y = point.y;
541 if(point.z > max.z) max.z = point.z;
549 Vector3Df points[8] =
551 { min.x, min.y, min.z },
552 { min.x, min.y, max.z },
553 { min.x, max.y, min.z },
554 { min.x, max.y, max.z },
555 { max.x, min.y, min.z },
556 { max.x, min.y, max.z },
557 { max.x, max.y, min.z },
558 { max.x, max.y, max.z }
560 Vector3Df halfExtent;
561 Vector3D halfExtentd;
564 center.Add(min, max);
565 center.Scale(center, 0.5f);
566 halfExtent.Subtract(max, min);
567 halfExtent.Scale(halfExtent, 0.5f);
568 radius = halfExtent.length;
572 Vector3D min { MAXFLOAT, MAXFLOAT, MAXFLOAT };
573 Vector3D max { -MAXFLOAT, -MAXFLOAT, -MAXFLOAT };
578 point.MultMatrixf(points[c], matrix);
580 if(point.x < min.x) min.x = point.x;
581 if(point.y < min.y) min.y = point.y;
582 if(point.z < min.z) min.z = point.z;
584 if(point.x > max.x) max.x = point.x;
585 if(point.y > max.y) max.y = point.y;
586 if(point.z > max.z) max.z = point.z;
591 wcenter.Add(wmin, wmax);
592 wcenter.Scale(wcenter, 0.5f);
594 halfExtentd.Subtract(wmax, wmin);
595 halfExtentd.Scale(halfExtentd, 0.5);
596 wradius = halfExtentd.length;
600 void Duplicate(Object model)
606 name = CopyString(model.name);
608 flags.ownMesh = false;
609 flags.transform = false;
614 radius = model.radius;
616 if(parent && !flags.root)
617 matrix.Multiply(localMatrix, parent.matrix);
619 matrix = localMatrix;
621 for(modelChild = model.children.first; modelChild; modelChild = modelChild.next)
623 Object child { parent = this };
624 child.localMatrix = modelChild.localMatrix;
625 child.transform = modelChild.transform;
626 child.Duplicate(modelChild);
627 children.AddName(child);
632 void Free(DisplaySystem displaySystem)
638 while((child = children.first))
640 children.Remove(child);
641 child.Free(displaySystem);
643 // We did not do this before so as to keep transform on reloading for new DisplaySystem
644 // However since children are removed, it seems that purpose has been gone, we'd need
645 // a new mechanism to handle lost resources reloading...
648 if(flags.ownMesh && mesh)
650 DisplaySystem meshDisplaySystem = mesh.displaySystem;
652 if(meshDisplaySystem)
653 meshDisplaySystem.RemoveMesh(mesh);
657 tracks.Free(FrameTrack::Free);
663 bool Load(const char * fileName, const char * type, DisplaySystem displaySystem)
665 char ext[MAX_EXTENSION];
666 subclass(ObjectFormat) format;
670 if(!type && fileName)
671 type = strlwr(GetExtension(fileName, ext));
673 for(link = class(ObjectFormat).derivatives.first; link; link = link.next)
676 if(format.extension && !strcmp(format.extension, type))
679 if(!link) format = null;
683 if((format.Load(this, fileName, displaySystem)))
687 ErrorLogCode(GERR_LOAD_OBJECT_FAILED, fileName);*/
691 void FreeMesh(DisplaySystem displaySystem)
697 for(child = children.first; child; child = child.next)
698 child.FreeMesh(displaySystem);
702 Object Find(const char * name)
708 if(this.name && !strcmp(this.name, name))
712 for(child = children.first; child; child = child.next)
714 Object result = child.Find(name);
723 void Initialize(void)
727 transform.scaling = { 1, 1, 1 };
728 transform.orientation = { 1,0,0,0 };
730 flags.transform = true;
735 Mesh InitializeMesh(DisplaySystem displaySystem)
743 flags.ownMesh = true;
747 FillBytes(mesh, 0, sizeof(class Mesh));
748 displaySystem.AddMesh(mesh);
756 bool AddName(Object object, const char * name)
761 char * newName = CopyString(name);
762 object.name = newName;
763 result = children.AddName(object);
765 object.parent = this;
766 object.flags.transform = true;
771 // TODO: Add support to Merge Vertex Colors mesh feature
772 bool Merge(DisplaySystem displaySystem)
776 if(!children.first && (!this.flags.mesh || this.flags.ownMesh))
780 Object child, nextChild;
782 MeshFeatures flags = 0;
783 Mesh objectMesh = this.flags.mesh ? mesh : null;
784 bool freeMesh = this.flags.ownMesh;
786 // Count total number of vertices
789 flags |= objectMesh.flags;
790 nVertices += objectMesh.nVertices;
793 for(child = children.first; child; child = child.next)
795 child.Merge(displaySystem);
796 if(child.flags.mesh && child.mesh)
798 nVertices += child.mesh.nVertices;
799 flags |= child.mesh.flags;
806 if(this.flags.camera)
810 this.flags.ownMesh = true;
811 this.flags.mesh = true;
812 displaySystem.AddMesh(mesh);
814 if(mesh.Allocate(flags, nVertices, displaySystem))
818 int vertexOffset = 0;
819 PrimitiveGroup group = null;
826 for(c = 0; c<objectMesh.nVertices; c++)
828 mesh.vertices[nVertices] = objectMesh.vertices[c];
830 if(objectMesh.normals)
831 mesh.normals[nVertices] = objectMesh.normals[c];
832 if(objectMesh.texCoords)
833 mesh.texCoords[nVertices] = objectMesh.texCoords[c];
834 if(objectMesh.tangents)
836 mesh.tangents[2*nVertices+0] = objectMesh.tangents[2*c+0];
837 mesh.tangents[2*nVertices+1] = objectMesh.tangents[2*c+1];
844 for(child = children.first; child; child = child.next)
846 Matrix matrix, normalMatrix;
848 matrix = child.localMatrix;
851 matrix.Scale(child.transform.scaling.x, child.transform.scaling.y, child.transform.scaling.z);
852 matrix.Rotate(child.transform.orientation);
855 normalMatrix = matrix;
857 normalMatrix.m[3][0] = 0;
858 normalMatrix.m[3][1] = 0;
859 normalMatrix.m[3][2] = 0;
861 // matrix.Translate(child.transform.position.x, child.transform.position.y, child.transform.position.z);
863 if(child.flags.mesh && child.mesh)
865 for(c = 0; c < child.mesh.nVertices; c++)
867 mesh.vertices[nVertices].MultMatrix(child.mesh.vertices[c], matrix);
868 if(child.mesh.normals)
869 mesh.normals[nVertices].MultMatrix(child.mesh.normals[c], normalMatrix);
870 if(child.mesh.texCoords)
871 mesh.texCoords[nVertices] = child.mesh.texCoords[c];
872 if(child.mesh.tangents)
874 mesh.tangents[2*nVertices+0].MultMatrix(child.mesh.tangents[2*c+0], normalMatrix);
875 mesh.tangents[2*nVertices+1].MultMatrix(child.mesh.tangents[2*c+1], normalMatrix);
882 // Merge Indexed Primitive Groups
886 PrimitiveGroupType type = (PrimitiveGroupType)-1;
887 Material material = null;
888 bool foundGroup = false;
890 // Find first group type/material to process and determine how many indices are required
893 for(group = objectMesh.groups.first; group; group = group.next)
895 if(!foundGroup && !(group.type.vertexRange))
897 if(!FindMaterialAndType(mesh, group.material, group.type))
899 material = group.material;
901 nIndices += group.nIndices;
905 else if(material == group.material && type == group.type)
906 nIndices += group.nIndices;
910 for(child = children.first; child; child = child.next)
912 if(child.flags.mesh && child.mesh)
914 for(group = child.mesh.groups.first; group; group = group.next)
916 if(!foundGroup && !(group.type.vertexRange))
918 if(!FindMaterialAndType(mesh, group.material ? group.material : child.material, group.type))
920 material = group.material ? group.material : child.material;
922 nIndices += group.nIndices;
926 else if(material == (group.material ? group.material : child.material) && type == group.type)
927 nIndices += group.nIndices;
932 // Merge with all similar groups
935 PrimitiveGroup newGroup = mesh.AddPrimitiveGroup(type, nIndices);
938 newGroup.material = material;
945 for(group = objectMesh.groups.first; group; group = group.next)
947 if(newGroup.material == group.material && newGroup.type == group.type)
950 if(group.type.indices32bit)
951 for(c = 0; c<group.nIndices; c++)
952 newGroup.indices32[nIndices++] = group.indices32[c] + vertexOffset;
954 for(c = 0; c<group.nIndices; c++)
955 newGroup.indices[nIndices++] = (uint16)(group.indices[c] + vertexOffset);
958 vertexOffset += objectMesh.nVertices;
961 for(child = children.first; child; child = child.next)
963 if(child.flags.mesh && child.mesh)
965 for(group = child.mesh.groups.first; group; group = group.next)
967 if(newGroup.material == (group.material ? group.material : child.material) &&
968 newGroup.type == group.type)
971 if(group.type.indices32bit)
972 for(c = 0; c<group.nIndices; c++)
973 newGroup.indices32[nIndices++] = group.indices32[c] + vertexOffset;
975 for(c = 0; c<group.nIndices; c++)
976 newGroup.indices[nIndices++] = (uint16)(group.indices[c] + vertexOffset);
979 vertexOffset += child.mesh.nVertices;
982 mesh.UnlockPrimitiveGroup(newGroup);
989 // Merge Non-Indexed Primitive Groups
994 for(group = objectMesh.groups.first; group; group = group.next)
996 if(group.type.vertexRange)
998 PrimitiveGroup newGroup = mesh.AddPrimitiveGroup(group.type, 0);
1001 newGroup.material = group.material;
1002 newGroup.nVertices = group.nVertices;
1003 newGroup.first = group.first + vertexOffset;
1007 vertexOffset += objectMesh.nVertices;
1010 for(child = children.first; child; child = child.next)
1012 if(child.flags.mesh && child.mesh)
1014 for(group = child.mesh.groups.first; group; group = group.next)
1016 if(group.type.vertexRange)
1018 PrimitiveGroup newGroup = mesh.AddPrimitiveGroup(group.type, 0);
1021 newGroup.material = group.material ? group.material : child.material;
1022 newGroup.nVertices = group.nVertices;
1023 newGroup.first = group.first + vertexOffset;
1027 vertexOffset += child.mesh.nVertices;
1033 nTriangles = objectMesh.nPrimitives;
1035 for(child = children.first; child; child = child.next)
1037 if(child.flags.mesh && child.mesh)
1038 nTriangles += child.mesh.nPrimitives;
1041 mesh.primitives = new PrimitiveSingle[nTriangles];
1042 mesh.nPrimitives = 0;
1046 for(c = 0; c<objectMesh.nPrimitives; c++)
1049 PrimitiveSingle * triangle = &mesh.primitives[mesh.nPrimitives++];
1050 PrimitiveSingle * src = &objectMesh.primitives[c];
1052 mesh.AllocatePrimitive(triangle, src->type, src->nIndices);
1053 triangle->material = src->material;
1054 triangle->middle = src->middle;
1055 triangle->plane = src->plane;
1058 //src->indices = null;
1061 if(triangle->type.indices32bit)
1062 for(i = 0; i<triangle->nIndices; i++)
1063 triangle->indices32[i] = src->indices32[i] + vertexOffset;
1065 for(i = 0; i<triangle->nIndices; i++)
1066 triangle->indices[i] = (uint16)(src->indices[i] + vertexOffset);
1067 mesh.UnlockPrimitive(triangle);
1069 vertexOffset += objectMesh.nVertices;
1072 for(child = children.first; child; child = child.next)
1074 if(child.flags.mesh && child.mesh)
1076 for(c = 0; c<child.mesh.nPrimitives; c++)
1079 PrimitiveSingle * triangle = &mesh.primitives[mesh.nPrimitives++];
1080 PrimitiveSingle * src = &child.mesh.primitives[c];
1082 mesh.AllocatePrimitive(triangle, src->type, src->nIndices);
1083 triangle->material = src->material ? src->material : child.material;
1084 triangle->middle = src->middle;
1085 triangle->plane = src->plane;
1088 //src->indices = null;
1091 if(triangle->type.indices32bit)
1093 for(i = 0; i<triangle->nIndices; i++)
1094 triangle->indices32[i] = src->indices32[i] + vertexOffset;
1098 for(i = 0; i<triangle->nIndices; i++)
1099 triangle->indices[i] = (uint16)(src->indices[i] + vertexOffset);
1101 mesh.UnlockPrimitive(triangle);
1103 vertexOffset += child.mesh.nVertices;
1108 for(child = children.first; child; child = nextChild)
1110 nextChild = child.next;
1111 children.Remove(child);
1112 child.Free(displaySystem);
1116 mesh.ApplyTranslucency(this);
1117 // this.flags.translucent = true;
1123 if(freeMesh && objectMesh)
1125 if(objectMesh.displaySystem)
1126 objectMesh.displaySystem.RemoveMesh(objectMesh);
1129 SetMinMaxRadius(true);
1134 void RotateEuler(Euler rotation, Euler min, Euler max)
1136 // WARNING: 'eulerOrientation' is only updated by this function
1137 Euler euler = eulerOrientation;//transform.orientation;
1138 euler.Add(euler, rotation);
1142 if(min.pitch && max.pitch)
1143 euler.pitch = Min(Max(euler.pitch, min.pitch), max.pitch);
1144 if(min.yaw && max.yaw)
1145 euler.yaw = Min(Max(euler.yaw, min.yaw), max.yaw);
1146 if(min.roll && max.roll)
1147 euler.roll = Min(Max(euler.roll, min.roll), max.roll);
1150 eulerOrientation = euler;
1151 transform.orientation = euler;
1155 void Move(Vector3D direction)
1160 matrix.RotationQuaternion(transform.orientation);
1161 offset.MultMatrix(direction, matrix);
1162 transform.position.Add(transform.position, offset);
1166 void UpdateTransform(void)
1168 SetTransformDirty();
1170 SetMinMaxRadius(false);
1173 void Animate(unsigned int frame)
1175 if(this && startFrame != endFrame)
1177 while(frame < startFrame) frame += (endFrame - startFrame + 1);
1178 while(frame > endFrame) frame -= (endFrame - startFrame + 1);
1183 SetMinMaxRadius(false);
1187 void DoubleSided(bool flag)
1192 mesh.DoubleSided(flag);
1193 for(child = children.first; child; child = child.next)
1194 child.DoubleSided(flag);
1198 bool IntersectsGroundPolygon(int count, Pointf * pointfs)
1200 bool result = false;
1204 double minX = wmin.x, maxX = wmax.x;
1205 double minY = wmin.z, maxY = wmax.z;
1206 double delta = (maxX - minX)/2;
1207 double x = (maxX + minX)/2, y = (maxY + minY)/2;
1209 for(c = 0; c<count; c++)
1213 p2 = &pointfs[(c == count-1) ? 0 : (c+1)];
1215 if( (p1->x < minX) && (p2->x < minX) )
1217 if((p1->y <= y) && (p2->y > y) )
1219 else if( (p1->y > y) && (p2->y <= y) )
1222 else if(!((p1->x > maxX && p2->x > maxX) || (p1->y < minY && p2->y < minY) || (p1->y > maxY && p2->y > maxY)))
1228 if (d < delta) return true;
1230 else if(p1->x == p2->x)
1234 if(d < delta) return true;
1235 else if(p1->x > x) ;
1236 else if( (p1->y <= y) && (p2->y > y) )
1238 else if( (p1->y > y) && (p2->y <= y) )
1249 d = a * x + b * y + (p2->x * p1->y) - (p2->y * p1->x);
1256 else if (d < b * delta)
1258 else if( ( (p1->y <= y) && (p2->y > y) ) || ( (p1->y > y) && (p2->y <= y) ) )
1262 xdy = (dx * (y - p1->y)) + (dy * p1->x);
1268 else if(xdy < x * dy)
1277 property Transform transform { set { transform = value; eulerOrientation = transform.orientation; } get { value = transform; } };
1278 property Material material { set { material = value; } get { return material; } };
1279 property Vector3Df max { get { value = max; } };
1280 property Vector3Df min { get { value = min; } };
1281 property Vector3Df center { get { value = center; } };
1282 property float radius { get { return radius; } };
1284 property Vector3D wmax { get { value = wmax; } };
1285 property Vector3D wmin { get { value = wmin; } };
1286 property Vector3D wcenter { get { value = wcenter; } };
1287 property double wradius { get { return wradius; } };
1289 property void * tag { set { tag = value; } get { return tag; } };
1290 property int frame { set { Animate(value); } get { return frame; } };
1291 property int startFrame { set { startFrame = value; } get { return startFrame; } };
1292 property int endFrame { set { endFrame = value; } get { return endFrame; } };
1294 property Mesh mesh { set { mesh = value; } get { return mesh; } };
1295 property Camera camera { get { return camera; } }; // Fix this with inheritance? camera inherit from Object?
1296 property Object firstChild { get { return children.first; } };
1297 property Object next { get { return next; } };
1298 property const char * name { get { return name; } };
1299 property Matrix matrix { get { value = matrix; } };
1300 property Object cameraTarget { set { cameraTarget = value; } get { return cameraTarget; } };
1301 property OldList * tracks { /* set { tracks = value; } */ get { return &tracks; } };
1302 property ObjectFlags flags { set { flags = value; } get { return flags; } };
1304 // TOFIX: 32-bit compiling with 64-bit SDK cannot access public members properly
1305 property Object parent { get { return parent; } }
1306 property uint numChildren { get { return children.count; } }
1308 property Matrix * localMatrixPtr { get { return &localMatrix; } }
1309 property Matrix * matrixPtr { get { return &matrix; } }
1314 children.offset = (uint)(uintptr)&((Object)0).prev;
1315 transform.scaling = { 1, 1, 1 };
1316 transform.orientation = { 1,0,0,0 };
1317 flags.transform = true;
1318 localMatrix.Identity();
1326 void SetTransformDirty()
1329 flags.transform = true;
1330 for(child = children.first; child; child = child.next)
1331 child.SetTransformDirty();
1334 void _UpdateTransform()
1340 // Cameras / Spot Lights must update their target first
1341 if(flags.camera && cameraTarget && cameraTarget.flags.transform)
1342 cameraTarget.UpdateTransform();
1343 else if(flags.light && light.flags.spot && light.target && light.target.flags.transform)
1344 light.target._UpdateTransform();
1346 if(flags.camera && cameraTarget)
1348 // Determine angle to look at target
1349 Vector3D position, direction;
1350 if(flags.root || !parent)
1351 position = transform.position;
1353 position.MultMatrix(transform.position, parent.matrix);
1355 direction.Subtract((Vector3D *)cameraTarget.matrix.m[3], position);
1356 transform.orientation.RotationDirection(direction);
1359 transform.orientation.RotateRoll(roll);
1362 if(flags.light && light.flags.spot)
1364 // Determine angle to look at target
1366 if(flags.root || !parent)
1367 position = transform.position;
1369 position.MultMatrix(transform.position, parent.matrix);
1373 light.direction.Subtract((Vector3D *) light.target.matrix.m[3], position);
1374 light.direction.Normalize(light.direction);
1378 if(!flags.localMatrixSet)
1380 localMatrix.Identity();
1381 localMatrix.Scale(transform.scaling.x, transform.scaling.y, transform.scaling.z);
1382 localMatrix.Rotate(transform.orientation);
1383 localMatrix.Translate(transform.position.x, transform.position.y, transform.position.z);
1386 // Compute transform (with ancestors)
1387 if(flags.root || !parent)
1388 matrix = localMatrix;
1390 matrix.Multiply(localMatrix, parent.matrix);
1392 flags.transform = false;
1394 for(child = children.first; child; child = child.next)
1396 if(child.flags.transform)
1397 child._UpdateTransform();
1402 void _Animate(unsigned int frame)
1407 for(track = tracks.first; track; track = track.next)
1413 unsigned int prev = 0, next = track.numKeys - 1;
1414 FrameKey * prevKey = &track.keys[prev], * nextKey = &track.keys[next];
1417 for(c = 0; c<track.numKeys; c++)
1419 FrameKey * key = track.keys + c;
1420 if(key->frame <= frame) { prevKey = key; prev = c; }
1421 if(key->frame >= frame) { nextKey = key; next = c; break; }
1424 if(nextKey->frame != prevKey->frame)
1425 t = ease((float) (frame - prevKey->frame) / (nextKey->frame - prevKey->frame), prevKey->easeFrom, nextKey->easeTo);
1427 switch(track.type.type)
1432 track.Interpolate(position, prevKey->position, nextKey->position, prev, next, t);
1433 transform.position = { (double)position.x, (double)position.y, (double)position.z };
1437 track.Interpolate(transform.scaling, prevKey->scaling, &nextKey->scaling, prev, next, t);
1440 track.InterpolateQuat(transform.orientation, prevKey->orientation, nextKey->orientation, prev, next, t);
1444 roll = track.InterpolateFloat(prevKey->roll, nextKey->roll, prev, next, t);
1448 camera.fov = track.InterpolateFloat(prevKey->fov, nextKey->fov, prev, next, t);
1450 double mm = (camera.fov - 5.05659508373109) / 1.13613250717301;
1451 camera.fov = 1248.58921609766 * pow(mm, -0.895625414990581);
1453 //camera.Setup(camera.width, camera.height, camera.origin);
1459 track.Interpolate((Vector3Df *)&light.diffuse,
1460 (Vector3Df *)&prevKey->color, (Vector3Df *)&nextKey->color, prev, next, t);
1461 light.specular = light.diffuse;
1466 light.fallOff = track.InterpolateFloat(prevKey->fallOff, nextKey->fallOff, prev, next, t);
1471 light.hotSpot = track.InterpolateFloat(prevKey->hotSpot, nextKey->hotSpot, prev, next, t);
1478 for(child = children.first; child; child = child.next)
1479 child._Animate(frame);
1481 flags.transform = true;
1485 FrustumPlacement InsideFrustum(Plane * planes)
1487 FrustumPlacement result = inside;
1490 // First test: Sphere
1491 for(p = 0; p<6; p++)
1493 Plane * plane = &planes[p];
1494 double dot = plane->normal.DotProduct(wcenter);
1495 double distance = dot + plane->d;
1496 if(distance < -wradius)
1501 if(Abs(distance) < wradius)
1502 result = intersecting;
1505 if(result == intersecting)
1507 // Second test: Bounding Box
1510 { wmin.x, wmin.y, wmin.z },
1511 { wmin.x, wmin.y, wmax.z },
1512 { wmin.x, wmax.y, wmin.z },
1513 { wmin.x, wmax.y, wmax.z },
1514 { wmax.x, wmin.y, wmin.z },
1515 { wmax.x, wmin.y, wmax.z },
1516 { wmax.x, wmax.y, wmin.z },
1517 { wmax.x, wmax.y, wmax.z }
1519 int numPlanesAllIn = 0;
1520 for(p = 0; p < 6; p++)
1522 Plane * plane = &planes[p];
1524 int numGoodPoints = 0;
1525 for(i = 0; i < 8; ++i)
1527 double dot = plane->normal.DotProduct(box[i]);
1528 double distance = dot + plane->d;
1537 if(numGoodPoints == 8)
1540 if(numPlanesAllIn == 6)
1554 unsigned startFrame, endFrame;
1558 public Transform transform;
1563 Vector3Df min, max, center;
1564 Vector3D wmin, wmax, wcenter;
1587 Object cameraTarget;
1592 public property Light light
1604 Euler eulerOrientation;