#include "OgrePlatformQueryManager.h" #include "OcclusionQuery.h" #include #include #include #include #include #include "OgrePlatformHierarchyInterface.h" namespace Ogre { //----------------------------------------------------------------------- void PlatformQueryManager::ComputeFromPointVisibility( const Vector3 &point, NodeInfoContainer *visibleNodes, MeshInfoContainer *visibleGeometry, PatchInfoContainer *visiblePatches, const bool relativeVisibility, const bool approximateVisibility) { SceneManager *sm = static_cast (mHierarchyInterface)->GetSceneManager(); // create a camera for the point query Camera *cam = sm->createCamera("PointQueryCam"); //save old camera Camera *savedCam = mViewport->getCamera(); ////////////// //-- initialise new camera mViewport->setCamera(cam); cam->setPosition(point); cam->setNearClipDistance(savedCam->getNearClipDistance()); cam->setFarClipDistance(savedCam->getFarClipDistance()); // set frustum to 45 degrees so all the scene can be captured with 6 shots cam->setAspectRatio(1.0); cam->setFOVy(Radian(Math::HALF_PI)); int sign = -1; /////////////// //-- capture visibility from all 6 directions for (int dir=0; dir < 6; dir++) { sign *= -1; // Print camera details if (0) { std::stringstream d; d << "Point query camera: " + StringConverter::toString(cam->getDerivedPosition()) + " " + "O: " + StringConverter::toString(cam->getDerivedOrientation()); LogManager::getSingleton().logMessage(d.str()); } // prevent from initialising geometry / node array again if (dir > 0) { mWasInitialised = true; } ComputeCameraVisibility(*cam, visibleNodes, visibleGeometry, visiblePatches, relativeVisibility, approximateVisibility); // permute directions Vector3 direction(0,0,0); direction[dir / 2] = sign; cam->setDirection(direction); } // reset camera mViewport->setCamera(savedCam); } //----------------------------------------------------------------------- void PlatformQueryManager::ComputeCameraVisibility( const Camera &camera, NodeInfoContainer *visibleNodes, MeshInfoContainer *visibleGeometry, PatchInfoContainer *visiblePatches, const bool relativeVisibility, const bool approximateVisibility) { // we need access to the scene manager and the rendersystem PlatformHierarchyInterface *pfHierarchyInterface = static_cast(mHierarchyInterface); SceneManager *sm = pfHierarchyInterface->GetSceneManager(); // const_cast allowed because camera is not changed in renderScene Camera *pCam = const_cast(&camera); // disable overlays, reset them later bool overlayEnabled = mViewport->getOverlaysEnabled(); mViewport->setOverlaysEnabled(false); // clear background with black (i.e., not a valid item id) ColourValue bg = mViewport->getBackgroundColour(); mViewport->setBackgroundColour(ColourValue(0, 0, 0, 0)); //pfHierarchyInterface->GetRenderSystem()->clearFrameBuffer(FBT_COLOUR | FBT_DEPTH); #ifdef ITEM_BUFFER // initialise item buffer (if not already initialised) InitItemBuffer(visibleGeometry, visiblePatches); ////////// //-- render scene with item buffer (i.e., objects with their id as color codes) // enable item buffer (must be provided by scene manager) bool useItemBuffer = true; sm->setOption("UseItemBuffer", &useItemBuffer); #endif // ITEM_BUFFER sm->_renderScene(pCam, mViewport, false); // render item buffer #ifdef ITEM_BUFFER ///////// //-- collect results CollectItemBufferResults(visibleGeometry, visiblePatches); ///////// //-- reset state useItemBuffer = false; // don't need item buffer anymore sm->setOption("UseItemBuffer", &useItemBuffer); #endif // ITEM_BUFFER mWasInitialised = false; // reset initialised - flag mViewport->setOverlaysEnabled(overlayEnabled); // reset old overlay status mViewport->setBackgroundColour(bg); // reset background color } #ifdef ITEM_BUFFER //----------------------------------------------------------------------- void PlatformQueryManager::CollectItemBufferResults( MeshInfoContainer *visibleGeometry, PatchInfoContainer *visiblePatches) { int dimx = 0; int dimy = 0; // copy frame buffer uchar *buf = mViewport->getTarget()->getBufferContents(dimx, dimy); // loop through frame buffer and collect visible pixels for (int idx = 0; idx < dimy * dimx * 3; idx += 3) { //-- decode color code to receive id int id = buf[idx] << 16; id += buf[idx + 1] << 8; id += buf[idx + 2]; // if valid id <= add visibility (id values start at 1) if (mQueryModes == PATCH_VISIBILITY) { if ((id > 0) && (id < (int)visiblePatches->size())) { ((*visiblePatches)[id]).AddVisibility(1, 0); } } else if (mQueryModes == GEOMETRY_VISIBILITY) { if ((id > 0) && (id < (int)visibleGeometry->size())) { ((*visibleGeometry)[id]).AddVisibility(1, 0); } } } delete [] buf; } //----------------------------------------------------------------------- void PlatformQueryManager::InitItemBuffer( MeshInfoContainer *visibleGeometry, PatchInfoContainer *visiblePatches) { if (mWasInitialised) return; mWasInitialised = true; SceneManager *sm = //static_cast(mHierarchyInterface)->GetSceneManager(); static_cast(mHierarchyInterface)->GetSceneManager(); SceneManager::EntityIterator it = sm->getEntityIterator(); // TODO: make the function more efficient visibleGeometry->clear(); visiblePatches->clear(); int id = 0; /* We can either use patches or meshes. If patches are used, an unique id must be given each patch. Otherwise the same id must be given to all patches belonging to the same mesh. */ while (it.hasMoreElements()) { Entity *ent = it.getNext(); for (int i = 0; i < (int)ent->getNumSubEntities(); ++i) { SubEntity *subEnt = ent->getSubEntity(i); if (mQueryModes == PATCH_VISIBILITY) { ++ id; visiblePatches->push_back(GtpVisibility::PatchInfo(subEnt, 0, 0)); } subEnt->setId(id); //subEnt->setId((41 << 16) + (4 << 8) + 60); } if (mQueryModes == GEOMETRY_VISIBILITY) { visibleGeometry->push_back(GtpVisibility::MeshInfo(ent, 0, 0)); ++ id; } } } #endif // ITEM_BUFFER //----------------------------------------------------------------------- void PlatformQueryManager::SetViewport(Viewport *vp) { mViewport = vp; } } // namespace Ogre