diff --git a/AUTHORS.md b/AUTHORS.md index 79cb87e64..6898c7a9a 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -94,6 +94,7 @@ Programmers Nolan Poe (nopoe) Paul Cercueil (pcercuei) Paul McElroy (Greendogo) + Pi03k Pieter van der Kloet (pvdk) pkubik Radu-Marius Popovici (rpopovici) diff --git a/apps/opencs/CMakeLists.txt b/apps/opencs/CMakeLists.txt index ee6a47db0..ec4737d16 100644 --- a/apps/opencs/CMakeLists.txt +++ b/apps/opencs/CMakeLists.txt @@ -90,7 +90,7 @@ opencs_units (view/render opencs_units_noqt (view/render lighting lightingday lightingnight - lightingbright object cell terrainstorage tagbase cellarrow cellmarker + lightingbright object cell terrainstorage tagbase cellarrow cellmarker cellborder ) opencs_hdrs_noqt (view/render diff --git a/apps/opencs/view/doc/subview.cpp b/apps/opencs/view/doc/subview.cpp index 67a8f8c70..82cbe835e 100644 --- a/apps/opencs/view/doc/subview.cpp +++ b/apps/opencs/view/doc/subview.cpp @@ -47,7 +47,7 @@ void CSVDoc::SubView::setUniversalId (const CSMWorld::UniversalId& id) void CSVDoc::SubView::closeEvent (QCloseEvent *event) { - emit updateSubViewIndicies (this); + emit updateSubViewIndices (this); } std::string CSVDoc::SubView::getTitle() const diff --git a/apps/opencs/view/doc/subview.hpp b/apps/opencs/view/doc/subview.hpp index 1c5f8a786..8402bf79a 100644 --- a/apps/opencs/view/doc/subview.hpp +++ b/apps/opencs/view/doc/subview.hpp @@ -64,7 +64,7 @@ namespace CSVDoc void updateTitle(); - void updateSubViewIndicies (SubView *view = 0); + void updateSubViewIndices (SubView *view = NULL); void universalIdChanged (const CSMWorld::UniversalId& universalId); diff --git a/apps/opencs/view/doc/view.cpp b/apps/opencs/view/doc/view.cpp index 3491c9de2..6f14e5a4d 100644 --- a/apps/opencs/view/doc/view.cpp +++ b/apps/opencs/view/doc/view.cpp @@ -343,7 +343,7 @@ void CSVDoc::View::updateTitle() setWindowTitle (QString::fromUtf8(stream.str().c_str())); } -void CSVDoc::View::updateSubViewIndicies(SubView *view) +void CSVDoc::View::updateSubViewIndices(SubView *view) { CSMPrefs::Category& windows = CSMPrefs::State::get()["Windows"]; @@ -373,7 +373,7 @@ void CSVDoc::View::updateSubViewIndicies(SubView *view) else { delete subView->titleBarWidget(); - subView->setTitleBarWidget (0); + subView->setTitleBarWidget (NULL); } } } @@ -402,7 +402,7 @@ void CSVDoc::View::updateActions() CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews) : mViewManager (viewManager), mDocument (document), mViewIndex (totalViews-1), - mViewTotal (totalViews), mScroll(0), mScrollbarOnly(false) + mViewTotal (totalViews), mScroll(NULL), mScrollbarOnly(false) { CSMPrefs::Category& windows = CSMPrefs::State::get()["Windows"]; @@ -419,10 +419,7 @@ CSVDoc::View::View (ViewManager& viewManager, CSMDoc::Document *document, int to } else { - mScroll = new QScrollArea(this); - mScroll->setWidgetResizable(true); - mScroll->setWidget(&mSubViewWindow); - setCentralWidget(mScroll); + createScrollArea(); } mOperations = new Operations; @@ -570,36 +567,11 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin // mScrollbarOnly = windows["mainwindow-scrollbar"].toString() == "Scrollbar Only"; - QDesktopWidget *dw = QApplication::desktop(); - QRect rect; - if (windows["grow-limit"].isTrue()) - rect = dw->screenGeometry(this); - else - rect = dw->screenGeometry(dw->screen(dw->screenNumber(this))); - - if (!mScrollbarOnly && mScroll && mSubViews.size() > 1) - { - int newWidth = width()+minWidth; - int frameWidth = frameGeometry().width() - width(); - if (newWidth+frameWidth <= rect.width()) - { - resize(newWidth, height()); - // WARNING: below code assumes that new subviews are added to the right - if (x() > rect.width()-(newWidth+frameWidth)) - move(rect.width()-(newWidth+frameWidth), y()); // shift left to stay within the screen - } - else - { - // full width - resize(rect.width()-frameWidth, height()); - mSubViewWindow.setMinimumWidth(mSubViewWindow.width()+minWidth); - move(0, y()); - } - } + updateWidth(windows["grow-limit"].isTrue(), minWidth); mSubViewWindow.addDockWidget (Qt::TopDockWidgetArea, view); - updateSubViewIndicies(); + updateSubViewIndices(); connect (view, SIGNAL (focusId (const CSMWorld::UniversalId&, const std::string&)), this, SLOT (addSubView (const CSMWorld::UniversalId&, const std::string&))); @@ -608,8 +580,8 @@ void CSVDoc::View::addSubView (const CSMWorld::UniversalId& id, const std::strin connect (view, SIGNAL (updateTitle()), this, SLOT (updateTitle())); - connect (view, SIGNAL (updateSubViewIndicies (SubView *)), - this, SLOT (updateSubViewIndicies (SubView *))); + connect (view, SIGNAL (updateSubViewIndices (SubView *)), + this, SLOT (updateSubViewIndices (SubView *))); view->show(); @@ -631,7 +603,7 @@ void CSVDoc::View::moveScrollBarToEnd(int min, int max) void CSVDoc::View::settingChanged (const CSMPrefs::Setting *setting) { if (*setting=="Windows/hide-subview") - updateSubViewIndicies (0); + updateSubViewIndices (NULL); else if (*setting=="Windows/mainwindow-scrollbar") { if (setting->toString()!="Grow Only") @@ -651,10 +623,7 @@ void CSVDoc::View::settingChanged (const CSMPrefs::Setting *setting) } else { - mScroll = new QScrollArea(this); - mScroll->setWidgetResizable(true); - mScroll->setWidget(&mSubViewWindow); - setCentralWidget(mScroll); + createScrollArea(); } } else if (mScroll) @@ -662,7 +631,7 @@ void CSVDoc::View::settingChanged (const CSMPrefs::Setting *setting) mScroll->takeWidget(); setCentralWidget (&mSubViewWindow); mScroll->deleteLater(); - mScroll = 0; + mScroll = NULL; } } } @@ -959,3 +928,41 @@ void CSVDoc::View::merge() { emit mergeDocument (mDocument); } + +void CSVDoc::View::updateWidth(bool isGrowLimit, int minSubViewWidth) +{ + QDesktopWidget *dw = QApplication::desktop(); + QRect rect; + if (isGrowLimit) + rect = dw->screenGeometry(this); + else + rect = dw->screenGeometry(dw->screen(dw->screenNumber(this))); + + if (!mScrollbarOnly && mScroll && mSubViews.size() > 1) + { + int newWidth = width()+minSubViewWidth; + int frameWidth = frameGeometry().width() - width(); + if (newWidth+frameWidth <= rect.width()) + { + resize(newWidth, height()); + // WARNING: below code assumes that new subviews are added to the right + if (x() > rect.width()-(newWidth+frameWidth)) + move(rect.width()-(newWidth+frameWidth), y()); // shift left to stay within the screen + } + else + { + // full width + resize(rect.width()-frameWidth, height()); + mSubViewWindow.setMinimumWidth(mSubViewWindow.width()+minSubViewWidth); + move(0, y()); + } + } +} + +void CSVDoc::View::createScrollArea() +{ + mScroll = new QScrollArea(this); + mScroll->setWidgetResizable(true); + mScroll->setWidget(&mSubViewWindow); + setCentralWidget(mScroll); +} diff --git a/apps/opencs/view/doc/view.hpp b/apps/opencs/view/doc/view.hpp index 7d5304269..d95499191 100644 --- a/apps/opencs/view/doc/view.hpp +++ b/apps/opencs/view/doc/view.hpp @@ -95,7 +95,8 @@ namespace CSVDoc void resizeViewHeight (int height); void updateScrollbar(); - + void updateWidth(bool isGrowLimit, int minSubViewWidth); + void createScrollArea(); public: View (ViewManager& viewManager, CSMDoc::Document *document, int totalViews); @@ -143,7 +144,7 @@ namespace CSVDoc void updateTitle(); // called when subviews are added or removed - void updateSubViewIndicies (SubView *view = 0); + void updateSubViewIndices (SubView *view = NULL); private slots: diff --git a/apps/opencs/view/render/cell.cpp b/apps/opencs/view/render/cell.cpp index 782a37796..9a352ffad 100644 --- a/apps/opencs/view/render/cell.cpp +++ b/apps/opencs/view/render/cell.cpp @@ -99,6 +99,9 @@ CSVRender::Cell::Cell (CSMWorld::Data& data, osg::Group* rootNode, const std::st mTerrain.reset(new Terrain::TerrainGrid(mCellNode, data.getResourceSystem().get(), NULL, new TerrainStorage(mData), Mask_Terrain)); mTerrain->loadCell(esmLand.mX, esmLand.mY); + + mCellBorder.reset(new CellBorder(mCellNode, mCoordinates)); + mCellBorder->buildShape(esmLand); } } } diff --git a/apps/opencs/view/render/cell.hpp b/apps/opencs/view/render/cell.hpp index 4af5e4a25..631df24aa 100644 --- a/apps/opencs/view/render/cell.hpp +++ b/apps/opencs/view/render/cell.hpp @@ -16,6 +16,7 @@ #include "object.hpp" #include "cellarrow.hpp" #include "cellmarker.hpp" +#include "cellborder.hpp" class QModelIndex; @@ -44,6 +45,7 @@ namespace CSVRender CSMWorld::CellCoordinates mCoordinates; std::auto_ptr mCellArrows[4]; std::auto_ptr mCellMarker; + std::auto_ptr mCellBorder; bool mDeleted; int mSubMode; unsigned int mSubModeElementMask; diff --git a/apps/opencs/view/render/cellborder.cpp b/apps/opencs/view/render/cellborder.cpp new file mode 100644 index 000000000..6073807ce --- /dev/null +++ b/apps/opencs/view/render/cellborder.cpp @@ -0,0 +1,96 @@ +#include "cellborder.hpp" + +#include +#include +#include +#include +#include + +#include + +#include "mask.hpp" + +#include "../../model/world/cellcoordinates.hpp" + +const int CSVRender::CellBorder::CellSize = ESM::Land::REAL_SIZE; +const int CSVRender::CellBorder::VertexCount = (ESM::Land::LAND_SIZE * 4) - 3; + + +CSVRender::CellBorder::CellBorder(osg::Group* cellNode, const CSMWorld::CellCoordinates& coords) + : mParentNode(cellNode) +{ + mBaseNode = new osg::PositionAttitudeTransform(); + mBaseNode->setNodeMask(Mask_CellBorder); + mBaseNode->setPosition(osg::Vec3f(coords.getX() * CellSize, coords.getY() * CellSize, 10)); + + mParentNode->addChild(mBaseNode); +} + +CSVRender::CellBorder::~CellBorder() +{ + mParentNode->removeChild(mBaseNode); +} + +void CSVRender::CellBorder::buildShape(const ESM::Land& esmLand) +{ + const ESM::Land::LandData* landData = esmLand.getLandData(ESM::Land::DATA_VHGT); + + if (!landData) + return; + + osg::ref_ptr geometry = new osg::Geometry(); + + // Vertices + osg::ref_ptr vertices = new osg::Vec3Array(); + + int x = 0, y = 0; + for (; x < ESM::Land::LAND_SIZE; ++x) + vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)])); + + x = ESM::Land::LAND_SIZE - 1; + for (; y < ESM::Land::LAND_SIZE; ++y) + vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)])); + + y = ESM::Land::LAND_SIZE - 1; + for (; x >= 0; --x) + vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)])); + + x = 0; + for (; y >= 0; --y) + vertices->push_back(osg::Vec3f(scaleToWorld(x), scaleToWorld(y), landData->mHeights[landIndex(x, y)])); + + geometry->setVertexArray(vertices); + + // Color + osg::ref_ptr colors = new osg::Vec4Array(); + colors->push_back(osg::Vec4f(0.f, 0.5f, 0.f, 1.f)); + + geometry->setColorArray(colors, osg::Array::BIND_PER_PRIMITIVE_SET); + + // Primitive + osg::ref_ptr primitives = + new osg::DrawElementsUShort(osg::PrimitiveSet::LINE_STRIP, VertexCount+1); + + for (size_t i = 0; i < VertexCount; ++i) + primitives->setElement(i, i); + + primitives->setElement(VertexCount, 0); + + geometry->addPrimitiveSet(primitives); + geometry->getOrCreateStateSet()->setMode(GL_LIGHTING, osg::StateAttribute::OFF); + + + osg::ref_ptr geode = new osg::Geode(); + geode->addDrawable(geometry); + mBaseNode->addChild(geode); +} + +size_t CSVRender::CellBorder::landIndex(int x, int y) +{ + return y * ESM::Land::LAND_SIZE + x; +} + +float CSVRender::CellBorder::scaleToWorld(int value) +{ + return (CellSize + 128) * (float)value / ESM::Land::LAND_SIZE; +} diff --git a/apps/opencs/view/render/cellborder.hpp b/apps/opencs/view/render/cellborder.hpp new file mode 100644 index 000000000..c91aa46c6 --- /dev/null +++ b/apps/opencs/view/render/cellborder.hpp @@ -0,0 +1,54 @@ +#ifndef OPENCS_VIEW_CELLBORDER_H +#define OPENCS_VIEW_CELLBORDER_H + +#include + +#include + +namespace osg +{ + class Group; + class PositionAttitudeTransform; +} + +namespace ESM +{ + struct Land; +} + +namespace CSMWorld +{ + class CellCoordinates; +} + +namespace CSVRender +{ + + class CellBorder + { + public: + + CellBorder(osg::Group* cellNode, const CSMWorld::CellCoordinates& coords); + ~CellBorder(); + + void buildShape(const ESM::Land& esmLand); + + private: + + static const int CellSize; + static const int VertexCount; + + size_t landIndex(int x, int y); + float scaleToWorld(int val); + + // unimplemented + CellBorder(const CellBorder&); + CellBorder& operator=(const CellBorder&); + + osg::Group* mParentNode; + osg::ref_ptr mBaseNode; + + }; +} + +#endif diff --git a/apps/opencs/view/render/pagedworldspacewidget.cpp b/apps/opencs/view/render/pagedworldspacewidget.cpp index 0ca3ff706..d96f36692 100644 --- a/apps/opencs/view/render/pagedworldspacewidget.cpp +++ b/apps/opencs/view/render/pagedworldspacewidget.cpp @@ -598,7 +598,7 @@ CSVWidget::SceneToolToggle *CSVRender::PagedWorldspaceWidget::makeControlVisibil mControlElements->addButton (":placeholder", Mask_CellMarker, ":placeholder", "Cell marker"); mControlElements->addButton (":placeholder", Mask_CellArrow, ":placeholder", "Cell arrows"); - mControlElements->addButton (":placeholder", Mask_CellBorder, ":placeholder", "Cell border"); + mControlElements->addButton (":scenetoolbar/grid", Mask_CellBorder, ":scenetoolbar/grid-small", "Cell border"); mControlElements->setSelectionMask (0xffffffff); diff --git a/apps/openmw/mwrender/animation.cpp b/apps/openmw/mwrender/animation.cpp index 7f7183b9e..5cf502476 100644 --- a/apps/openmw/mwrender/animation.cpp +++ b/apps/openmw/mwrender/animation.cpp @@ -1363,6 +1363,7 @@ namespace MWRender foundKeyframeCtrl = true; break; } + cb = cb->getNestedCallback(); } if (foundKeyframeCtrl) diff --git a/apps/openmw/mwrender/weaponanimation.cpp b/apps/openmw/mwrender/weaponanimation.cpp index 2627d3fc6..d5fb70d16 100644 --- a/apps/openmw/mwrender/weaponanimation.cpp +++ b/apps/openmw/mwrender/weaponanimation.cpp @@ -182,23 +182,30 @@ void WeaponAnimation::deleteControllers() void WeaponAnimation::configureControllers(float characterPitchRadians) { - if (!mSpineControllers[0]) - return; - if (mPitchFactor == 0.f || characterPitchRadians == 0.f) { - for (int i=0; i<2; ++i) - mSpineControllers[i]->setEnabled(false); + setControllerEnabled(false); return; } float pitch = characterPitchRadians * mPitchFactor; osg::Quat rotate (pitch/2, osg::Vec3f(-1,0,0)); + setControllerRotate(rotate); + setControllerEnabled(true); +} + +void WeaponAnimation::setControllerRotate(const osg::Quat& rotate) +{ for (int i=0; i<2; ++i) - { - mSpineControllers[i]->setRotate(rotate); - mSpineControllers[i]->setEnabled(true); - } + if (mSpineControllers[i]) + mSpineControllers[i]->setRotate(rotate); +} + +void WeaponAnimation::setControllerEnabled(bool enabled) +{ + for (int i=0; i<2; ++i) + if (mSpineControllers[i]) + mSpineControllers[i]->setEnabled(enabled); } } diff --git a/apps/openmw/mwrender/weaponanimation.hpp b/apps/openmw/mwrender/weaponanimation.hpp index 3bf0fb721..d50729c62 100644 --- a/apps/openmw/mwrender/weaponanimation.hpp +++ b/apps/openmw/mwrender/weaponanimation.hpp @@ -52,6 +52,9 @@ namespace MWRender osg::ref_ptr mSpineControllers[2]; + void setControllerRotate(const osg::Quat& rotate); + void setControllerEnabled(bool enabled); + virtual osg::Group* getArrowBone() = 0; virtual osg::Node* getWeaponNode() = 0; virtual Resource::ResourceSystem* getResourceSystem() = 0; diff --git a/apps/openmw/mwworld/worldimp.cpp b/apps/openmw/mwworld/worldimp.cpp index 2ab027cd6..0dbadca17 100644 --- a/apps/openmw/mwworld/worldimp.cpp +++ b/apps/openmw/mwworld/worldimp.cpp @@ -2039,7 +2039,7 @@ namespace MWWorld bool World::isUnderwater(const MWWorld::CellStore* cell, const osg::Vec3f &pos) const { - if (!(cell->getCell()->mData.mFlags & ESM::Cell::HasWater)) { + if (!(cell->getCell()->hasWater())) { return false; } return pos.z() < cell->getWaterLevel(); diff --git a/components/esm/loadcell.hpp b/components/esm/loadcell.hpp index f92e0b5b7..cab8cf65e 100644 --- a/components/esm/loadcell.hpp +++ b/components/esm/loadcell.hpp @@ -141,7 +141,7 @@ struct Cell bool hasWater() const { - return (mData.mFlags&HasWater) != 0; + return ((mData.mFlags&HasWater) != 0) || isExterior(); } // Restore the given reader to the stored position. Will try to open diff --git a/components/nifosg/nifloader.cpp b/components/nifosg/nifloader.cpp index ab6bfcff3..705dbe83a 100644 --- a/components/nifosg/nifloader.cpp +++ b/components/nifosg/nifloader.cpp @@ -470,7 +470,7 @@ namespace NifOsg const Nif::NiTextureEffect* textureEffect = static_cast(nifNode); if (textureEffect->textureType != Nif::NiTextureEffect::Environment_Map) { - std::cerr << "Unhandled NiTextureEffect type " << textureEffect->textureType << std::endl; + std::cerr << "Unhandled NiTextureEffect type " << textureEffect->textureType << " in " << mFilename << std::endl; return; } @@ -487,7 +487,7 @@ namespace NifOsg texGen->setMode(osg::TexGen::SPHERE_MAP); break; default: - std::cerr << "Unhandled NiTextureEffect coordGenType " << textureEffect->coordGenType << std::endl; + std::cerr << "Unhandled NiTextureEffect coordGenType " << textureEffect->coordGenType << " in " << mFilename << std::endl; return; } @@ -1374,17 +1374,15 @@ namespace NifOsg case Nif::NiTexturingProperty::DarkTexture: case Nif::NiTexturingProperty::BumpTexture: case Nif::NiTexturingProperty::DetailTexture: + case Nif::NiTexturingProperty::DecalTexture: break; case Nif::NiTexturingProperty::GlossTexture: { + // Not used by the vanilla engine. MCP (Morrowind Code Patch) adds an option to use Gloss maps: + // "- Gloss map fix. Morrowind removed gloss map entries from model files after loading them. This stops Morrowind from removing them." std::cerr << "NiTexturingProperty::GlossTexture in " << mFilename << " not currently used." << std::endl; continue; } - case Nif::NiTexturingProperty::DecalTexture: - { - std::cerr << "NiTexturingProperty::DecalTexture in " << mFilename << " not currently used." << std::endl; - continue; - } default: { std::cerr << "Warning: unhandled texture stage " << i << " in " << mFilename << std::endl; @@ -1435,16 +1433,16 @@ namespace NifOsg { osg::TexEnvCombine* texEnv = new osg::TexEnvCombine; texEnv->setScale_RGB(2.f); - texEnv->setCombine_Alpha(GL_MODULATE); - texEnv->setOperand0_Alpha(GL_SRC_ALPHA); - texEnv->setOperand1_Alpha(GL_SRC_ALPHA); - texEnv->setSource0_Alpha(GL_PREVIOUS_ARB); - texEnv->setSource1_Alpha(GL_TEXTURE); - texEnv->setCombine_RGB(GL_MODULATE); - texEnv->setOperand0_RGB(GL_SRC_COLOR); - texEnv->setOperand1_RGB(GL_SRC_COLOR); - texEnv->setSource0_RGB(GL_PREVIOUS_ARB); - texEnv->setSource1_RGB(GL_TEXTURE); + texEnv->setCombine_Alpha(osg::TexEnvCombine::MODULATE); + texEnv->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA); + texEnv->setOperand1_Alpha(osg::TexEnvCombine::SRC_ALPHA); + texEnv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); + texEnv->setSource1_Alpha(osg::TexEnvCombine::TEXTURE); + texEnv->setCombine_RGB(osg::TexEnvCombine::MODULATE); + texEnv->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR); + texEnv->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR); + texEnv->setSource0_RGB(osg::TexEnvCombine::PREVIOUS); + texEnv->setSource1_RGB(osg::TexEnvCombine::TEXTURE); stateset->setTextureAttributeAndModes(texUnit, texEnv, osg::StateAttribute::ON); } else if (i == Nif::NiTexturingProperty::BumpTexture) @@ -1452,6 +1450,21 @@ namespace NifOsg // Set this texture to Off by default since we can't render it with the fixed-function pipeline stateset->setTextureMode(texUnit, GL_TEXTURE_2D, osg::StateAttribute::OFF); } + else if (i == Nif::NiTexturingProperty::DecalTexture) + { + osg::TexEnvCombine* texEnv = new osg::TexEnvCombine; + texEnv->setCombine_RGB(osg::TexEnvCombine::INTERPOLATE); + texEnv->setSource0_RGB(osg::TexEnvCombine::TEXTURE); + texEnv->setOperand0_RGB(osg::TexEnvCombine::SRC_COLOR); + texEnv->setSource1_RGB(osg::TexEnvCombine::PREVIOUS); + texEnv->setOperand1_RGB(osg::TexEnvCombine::SRC_COLOR); + texEnv->setSource2_RGB(osg::TexEnvCombine::TEXTURE); + texEnv->setOperand2_RGB(osg::TexEnvCombine::SRC_ALPHA); + texEnv->setCombine_Alpha(osg::TexEnvCombine::REPLACE); + texEnv->setSource0_Alpha(osg::TexEnvCombine::PREVIOUS); + texEnv->setOperand0_Alpha(osg::TexEnvCombine::SRC_ALPHA); + stateset->setTextureAttributeAndModes(texUnit, texEnv, osg::StateAttribute::ON); + } switch (i) { @@ -1470,6 +1483,9 @@ namespace NifOsg case Nif::NiTexturingProperty::DetailTexture: texture2d->setName("detailMap"); break; + case Nif::NiTexturingProperty::DecalTexture: + texture2d->setName("decalMap"); + break; default: break; } diff --git a/components/resource/resourcemanager.cpp b/components/resource/resourcemanager.cpp index 0a9784e6b..d19d9cf80 100644 --- a/components/resource/resourcemanager.cpp +++ b/components/resource/resourcemanager.cpp @@ -13,6 +13,10 @@ namespace Resource } + ResourceManager::~ResourceManager() + { + } + void ResourceManager::updateCache(double referenceTime) { mCache->updateTimeStampOfObjectsInCacheWithExternalReferences(referenceTime); diff --git a/components/resource/resourcemanager.hpp b/components/resource/resourcemanager.hpp index 34fce0145..b69256834 100644 --- a/components/resource/resourcemanager.hpp +++ b/components/resource/resourcemanager.hpp @@ -18,6 +18,7 @@ namespace Resource { public: ResourceManager(const VFS::Manager* vfs); + virtual ~ResourceManager(); /// Clear cache entries that have not been referenced for longer than expiryDelay. virtual void updateCache(double referenceTime); diff --git a/components/sceneutil/attach.cpp b/components/sceneutil/attach.cpp index 38330901d..8ac0aa992 100644 --- a/components/sceneutil/attach.cpp +++ b/components/sceneutil/attach.cpp @@ -102,9 +102,15 @@ namespace SceneUtil // Need to invert culling because of the negative scale // Note: for absolute correctness we would need to check the current front face for every mesh then invert it // However MW isn't doing this either, so don't. Assuming all meshes are using backface culling is more efficient. - osg::FrontFace* frontFace = new osg::FrontFace; - frontFace->setMode(osg::FrontFace::CLOCKWISE); - trans->getOrCreateStateSet()->setAttributeAndModes(frontFace, osg::StateAttribute::ON); + static osg::ref_ptr frontFaceStateSet; + if (!frontFaceStateSet) + { + frontFaceStateSet = new osg::StateSet; + osg::FrontFace* frontFace = new osg::FrontFace; + frontFace->setMode(osg::FrontFace::CLOCKWISE); + frontFaceStateSet->setAttributeAndModes(frontFace, osg::StateAttribute::ON); + } + trans->setStateSet(frontFaceStateSet); } if (trans) diff --git a/components/shader/shadervisitor.cpp b/components/shader/shadervisitor.cpp index b06ceafde..92bdac7b7 100644 --- a/components/shader/shadervisitor.cpp +++ b/components/shader/shadervisitor.cpp @@ -88,11 +88,11 @@ namespace Shader return newStateSet.get(); } - const char* defaultTextures[] = { "diffuseMap", "normalMap", "emissiveMap", "darkMap", "detailMap", "envMap", "specularMap" }; + const char* defaultTextures[] = { "diffuseMap", "normalMap", "emissiveMap", "darkMap", "detailMap", "envMap", "specularMap", "decalMap" }; bool isTextureNameRecognized(const std::string& name) { for (unsigned int i=0; iflying eye.png orbit2.png scene-play.png + grid-view.png + grid-view-small.png scene-view-references.png scene-view-terrain.png scene-view-water.png diff --git a/files/shaders/objects_fragment.glsl b/files/shaders/objects_fragment.glsl index a648f8484..2304d9ade 100644 --- a/files/shaders/objects_fragment.glsl +++ b/files/shaders/objects_fragment.glsl @@ -15,6 +15,11 @@ uniform sampler2D detailMap; varying vec2 detailMapUV; #endif +#if @decalMap +uniform sampler2D decalMap; +varying vec2 decalMapUV; +#endif + #if @emissiveMap uniform sampler2D emissiveMap; varying vec2 emissiveMapUV; @@ -67,6 +72,11 @@ void main() gl_FragData[0].xyz *= texture2D(darkMap, darkMapUV).xyz; #endif +#if @decalMap + vec4 decalTex = texture2D(decalMap, decalMapUV); + gl_FragData[0].xyz = mix(gl_FragData[0].xyz, decalTex.xyz, decalTex.a); +#endif + vec3 viewNormal = passViewNormal; #if @normalMap diff --git a/files/shaders/objects_vertex.glsl b/files/shaders/objects_vertex.glsl index b1004aad3..b65e49666 100644 --- a/files/shaders/objects_vertex.glsl +++ b/files/shaders/objects_vertex.glsl @@ -12,6 +12,10 @@ varying vec2 darkMapUV; varying vec2 detailMapUV; #endif +#if @decalMap +varying vec2 decalMapUV; +#endif + #if @emissiveMap varying vec2 emissiveMapUV; #endif @@ -68,7 +72,11 @@ void main(void) #endif #if @detailMap - detailMapUV = (gl_TextureMatrix[@detailMap] * gl_MultiTexCoord@detailMap).xy; + detailMapUV = (gl_TextureMatrix[@detailMapUV] * gl_MultiTexCoord@detailMapUV).xy; +#endif + +#if @decalMap + decalMapUV = (gl_TextureMatrix[@decalMapUV] * gl_MultiTexCoord@decalMapUV).xy; #endif #if @emissiveMap