int KX_NavMeshObject::FindPath(const MT_Point3& from, const MT_Point3& to, float* path, int maxPathLen) { if (!m_navMesh) return 0; MT_Point3 localfrom = TransformToLocalCoords(from); MT_Point3 localto = TransformToLocalCoords(to); float spos[3], epos[3]; localfrom.getValue(spos); flipAxes(spos); localto.getValue(epos); flipAxes(epos); dtStatPolyRef sPolyRef = m_navMesh->findNearestPoly(spos, polyPickExt); dtStatPolyRef ePolyRef = m_navMesh->findNearestPoly(epos, polyPickExt); int pathLen = 0; if (sPolyRef && ePolyRef) { dtStatPolyRef* polys = new dtStatPolyRef[maxPathLen]; int npolys; npolys = m_navMesh->findPath(sPolyRef, ePolyRef, spos, epos, polys, maxPathLen); if (npolys) { pathLen = m_navMesh->findStraightPath(spos, epos, polys, npolys, path, maxPathLen); for (int i=0; i<pathLen; i++) { flipAxes(&path[i*3]); MT_Point3 waypoint(&path[i*3]); waypoint = TransformToWorldCoords(waypoint); waypoint.getValue(&path[i*3]); } } delete[] polys; } return pathLen; }
/** * Returns the center of the circle defined by three points. * @param p1 point * @param p2 point * @param p3 point * @param center circle center * @return false if points are collinears, true otherwise */ bool BOP_getCircleCenter(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, MT_Point3& center) { // Compute quad plane MT_Vector3 p1p2 = p2-p1; MT_Vector3 p1p3 = p3-p1; MT_Plane3 plane1(p1,p2,p3); MT_Vector3 plane = plane1.Normal(); // Compute first line vector, perpendicular to plane vector and edge (p1,p2) MT_Vector3 vL1 = p1p2.cross(plane); if( MT_fuzzyZero(vL1.length() ) ) return false; vL1.normalize(); // Compute first line point, middle point of edge (p1,p2) MT_Point3 pL1 = p1.lerp(p2, 0.5); // Compute second line vector, perpendicular to plane vector and edge (p1,p3) MT_Vector3 vL2 = p1p3.cross(plane); if( MT_fuzzyZero(vL2.length() ) ) return false; vL2.normalize(); // Compute second line point, middle point of edge (p1,p3) MT_Point3 pL2 = p1.lerp(p3, 0.5); // Compute intersection (the lines lay on the same plane, so the intersection exists // only if they are not parallel!!) return BOP_intersect(vL1,pL1,vL2,pL2,center); }
MT_CmMatrix4x4::MT_CmMatrix4x4(const MT_Point3& orig, const MT_Vector3& dir, const MT_Vector3 up) { MT_Vector3 z = -(dir.normalized()); MT_Vector3 x = (up.cross(z)).normalized(); MT_Vector3 y = (z.cross(x)); m_V[0][0] = x.x(); m_V[0][1] = y.x(); m_V[0][2] = z.x(); m_V[0][3] = 0.0f; m_V[1][0] = x.y(); m_V[1][1] = y.y(); m_V[1][2] = z.y(); m_V[1][3] = 0.0f; m_V[2][0] = x.z(); m_V[2][1] = y.z(); m_V[2][2] = z.z(); m_V[2][3] = 0.0f; m_V[3][0] = orig.x();//0.0f; m_V[3][1] = orig.y();//0.0f; m_V[3][2] = orig.z();//0.0f; m_V[3][3] = 1.0f; //Translate(-orig); }
bool KX_RayCast::RayTest(PHY_IPhysicsEnvironment* physics_environment, const MT_Point3& _frompoint, const MT_Point3& topoint, KX_RayCast& callback) { if(physics_environment==NULL) return false; /* prevents crashing in some cases */ // Loops over all physics objects between frompoint and topoint, // calling callback.RayHit for each one. // // callback.RayHit should return true to stop looking, or false to continue. // // returns true if an object was found, false if not. MT_Point3 frompoint(_frompoint); const MT_Vector3 todir( (topoint - frompoint).safe_normalized() ); MT_Point3 prevpoint(_frompoint+todir*(-1.f)); PHY_IPhysicsController* hit_controller; while((hit_controller = physics_environment->rayTest(callback, frompoint.x(),frompoint.y(),frompoint.z(), topoint.x(),topoint.y(),topoint.z())) != NULL) { KX_ClientObjectInfo* info = static_cast<KX_ClientObjectInfo*>(hit_controller->getNewClientInfo()); if (!info) { printf("no info!\n"); MT_assert(info && "Physics controller with no client object info"); break; } // The biggest danger to endless loop, prevent this by checking that the // hit point always progresses along the ray direction.. prevpoint -= callback.m_hitPoint; if (prevpoint.length2() < MT_EPSILON) break; if (callback.RayHit(info)) // caller may decide to stop the loop and still cancel the hit return callback.m_hitFound; // Skip past the object and keep tracing. // Note that retrieving in a single shot multiple hit points would be possible // but it would require some change in Bullet. prevpoint = callback.m_hitPoint; /* We add 0.001 of fudge, so that if the margin && radius == 0., we don't endless loop. */ MT_Scalar marg = 0.001 + hit_controller->GetMargin(); marg *= 2.f; /* Calculate the other side of this object */ MT_Scalar h = MT_abs(todir.dot(callback.m_hitNormal)); if (h <= 0.01) // the normal is almost orthogonal to the ray direction, cannot compute the other side break; marg /= h; frompoint = callback.m_hitPoint + marg * todir; // verify that we are not passed the to point if ((topoint - frompoint).dot(todir) < 0.f) break; } return false; }
/** * Returns which of vertex v1 or v2 is nearest to u. * @param mesh mesh that contains the faces, edges and vertices * @param u reference vertex index * @param v1 first vertex index * @param v2 second vertex index * @return the nearest vertex index */ BOP_Index BOP_getNearestVertex(BOP_Mesh* mesh, BOP_Index u, BOP_Index v1, BOP_Index v2) { MT_Point3 q = mesh->getVertex(u)->getPoint(); MT_Point3 p1 = mesh->getVertex(v1)->getPoint(); MT_Point3 p2 = mesh->getVertex(v2)->getPoint(); if (BOP_comp(q.distance(p1), q.distance(p2)) > 0) return v2; else return v1; }
/** * Pre: p0, p1 and q are collinears. * @param p0 point * @param p1 point * @param q point * @return 0 if q == p0, 1 if q == p1, or a value between 0 and 1 otherwise * * (p0)-----(q)------------(p1) * |<-d1-->| | * |<---------d0---------->| * */ MT_Scalar BOP_EpsilonDistance(const MT_Point3& p0, const MT_Point3& p1, const MT_Point3& q) { MT_Scalar d0 = p0.distance(p1); MT_Scalar d1 = p0.distance(q); MT_Scalar d; if (BOP_fuzzyZero(d0)) d = 1.0; else if (BOP_fuzzyZero(d1)) d = 0.0; else d = d1 / d0; return d; }
/** * Returns if points p4 or p5 is inside the circle defined by p1, p2 and p3. * @param p1 point * @param p2 point * @param p3 point * @param p4 point * @param p5 point * @return true if p4 or p5 is inside the circle, false otherwise. If * the circle does not exist (p1, p2 and p3 are collinears) returns true */ bool BOP_isInsideCircle(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, const MT_Point3& p4, const MT_Point3& p5) { MT_Point3 center; bool ok = BOP_getCircleCenter(p1,p2,p3,center); if (!ok) return true; // Collinear points! // Check if p4 or p5 is inside the circle MT_Scalar r = p1.distance(center); MT_Scalar d1 = p4.distance(center); MT_Scalar d2 = p5.distance(center); return (BOP_comp(d1,r) <= 0 || BOP_comp(d2,r) <= 0); }
float KX_NavMeshObject::Raycast(const MT_Point3& from, const MT_Point3& to) { if (!m_navMesh) return 0.f; MT_Point3 localfrom = TransformToLocalCoords(from); MT_Point3 localto = TransformToLocalCoords(to); float spos[3], epos[3]; localfrom.getValue(spos); flipAxes(spos); localto.getValue(epos); flipAxes(epos); dtStatPolyRef sPolyRef = m_navMesh->findNearestPoly(spos, polyPickExt); float t=0; static dtStatPolyRef polys[MAX_PATH_LEN]; m_navMesh->raycast(sPolyRef, spos, epos, t, polys, MAX_PATH_LEN); return t; }
/** * Returns if points q is inside the circle defined by p1, p2 and p3. * @param p1 point * @param p2 point * @param p3 point * @param q point * @return true if p4 or p5 are inside the circle, false otherwise. If * the circle does not exist (p1, p2 and p3 are collinears) returns true */ bool BOP_isInsideCircle(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3, const MT_Point3& q) { MT_Point3 center; // Compute circle center bool ok = BOP_getCircleCenter(p1,p2,p3,center); if (!ok) return true; // p1,p2 and p3 are collinears // Check if q is inside the circle MT_Scalar r = p1.distance(center); MT_Scalar d = q.distance(center); return (BOP_comp(d,r) <= 0); }
static bool filterObstacle(KX_Obstacle* activeObst, KX_NavMeshObject* activeNavMeshObj, KX_Obstacle* otherObst, float levelHeight) { //filter obstacles by type if ( (otherObst == activeObst) || (otherObst->m_type==KX_OBSTACLE_NAV_MESH && otherObst->m_gameObj!=activeNavMeshObj) ) return false; //filter obstacles by position MT_Point3 p = nearestPointToObstacle(activeObst->m_pos, otherObst); if ( fabs(activeObst->m_pos.z() - p.z()) > levelHeight) return false; return true; }
int KX_Camera::SphereInsideFrustum(const MT_Point3& center, const MT_Scalar &radius) { ExtractFrustumSphere(); if (center.distance2(m_frustum_center) > (radius + m_frustum_radius)*(radius + m_frustum_radius)) return OUTSIDE; unsigned int p; ExtractClipPlanes(); NormalizeClipPlanes(); MT_Scalar distance; int intersect = INSIDE; // distance: <-------- OUTSIDE -----|----- INTERSECT -----0----- INTERSECT -----|----- INSIDE --------> // -radius radius for (p = 0; p < 6; p++) { distance = m_planes[p][0]*center[0] + m_planes[p][1]*center[1] + m_planes[p][2]*center[2] + m_planes[p][3]; if (fabs(distance) <= radius) intersect = INTERSECT; else if (distance < -radius) return OUTSIDE; } return intersect; }
void KX_KetsjiEngine::DoSound(KX_Scene* scene) { m_logger->StartLog(tc_sound, m_kxsystem->GetTimeInSeconds(), true); KX_Camera* cam = scene->GetActiveCamera(); if (!cam) return; MT_Point3 listenerposition = cam->NodeGetWorldPosition(); MT_Vector3 listenervelocity = cam->GetLinearVelocity(); MT_Matrix3x3 listenerorientation = cam->NodeGetWorldOrientation(); { AUD_3DData data; float f; listenerorientation.getValue3x3(data.orientation); listenerposition.getValue(data.position); listenervelocity.getValue(data.velocity); f = data.position[1]; data.position[1] = data.position[2]; data.position[2] = -f; f = data.velocity[1]; data.velocity[1] = data.velocity[2]; data.velocity[2] = -f; f = data.orientation[1]; data.orientation[1] = data.orientation[2]; data.orientation[2] = -f; f = data.orientation[3]; data.orientation[3] = -data.orientation[6]; data.orientation[6] = f; f = data.orientation[4]; data.orientation[4] = -data.orientation[8]; data.orientation[8] = -f; f = data.orientation[5]; data.orientation[5] = data.orientation[7]; data.orientation[7] = f; AUD_updateListener(&data); } }
RAS_TexVert::RAS_TexVert(const MT_Point3& xyz, const MT_Point2& uv, const MT_Point2& uv2, const MT_Vector4& tangent, const unsigned int rgba, const MT_Vector3& normal, const bool flat, const unsigned int origindex) { xyz.getValue(m_localxyz); uv.getValue(m_uv1); uv2.getValue(m_uv2); SetRGBA(rgba); SetNormal(normal); tangent.getValue(m_tangent); m_flag = (flat)? FLAT: 0; m_origindex = origindex; m_unit = 2; m_softBodyIndex = -1; }
RAS_TexVert::RAS_TexVert(const MT_Point3& xyz, const MT_Point2 uvs[MAX_UNIT], const MT_Vector4& tangent, const unsigned int rgba, const MT_Vector3& normal, const bool flat, const unsigned int origindex) { xyz.getValue(m_localxyz); SetRGBA(rgba); SetNormal(normal); tangent.getValue(m_tangent); m_flag = (flat)? FLAT: 0; m_origindex = origindex; m_unit = 2; m_softBodyIndex = -1; for (int i = 0; i < MAX_UNIT; ++i) { uvs[i].getValue(m_uvs[i]); } }
void RAS_TexVert::SetXYZ(const MT_Point3& xyz) { xyz.getValue(m_localxyz); }
bool KX_SoundActuator::Update(double curtime, bool frame) { if (!frame) return true; bool result = false; // do nothing on negative events, otherwise sounds are played twice! bool bNegativeEvent = IsNegativeEvent(); bool bPositiveEvent = m_posevent; RemoveAllEvents(); if (!m_sound) return false; // actual audio device playing state bool isplaying = m_handle ? (AUD_Handle_getStatus(m_handle) == AUD_STATUS_PLAYING) : false; if (bNegativeEvent) { // here must be a check if it is still playing if (m_isplaying && isplaying) { switch (m_type) { case KX_SOUNDACT_PLAYSTOP: case KX_SOUNDACT_LOOPSTOP: case KX_SOUNDACT_LOOPBIDIRECTIONAL_STOP: { // stop immediately if (m_handle) { AUD_Handle_stop(m_handle); m_handle = NULL; } break; } case KX_SOUNDACT_PLAYEND: { // do nothing, sound will stop anyway when it's finished break; } case KX_SOUNDACT_LOOPEND: case KX_SOUNDACT_LOOPBIDIRECTIONAL: { // stop the looping so that the sound stops when it finished if (m_handle) AUD_Handle_setLoopCount(m_handle, 0); break; } default: // implement me !! break; } } // remember that we tried to stop the actuator m_isplaying = false; } #if 1 // Warning: when de-activating the actuator, after a single negative event this runs again with... // m_posevent==false && m_posevent==false, in this case IsNegativeEvent() returns false // and assumes this is a positive event. // check that we actually have a positive event so as not to play sounds when being disabled. else if (bPositiveEvent) /* <- added since 2.49 */ #else else // <- works in most cases except a loop-end sound will never stop unless // the negative pulse is done continuesly #endif { if (!m_isplaying) play(); } // verify that the sound is still playing isplaying = m_handle ? (AUD_Handle_getStatus(m_handle) == AUD_STATUS_PLAYING) : false; if (isplaying) { if (m_is3d) { KX_Camera* cam = KX_GetActiveScene()->GetActiveCamera(); if (cam) { KX_GameObject* obj = (KX_GameObject*)this->GetParent(); MT_Point3 p; MT_Matrix3x3 Mo; float data[4]; Mo = cam->NodeGetWorldOrientation().inverse(); p = (obj->NodeGetWorldPosition() - cam->NodeGetWorldPosition()); p = Mo * p; p.getValue(data); AUD_Handle_setLocation(m_handle, data); p = (obj->GetLinearVelocity() - cam->GetLinearVelocity()); p = Mo * p; p.getValue(data); AUD_Handle_setVelocity(m_handle, data); (Mo * obj->NodeGetWorldOrientation()).getRotation().getValue(data); AUD_Handle_setOrientation(m_handle, data); } } result = true; } else { m_isplaying = false; result = false; } return result; }
/** * Pre: p0, p1 and p2 is a triangle and q is an interior point. * @param p0 point * @param p1 point * @param p2 point * @param q point * @return intersection point I * v * (p0)-----(I)----->(p1) * \ ^ / * \ |w / * \ | / * \ (q) / * \ | / * \ | / * \ | / * (p2) * * v = P1-P2 * w = P3-Q * r0(t) = v*t+P1 * r1(t) = w*t+P3 * I = r0^r1 */ MT_Point3 BOP_4PointIntersect(const MT_Point3& p0, const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& q) { MT_Vector3 v(p0.x()-p1.x(), p0.y()-p1.y(), p0.z()-p1.z()); MT_Vector3 w(p2.x()-q.x(), p2.y()-q.y(), p2.z()-q.z()); MT_Point3 I; BOP_intersect(v,p0,w,p2,I); return I; }
/** * Intersects a plane with the line that contains the specified points. * @param plane split plane * @param p1 first line point * @param p2 second line point * @return intersection between plane and line that contains p1 and p2 */ MT_Point3 BOP_intersectPlane(const MT_Plane3& plane, const MT_Point3& p1, const MT_Point3& p2) { // Compute intersection between plane and line ... // // L: (p2-p1)lambda + p1 // // supposes resolve equation ... // // coefA*((p2.x - p1.y)*lambda + p1.x) + ... + coefD = 0 MT_Point3 intersection = MT_Point3(0,0,0); //never ever return anything undefined! MT_Scalar den = plane.x()*(p2.x()-p1.x()) + plane.y()*(p2.y()-p1.y()) + plane.z()*(p2.z()-p1.z()); if (den != 0) { MT_Scalar lambda = (-plane.x()*p1.x()-plane.y()*p1.y()-plane.z()*p1.z()-plane.w()) / den; intersection.setValue(p1.x() + (p2.x()-p1.x())*lambda, p1.y() + (p2.y()-p1.y())*lambda, p1.z() + (p2.z()-p1.z())*lambda); return intersection; } return intersection; }
bool BL_ShapeActionActuator::Update(double curtime, bool frame) { bool bNegativeEvent = false; bool bPositiveEvent = false; bool keepgoing = true; bool wrap = false; bool apply=true; int priority; float newweight; curtime -= KX_KetsjiEngine::GetSuspendedDelta(); // result = true if animation has to be continued, false if animation stops // maybe there are events for us in the queue ! if (frame) { bNegativeEvent = m_negevent; bPositiveEvent = m_posevent; RemoveAllEvents(); if (bPositiveEvent) m_flag |= ACT_FLAG_ACTIVE; if (bNegativeEvent) { if (!(m_flag & ACT_FLAG_ACTIVE)) return false; m_flag &= ~ACT_FLAG_ACTIVE; } } /* This action can only be attached to a deform object */ BL_DeformableGameObject *obj = (BL_DeformableGameObject*)GetParent(); float length = m_endframe - m_startframe; priority = m_priority; /* Determine pre-incrementation behaviour and set appropriate flags */ switch (m_playtype){ case ACT_ACTION_MOTION: if (bNegativeEvent){ keepgoing=false; apply=false; }; break; case ACT_ACTION_FROM_PROP: if (bNegativeEvent){ apply=false; keepgoing=false; } break; case ACT_ACTION_LOOP_END: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_KEYUP; m_flag &= ~ACT_FLAG_REVERSE; m_flag |= ACT_FLAG_LOCKINPUT; m_localtime = m_startframe; m_starttime = curtime; } } if (bNegativeEvent){ m_flag |= ACT_FLAG_KEYUP; } break; case ACT_ACTION_LOOP_STOP: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_REVERSE; m_flag &= ~ACT_FLAG_KEYUP; m_flag |= ACT_FLAG_LOCKINPUT; SetStartTime(curtime); } } if (bNegativeEvent){ m_flag |= ACT_FLAG_KEYUP; m_flag &= ~ACT_FLAG_LOCKINPUT; keepgoing=false; apply=false; } break; case ACT_ACTION_PINGPONG: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_KEYUP; m_localtime = m_starttime; m_starttime = curtime; m_flag |= ACT_FLAG_LOCKINPUT; } } break; case ACT_ACTION_FLIPPER: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_REVERSE; m_flag |= ACT_FLAG_LOCKINPUT; SetStartTime(curtime); } } else if (bNegativeEvent){ m_flag |= ACT_FLAG_REVERSE; m_flag &= ~ACT_FLAG_LOCKINPUT; SetStartTime(curtime); } break; case ACT_ACTION_PLAY: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_REVERSE; m_localtime = m_starttime; m_starttime = curtime; m_flag |= ACT_FLAG_LOCKINPUT; } } break; default: break; } /* Perform increment */ if (keepgoing){ if (m_playtype == ACT_ACTION_MOTION){ MT_Point3 newpos; MT_Point3 deltapos; newpos = obj->NodeGetWorldPosition(); /* Find displacement */ deltapos = newpos-m_lastpos; m_localtime += (length/m_stridelength) * deltapos.length(); m_lastpos = newpos; } else{ SetLocalTime(curtime); } } /* Check if a wrapping response is needed */ if (length){ if (m_localtime < m_startframe || m_localtime > m_endframe) { m_localtime = m_startframe + fmod(m_localtime, length); wrap = true; } } else m_localtime = m_startframe; /* Perform post-increment tasks */ switch (m_playtype){ case ACT_ACTION_FROM_PROP: { CValue* propval = GetParent()->GetProperty(m_propname); if (propval) m_localtime = propval->GetNumber(); if (bNegativeEvent){ keepgoing=false; } } break; case ACT_ACTION_MOTION: break; case ACT_ACTION_LOOP_STOP: break; case ACT_ACTION_PINGPONG: if (wrap){ if (!(m_flag & ACT_FLAG_REVERSE)) m_localtime = m_endframe; else m_localtime = m_startframe; m_flag &= ~ACT_FLAG_LOCKINPUT; m_flag ^= ACT_FLAG_REVERSE; //flip direction keepgoing = false; } break; case ACT_ACTION_FLIPPER: if (wrap){ if (!(m_flag & ACT_FLAG_REVERSE)){ m_localtime=m_endframe; //keepgoing = false; } else { m_localtime=m_startframe; keepgoing = false; } } break; case ACT_ACTION_LOOP_END: if (wrap){ if (m_flag & ACT_FLAG_KEYUP){ keepgoing = false; m_localtime = m_endframe; m_flag &= ~ACT_FLAG_LOCKINPUT; } SetStartTime(curtime); } break; case ACT_ACTION_PLAY: if (wrap){ m_localtime = m_endframe; keepgoing = false; m_flag &= ~ACT_FLAG_LOCKINPUT; } break; default: keepgoing = false; break; } /* Set the property if its defined */ if (m_framepropname[0] != '\0') { CValue* propowner = GetParent(); CValue* oldprop = propowner->GetProperty(m_framepropname); CValue* newval = new CFloatValue(m_localtime); if (oldprop) { oldprop->SetValue(newval); } else { propowner->SetProperty(m_framepropname, newval); } newval->Release(); } if (bNegativeEvent) m_blendframe=0.0f; /* Apply the pose if necessary*/ if (apply) { /* Priority test */ if (obj->SetActiveAction(this, priority, curtime)){ BL_ShapeDeformer *shape_deformer = dynamic_cast<BL_ShapeDeformer*>(obj->GetDeformer()); Key *key = NULL; if (shape_deformer) key = shape_deformer->GetKey(); if (!key) { // this could happen if the mesh was changed in the middle of an action // and the new mesh has no key, stop the action keepgoing = false; } else { ListBase tchanbase= {NULL, NULL}; if (m_blendin && m_blendframe==0.0f){ // this is the start of the blending, remember the startup shape obj->GetShape(m_blendshape); m_blendstart = curtime; } KeyBlock *kb; // We go through and clear out the keyblocks so there isn't any interference // from other shape actions for (kb=(KeyBlock*)key->block.first; kb; kb=(KeyBlock*)kb->next) kb->curval = 0.f; animsys_evaluate_action(m_idptr, m_action, NULL, m_localtime); // XXX - in 2.5 theres no way to do this. possibly not that important to support - Campbell if (0) { // XXX !execute_ipochannels(&tchanbase)) { // no update, this is possible if action does not match the keys, stop the action keepgoing = false; } else { // the key have changed, apply blending if needed if (m_blendin && (m_blendframe<m_blendin)){ newweight = (m_blendframe/(float)m_blendin); BlendShape(key, 1.0f - newweight); /* Increment current blending percentage */ m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate(); if (m_blendframe>m_blendin) m_blendframe = m_blendin; } m_lastUpdate = m_localtime; } BLI_freelistN(&tchanbase); } } else{ m_blendframe = 0.0f; } } if (!keepgoing){ m_blendframe = 0.0f; } return keepgoing; };
void ImageRender::Render() { RAS_FrameFrustum frustrum; if (!m_render) return; if (m_mirror) { // mirror mode, compute camera frustrum, position and orientation // convert mirror position and normal in world space const MT_Matrix3x3 & mirrorObjWorldOri = m_mirror->GetSGNode()->GetWorldOrientation(); const MT_Point3 & mirrorObjWorldPos = m_mirror->GetSGNode()->GetWorldPosition(); const MT_Vector3 & mirrorObjWorldScale = m_mirror->GetSGNode()->GetWorldScaling(); MT_Point3 mirrorWorldPos = mirrorObjWorldPos + mirrorObjWorldScale * (mirrorObjWorldOri * m_mirrorPos); MT_Vector3 mirrorWorldZ = mirrorObjWorldOri * m_mirrorZ; // get observer world position const MT_Point3 & observerWorldPos = m_observer->GetSGNode()->GetWorldPosition(); // get plane D term = mirrorPos . normal MT_Scalar mirrorPlaneDTerm = mirrorWorldPos.dot(mirrorWorldZ); // compute distance of observer to mirror = D - observerPos . normal MT_Scalar observerDistance = mirrorPlaneDTerm - observerWorldPos.dot(mirrorWorldZ); // if distance < 0.01 => observer is on wrong side of mirror, don't render if (observerDistance < 0.01) return; // set camera world position = observerPos + normal * 2 * distance MT_Point3 cameraWorldPos = observerWorldPos + (MT_Scalar(2.0)*observerDistance)*mirrorWorldZ; m_camera->GetSGNode()->SetLocalPosition(cameraWorldPos); // set camera orientation: z=normal, y=mirror_up in world space, x= y x z MT_Vector3 mirrorWorldY = mirrorObjWorldOri * m_mirrorY; MT_Vector3 mirrorWorldX = mirrorObjWorldOri * m_mirrorX; MT_Matrix3x3 cameraWorldOri( mirrorWorldX[0], mirrorWorldY[0], mirrorWorldZ[0], mirrorWorldX[1], mirrorWorldY[1], mirrorWorldZ[1], mirrorWorldX[2], mirrorWorldY[2], mirrorWorldZ[2]); m_camera->GetSGNode()->SetLocalOrientation(cameraWorldOri); m_camera->GetSGNode()->UpdateWorldData(0.0); // compute camera frustrum: // get position of mirror relative to camera: offset = mirrorPos-cameraPos MT_Vector3 mirrorOffset = mirrorWorldPos - cameraWorldPos; // convert to camera orientation mirrorOffset = mirrorOffset * cameraWorldOri; // scale mirror size to world scale: // get closest local axis for mirror Y and X axis and scale height and width by local axis scale MT_Scalar x, y; x = fabs(m_mirrorY[0]); y = fabs(m_mirrorY[1]); float height = (x > y) ? ((x > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]): ((y > fabs(m_mirrorY[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]); x = fabs(m_mirrorX[0]); y = fabs(m_mirrorX[1]); float width = (x > y) ? ((x > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[0] : mirrorObjWorldScale[2]): ((y > fabs(m_mirrorX[2])) ? mirrorObjWorldScale[1] : mirrorObjWorldScale[2]); width *= m_mirrorHalfWidth; height *= m_mirrorHalfHeight; // left = offsetx-width // right = offsetx+width // top = offsety+height // bottom = offsety-height // near = -offsetz // far = near+100 frustrum.x1 = mirrorOffset[0]-width; frustrum.x2 = mirrorOffset[0]+width; frustrum.y1 = mirrorOffset[1]-height; frustrum.y2 = mirrorOffset[1]+height; frustrum.camnear = -mirrorOffset[2]; frustrum.camfar = -mirrorOffset[2]+m_clip; } // Store settings to be restored later const RAS_IRasterizer::StereoMode stereomode = m_rasterizer->GetStereoMode(); RAS_Rect area = m_canvas->GetWindowArea(); // The screen area that ImageViewport will copy is also the rendering zone m_canvas->SetViewPort(m_position[0], m_position[1], m_position[0]+m_capSize[0]-1, m_position[1]+m_capSize[1]-1); m_canvas->ClearColor(m_background[0], m_background[1], m_background[2], m_background[3]); m_canvas->ClearBuffer(RAS_ICanvas::COLOR_BUFFER|RAS_ICanvas::DEPTH_BUFFER); m_rasterizer->BeginFrame(m_engine->GetClockTime()); m_scene->GetWorldInfo()->UpdateWorldSettings(); m_rasterizer->SetAuxilaryClientInfo(m_scene); m_rasterizer->DisplayFog(); // matrix calculation, don't apply any of the stereo mode m_rasterizer->SetStereoMode(RAS_IRasterizer::RAS_STEREO_NOSTEREO); if (m_mirror) { // frustrum was computed above // get frustrum matrix and set projection matrix MT_Matrix4x4 projmat = m_rasterizer->GetFrustumMatrix( frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar); m_camera->SetProjectionMatrix(projmat); } else if (m_camera->hasValidProjectionMatrix()) { m_rasterizer->SetProjectionMatrix(m_camera->GetProjectionMatrix()); } else { float lens = m_camera->GetLens(); float sensor_x = m_camera->GetSensorWidth(); float sensor_y = m_camera->GetSensorHeight(); float shift_x = m_camera->GetShiftHorizontal(); float shift_y = m_camera->GetShiftVertical(); bool orthographic = !m_camera->GetCameraData()->m_perspective; float nearfrust = m_camera->GetCameraNear(); float farfrust = m_camera->GetCameraFar(); float aspect_ratio = 1.0f; Scene *blenderScene = m_scene->GetBlenderScene(); MT_Matrix4x4 projmat; // compute the aspect ratio from frame blender scene settings so that render to texture // works the same in Blender and in Blender player if (blenderScene->r.ysch != 0) aspect_ratio = float(blenderScene->r.xsch*blenderScene->r.xasp) / float(blenderScene->r.ysch*blenderScene->r.yasp); if (orthographic) { RAS_FramingManager::ComputeDefaultOrtho( nearfrust, farfrust, m_camera->GetScale(), aspect_ratio, m_camera->GetSensorFit(), shift_x, shift_y, frustrum ); projmat = m_rasterizer->GetOrthoMatrix( frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar); } else { RAS_FramingManager::ComputeDefaultFrustum( nearfrust, farfrust, lens, sensor_x, sensor_y, RAS_SENSORFIT_AUTO, shift_x, shift_y, aspect_ratio, frustrum); projmat = m_rasterizer->GetFrustumMatrix( frustrum.x1, frustrum.x2, frustrum.y1, frustrum.y2, frustrum.camnear, frustrum.camfar); } m_camera->SetProjectionMatrix(projmat); } MT_Transform camtrans(m_camera->GetWorldToCamera()); MT_Matrix4x4 viewmat(camtrans); m_rasterizer->SetViewMatrix(viewmat, m_camera->NodeGetWorldOrientation(), m_camera->NodeGetWorldPosition(), m_camera->GetCameraData()->m_perspective); m_camera->SetModelviewMatrix(viewmat); // restore the stereo mode now that the matrix is computed m_rasterizer->SetStereoMode(stereomode); if (stereomode == RAS_IRasterizer::RAS_STEREO_QUADBUFFERED) { // In QUAD buffer stereo mode, the GE render pass ends with the right eye on the right buffer // but we need to draw on the left buffer to capture the render // TODO: implement an explicit function in rasterizer to restore the left buffer. m_rasterizer->SetEye(RAS_IRasterizer::RAS_STEREO_LEFTEYE); } m_scene->CalculateVisibleMeshes(m_rasterizer,m_camera); m_engine->UpdateAnimations(m_scene); m_scene->RenderBuckets(camtrans, m_rasterizer); m_scene->RenderFonts(); // restore the canvas area now that the render is completed m_canvas->GetWindowArea() = area; }
/** * Computes the intersection between two lines (on the same plane). * @param vL1 first line vector * @param pL1 first line point * @param vL2 second line vector * @param pL2 second line point * @param intersection intersection point (if exists) * @return false if lines are parallels, true otherwise */ bool BOP_intersect(const MT_Vector3& vL1, const MT_Point3& pL1, const MT_Vector3& vL2, const MT_Point3& pL2, MT_Point3 &intersection) { // NOTE: // If the lines aren't on the same plane, the intersection point will not be valid. // So be careful !! MT_Scalar t = -1; MT_Scalar den = (vL1.y()*vL2.x() - vL1.x() * vL2.y()); if (!BOP_fuzzyZero(den)) { t = (pL2.y()*vL1.x() - vL1.y()*pL2.x() + pL1.x()*vL1.y() - pL1.y()*vL1.x()) / den ; } else { den = (vL1.y()*vL2.z() - vL1.z() * vL2.y()); if (!BOP_fuzzyZero(den)) { t = (pL2.y()*vL1.z() - vL1.y()*pL2.z() + pL1.z()*vL1.y() - pL1.y()*vL1.z()) / den ; } else { den = (vL1.x()*vL2.z() - vL1.z() * vL2.x()); if (!BOP_fuzzyZero(den)) { t = (pL2.x()*vL1.z() - vL1.x()*pL2.z() + pL1.z()*vL1.x() - pL1.x()*vL1.z()) / den ; } else { return false; } } } intersection.setValue(vL2.x()*t + pL2.x(), vL2.y()*t + pL2.y(), vL2.z()*t + pL2.z()); return true; }
/** * Returns if p1 is between p2 and p3 and lay on the same line (are collinears). * @param p1 point * @param p2 point * @param p3 point * @return true if p1 is between p2 and p3 and lay on the same line, false otherwise */ bool BOP_between(const MT_Point3& p1, const MT_Point3& p2, const MT_Point3& p3) { MT_Scalar distance = p2.distance(p3); return (p1.distance(p2) < distance && p1.distance(p3) < distance) && BOP_collinear(p1,p2,p3); }
void KX_Camera::ExtractFrustumSphere() { if (m_set_frustum_center) return; // compute sphere for the general case and not only symmetric frustum: // the mirror code in ImageRender can use very asymmetric frustum. // We will put the sphere center on the line that goes from origin to the center of the far clipping plane // This is the optimal position if the frustum is symmetric or very asymmetric and probably close // to optimal for the general case. The sphere center position is computed so that the distance to // the near and far extreme frustum points are equal. // get the transformation matrix from device coordinate to camera coordinate MT_Matrix4x4 clip_camcs_matrix = m_projection_matrix; clip_camcs_matrix.invert(); if (m_projection_matrix[3][3] == MT_Scalar(0.0)) { // frustrum projection // detect which of the corner of the far clipping plane is the farthest to the origin MT_Vector4 nfar; // far point in device normalized coordinate MT_Point3 farpoint; // most extreme far point in camera coordinate MT_Point3 nearpoint;// most extreme near point in camera coordinate MT_Point3 farcenter(0.0, 0.0, 0.0);// center of far cliping plane in camera coordinate MT_Scalar F=-1.0, N; // square distance of far and near point to origin MT_Scalar f, n; // distance of far and near point to z axis. f is always > 0 but n can be < 0 MT_Scalar e, s; // far and near clipping distance (<0) MT_Scalar c; // slope of center line = distance of far clipping center to z axis / far clipping distance MT_Scalar z; // projection of sphere center on z axis (<0) // tmp value MT_Vector4 npoint(1.0, 1.0, 1.0, 1.0); MT_Vector4 hpoint; MT_Point3 point; MT_Scalar len; for (int i=0; i<4; i++) { hpoint = clip_camcs_matrix*npoint; point.setValue(hpoint[0]/hpoint[3], hpoint[1]/hpoint[3], hpoint[2]/hpoint[3]); len = point.dot(point); if (len > F) { nfar = npoint; farpoint = point; F = len; } // rotate by 90 degree along the z axis to walk through the 4 extreme points of the far clipping plane len = npoint[0]; npoint[0] = -npoint[1]; npoint[1] = len; farcenter += point; } // the far center is the average of the far clipping points farcenter *= 0.25; // the extreme near point is the opposite point on the near clipping plane nfar.setValue(-nfar[0], -nfar[1], -1.0, 1.0); nfar = clip_camcs_matrix*nfar; nearpoint.setValue(nfar[0]/nfar[3], nfar[1]/nfar[3], nfar[2]/nfar[3]); // this is a frustrum projection N = nearpoint.dot(nearpoint); e = farpoint[2]; s = nearpoint[2]; // projection on XY plane for distance to axis computation MT_Point2 farxy(farpoint[0], farpoint[1]); // f is forced positive by construction f = farxy.length(); // get corresponding point on the near plane farxy *= s/e; // this formula preserve the sign of n n = f*s/e - MT_Point2(nearpoint[0]-farxy[0], nearpoint[1]-farxy[1]).length(); c = MT_Point2(farcenter[0], farcenter[1]).length()/e; // the big formula, it simplifies to (F-N)/(2(e-s)) for the symmetric case z = (F-N)/(2.0*(e-s+c*(f-n))); m_frustum_center = MT_Point3(farcenter[0]*z/e, farcenter[1]*z/e, z); m_frustum_radius = m_frustum_center.distance(farpoint); } else { // orthographic projection // The most extreme points on the near and far plane. (normalized device coords) MT_Vector4 hnear(1.0, 1.0, 1.0, 1.0), hfar(-1.0, -1.0, -1.0, 1.0); // Transform to hom camera local space hnear = clip_camcs_matrix*hnear; hfar = clip_camcs_matrix*hfar; // Tranform to 3d camera local space. MT_Point3 nearpoint(hnear[0]/hnear[3], hnear[1]/hnear[3], hnear[2]/hnear[3]); MT_Point3 farpoint(hfar[0]/hfar[3], hfar[1]/hfar[3], hfar[2]/hfar[3]); // just use mediant point m_frustum_center = (farpoint + nearpoint)*0.5; m_frustum_radius = m_frustum_center.distance(farpoint); } // Transform to world space. m_frustum_center = GetCameraToWorld()(m_frustum_center); m_frustum_radius /= fabs(NodeGetWorldScaling()[NodeGetWorldScaling().closestAxis()]); m_set_frustum_center = true; }
void KX_BulletPhysicsController::setPosition(const MT_Point3& pos) { CcdPhysicsController::setPosition(pos.x(),pos.y(),pos.z()); }
bool BL_ActionActuator::Update(double curtime, bool frame) { bool bNegativeEvent = false; bool bPositiveEvent = false; bool keepgoing = true; bool wrap = false; bool apply=true; int priority; float newweight; curtime -= KX_KetsjiEngine::GetSuspendedDelta(); // result = true if animation has to be continued, false if animation stops // maybe there are events for us in the queue ! if (frame) { bNegativeEvent = m_negevent; bPositiveEvent = m_posevent; RemoveAllEvents(); if (bPositiveEvent) m_flag |= ACT_FLAG_ACTIVE; if (bNegativeEvent) { // dont continue where we left off when restarting if (m_end_reset) { m_flag &= ~ACT_FLAG_LOCKINPUT; } if (!(m_flag & ACT_FLAG_ACTIVE)) return false; m_flag &= ~ACT_FLAG_ACTIVE; } } /* We know that action actuators have been discarded from all non armature objects: if we're being called, we're attached to a BL_ArmatureObject */ BL_ArmatureObject *obj = (BL_ArmatureObject*)GetParent(); float length = m_endframe - m_startframe; priority = m_priority; /* Determine pre-incrementation behaviour and set appropriate flags */ switch (m_playtype){ case ACT_ACTION_MOTION: if (bNegativeEvent){ keepgoing=false; apply=false; }; break; case ACT_ACTION_FROM_PROP: if (bNegativeEvent){ apply=false; keepgoing=false; } break; case ACT_ACTION_LOOP_END: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_KEYUP; m_flag &= ~ACT_FLAG_REVERSE; m_flag |= ACT_FLAG_LOCKINPUT; m_localtime = m_startframe; m_starttime = curtime; } } if (bNegativeEvent){ m_flag |= ACT_FLAG_KEYUP; } break; case ACT_ACTION_LOOP_STOP: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_REVERSE; m_flag &= ~ACT_FLAG_KEYUP; m_flag |= ACT_FLAG_LOCKINPUT; SetStartTime(curtime); } } if (bNegativeEvent){ m_flag |= ACT_FLAG_KEYUP; m_flag &= ~ACT_FLAG_LOCKINPUT; keepgoing=false; apply=false; } break; case ACT_ACTION_FLIPPER: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_REVERSE; m_flag |= ACT_FLAG_LOCKINPUT; SetStartTime(curtime); } } else if (bNegativeEvent){ m_flag |= ACT_FLAG_REVERSE; m_flag &= ~ACT_FLAG_LOCKINPUT; SetStartTime(curtime); } break; case ACT_ACTION_PLAY: if (bPositiveEvent){ if (!(m_flag & ACT_FLAG_LOCKINPUT)){ m_flag &= ~ACT_FLAG_REVERSE; m_localtime = m_starttime; m_starttime = curtime; m_flag |= ACT_FLAG_LOCKINPUT; } } break; default: break; } /* Perform increment */ if (keepgoing){ if (m_playtype == ACT_ACTION_MOTION){ MT_Point3 newpos; MT_Point3 deltapos; newpos = obj->NodeGetWorldPosition(); /* Find displacement */ deltapos = newpos-m_lastpos; m_localtime += (length/m_stridelength) * deltapos.length(); m_lastpos = newpos; } else{ SetLocalTime(curtime); } } /* Check if a wrapping response is needed */ if (length){ if (m_localtime < m_startframe || m_localtime > m_endframe) { m_localtime = m_startframe + fmod(m_localtime, length); wrap = true; } } else m_localtime = m_startframe; /* Perform post-increment tasks */ switch (m_playtype){ case ACT_ACTION_FROM_PROP: { CValue* propval = GetParent()->GetProperty(m_propname); if (propval) m_localtime = propval->GetNumber(); if (bNegativeEvent){ keepgoing=false; } } break; case ACT_ACTION_MOTION: break; case ACT_ACTION_LOOP_STOP: break; case ACT_ACTION_FLIPPER: if (wrap){ if (!(m_flag & ACT_FLAG_REVERSE)){ m_localtime=m_endframe; //keepgoing = false; } else { m_localtime=m_startframe; keepgoing = false; } } break; case ACT_ACTION_LOOP_END: if (wrap){ if (m_flag & ACT_FLAG_KEYUP){ keepgoing = false; m_localtime = m_endframe; m_flag &= ~ACT_FLAG_LOCKINPUT; } SetStartTime(curtime); } break; case ACT_ACTION_PLAY: if (wrap){ m_localtime = m_endframe; keepgoing = false; m_flag &= ~ACT_FLAG_LOCKINPUT; } break; default: keepgoing = false; break; } /* Set the property if its defined */ if (m_framepropname[0] != '\0') { CValue* propowner = GetParent(); CValue* oldprop = propowner->GetProperty(m_framepropname); CValue* newval = new CFloatValue(m_localtime); if (oldprop) { oldprop->SetValue(newval); } else { propowner->SetProperty(m_framepropname, newval); } newval->Release(); } if (bNegativeEvent) m_blendframe=0.0; /* Apply the pose if necessary*/ if (apply){ /* Priority test */ if (obj->SetActiveAction(this, priority, curtime)){ /* Get the underlying pose from the armature */ obj->GetPose(&m_pose); // 2.4x function, /* Override the necessary channels with ones from the action */ // XXX extract_pose_from_action(m_pose, m_action, m_localtime); // 2.5x - replacement for extract_pose_from_action(...) above. { struct PointerRNA id_ptr; Object *arm= obj->GetArmatureObject(); bPose *pose_back= arm->pose; arm->pose= m_pose; RNA_id_pointer_create((ID *)arm, &id_ptr); animsys_evaluate_action(&id_ptr, m_action, NULL, m_localtime); arm->pose= pose_back; // 2.5x - could also do this but looks too high level, constraints use this, it works ok. // Object workob; /* evaluate using workob */ // what_does_obaction((Scene *)obj->GetScene(), obj->GetArmatureObject(), &workob, m_pose, m_action, NULL, m_localtime); } // done getting the pose from the action /* Perform the user override (if any) */ if (m_userpose){ extract_pose_from_pose(m_pose, m_userpose); game_free_pose(m_userpose); //cant use MEM_freeN(m_userpose) because the channels need freeing too. m_userpose = NULL; } #if 1 /* Handle blending */ if (m_blendin && (m_blendframe<m_blendin)){ /* If this is the start of a blending sequence... */ if ((m_blendframe==0.0) || (!m_blendpose)){ obj->GetMRDPose(&m_blendpose); m_blendstart = curtime; } /* Find percentages */ newweight = (m_blendframe/(float)m_blendin); game_blend_poses(m_pose, m_blendpose, 1.0 - newweight); /* Increment current blending percentage */ m_blendframe = (curtime - m_blendstart)*KX_KetsjiEngine::GetAnimFrameRate(); if (m_blendframe>m_blendin) m_blendframe = m_blendin; } #endif m_lastUpdate = m_localtime; obj->SetPose (m_pose); } else{ m_blendframe = 0.0; } } if (!keepgoing){ m_blendframe = 0.0; } return keepgoing; };