diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index c9991b58e..0c53fd41d 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -186,60 +186,30 @@ void CSVRender::PagedWorldspaceWidget::mouseReleaseEvent (QMouseEvent *event) } } } - - // mouse picking - // FIXME: need to virtualise mouse buttons - int viewportWidth = getCamera()->getViewport()->getActualWidth(); - int viewportHeight = getCamera()->getViewport()->getActualHeight(); - - float mouseX = (float) event->x()/viewportWidth; - float mouseY = (float) event->y()/viewportHeight; - - getPhysics()->castRay(mouseX, mouseY, NULL, NULL, getCamera()); - //Ogre::Ray mouseRay = getCamera()->getCameraToViewportRay(mouseX, mouseY); - - // Issue: Say 800 pixels (a typical viewport size) representing 8000 units (in one cell) - // So best case resolution is 10 units per pixel. - -#if 0 - Ogre::RaySceneQuery *rayScnQuery = getSceneManager()->createRayQuery(Ogre::Ray()); - rayScnQuery->setRay(mouseRay); - rayScnQuery->setSortByDistance(true); - // kinda works, but bounding box tests aren't accurate - Ogre::RaySceneQueryResult result = rayScnQuery->execute(); - - std::cout << "geometry: " + std::to_string(width()) + ", " + std::to_string(height()) << std::endl; - std::cout << "event: " + std::to_string(event->x()) + ", " + std::to_string(event->y()) << std::endl; - std::cout << "viewport: " + std::to_string(viewportWidth) + ", " + std::to_string(viewportHeight) << std::endl; - std::cout << "mouse: " + std::to_string(mouseX) + ", " + std::to_string(mouseY) << std::endl; - - std::cout << "camera: " + std::to_string(getCamera()->getPosition().x) - + ", " + std::to_string(getCamera()->getPosition().y) - + ", " + std::to_string(getCamera()->getPosition().z) - << std::endl; - std::cout << "ray origin: " + std::to_string(mouseRay.getOrigin().x) - + ", " + std::to_string(mouseRay.getOrigin().y) - + ", " + std::to_string(mouseRay.getOrigin().z) - << std::endl; - std::cout << "ray direction: " + std::to_string(mouseRay.getDirection().x) - + ", " + std::to_string(mouseRay.getDirection().y) - + ", " + std::to_string(mouseRay.getDirection().z) - << std::endl; - //std::cout << "fov" + std::to_string(getCamera()->getFOVy().valueDegrees()) << std::endl; - - Ogre::Vector3 res; - Ogre::Vector3 direction = mouseRay.getDirection(); - OgreRay ray(getSceneManager()); - //if(!clicked && ray.RaycastFromPoint(getCamera()->getPosition(), direction, res)) - if(!clicked && ray.RaycastFromPoint(mouseRay.getOrigin(), direction, res)) + else { - //std::cout << "found: " << std::endl; - } + // mouse picking + // FIXME: need to virtualise mouse buttons + // Issue: Say 800 pixels (a typical viewport size) representing 8000 units (in one cell) + // So best case resolution is 10 units per pixel. + int viewportWidth = getCamera()->getViewport()->getActualWidth(); + int viewportHeight = getCamera()->getViewport()->getActualHeight(); - Ogre::Root::getSingleton().renderOneFrame(); // FIXME: for testing (to show the bounding box) + float mouseX = (float) event->x()/viewportWidth; + float mouseY = (float) event->y()/viewportHeight; - getSceneManager()->destroyQuery(rayScnQuery); + getPhysics()->castRay(mouseX, mouseY, NULL, NULL, getCamera()); +#if 0 + std::cout << "geometry: " + std::to_string(width()) + ", " + std::to_string(height()) << std::endl; + std::cout << "event: " + std::to_string(event->x()) + ", " + std::to_string(event->y()) << std::endl; + std::cout << "viewport: " + std::to_string(viewportWidth) + ", " + std::to_string(viewportHeight) << std::endl; + std::cout << "mouse: " + std::to_string(mouseX) + ", " + std::to_string(mouseY) << std::endl; + std::cout << "camera: " + std::to_string(getCamera()->getPosition().x) + + ", " + std::to_string(getCamera()->getPosition().y) + + ", " + std::to_string(getCamera()->getPosition().z) + << std::endl; #endif + } } void CSVRender::PagedWorldspaceWidget::mouseDoubleClickEvent (QMouseEvent *event) diff --git a/apps/opencs/view/render/scenewidget.cpp b/apps/opencs/view/render/scenewidget.cpp index bb7102f34..ca58d6fd4 100644 --- a/apps/opencs/view/render/scenewidget.cpp +++ b/apps/opencs/view/render/scenewidget.cpp @@ -51,6 +51,7 @@ namespace CSVRender mCamera->setPosition (300, 0, 0); mCamera->lookAt (0, 0, 0); mCamera->setNearClipDistance (0.1); + //mCamera->setProjectionType(Ogre::PT_ORTHOGRAPHIC); // FIXME: debugging only CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); diff --git a/apps/opencs/view/world/physicssystem.cpp b/apps/opencs/view/world/physicssystem.cpp index 5db37f068..39b402e62 100644 --- a/apps/opencs/view/world/physicssystem.cpp +++ b/apps/opencs/view/world/physicssystem.cpp @@ -1,24 +1,82 @@ #include "physicssystem.hpp" +#include // FIXME: debug only + #include #include +#include // FIXME: debug cursor position +#include // FIXME: visual highlight, clone +#include // FIXME: visual highlight, material +#include // FIXME: visual highlight, texture #include // FIXME: renderOneFrame #include -//#include -//#include - #include +#include "../../model/settings/usersettings.hpp" namespace CSVWorld { - PhysicsSystem::PhysicsSystem(Ogre::SceneManager *sceneMgr) + PhysicsSystem::PhysicsSystem(Ogre::SceneManager *sceneMgr) : mSceneMgr(sceneMgr) { // Create physics. shapeLoader is deleted by the physic engine NifBullet::ManualBulletShapeLoader* shapeLoader = new NifBullet::ManualBulletShapeLoader(); mEngine = new OEngine::Physic::PhysicEngine(shapeLoader); mEngine->setSceneManager(sceneMgr); // needed for toggleDebugRendering() + + // material for visual cue + Ogre::TexturePtr texture = Ogre::TextureManager::getSingleton().getByName("DynamicTrans"); + if(texture.isNull()) + { + texture = Ogre::TextureManager::getSingleton().createManual( + "DynamicTrans", // name + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, + Ogre::TEX_TYPE_2D, // type + 8, 8, // width & height + 0, // number of mipmaps + Ogre::PF_BYTE_BGRA, // pixel format + Ogre::TU_DEFAULT); // usage; should be TU_DYNAMIC_WRITE_ONLY_DISCARDABLE for + // textures updated very often (e.g. each frame) + + Ogre::HardwarePixelBufferSharedPtr pixelBuffer = texture->getBuffer(); + pixelBuffer->lock(Ogre::HardwareBuffer::HBL_NORMAL); + const Ogre::PixelBox& pixelBox = pixelBuffer->getCurrentLock(); + + uint8_t* pDest = static_cast(pixelBox.data); + + // Fill in some pixel data. This will give a semi-transparent colour, + // but this is of course dependent on the chosen pixel format. + for (size_t j = 0; j < 8; j++) + { + for(size_t i = 0; i < 8; i++) + { + *pDest++ = 255; // B + *pDest++ = 255; // G + *pDest++ = 127; // R + *pDest++ = 63; // A + } + + pDest += pixelBox.getRowSkip() * Ogre::PixelUtil::getNumElemBytes(pixelBox.format); + } + pixelBuffer->unlock(); + } + Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().getByName( + "TransMaterial"); + if(material.isNull()) + { + Ogre::MaterialPtr material = Ogre::MaterialManager::getSingleton().create( + "TransMaterial", + Ogre::ResourceGroupManager::DEFAULT_RESOURCE_GROUP_NAME, true ); + Ogre::Pass *pass = material->getTechnique( 0 )->getPass( 0 ); + pass->setLightingEnabled( false ); + pass->setDepthWriteEnabled( false ); + pass->setSceneBlending( Ogre::SBT_TRANSPARENT_ALPHA ); + + Ogre::TextureUnitState *tex = pass->createTextureUnitState("CustomState", 0); + tex->setTextureName("DynamicTrans"); + tex->setTextureFiltering( Ogre::TFO_ANISOTROPIC ); + material->load(); + } } PhysicsSystem::~PhysicsSystem() @@ -46,17 +104,17 @@ namespace CSVWorld { mEngine->toggleDebugRendering(); mEngine->stepSimulation(0.0167); // FIXME: DebugDrawer::step() not accessible - Ogre::Root::getSingleton().renderOneFrame(); // FIXME: temporary workaround for immediate visual feedback + Ogre::Root::getSingleton().renderOneFrame(); // FIXME: temporary workaround for immediate visual feedback } /*std::pair*/ void PhysicsSystem::castRay(float mouseX, float mouseY, Ogre::Vector3* normal, std::string* hit, Ogre::Camera *camera) { - Ogre::Ray ray = camera->getCameraToViewportRay( - mouseX, - mouseY); + Ogre::Ray ray = camera->getCameraToViewportRay(mouseX, mouseY); Ogre::Vector3 from = ray.getOrigin(); - Ogre::Vector3 to = ray.getPoint(200000); + CSMSettings::UserSettings &userSettings = CSMSettings::UserSettings::instance(); + float farClipDist = userSettings.setting("Scene/far clip distance", QString("300000")).toFloat(); + Ogre::Vector3 to = ray.getPoint(farClipDist); //Ogre::Vector3 to = ray.getDirection(); btVector3 _from, _to; @@ -66,7 +124,8 @@ namespace CSVWorld bool raycastingObjectOnly = true; bool ignoreHeightMap = false; Ogre::Vector3 norm; - std::pair result = mEngine->rayTest(_from, _to, raycastingObjectOnly, ignoreHeightMap, &norm); + std::pair result = + mEngine->rayTest(_from, _to, raycastingObjectOnly, ignoreHeightMap, &norm); if (result.first == "") //return std::make_pair(false, Ogre::Vector3()); @@ -74,13 +133,97 @@ namespace CSVWorld else { std::cout << "hit " << result.first - + " result " + std::to_string(result.second) << std::endl; + + " result " + std::to_string(result.second*farClipDist) << std::endl; std::cout << "normal " + std::to_string(norm.x) + ", " + std::to_string(norm.y) + ", " + std::to_string(norm.z) << std::endl; - std::cout << "hit pos" + std::to_string(ray.getPoint(200000*result.second).x) - + ", " + std::to_string(ray.getPoint(200000*result.second).y) - + ", " + std::to_string(ray.getPoint(200000*result.second).z) << std::endl; + std::cout << "hit pos "+ std::to_string(ray.getPoint(farClipDist*result.second).x) + + ", " + std::to_string(ray.getPoint(farClipDist*result.second).y) + + ", " + std::to_string(ray.getPoint(farClipDist*result.second).z) << std::endl; + if(mSceneMgr->hasSceneNode(result.first)) + { + // FIXME: for debugging cursor position + // If using orthographic projection the cursor position is very accurate, + // but with the default perspective view the cursor position is not properly + // calculated when using getCameraToViewportRay. + // See http://www.ogre3d.org/forums/viewtopic.php?p=241933 + mSceneMgr->destroyManualObject("manual" + result.first); + Ogre::ManualObject* manual = mSceneMgr->createManualObject("manual" + result.first); + manual->begin("BaseWhite", Ogre::RenderOperation::OT_LINE_LIST); + manual-> position(ray.getPoint(farClipDist*result.second).x, + ray.getPoint(farClipDist*result.second).y, + ray.getPoint(farClipDist*result.second).z); + manual-> position(ray.getPoint(farClipDist*result.second).x, + ray.getPoint(farClipDist*result.second).y, + ray.getPoint(farClipDist*result.second).z+2000); + manual-> position(ray.getPoint(farClipDist*result.second).x, + ray.getPoint(farClipDist*result.second).y, + ray.getPoint(farClipDist*result.second).z); + manual-> position(ray.getPoint(farClipDist*result.second).x, + ray.getPoint(farClipDist*result.second).y+2000, + ray.getPoint(farClipDist*result.second).z); + manual-> position(ray.getPoint(farClipDist*result.second).x, + ray.getPoint(farClipDist*result.second).y, + ray.getPoint(farClipDist*result.second).z); + manual-> position(ray.getPoint(farClipDist*result.second).x+2000, + ray.getPoint(farClipDist*result.second).y, + ray.getPoint(farClipDist*result.second).z); + manual->end(); + mSceneMgr->getRootSceneNode()->createChildSceneNode()->attachObject(manual); + // end debugging cursor position + + Ogre::SceneNode *scene = mSceneMgr->getSceneNode(result.first); + std::map>::iterator iter = + mSelectedEntities.find(result.first); + if(iter != mSelectedEntities.end()) // currently selected + { + //scene->showBoundingBox(false); + std::vector deletedEntities = mSelectedEntities[result.first]; + while(!deletedEntities.empty()) + { + scene->detachObject(deletedEntities.back()); + mSceneMgr->destroyEntity(deletedEntities.back()); + deletedEntities.pop_back(); + } + mSelectedEntities.erase(iter); + mSceneMgr->destroyManualObject("manual" + result.first); + } + else + { + //scene->showBoundingBox(true); + std::vector clonedEntities; + Ogre::SceneNode::ObjectIterator iter = scene->getAttachedObjectIterator(); + iter.begin(); + while(iter.hasMoreElements()) + { + Ogre::MovableObject * element = iter.getNext(); + if(element->getMovableType() != "Entity") + continue; + + Ogre::Entity * e = dynamic_cast(element); + if(mSceneMgr->hasEntity(e->getName()+"cover")) + { + // FIXME: this shouldn't really happen... + scene->detachObject(e->getName()+"cover"); + mSceneMgr->destroyEntity(e->getName()+"cover"); + } + Ogre::Entity * clone = e->clone(e->getName()+"cover"); + + Ogre::MaterialPtr mat = + Ogre::MaterialManager::getSingleton().getByName("TransMaterial"); + if(!mat.isNull()) + { + clone->setMaterial(mat); + scene->attachObject(clone); + clonedEntities.push_back(e->getName()+"cover"); + } + + } + mSelectedEntities[result.first] = clonedEntities; + } + // FIXME: temporary workaround for immediate visual feedback + Ogre::Root::getSingleton().renderOneFrame(); + } } } } diff --git a/apps/opencs/view/world/physicssystem.hpp b/apps/opencs/view/world/physicssystem.hpp index 0aeffc9b2..109a20893 100644 --- a/apps/opencs/view/world/physicssystem.hpp +++ b/apps/opencs/view/world/physicssystem.hpp @@ -2,6 +2,7 @@ #define CSV_WORLD_PHYSICSSYSTEM_H #include +#include namespace Ogre { @@ -25,7 +26,8 @@ namespace CSVWorld { std::map handleToMesh; OEngine::Physic::PhysicEngine* mEngine; - //Ogre::SceneManager *mSceneMgr; + Ogre::SceneManager *mSceneMgr; + std::map> mSelectedEntities; public: