void DotSceneLoader::processLookTarget(rapidxml::xml_node<>* XMLNode, Ogre::SceneNode *pParent) { //! @todo Is this correct? Cause I don't have a clue actually // Process attributes Ogre::String nodeName = getAttrib(XMLNode, "nodeName"); Ogre::Node::TransformSpace relativeTo = Ogre::Node::TS_PARENT; Ogre::String sValue = getAttrib(XMLNode, "relativeTo"); if (sValue == "local") relativeTo = Ogre::Node::TS_LOCAL; else if (sValue == "parent") relativeTo = Ogre::Node::TS_PARENT; else if (sValue == "world") relativeTo = Ogre::Node::TS_WORLD; rapidxml::xml_node<>* pElement; // Process position (?) Ogre::Vector3 position; pElement = XMLNode->first_node("position"); if (pElement) position = parseVector3(pElement); // Process localDirection (?) Ogre::Vector3 localDirection = Ogre::Vector3::NEGATIVE_UNIT_Z; pElement = XMLNode->first_node("localDirection"); if (pElement) localDirection = parseVector3(pElement); // Setup the look target try { if (!nodeName.empty()) { Ogre::SceneNode *pLookNode = mSceneMgr->getSceneNode(nodeName); position = pLookNode->_getDerivedPosition(); } pParent->lookAt(position, relativeTo, localDirection); } catch (Ogre::Exception &/*e*/) { Ogre::LogManager::getSingleton().logMessage("[DotSceneLoader] Error processing a look target!"); } }
float3x4 EC_Mesh::LocalToWorld() const { if (!entity_) { LogError("EC_Mesh::LocalToParent failed! No entity exists in this mesh!"); return float3x4::identity; } Ogre::SceneNode *node = entity_->getParentSceneNode(); if (!node) { LogError("EC_Mesh::LocalToParent failed! Ogre::Entity is not attached to a Ogre::SceneNode!"); return float3x4::identity; } return float3x4::FromTRS(node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale()); }
float3x4 EC_Mesh::LocalToWorld() const { if (!entity_) { LogError(QString("EC_Mesh::LocalToWorld failed! No entity exists in mesh \"%1\" (entity: \"%2\")!").arg(meshRef.Get().ref).arg(ParentEntity() ? ParentEntity()->Name() : "(EC_Mesh with no parent entity)")); return float3x4::identity; } Ogre::SceneNode *node = entity_->getParentSceneNode(); if (!node) { LogError(QString("EC_Mesh::LocalToWorld failed! Ogre::Entity is not attached to a Ogre::SceneNode! Mesh \"%1\" (entity: \"%2\")!").arg(meshRef.Get().ref).arg(ParentEntity() ? ParentEntity()->Name() : "(EC_Mesh with no parent entity)")); return float3x4::identity; } assume(!float3(node->_getDerivedScale()).IsZero()); float3x4 tm = float3x4::FromTRS(node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale()); assume(tm.IsColOrthogonal()); return tm; }
void Renderer::FindClosestPolygon(Ogre::Entity* entity, float& closestDistance, Ogre::Vector3& position, Ogre::Vector3& normal) { closestDistance = std::numeric_limits<float>::max(); // default value (means // nothing detected) // Get transformation Ogre::SceneNode* parentNode = entity->getParentSceneNode(); Ogre::Vector3 parentPos; Ogre::Quaternion parentOrientation; Ogre::Vector3 parentScale; if (parentNode) { parentPos = parentNode->_getDerivedPosition(); parentOrientation = parentNode->_getDerivedOrientation(); parentScale = parentNode->_getDerivedScale(); } else { parentPos = Ogre::Vector3::ZERO; parentOrientation = Ogre::Quaternion::IDENTITY; parentScale = Ogre::Vector3::UNIT_SCALE; } // Handle animated entities bool isAnimated = entity->hasSkeleton(); if (isAnimated) { entity->addSoftwareAnimationRequest(false); entity->_updateAnimation(); } // Loop through each submesh Ogre::MeshPtr mesh = entity->getMesh(); for (uint i = 0; i < mesh->getNumSubMeshes(); ++i) { Ogre::SubMesh* subMesh = mesh->getSubMesh(i); // Ignore anything that isn't a triangle List if (subMesh->operationType != Ogre::RenderOperation::OT_TRIANGLE_LIST) continue; // Get the vertex data Ogre::VertexData* vertexData; if (subMesh->useSharedVertices) { if (isAnimated) vertexData = entity->_getSkelAnimVertexData(); else vertexData = mesh->sharedVertexData; } else { if (isAnimated) vertexData = entity->getSubEntity(i)->_getSkelAnimVertexData(); else vertexData = subMesh->vertexData; } // Get the size of one vertex const Ogre::VertexElement* posEl = vertexData->vertexDeclaration->findElementBySemantic(Ogre::VES_POSITION); Ogre::HardwareVertexBufferSharedPtr vBuff = vertexData->vertexBufferBinding->getBuffer(posEl->getSource()); uint vertexSize = vBuff->getVertexSize(); // Save pointer to first vertex short* pVertex = (short*)vBuff->lock(Ogre::HardwareBuffer::HBL_READ_ONLY); short* pStartVertex = pVertex; // Get the index buffer // If it is null then skip as it must be a point cloud Ogre::HardwareIndexBufferSharedPtr iBuff = subMesh->indexData->indexBuffer; if (iBuff.isNull()) continue; uint* pLong = (uint*)iBuff->lock(Ogre::HardwareBuffer::HBL_READ_ONLY); uint16_t* pShort = (uint16_t*)pLong; // Look through each vertex and check each triangle with the ray Ogre::Vector3 vertexPos; Ogre::Vector3 vertex1; Ogre::Vector3 vertex2; float* pReal; uint index; for (uint k = 0; k < subMesh->indexData->indexCount; k++) { // Read index value if (iBuff->getType() == Ogre::HardwareIndexBuffer::IT_32BIT) // if 32bit indexes { index = (uint)pLong[k]; } else { index = (uint)pShort[k]; } // Read referenced vertex pVertex = pStartVertex + (vertexSize * index); // calculate pointer posEl->baseVertexPointerToElement(pVertex, &pReal); // read vertex vertexPos = Ogre::Vector3(pReal[0], pReal[1], pReal[2]); // read position values // Apply world transformations if (parentNode) vertexPos = (parentOrientation * (vertexPos * parentScale)) + parentPos; // Figure out triangle and calculate the distance if it's the closest switch (k % 3) { case 0: vertex1 = vertexPos; break; case 1: vertex2 = vertexPos; break; case 2: RayToTriangleCheck(vertex1, vertex2, vertexPos, closestDistance, position, normal); break; default: break; } } iBuff->unlock(); vBuff->unlock(); } if (isAnimated) { entity->removeSoftwareAnimationRequest(false); } }
void CsCameraManager::Update() { static clock_t prevTime = clock(); static Ogre::Vector3 lerpPos; static Ogre::Quaternion slerpRot; static float linLerpStep; static float angLerpStep; clock_t curTime = clock(); float timeStep = (curTime - prevTime) / (float) CLOCKS_PER_SEC; Ogre::SceneNode* camNode = mCameraList[mCurrentCamera].second; // the interpolation ---------------------------------------- // the current camera is not actually used, the default camera is used to approximate // the current camera posA = mDefaultCamNode->_getDerivedPosition(); rotA = mDefaultCamNode->_getDerivedOrientation(); posB = camNode->_getDerivedPosition(); rotB = camNode->_getDerivedOrientation(); linLerpStep = 0.5 * timeStep / 0.12; // reaches half i 0.3 seconds angLerpStep = 0.5 * timeStep / 0.12; // for fast moving targets if (mTargetObject) { float linear = mTargetObject->GetLinearVelocity().length(); float angular = mTargetObject->GetAngularVelocity().length(); if (linear > 200.0f) { linLerpStep += (linear - 150) / 300.0f; angLerpStep += (linear - 150) / 300.0f; } if (angular > 3.0f) { linLerpStep += (angular - 2.0f) / 8.0f; angLerpStep += (angular - 2.0f) / 8.0f; } } if (linLerpStep > 1.0f) linLerpStep = 0.90f; if (angLerpStep > 1.0f) angLerpStep = 0.90f; if (linLerpStep < 0.0f) linLerpStep = 0.1f; if (angLerpStep < 0.0f) angLerpStep = 0.1f; lerpPos = (posB - posA) * linLerpStep + posA; slerpRot = Ogre::Quaternion::Slerp(angLerpStep, rotA, rotB, true); mDefaultCamNode->setPosition(lerpPos); mDefaultCamNode->setOrientation(slerpRot); // ---------------------------------------------------------- if (mCameraType[mCurrentCamera] == Chaos::ORBIT_CAMERA) { Orbit(timeStep); } else if (mCameraType[mCurrentCamera] == Chaos::FREE_CAMERA) { if ( mButtonState[Chaos::ARROW_UP]) camNode->translate(0,0,-timeStep * MOVE_SPEED, Ogre::Node::TS_LOCAL); if ( mButtonState[Chaos::ARROW_DOWN]) camNode->translate(0,0,timeStep * MOVE_SPEED, Ogre::Node::TS_LOCAL); if ( mButtonState[Chaos::ARROW_LEFT]) camNode->translate(-timeStep * MOVE_SPEED,0,0, Ogre::Node::TS_LOCAL); if ( mButtonState[Chaos::ARROW_RIGHT]) camNode->translate(timeStep * MOVE_SPEED,0,0, Ogre::Node::TS_LOCAL); if (xrel) camNode->yaw(Ogre::Radian(Ogre::Degree(-LOOK_SPEED * xrel * timeStep)), Ogre::Node::TS_WORLD); if (yrel) camNode->pitch(Ogre::Radian(Ogre::Degree(-LOOK_SPEED * yrel * timeStep)), Ogre::Node::TS_LOCAL); } xrel = yrel = zrel = 0; prevTime = curTime; }
void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh) { Ogre::SceneNode* insert = ptr.getRefData().getBaseNode(); assert(insert); Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; NifOgre::EntityList entities = NifOgre::NIFLoader::createEntities(insert, NULL, mesh); for(size_t i = 0;i < entities.mEntities.size();i++) { const Ogre::AxisAlignedBox &tmp = entities.mEntities[i]->getBoundingBox(); bounds.merge(Ogre::AxisAlignedBox(insert->_getDerivedPosition() + tmp.getMinimum(), insert->_getDerivedPosition() + tmp.getMaximum()) ); } Ogre::Vector3 extents = bounds.getSize(); extents *= insert->getScale(); float size = std::max(std::max(extents.x, extents.y), extents.z); bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) && Settings::Manager::getBool("limit small object distance", "Viewing distance"); // do not fade out doors. that will cause holes and look stupid if (ptr.getTypeName().find("Door") != std::string::npos) small = false; if (mBounds.find(ptr.getCell()) == mBounds.end()) mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL; mBounds[ptr.getCell()].merge(bounds); bool transparent = false; for(size_t i = 0;i < entities.mEntities.size();i++) { Ogre::Entity *ent = entities.mEntities[i]; for (unsigned int i=0; i<ent->getNumSubEntities(); ++i) { Ogre::MaterialPtr mat = ent->getSubEntity(i)->getMaterial(); Ogre::Material::TechniqueIterator techIt = mat->getTechniqueIterator(); while (techIt.hasMoreElements()) { Ogre::Technique* tech = techIt.getNext(); Ogre::Technique::PassIterator passIt = tech->getPassIterator(); while (passIt.hasMoreElements()) { Ogre::Pass* pass = passIt.getNext(); if (pass->getDepthWriteEnabled() == false) transparent = true; } } } } if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || transparent) { for(size_t i = 0;i < entities.mEntities.size();i++) { Ogre::Entity *ent = entities.mEntities[i]; ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); ent->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); } } else { Ogre::StaticGeometry* sg = 0; if (small) { if( mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end()) { uniqueID = uniqueID +1; sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID)); mStaticGeometrySmall[ptr.getCell()] = sg; sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance")); } else sg = mStaticGeometrySmall[ptr.getCell()]; } else { if( mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end()) { uniqueID = uniqueID +1; sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID)); mStaticGeometry[ptr.getCell()] = sg; } else sg = mStaticGeometry[ptr.getCell()]; } // This specifies the size of a single batch region. // If it is set too high: // - there will be problems choosing the correct lights // - the culling will be more inefficient // If it is set too low: // - there will be too many batches. sg->setRegionDimensions(Ogre::Vector3(2500,2500,2500)); sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics); sg->setCastShadows(true); sg->setRenderQueueGroup(transparent ? RQG_Alpha : RQG_Main); for(size_t i = 0;i < entities.mEntities.size();i++) { Ogre::Entity *ent = entities.mEntities[i]; insert->detachObject(ent); sg->addEntity(ent,insert->_getDerivedPosition(),insert->_getDerivedOrientation(),insert->_getDerivedScale()); mRenderer.getScene()->destroyEntity(ent); } } }
void Objects::insertMesh (const MWWorld::Ptr& ptr, const std::string& mesh, bool light) { Ogre::SceneNode* insert = ptr.getRefData().getBaseNode(); assert(insert); Ogre::AxisAlignedBox bounds = Ogre::AxisAlignedBox::BOX_NULL; NifOgre::ObjectList objects = NifOgre::Loader::createObjects(insert, mesh); for(size_t i = 0;i < objects.mEntities.size();i++) bounds.merge(objects.mEntities[i]->getWorldBoundingBox(true)); Ogre::Vector3 extents = bounds.getSize(); extents *= insert->getScale(); float size = std::max(std::max(extents.x, extents.y), extents.z); bool small = (size < Settings::Manager::getInt("small object size", "Viewing distance")) && Settings::Manager::getBool("limit small object distance", "Viewing distance"); // do not fade out doors. that will cause holes and look stupid if (ptr.getTypeName().find("Door") != std::string::npos) small = false; if (mBounds.find(ptr.getCell()) == mBounds.end()) mBounds[ptr.getCell()] = Ogre::AxisAlignedBox::BOX_NULL; mBounds[ptr.getCell()].merge(bounds); bool anyTransparency = false; for(size_t i = 0;!anyTransparency && i < objects.mEntities.size();i++) { Ogre::Entity *ent = objects.mEntities[i]; for(unsigned int i=0;!anyTransparency && i < ent->getNumSubEntities(); ++i) { anyTransparency = ent->getSubEntity(i)->getMaterial()->isTransparent(); } } if(!mIsStatic || !Settings::Manager::getBool("use static geometry", "Objects") || anyTransparency || objects.mParticles.size() > 0) { for(size_t i = 0;i < objects.mEntities.size();i++) { Ogre::Entity *ent = objects.mEntities[i]; for(unsigned int i=0; i < ent->getNumSubEntities(); ++i) { Ogre::SubEntity* subEnt = ent->getSubEntity(i); subEnt->setRenderQueueGroup(subEnt->getMaterial()->isTransparent() ? RQG_Alpha : RQG_Main); } ent->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); ent->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); } for(size_t i = 0;i < objects.mParticles.size();i++) { Ogre::ParticleSystem *part = objects.mParticles[i]; // TODO: Check the particle system's material for actual transparency part->setRenderQueueGroup(RQG_Alpha); part->setRenderingDistance(small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0); part->setVisibilityFlags(mIsStatic ? (small ? RV_StaticsSmall : RV_Statics) : RV_Misc); } } else { Ogre::StaticGeometry* sg = 0; if (small) { if( mStaticGeometrySmall.find(ptr.getCell()) == mStaticGeometrySmall.end()) { uniqueID = uniqueID +1; sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID)); mStaticGeometrySmall[ptr.getCell()] = sg; sg->setRenderingDistance(Settings::Manager::getInt("small object distance", "Viewing distance")); } else sg = mStaticGeometrySmall[ptr.getCell()]; } else { if( mStaticGeometry.find(ptr.getCell()) == mStaticGeometry.end()) { uniqueID = uniqueID +1; sg = mRenderer.getScene()->createStaticGeometry( "sg" + Ogre::StringConverter::toString(uniqueID)); mStaticGeometry[ptr.getCell()] = sg; } else sg = mStaticGeometry[ptr.getCell()]; } // This specifies the size of a single batch region. // If it is set too high: // - there will be problems choosing the correct lights // - the culling will be more inefficient // If it is set too low: // - there will be too many batches. sg->setRegionDimensions(Ogre::Vector3(2500,2500,2500)); sg->setVisibilityFlags(small ? RV_StaticsSmall : RV_Statics); sg->setCastShadows(true); sg->setRenderQueueGroup(RQG_Main); std::vector<Ogre::Entity*>::reverse_iterator iter = objects.mEntities.rbegin(); while(iter != objects.mEntities.rend()) { Ogre::Node *node = (*iter)->getParentNode(); sg->addEntity(*iter, node->_getDerivedPosition(), node->_getDerivedOrientation(), node->_getDerivedScale()); (*iter)->detachFromParent(); mRenderer.getScene()->destroyEntity(*iter); iter++; } } if (light) { insertLight(ptr, objects.mSkelBase, bounds.getCenter() - insert->_getDerivedPosition()); } }