diff --git a/apps/openmw/mwrender/objectpaging.cpp b/apps/openmw/mwrender/objectpaging.cpp index 4c8706caf8..365e8ec91b 100644 --- a/apps/openmw/mwrender/objectpaging.cpp +++ b/apps/openmw/mwrender/objectpaging.cpp @@ -14,6 +14,8 @@ #include #include #include +#include +#include #include #include @@ -33,18 +35,16 @@ namespace MWRender { - bool typeFilter(int type, bool far, bool activeGrid) + bool typeFilter(int type, bool far) { switch (type) { case ESM::REC_STAT: - return true; - - case ESM::REC_ACTI: // TODO enable when intersectionvisitor supported + case ESM::REC_ACTI: case ESM::REC_DOOR: - return !activeGrid; + return true; case ESM::REC_CONT: - return far ? false : !activeGrid; + return !far; default: return false; @@ -321,6 +321,21 @@ namespace MWRender } }; + class AddRefnumMarkerVisitor : public osg::NodeVisitor + { + public: + AddRefnumMarkerVisitor(const ESM::RefNum &refnum) : osg::NodeVisitor(TRAVERSE_ALL_CHILDREN), mRefnum(refnum) {} + ESM::RefNum mRefnum; + virtual void apply(osg::Geometry &node) + { + osg::ref_ptr marker (new RefnumMarker); + marker->mRefnum = mRefnum; + if (osg::Array* array = node.getVertexArray()) + marker->mNumVertices = array->getNumElements(); + node.getOrCreateUserDataContainer()->addUserObject(marker); + } + }; + ObjectPaging::ObjectPaging(Resource::SceneManager* sceneManager) : GenericResourceManager(nullptr) , mSceneManager(sceneManager) @@ -365,7 +380,7 @@ namespace MWRender { if (std::find(cell->mMovedRefs.begin(), cell->mMovedRefs.end(), ref.mRefNum) != cell->mMovedRefs.end()) continue; int type = store.findStatic(Misc::StringUtils::lowerCase(ref.mRefID)); - if (!typeFilter(type,size>=2,activeGrid)) continue; + if (!typeFilter(type,size>=2)) continue; if (deleted) { refs.erase(ref.mRefNum); continue; } refs[ref.mRefNum] = ref; } @@ -381,7 +396,7 @@ namespace MWRender bool deleted = it->second; if (deleted) { refs.erase(ref.mRefNum); continue; } int type = store.findStatic(Misc::StringUtils::lowerCase(ref.mRefID)); - if (!typeFilter(type,size>=2,activeGrid)) continue; + if (!typeFilter(type,size>=2)) continue; refs[ref.mRefNum] = ref; } } @@ -446,15 +461,32 @@ namespace MWRender std::string model = getModel(type, id, store); if (model.empty()) continue; model = "meshes/" + model; -/* + bool useAnim = type != ESM::REC_STAT; if (useAnim) + { model = Misc::ResourceHelpers::correctActorModelPath(model, mSceneManager->getVFS()); -*/ + if (activeGrid) + { + std::string kfname = Misc::StringUtils::lowerCase(model); + if(kfname.size() > 4 && kfname.compare(kfname.size()-4, 4, ".nif") == 0) + { + kfname.replace(kfname.size()-4, 4, ".kf"); + if (mSceneManager->getVFS()->exists(kfname)) + continue; + } + } + } + osg::ref_ptr cnode = mSceneManager->getTemplate(model, false); if (activeGrid) - refnumSet->mRefnums.insert(pair.first); + { + if (cnode->getNumChildrenRequiringUpdateTraversal() > 0 || SceneUtil::hasUserDescription(cnode, Constants::NightDayLabel) || SceneUtil::hasUserDescription(cnode, Constants::HerbalismLabel)) + continue; + else + refnumSet->mRefnums.insert(pair.first); + } { OpenThreads::ScopedLock lock(mDisabledMutex); @@ -472,9 +504,6 @@ namespace MWRender continue; } - if (activeGrid && cnode->getNumChildrenRequiringUpdateTraversal() > 0) - continue; - auto emplaced = nodes.emplace(cnode, InstanceList()); if (emplaced.second) { @@ -537,6 +566,20 @@ namespace MWRender osg::ref_ptr node = osg::clone(cnode, co); node->setUserDataContainer(nullptr); + if (activeGrid) + { + if (merge) + { + AddRefnumMarkerVisitor visitor(ref.mRefNum); + node->accept(visitor); + } + else + { + osg::ref_ptr marker = new RefnumMarker; marker->mRefnum = ref.mRefNum; + node->getOrCreateUserDataContainer()->addUserObject(marker); + } + } + trans->addChild(node); if (merge) @@ -636,7 +679,7 @@ namespace MWRender bool ObjectPaging::enableObject(int type, const ESM::RefNum & refnum, const osg::Vec3f& pos, bool enabled) { - if (!typeFilter(type, false, false)) + if (!typeFilter(type, false)) return false; { @@ -655,7 +698,7 @@ namespace MWRender bool ObjectPaging::blacklistObject(int type, const ESM::RefNum & refnum, const osg::Vec3f& pos) { - if (!typeFilter(type, false, true)) + if (!typeFilter(type, false)) return false; { diff --git a/apps/openmw/mwrender/objectpaging.hpp b/apps/openmw/mwrender/objectpaging.hpp index 4419cd86a9..03d9ccfad0 100644 --- a/apps/openmw/mwrender/objectpaging.hpp +++ b/apps/openmw/mwrender/objectpaging.hpp @@ -63,6 +63,16 @@ namespace MWRender SizeCache mSizeCache; }; + class RefnumMarker : public osg::Object + { + public: + RefnumMarker() : mNumVertices(0) {} + RefnumMarker(const RefnumMarker ©, osg::CopyOp co) : mRefnum(copy.mRefnum), mNumVertices(copy.mNumVertices) {} + META_Object(MWRender, RefnumMarker) + + ESM::RefNum mRefnum; + unsigned int mNumVertices; + }; } #endif diff --git a/apps/openmw/mwrender/renderingmanager.cpp b/apps/openmw/mwrender/renderingmanager.cpp index 590c59302e..bb7528a20a 100644 --- a/apps/openmw/mwrender/renderingmanager.cpp +++ b/apps/openmw/mwrender/renderingmanager.cpp @@ -1016,6 +1016,7 @@ namespace MWRender { RenderingManager::RayResult result; result.mHit = false; + result.mHitRefnum.mContentFile = -1; result.mRatio = 0; if (intersector->containsIntersections()) { @@ -1027,6 +1028,7 @@ namespace MWRender result.mRatio = intersection.ratio; PtrHolder* ptrHolder = nullptr; + std::vector refnumMarkers; for (osg::NodePath::const_iterator it = intersection.nodePath.begin(); it != intersection.nodePath.end(); ++it) { osg::UserDataContainer* userDataContainer = (*it)->getUserDataContainer(); @@ -1036,11 +1038,25 @@ namespace MWRender { if (PtrHolder* p = dynamic_cast(userDataContainer->getUserObject(i))) ptrHolder = p; + if (RefnumMarker* r = dynamic_cast(userDataContainer->getUserObject(i))) + refnumMarkers.push_back(r); } } if (ptrHolder) result.mHitObject = ptrHolder->mPtr; + + unsigned int vertexCounter = 0; + for (unsigned int i=0; imNumVertices || (intersectionIndex >= vertexCounter && intersectionIndex < vertexCounter + refnumMarkers[i]->mNumVertices)) + { + result.mHitRefnum = refnumMarkers[i]->mRefnum; + break; + } + vertexCounter += refnumMarkers[i]->mNumVertices; + } } return result; diff --git a/apps/openmw/mwrender/renderingmanager.hpp b/apps/openmw/mwrender/renderingmanager.hpp index c46c2f3434..28376d1d67 100644 --- a/apps/openmw/mwrender/renderingmanager.hpp +++ b/apps/openmw/mwrender/renderingmanager.hpp @@ -157,6 +157,7 @@ namespace MWRender osg::Vec3f mHitNormalWorld; osg::Vec3f mHitPointWorld; MWWorld::Ptr mHitObject; + ESM::RefNum mHitRefnum; float mRatio; }; diff --git a/apps/openmw/mwworld/cellstore.cpp b/apps/openmw/mwworld/cellstore.cpp index 36f568a5f7..2cda83e17d 100644 --- a/apps/openmw/mwworld/cellstore.cpp +++ b/apps/openmw/mwworld/cellstore.cpp @@ -165,28 +165,6 @@ namespace ref.load (state); collection.mList.push_back (ref); } - - struct SearchByRefNumVisitor - { - MWWorld::LiveCellRefBase* mFound; - ESM::RefNum mRefNumToFind; - - SearchByRefNumVisitor(const ESM::RefNum& toFind) - : mFound(nullptr) - , mRefNumToFind(toFind) - { - } - - bool operator()(const MWWorld::Ptr& ptr) - { - if (ptr.getCellRef().getRefNum() == mRefNumToFind) - { - mFound = ptr.getBase(); - return false; - } - return true; - } - }; } namespace MWWorld @@ -263,9 +241,7 @@ namespace MWWorld throw std::runtime_error("moveTo: can't move object from a non-loaded cell (how did you get this object anyway?)"); // Ensure that the object actually exists in the cell - SearchByRefNumVisitor searchVisitor(object.getCellRef().getRefNum()); - forEach(searchVisitor); - if (!searchVisitor.mFound) + if (searchViaRefNum(object.getCellRef().getRefNum()).isEmpty()) throw std::runtime_error("moveTo: object is not in this cell"); @@ -942,26 +918,22 @@ namespace MWWorld movedTo.load(reader); // Search for the reference. It might no longer exist if its content file was removed. - SearchByRefNumVisitor visitor(refnum); - forEachInternal(visitor); - - if (!visitor.mFound) + Ptr movedRef = searchViaRefNum(refnum); + if (movedRef.isEmpty()) { Log(Debug::Warning) << "Warning: Dropping moved ref tag for " << refnum.mIndex << " (moved object no longer exists)"; continue; } - MWWorld::LiveCellRefBase* movedRef = visitor.mFound; - CellStore* otherCell = callback->getCellStore(movedTo); if (otherCell == nullptr) { - Log(Debug::Warning) << "Warning: Dropping moved ref tag for " << movedRef->mRef.getRefId() + Log(Debug::Warning) << "Warning: Dropping moved ref tag for " << movedRef.getCellRef().getRefId() << " (target cell " << movedTo.mWorldspace << " no longer exists). Reference moved back to its original location."; // Note by dropping tag the object will automatically re-appear in its original cell, though potentially at inapproriate coordinates. // Restore original coordinates: - movedRef->mData.setPosition(movedRef->mRef.getPosition()); + movedRef.getRefData().setPosition(movedRef.getCellRef().getPosition()); continue; } @@ -972,7 +944,7 @@ namespace MWWorld continue; } - moveTo(MWWorld::Ptr(movedRef, this), otherCell); + moveTo(movedRef, otherCell); } } diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2975240e78..5f1c8aaa25 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -1965,6 +1965,14 @@ namespace MWWorld rayToObject = mRendering->castCameraToViewportRay(0.5f, 0.5f, maxDistance, ignorePlayer); facedObject = rayToObject.mHitObject; + if (facedObject.isEmpty() && rayToObject.mHitRefnum.hasContentFile()) + { + for (CellStore* cellstore : mWorldScene->getActiveCells()) + { + facedObject = cellstore->searchViaRefNum(rayToObject.mHitRefnum); + if (!facedObject.isEmpty()) break; + } + } if (rayToObject.mHit) mDistanceToFacedObject = (rayToObject.mRatio * maxDistance) - camDist; else diff --git a/components/sceneutil/optimizer.cpp b/components/sceneutil/optimizer.cpp index 985fd9ee25..f0da9e7e24 100644 --- a/components/sceneutil/optimizer.cpp +++ b/components/sceneutil/optimizer.cpp @@ -1824,6 +1824,10 @@ bool Optimizer::MergeGeometryVisitor::mergeGeometry(osg::Geometry& lhs,osg::Geom lhs.dirtyBound(); lhs.dirtyDisplayList(); + if (osg::UserDataContainer* rhsUserData = rhs.getUserDataContainer()) + for (unsigned int i=0; igetNumUserObjects(); ++i) + lhs.getOrCreateUserDataContainer()->addUserObject(rhsUserData->getUserObject(i)); + return true; }