void ShaderRenderer::drawTexturedRect3D(const Math::Vector3d &topLeft, const Math::Vector3d &bottomLeft, const Math::Vector3d &topRight, const Math::Vector3d &bottomRight, Texture *texture) { OpenGLTexture *glTexture = static_cast<OpenGLTexture *>(texture); const float w = glTexture->width / (float)glTexture->internalWidth; const float h = glTexture->height / (float)glTexture->internalHeight; glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); glDepthMask(GL_FALSE); glBindTexture(GL_TEXTURE_2D, glTexture->id); const GLfloat vertices[] = { // S T X Y Z 0, 0, -topLeft.x(), topLeft.y(), topLeft.z(), 0, h, -bottomLeft.x(), bottomLeft.y(), bottomLeft.z(), w, 0, -topRight.x(), topRight.y(), topRight.z(), w, h, -bottomRight.x(), bottomRight.y(), bottomRight.z(), }; _rect3dShader->use(); _rect3dShader->setUniform1f("texScale", 1.0f); _rect3dShader->setUniform("mvpMatrix", _mvpMatrix); glBindBuffer(GL_ARRAY_BUFFER, _rect3dVBO); glBufferSubData(GL_ARRAY_BUFFER, 0, 20 * sizeof(float), vertices); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); glDisable(GL_BLEND); glDepthMask(GL_TRUE); }
void TinyGLRenderer::drawTexturedRect3D(const Math::Vector3d &topLeft, const Math::Vector3d &bottomLeft, const Math::Vector3d &topRight, const Math::Vector3d &bottomRight, Texture *texture) { TinyGLTexture *glTexture = static_cast<TinyGLTexture *>(texture); const float w = glTexture->width / (float)glTexture->internalWidth; const float h = glTexture->height / (float)glTexture->internalHeight; tglBlendFunc(TGL_SRC_ALPHA, TGL_ONE_MINUS_SRC_ALPHA); tglEnable(TGL_BLEND); tglDepthMask(TGL_FALSE); tglBindTexture(TGL_TEXTURE_2D, glTexture->id); tglBegin(TGL_TRIANGLE_STRIP); tglTexCoord2f(0, 0); tglVertex3f(-topLeft.x(), topLeft.y(), topLeft.z()); tglTexCoord2f(0, h); tglVertex3f(-bottomLeft.x(), bottomLeft.y(), bottomLeft.z()); tglTexCoord2f(w, 0); tglVertex3f(-topRight.x(), topRight.y(), topRight.z()); tglTexCoord2f(w, h); tglVertex3f(-bottomRight.x(), bottomRight.y(), bottomRight.z()); tglEnd(); tglDisable(TGL_BLEND); tglDepthMask(TGL_TRUE); }
void Lua_V2::WorldToScreen() { lua_Object xObj = lua_getparam(1); lua_Object yObj = lua_getparam(2); lua_Object zObj = lua_getparam(3); if (!lua_isnumber(xObj) || !lua_isnumber(yObj) || !lua_isnumber(zObj)) { lua_pushnumber(0.0); lua_pushnumber(0.0); return; } float x = lua_getnumber(xObj); float y = lua_getnumber(yObj); float z = lua_getnumber(zObj); Math::Vector3d pos = Math::Vector3d(x, y, z); const Set::Setup *setup = g_emi->getCurrSet()->getCurrSetup(); const Math::Vector3d interest = setup->_interest; const float roll = setup->_roll; const Math::Quaternion quat = Math::Quaternion(interest.x(), interest.y(), interest.z(), roll); Math::Matrix4 view = quat.toMatrix(); view.transpose(); pos -= setup->_pos; pos = view.getRotation() * pos; pos.z() = -pos.z(); Math::Matrix4 proj = GfxBase::makeProjMatrix(setup->_fov, setup->_nclip, setup->_fclip); proj.transpose(); Math::Vector4d screen = proj * Math::Vector4d(pos.x(), pos.y(), pos.z(), 1.0); screen /= screen.w(); lua_pushnumber((screen.x() + 1) * 320); lua_pushnumber((1 - screen.y()) * 240); }
/** * @class Model */ Model::Model(const Common::String &filename, const char *data, int len, CMap *cmap, Model *parent) : Object(), _parent(parent), _numMaterials(0), _numGeosets(0), _cmap(cmap) { _fname = filename; if (g_grim->getGameType() == GType_MONKEY4) { Common::MemoryReadStream ms((const byte *)data, len); loadEMI(ms); } else if (len >= 4 && READ_BE_UINT32(data) == MKTAG('L','D','O','M')) loadBinary(data, cmap); else { TextSplitter ts(data, len); loadText(&ts, cmap); } Math::Vector3d max; _rootHierNode->update(); bool first = true; for (int i = 0; i < _numHierNodes; ++i) { ModelNode &node = _rootHierNode[i]; if (node._mesh) { Mesh &mesh = *node._mesh; //NOTE: Setting p to mesh._matrix._pos seems more similar to original // but, as in original, it also stops manny quite far away from the // bone wagon when approaching it from behind in set sg. // Using the node position looks instead more realistic, but, on the // other hand, it may not work right in all cases. Math::Vector3d p = node._matrix.getPosition(); float x = p.x(); float y = p.y(); float z = p.z(); for (int k = 0; k < mesh._numVertices * 3; k += 3) { if (first || mesh._vertices[k] + x < _bboxPos.x()) _bboxPos.x() = mesh._vertices[k] + x; if (mesh._vertices[k + 1] + y < _bboxPos.y()) _bboxPos.y() = mesh._vertices[k + 1] + y; if (mesh._vertices[k + 2] + z < _bboxPos.z()) _bboxPos.z() = mesh._vertices[k + 2] + z; if (first || mesh._vertices[k] + x > max.x()) max.x() = mesh._vertices[k] + x; if (mesh._vertices[k + 1] + y > max.y()) max.y() = mesh._vertices[k + 1] + y; if (mesh._vertices[k + 2] + z > max.z()) max.z() = mesh._vertices[k + 2] + z; first = false; } } } _bboxSize = max - _bboxPos; }
/** * @class Model */ Model::Model(const Common::String &filename, Common::SeekableReadStream *data, CMap *cmap, Model *parent) : Object(), _parent(parent), _numMaterials(0), _numGeosets(0), _cmap(cmap) { _fname = filename; if (g_grim->getGameType() == GType_MONKEY4) { loadEMI(data); } else if (data->readUint32BE() == MKTAG('L','D','O','M')) loadBinary(data, cmap); else { data->seek(0, SEEK_SET); TextSplitter ts(data); loadText(&ts, cmap); } delete data; Math::Vector3d max; _rootHierNode->update(); bool first = true; for (int i = 0; i < _numHierNodes; ++i) { ModelNode &node = _rootHierNode[i]; if (node._mesh) { Mesh &mesh = *node._mesh; Math::Vector3d p = mesh._matrix.getPosition(); float x = p.x(); float y = p.y(); float z = p.z(); for (int k = 0; k < mesh._numVertices * 3; k += 3) { if (first || mesh._vertices[k] + x < _bboxPos.x()) _bboxPos.x() = mesh._vertices[k] + x; if (first || mesh._vertices[k + 1] + y < _bboxPos.y()) _bboxPos.y() = mesh._vertices[k + 1] + y; if (first || mesh._vertices[k + 2] + z < _bboxPos.z()) _bboxPos.z() = mesh._vertices[k + 2] + z; if (first || mesh._vertices[k] + x > max.x()) max.x() = mesh._vertices[k] + x; if (first || mesh._vertices[k + 1] + y > max.y()) max.y() = mesh._vertices[k + 1] + y; if (first || mesh._vertices[k + 2] + z > max.z()) max.z() = mesh._vertices[k + 2] + z; first = false; } } } _bboxSize = max - _bboxPos; }
void ShaderRenderer::screenPosToDirection(const Common::Point screen, float &pitch, float &heading) { double x, y, z; x = screen.x; y = kOriginalHeight - screen.y; z = 0.9f; const Math::Vector2d tl = _viewport.getTopLeft(); x = 2 * double(x - tl.getX()) / _viewport.getWidth() - 1.0f; y = 2 * double(y - tl.getY()) / _viewport.getHeight() - 1.0f; z = 2 * z - 1.0f; // Screen coords to 3D coords Math::Vector4d point = Math::Vector4d(x, y, z, 1.0f); point = _mvpMatrix * point; // 3D coords to polar coords Math::Vector3d v = Math::Vector3d(point.x(), point.y(), point.z()); v.normalize(); Math::Vector2d horizontalProjection = Math::Vector2d(v.x(), v.z()); horizontalProjection.normalize(); pitch = 90 - Math::Angle::arcCosine(v.y()).getDegrees(); heading = Math::Angle::arcCosine(horizontalProjection.getY()).getDegrees(); if (horizontalProjection.getX() > 0.0) heading = 360 - heading; }
Math::Vector3d Actor::getTangentPos(const Math::Vector3d &pos, const Math::Vector3d &dest) const { if (_collisionMode == CollisionOff) { return dest; } Model *model = getCurrentCostume()->getModel(); Math::Vector3d p = _pos + model->_insertOffset; float size = model->_radius * _collisionScale; Math::Vector2d p1(pos.x(), pos.y()); Math::Vector2d p2(dest.x(), dest.y()); Math::Segment2d segment(p1, p2); // TODO: collision with Box // if (_collisionMode == CollisionSphere) { Math::Vector2d center(p.x(), p.y()); Math::Vector2d inter; float distance = segment.getLine().getDistanceTo(center, &inter); if (distance < size && segment.containsPoint(inter)) { Math::Vector2d v(inter - center); v.normalize(); v *= size; v += center; return Math::Vector3d(v.getX(), v.getY(), dest.z()); } // } else { // } return dest; }
/* Given a position and a size this function calculates and pushes * the nearest point to that which will be valid if the boxes are * shrunk by the amount specified. */ void Lua_V1::GetShrinkPos() { lua_Object xObj = lua_getparam(1); lua_Object yObj = lua_getparam(2); lua_Object zObj = lua_getparam(3); lua_Object rObj = lua_getparam(4); if (!lua_isnumber(xObj) || !lua_isnumber(yObj) || !lua_isnumber(zObj) || !lua_isnumber(rObj)) return; float x = lua_getnumber(xObj); float y = lua_getnumber(yObj); float z = lua_getnumber(zObj); float r = lua_getnumber(rObj); Math::Vector3d pos; pos.set(x, y, z); Sector* sector; g_grim->getCurrSet()->shrinkBoxes(r); g_grim->getCurrSet()->findClosestSector(pos, §or, &pos); g_grim->getCurrSet()->unshrinkBoxes(); if (sector) { lua_pushnumber(pos.x()); lua_pushnumber(pos.y()); lua_pushnumber(pos.z()); } else { lua_pushnil(); } }
bool Sector::isPointInSector(const Math::Vector3d &point) const { // Calculate the distance of the point from the plane of the sector. // Return false if it isn't within a margin. if (_height < 9000.f) { // No need to check when height is 9999. // The plane has equation ax + by + cz + d = 0 float a = _normal.x(); float b = _normal.y(); float c = _normal.z(); float d = -_vertices[0].x() * a - _vertices[0].y() * b - _vertices[0].z() * c; float dist = (a * point.x() + b * point.y() + c * point.z() + d) / sqrt(a * a + b * b + c * c); // dist is positive if it is above the plain, negative if it is // below and 0 if it is on the plane. if (fabsf(dist) > _height + 0.01) // Add an error margin return false; } // On the plane, so check if it is inside the polygon. for (int i = 0; i < _numVertices; i++) { Math::Vector3d edge = _vertices[i + 1] - _vertices[i]; Math::Vector3d delta = point - _vertices[i]; if (edge.x() * delta.y() < edge.y() * delta.x()) return false; } return true; }
void Lua_V2::GetActorPuckVector() { lua_Object actorObj = lua_getparam(1); lua_Object addObj = lua_getparam(2); if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R')) { lua_pushnil(); return; } Actor *actor = getactor(actorObj); // Note: The wear chore of dumbshadow.cos is only started from Lua if // GetActorPuckVector returns a non-nil value. The original engine seems // to return nil for all actors that have never followed walkboxes. if (!actor || !actor->hasFollowedBoxes()) { lua_pushnil(); return; } Math::Vector3d result = actor->getPuckVector(); if (!lua_isnil(addObj)) result += actor->getPos(); lua_pushnumber(result.x()); lua_pushnumber(result.y()); lua_pushnumber(result.z()); }
Math::Vector3d Sector::getProjectionToPuckVector(const Math::Vector3d &v) const { if (_normal.z() == 0) error("Trying to walk along vertical plane"); Math::Vector3d result = v; result.z() -= Math::Vector3d::dotProduct(_normal, v) / _normal.z(); return result; }
bool Actor::shouldDrawShadow(int shadowId) { Shadow *shadow = &_shadowArray[shadowId]; if (!shadow->active) return false; // Don't draw a shadow if the shadow caster and the actor are on different sides // of the the shadow plane. Sector *sector = shadow->planeList.front().sector; Math::Vector3d n = sector->getNormal(); Math::Vector3d p = sector->getVertices()[0]; float d = -(n.x() * p.x() + n.y() * p.y() + n.z() * p.z()); p = getPos(); // Move the tested point a bit above ground level. if (g_grim->getGameType() == GType_MONKEY4) p.y() += 0.01; else p.z() += 0.01; bool actorSide = n.x() * p.x() + n.y() * p.y() + n.z() * p.z() + d < 0.f; p = shadow->pos; bool shadowSide = n.x() * p.x() + n.y() * p.y() + n.z() * p.z() + d < 0.f; if (actorSide == shadowSide) return true; return false; }
Math::Vector3d Sector::getProjectionToPlane(const Math::Vector3d &point) const { if (_normal.z() == 0) error("Trying to walk along vertical plane"); // Formula: return p - (n . (p - v_0))/(n . k) k Math::Vector3d result = point; result.z() -= Math::Vector3d::dotProduct(_normal, point - _vertices[0]) / _normal.z(); return result; }
Math::Angle Actor::getYawTo(const Math::Vector3d &p) const { Math::Vector3d dpos = p - _pos; if (g_grim->getGameType() == GType_MONKEY4) { dpos.y() = dpos.z(); } if (dpos.x() == 0 && dpos.y() == 0) return 0; else return Math::Angle::arcTangent2(-dpos.x(), dpos.y()); }
Math::Angle Actor::getYawTo(Actor *a) const { Math::Vector3d forwardVec = getSimplePuckVector(); Math::Vector3d delta = a->getPos() - _pos; if (g_grim->getGameType() == GType_MONKEY4) { delta.y() = 0; } else { delta.z() = 0; } return Math::Vector3d::angle(forwardVec, delta); }
float Sector::distanceToPoint(const Math::Vector3d &point) const { // The plane has equation ax + by + cz + d = 0 float a = _normal.x(); float b = _normal.y(); float c = _normal.z(); float d = -_vertices[0].x() * a - _vertices[0].y() * b - _vertices[0].z() * c; // dist is positive if it is above the plain, negative if it is // below and 0 if it is on the plane. float dist = (a * point.x() + b * point.y() + c * point.z() + d); dist /= sqrt(a * a + b * b + c * c); return dist; }
bool Frustum::isInside(const Math::AABB &aabb) const { Math::Vector3d min = aabb.getMin(); Math::Vector3d max = aabb.getMax(); for (int i = 0; i < 6; ++i) { const Plane &plane = _planes[i]; Math::Vector3d positive = min; if (plane._normal.x() >= 0.0f) positive.x() = max.x(); if (plane._normal.y() >= 0.0f) positive.y() = max.y(); if (plane._normal.z() >= 0.0f) positive.z() = max.z(); float dist = _planes[i].getSignedDistance(positive); if (dist < 0.0f) return false; } return true; }
float Movement::computeAngleBetweenVectorsXYPlane(const Math::Vector3d &v1, const Math::Vector3d &v2) const { Math::Vector3d v1XY = v1; v1XY.z() = 0.0; Math::Vector3d v2XY = v2; v2XY.z() = 0.0; Math::Angle angle = Math::Vector3d::angle(v1XY, v2XY); Math::Vector3d cross = Math::Vector3d::crossProduct(v1XY, v2XY); if (cross.z() < 0) { angle = -angle; } return angle.getDegrees(); }
void Lua_V2::GetActorWorldPos() { lua_Object actorObj = lua_getparam(1); if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R')) return; Actor *actor = getactor(actorObj); if (!actor) return; Math::Vector3d pos = actor->getWorldPos(); lua_pushnumber(pos.x()); lua_pushnumber(pos.y()); lua_pushnumber(pos.z()); }
void BaseRenderer::screenPosToDirection(const Common::Point screen, float &pitch, float &heading) { // Screen coords to 3D coords Math::Vector3d obj; Math::gluMathUnProject(Math::Vector3d(screen.x, _system->getHeight() - screen.y, 0.9f), _mvpMatrix, frameViewport(), obj); // 3D coords to polar coords obj.normalize(); Math::Vector2d horizontalProjection = Math::Vector2d(obj.x(), obj.z()); horizontalProjection.normalize(); pitch = 90 - Math::Angle::arcCosine(obj.y()).getDegrees(); heading = Math::Angle::arcCosine(horizontalProjection.getY()).getDegrees(); if (horizontalProjection.getX() > 0.0) heading = 360 - heading; }
void TinyGLRenderer::screenPosToDirection(const Common::Point screen, float &pitch, float &heading) { // Screen coords to 3D coords Math::Vector3d obj; Math::gluMathUnProject<float, int>(Math::Vector3d(screen.x, kOriginalHeight - screen.y, 0.9), _cubeModelViewMatrix, _cubeProjectionMatrix, _cubeViewport, obj); // 3D coords to polar coords obj.normalize(); Math::Vector2d horizontalProjection = Math::Vector2d(obj.x(), obj.z()); horizontalProjection.normalize(); pitch = 90 - Math::Angle::arcCosine(obj.y()).getDegrees(); heading = Math::Angle::arcCosine(horizontalProjection.getY()).getDegrees(); if (horizontalProjection.getX() > 0.0) heading = 360 - heading; }
void Renderer::screenPosToDirection(const Common::Point screen, float &pitch, float &heading) { double x, y, z; // Screen coords to 3D coords gluUnProject(screen.x, kOriginalHeight - screen.y, 0.9, _cubeModelViewMatrix, _cubeProjectionMatrix, (GLint *)_cubeViewport, &x, &y, &z); // 3D coords to polar coords Math::Vector3d v = Math::Vector3d(x, y, z); v.normalize(); Math::Vector2d horizontalProjection = Math::Vector2d(v.x(), v.z()); horizontalProjection.normalize(); pitch = 90 - Math::Angle::arcCosine(v.y()).getDegrees(); heading = Math::Angle::arcCosine(horizontalProjection.getY()).getDegrees(); if (horizontalProjection.getX() > 0.0) heading = 360 - heading; }
void Lua_V1::GetSectorOppositeEdge() { lua_Object actorObj = lua_getparam(1); lua_Object nameObj = lua_getparam(2); if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R')) return; if (!lua_isstring(nameObj)) { lua_pushnil(); return; } Actor *actor = getactor(actorObj); const char *name = lua_getstring(nameObj); int numSectors = g_grim->getCurrSet()->getSectorCount(); for (int i = 0; i < numSectors; i++) { Sector *sector = g_grim->getCurrSet()->getSectorBase(i); if (strmatch(sector->getName(), name)) { if (sector->getNumVertices() != 4) warning("GetSectorOppositeEdge(): cheat box with %d (!= 4) edges!", sector->getNumVertices()); Math::Vector3d* vertices = sector->getVertices(); Sector::ExitInfo e; sector->getExitInfo(actor->getPos(), -actor->getPuckVector(), &e); float frac = (e.exitPoint - vertices[e.edgeVertex + 1]).getMagnitude() / e.edgeDir.getMagnitude(); e.edgeVertex -= 2; if (e.edgeVertex < 0) e.edgeVertex += sector->getNumVertices(); Math::Vector3d edge = vertices[e.edgeVertex + 1] - vertices[e.edgeVertex]; Math::Vector3d p = vertices[e.edgeVertex] + edge * frac; lua_pushnumber(p.x()); lua_pushnumber(p.y()); lua_pushnumber(p.z()); return; } } lua_pushnil(); }
static void polarRectTo3dRect(const PolarRect &polarRect, Math::Vector3d &topLeft, Math::Vector3d &topRight, Math::Vector3d &bottomLeft, Math::Vector3d &bottomRight) { static const float scale = 50.0; Math::Vector3d direction = Scene::directionToVector(polarRect.centerPitch, 90.0 - polarRect.centerHeading) * scale; Math::Vector3d u = Math::Vector3d(direction.z(), 0.0, -direction.x()); u.normalize(); Math::Vector3d v = Math::Vector3d::crossProduct(direction, u); v.normalize(); Math::Vector3d sizeU = u * polarRect.width / 90.0 * scale; Math::Vector3d sizeV = v * polarRect.height / 90.0 * scale; topRight = direction + sizeV + sizeU; bottomRight = direction - sizeV + sizeU; bottomLeft = direction - sizeV - sizeU; topLeft = direction + sizeV - sizeU; }
void Lua_V2::GetActorPuckVector() { lua_Object actorObj = lua_getparam(1); lua_Object addObj = lua_getparam(2); if (!lua_isuserdata(actorObj) || lua_tag(actorObj) != MKTAG('A','C','T','R')) { lua_pushnil(); return; } Actor *actor = getactor(actorObj); if (!actor) { lua_pushnil(); return; } Math::Vector3d result = actor->getPuckVector(); if (!lua_isnil(addObj)) result += actor->getPos(); lua_pushnumber(result.x()); lua_pushnumber(result.y()); lua_pushnumber(result.z()); }
/** * Generates a lookat matrix. For reference, see * http://clb.demon.fi/MathGeoLib/docs/float3x3_LookAt.php */ void Matrix<3, 3>::buildFromTargetDir(const Math::Vector3d &modelForward, const Math::Vector3d &targetDirection, const Math::Vector3d &modelUp, const Math::Vector3d &worldUp) { Math::Vector3d modelRight = Math::Vector3d::crossProduct(modelUp, modelForward); modelRight.normalize(); Math::Vector3d worldRight = Math::Vector3d::crossProduct(worldUp, targetDirection); worldRight.normalize(); Math::Vector3d perpWorldUp = Math::Vector3d::crossProduct(targetDirection, worldRight); perpWorldUp.normalize(); Math::Matrix3 m1; m1.getRow(0) << worldRight.x() << worldRight.y() << worldRight.z(); m1.getRow(1) << perpWorldUp.x() << perpWorldUp.y() << perpWorldUp.z(); m1.getRow(2) << targetDirection.x() << targetDirection.y() << targetDirection.z(); m1.transpose(); Math::Matrix3 m2; m2.getRow(0) << modelRight.x() << modelRight.y() << modelRight.z(); m2.getRow(1) << modelUp.x() << modelUp.y() << modelUp.z(); m2.getRow(2) << modelForward.x() << modelForward.y() << modelForward.z(); this->operator=(m1 * m2); }
void ResourceSerializer::syncAsVector3d(Math::Vector3d &value) { syncAsFloat(value.x()); syncAsFloat(value.y()); syncAsFloat(value.z()); }
void AnimationEmi::animate(Skeleton *skel, float delta) { _time += delta; if (_time > _duration) { _time = _duration; } for (int bone = 0; bone < _numBones; ++bone) { Bone &curBone = _bones[bone]; if (!curBone._target) curBone._target = skel->getJointNamed(curBone._boneName); Math::Matrix4 &relFinal = curBone._target->_finalMatrix; Math::Quaternion &quatFinal = curBone._target->_finalQuat; if (curBone._rotations) { int keyfIdx = 0; Math::Quaternion quat; Math::Vector3d relPos = relFinal.getPosition(); for (int curKeyFrame = 0; curKeyFrame < curBone._count; curKeyFrame++) { if (curBone._rotations[curKeyFrame]._time >= _time) { keyfIdx = curKeyFrame; break; } } if (keyfIdx == 0) { quat = curBone._rotations[keyfIdx]._quat; } else if (keyfIdx == curBone._count - 1) { quat = curBone._rotations[keyfIdx - 1]._quat; } else { float timeDelta = curBone._rotations[keyfIdx - 1]._time - curBone._rotations[keyfIdx]._time; float interpVal = (_time - curBone._rotations[keyfIdx]._time) / timeDelta; // Might be the other way around (keyfIdx - 1 slerped against keyfIdx) quat = curBone._rotations[keyfIdx]._quat.slerpQuat(curBone._rotations[keyfIdx - 1]._quat, interpVal); } quat.toMatrix(relFinal); quatFinal = quat; relFinal.setPosition(relPos); } if (curBone._translations) { int keyfIdx = 0; Math::Vector3d vec; for (int curKeyFrame = 0; curKeyFrame < curBone._count; curKeyFrame++) { if (curBone._translations[curKeyFrame]._time >= _time) { keyfIdx = curKeyFrame; break; } } if (keyfIdx == 0) { vec = curBone._translations[keyfIdx]._vec; } else if (keyfIdx == curBone._count - 1) { vec = curBone._translations[keyfIdx - 1]._vec; } else { float timeDelta = curBone._translations[keyfIdx - 1]._time - curBone._translations[keyfIdx]._time; float interpVal = (_time - curBone._translations[keyfIdx]._time) / timeDelta; vec.x() = curBone._translations[keyfIdx - 1]._vec.x() + (curBone._translations[keyfIdx]._vec.x() - curBone._translations[keyfIdx - 1]._vec.x()) * interpVal; vec.y() = curBone._translations[keyfIdx - 1]._vec.y() + (curBone._translations[keyfIdx]._vec.y() - curBone._translations[keyfIdx - 1]._vec.y()) * interpVal; vec.z() = curBone._translations[keyfIdx - 1]._vec.z() + (curBone._translations[keyfIdx]._vec.z() - curBone._translations[keyfIdx - 1]._vec.z()) * interpVal; } relFinal.setPosition(vec); } } }
void Walk::onGameLoop() { if (!_path->hasSteps()) { // There is no path to the destination stop(); return; } Resources::Floor *floor = StarkGlobal->getCurrent()->getFloor(); // Get the target to walk to Math::Vector3d currentPosition = _item3D->getPosition3D(); Math::Vector3d target = _path->computeWalkTarget(currentPosition); // Compute the direction to walk into Math::Vector3d direction = target - currentPosition; direction.z() = 0; direction.normalize(); // Compute the angle with the current character direction Math::Vector3d currentDirection = _item3D->getDirectionVector(); float directionDeltaAngle = computeAngleBetweenVectorsXYPlane(currentDirection, direction); // If the angle between the current direction and the new one is too high, // make the character turn on itself until the angle is low enough if (ABS(directionDeltaAngle) > getAngularSpeed() + 0.1f) { _turnDirection = directionDeltaAngle < 0 ? kTurnLeft : kTurnRight; } else { _turnDirection = kTurnNone; } float distancePerGameloop = computeDistancePerGameLoop(); Math::Vector3d newPosition; if (_turnDirection == kTurnNone) { // Compute the new position using the distance per gameloop if (currentPosition.getDistanceTo(target) > distancePerGameloop) { newPosition = currentPosition + direction * distancePerGameloop; } else { newPosition = target; } } else { // The character does not change position when it is turning newPosition = currentPosition; direction = currentDirection; Math::Matrix3 rot; rot.buildAroundZ(_turnDirection == kTurnLeft ? -getAngularSpeed() : getAngularSpeed()); rot.transformVector(&direction); } // Some scripts expect the character position to be the exact destination if (newPosition == _destination) { _reachedDestination = true; stop(); } // Update the new position's height according to the floor int32 newFloorFaceIndex = floor->findFaceContainingPoint(newPosition); if (newFloorFaceIndex >= 0) { floor->computePointHeightInFace(newPosition, newFloorFaceIndex); } else { warning("Item %s is walking off the floor", _item->getName().c_str()); } // Update the item's properties _item3D->setPosition3D(newPosition); if (direction.getMagnitude() != 0.0) { _item3D->setDirection(computeAngleBetweenVectorsXYPlane(direction, Math::Vector3d(1.0, 0.0, 0.0))); } if (newFloorFaceIndex >= 0) { // When unable to find the face containing the new position, keep the previous one // to prevent draw order glitches. _item3D->setFloorFaceIndex(newFloorFaceIndex); } changeItemAnim(); }
void SaveGame::writeVector3d(const Math::Vector3d &vec) { writeFloat(vec.x()); writeFloat(vec.y()); writeFloat(vec.z()); }