Merge pull request #145 from OpenMW/master while resolving conflicts

# Conflicts:
#	CMakeLists.txt
pull/163/head
David Cernat 8 years ago
commit ae23c6d6a5

@ -46,7 +46,7 @@ if(EXISTS ${PROJECT_SOURCE_DIR}/.git)
else(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
message(STATUS "Shallow Git clone detected, not attempting to retrieve version info")
endif(NOT EXISTS ${PROJECT_SOURCE_DIR}/.git/shallow)
endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
endif(EXISTS ${PROJECT_SOURCE_DIR}/.git)
# Macros
include(OpenMWMacros)
@ -165,10 +165,10 @@ else()
endif()
IF(BUILD_OPENMW OR BUILD_OPENCS)
# Sound setup
find_package(FFmpeg REQUIRED COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE)
# Required for building the FFmpeg headers
add_definitions(-D__STDC_CONSTANT_MACROS)
# Sound setup
find_package(FFmpeg REQUIRED COMPONENTS AVCODEC AVFORMAT AVUTIL SWSCALE SWRESAMPLE)
# Required for building the FFmpeg headers
add_definitions(-D__STDC_CONSTANT_MACROS)
# TinyXML
option(USE_SYSTEM_TINYXML "Use system TinyXML library instead of internal." OFF)
@ -252,10 +252,15 @@ IF(BUILD_OPENMW OR BUILD_OPENCS)
endif()
endif()
set(REQUIRED_BULLET_VERSION 286) # Bullet 286 required due to runtime bugfixes for btCapsuleShape
if (DEFINED ENV{TRAVIS_BRANCH} OR DEFINED ENV{APPVEYOR})
set(REQUIRED_BULLET_VERSION 283) # but for build testing, 283 is fine
endif()
find_package(MyGUI 3.2.1 REQUIRED)
find_package(SDL2 REQUIRED)
find_package(OpenAL REQUIRED)
find_package(Bullet 283 REQUIRED COMPONENTS BulletCollision LinearMath)
find_package(Bullet ${REQUIRED_BULLET_VERSION} REQUIRED COMPONENTS BulletCollision LinearMath)
ENDIF(BUILD_OPENMW OR BUILD_OPENCS)

@ -675,8 +675,6 @@ void OMW::Engine::go()
}
else if (!mSkipMenu)
{
mEnvironment.getWorld()->preloadCommonAssets();
// start in main menu
mEnvironment.getWindowManager()->pushGuiMode (MWGui::GM_MainMenu);
try

@ -95,8 +95,6 @@ namespace MWBase
virtual ~World() {}
virtual void preloadCommonAssets() = 0;
virtual void startNewGame (bool bypass) = 0;
///< \param bypass Bypass regular game start.

@ -268,12 +268,12 @@ namespace MWPhysics
( (toOsg(resultCallback1.m_hitPointWorld) - tracer.mEndPos).length2() > 35*35
|| !isWalkableSlope(tracer.mPlaneNormal)))
{
actor->setOnSlope(isWalkableSlope(resultCallback1.m_hitNormalWorld));
actor->setOnSlope(!isWalkableSlope(resultCallback1.m_hitNormalWorld));
return toOsg(resultCallback1.m_hitPointWorld) + osg::Vec3f(0.f, 0.f, 1.f);
}
else
{
actor->setOnSlope(isWalkableSlope(tracer.mPlaneNormal));
actor->setOnSlope(!isWalkableSlope(tracer.mPlaneNormal));
}
return tracer.mEndPos;

@ -543,7 +543,7 @@ namespace MWRender
size_t blendMask = detectBlendMask(node);
// clone the controller, because each Animation needs its own ControllerSource
osg::ref_ptr<NifOsg::KeyframeController> cloned = osg::clone(it->second.get(), osg::CopyOp::DEEP_COPY_ALL);
osg::ref_ptr<NifOsg::KeyframeController> cloned = new NifOsg::KeyframeController(*it->second, osg::CopyOp::SHALLOW_COPY);
cloned->setSource(mAnimationTimePtr[blendMask]);
animsrc->mControllerMap[blendMask].insert(std::make_pair(bonename, cloned));
@ -1272,7 +1272,7 @@ namespace MWRender
writableStateSet = node->getOrCreateStateSet();
else
{
writableStateSet = osg::clone(node->getStateSet(), osg::CopyOp::SHALLOW_COPY);
writableStateSet = new osg::StateSet(*node->getStateSet(), osg::CopyOp::SHALLOW_COPY);
node->setStateSet(writableStateSet);
}
writableStateSet->setTextureAttributeAndModes(texUnit, textures.front(), osg::StateAttribute::ON);

@ -231,13 +231,51 @@ void LocalMap::setupRenderToTexture(osg::ref_ptr<osg::Camera> camera, int x, int
segment.mMapTexture = texture;
}
bool needUpdate(std::set<std::pair<int, int> >& renderedGrid, std::set<std::pair<int, int> >& currentGrid, int cellX, int cellY)
{
// if all the cells of the current grid are contained in the rendered grid then we can keep the old render
for (int dx=-1;dx<2;dx+=1)
{
for (int dy=-1;dy<2;dy+=1)
{
bool haveInRenderedGrid = renderedGrid.find(std::make_pair(cellX+dx,cellY+dy)) != renderedGrid.end();
bool haveInCurrentGrid = currentGrid.find(std::make_pair(cellX+dx,cellY+dy)) != currentGrid.end();
if (haveInCurrentGrid && !haveInRenderedGrid)
return true;
}
}
return false;
}
void LocalMap::requestMap(std::set<const MWWorld::CellStore*> cells)
{
std::set<std::pair<int, int> > grid;
for (std::set<const MWWorld::CellStore*>::iterator it = cells.begin(); it != cells.end(); ++it)
{
const MWWorld::CellStore* cell = *it;
if (cell->isExterior())
grid.insert(std::make_pair(cell->getCell()->getGridX(), cell->getCell()->getGridY()));
}
for (std::set<const MWWorld::CellStore*>::iterator it = cells.begin(); it != cells.end(); ++it)
{
const MWWorld::CellStore* cell = *it;
if (cell->isExterior())
requestExteriorMap(cell);
{
int cellX = cell->getCell()->getGridX();
int cellY = cell->getCell()->getGridY();
MapSegment& segment = mSegments[std::make_pair(cellX, cellY)];
if (!needUpdate(segment.mGrid, grid, cellX, cellY))
{
continue;
}
else
{
segment.mGrid = grid;
requestExteriorMap(cell);
}
}
else
requestInteriorMap(cell);
}

@ -124,6 +124,8 @@ namespace MWRender
osg::ref_ptr<osg::Texture2D> mFogOfWarTexture;
osg::ref_ptr<osg::Image> mFogOfWarImage;
std::set<std::pair<int, int> > mGrid; // the grid that was active at the time of rendering this segment
bool mHasFogState;
};

@ -20,6 +20,7 @@
#include <components/resource/resourcesystem.hpp>
#include <components/resource/imagemanager.hpp>
#include <components/resource/scenemanager.hpp>
#include <components/resource/keyframemanager.hpp>
#include <components/settings/settings.hpp>
@ -140,14 +141,24 @@ namespace MWRender
virtual void doWork()
{
for (std::vector<std::string>::const_iterator it = mModels.begin(); it != mModels.end(); ++it)
mResourceSystem->getSceneManager()->getTemplate(*it);
for (std::vector<std::string>::const_iterator it = mTextures.begin(); it != mTextures.end(); ++it)
mResourceSystem->getImageManager()->getImage(*it);
try
{
for (std::vector<std::string>::const_iterator it = mModels.begin(); it != mModels.end(); ++it)
mResourceSystem->getSceneManager()->cacheInstance(*it);
for (std::vector<std::string>::const_iterator it = mTextures.begin(); it != mTextures.end(); ++it)
mResourceSystem->getImageManager()->getImage(*it);
for (std::vector<std::string>::const_iterator it = mKeyframes.begin(); it != mKeyframes.end(); ++it)
mResourceSystem->getKeyframeManager()->get(*it);
}
catch (std::exception&)
{
// ignore error (will be shown when these are needed proper)
}
}
std::vector<std::string> mModels;
std::vector<std::string> mTextures;
std::vector<std::string> mKeyframes;
private:
Resource::ResourceSystem* mResourceSystem;
@ -308,6 +319,13 @@ namespace MWRender
mSky->listAssetsToPreload(workItem->mModels, workItem->mTextures);
mWater->listAssetsToPreload(workItem->mTextures);
const char* basemodels[] = {"xbase_anim", "xbase_anim.1st", "xbase_anim_female", "xbase_animkna"};
for (size_t i=0; i<sizeof(basemodels)/sizeof(basemodels[0]); ++i)
{
workItem->mModels.push_back(std::string("meshes/") + basemodels[i] + ".nif");
workItem->mKeyframes.push_back(std::string("meshes/") + basemodels[i] + ".kf");
}
workItem->mTextures.push_back("textures/_land_default.dds");
mWorkQueue->addWorkItem(workItem);
@ -435,14 +453,6 @@ namespace MWRender
mViewer->getCamera()->setCullMask(mask);
return enabled;
}
/*
else //if (mode == Render_BoundingBoxes)
{
bool show = !mRendering.getScene()->getShowBoundingBoxes();
mRendering.getScene()->showBoundingBoxes(show);
return show;
}
*/
return false;
}

@ -9,7 +9,6 @@ namespace MWRender
Render_CollisionDebug,
Render_Wireframe,
Render_Pathgrid,
Render_BoundingBoxes,
Render_Water,
Render_Scene
};

@ -55,7 +55,7 @@ void overrideTexture(const std::string &texture, Resource::ResourceSystem *resou
osg::ref_ptr<osg::StateSet> stateset;
if (node->getStateSet())
stateset = osg::clone(node->getStateSet(), osg::CopyOp::SHALLOW_COPY);
stateset = new osg::StateSet(*node->getStateSet(), osg::CopyOp::SHALLOW_COPY);
else
stateset = new osg::StateSet;

@ -278,10 +278,10 @@ namespace MWScript
virtual void execute (Interpreter::Runtime& runtime)
{
bool enabled =
MWBase::Environment::get().getWorld()->toggleRenderMode (MWRender::Render_BoundingBoxes);
MWBase::Environment::get().getWorld()->toggleRenderMode (MWRender::Render_CollisionDebug);
runtime.getContext().report (enabled ?
"Bounding Box Rendering -> On" : "Bounding Box Rendering -> Off");
"Collision Mesh Rendering -> On" : "Collision Mesh Rendering -> Off");
}
};

@ -242,6 +242,10 @@ void FFmpeg_Decoder::open(const std::string &fname)
}
catch(std::exception&)
{
if(mStream)
avcodec_close((*mStream)->codec);
mStream = NULL;
if (mFormatCtx->pb->buffer != NULL)
{
av_free(mFormatCtx->pb->buffer);

@ -55,6 +55,7 @@ namespace MWWorld
, mKeyframeManager(keyframeManager)
, mTerrain(terrain)
, mPreloadInstances(preloadInstances)
, mAbort(false)
{
ListModelsVisitor visitor (mMeshes);
if (cell->getState() == MWWorld::CellStore::State_Loaded)
@ -76,11 +77,30 @@ namespace MWWorld
}
}
virtual void abort()
{
mAbort = true;
}
/// Preload work to be called from the worker thread.
virtual void doWork()
{
if (mIsExterior)
{
try
{
mPreloadedObjects.push_back(mTerrain->cacheCell(mX, mY));
}
catch(std::exception& e)
{
}
}
for (MeshList::const_iterator it = mMeshes.begin(); it != mMeshes.end(); ++it)
{
if (mAbort)
break;
try
{
std::string mesh = *it;
@ -119,17 +139,6 @@ namespace MWWorld
// error will be shown when visiting the cell
}
}
if (mIsExterior)
{
try
{
mPreloadedObjects.push_back(mTerrain->cacheCell(mX, mY));
}
catch(std::exception& e)
{
}
}
}
private:
@ -144,6 +153,8 @@ namespace MWWorld
Terrain::World* mTerrain;
bool mPreloadInstances;
volatile bool mAbort;
// keep a ref to the loaded objects to make sure it stays loaded as long as this cell is in the preloaded state
std::vector<osg::ref_ptr<const osg::Object> > mPreloadedObjects;
};
@ -187,7 +198,10 @@ namespace MWWorld
CellPreloader::~CellPreloader()
{
for (PreloadMap::iterator it = mPreloadCells.begin(); it != mPreloadCells.end();++it)
{
it->second.mWorkItem->abort();
it->second.mWorkItem->waitTillDone();
}
mPreloadCells.clear();
}
@ -228,7 +242,10 @@ namespace MWWorld
}
if (oldestTimestamp + threshold < timestamp)
{
oldestCell->second.mWorkItem->abort();
mPreloadCells.erase(oldestCell);
}
else
return;
}
@ -246,18 +263,42 @@ namespace MWWorld
{
// do the deletion in the background thread
if (found->second.mWorkItem)
{
found->second.mWorkItem->abort();
mUnrefQueue->push(mPreloadCells[cell].mWorkItem);
}
mPreloadCells.erase(found);
}
}
void CellPreloader::clear()
{
for (PreloadMap::iterator it = mPreloadCells.begin(); it != mPreloadCells.end();)
{
if (it->second.mWorkItem)
{
it->second.mWorkItem->abort();
mUnrefQueue->push(it->second.mWorkItem);
}
mPreloadCells.erase(it++);
}
}
void CellPreloader::updateCache(double timestamp)
{
for (PreloadMap::iterator it = mPreloadCells.begin(); it != mPreloadCells.end();)
{
if (mPreloadCells.size() >= mMinCacheSize && it->second.mTimeStamp < timestamp - mExpiryDelay)
{
if (it->second.mWorkItem)
{
it->second.mWorkItem->abort();
mUnrefQueue->push(it->second.mWorkItem);
}
mPreloadCells.erase(it++);
}
else
++it;
}

@ -37,6 +37,8 @@ namespace MWWorld
void notifyLoaded(MWWorld::CellStore* cell);
void clear();
/// Removes preloaded cells that have not had a preload request for a while.
void updateCache(double timestamp);

@ -205,9 +205,9 @@ namespace MWWorld
if (mPreloadEnabled)
{
mPreloadTimer += duration;
if (mPreloadTimer > 0.25f)
if (mPreloadTimer > 0.1f)
{
preloadCells();
preloadCells(0.1f);
mPreloadTimer = 0.f;
}
}
@ -328,13 +328,15 @@ namespace MWWorld
mPreloader->notifyLoaded(cell);
}
void Scene::changeToVoid()
void Scene::clear()
{
CellStoreCollection::iterator active = mActiveCells.begin();
while (active!=mActiveCells.end())
unloadCell (active++);
assert(mActiveCells.empty());
mCurrentCell = NULL;
mPreloader->clear();
}
void Scene::playerMoved(const osg::Vec3f &pos)
@ -481,6 +483,8 @@ namespace MWWorld
mechMgr->watchActor(player);
MWBase::Environment::get().getWorld()->adjustSky();
mLastPlayerPos = pos.asVec3();
}
Scene::Scene (MWRender::RenderingManager& rendering, MWPhysics::PhysicsSystem *physics)
@ -675,17 +679,24 @@ namespace MWWorld
return Ptr();
}
void Scene::preloadCells()
void Scene::preloadCells(float dt)
{
const MWWorld::ConstPtr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
osg::Vec3f playerPos = player.getRefData().getPosition().asVec3();
osg::Vec3f moved = playerPos - mLastPlayerPos;
osg::Vec3f predictedPos = playerPos + moved / dt;
mLastPlayerPos = playerPos;
if (mPreloadDoors)
preloadTeleportDoorDestinations();
preloadTeleportDoorDestinations(playerPos, predictedPos);
if (mPreloadExteriorGrid)
preloadExteriorGrid();
preloadExteriorGrid(playerPos, predictedPos);
if (mPreloadFastTravel)
preloadFastTravelDestinations();
preloadFastTravelDestinations(playerPos, predictedPos);
}
void Scene::preloadTeleportDoorDestinations()
void Scene::preloadTeleportDoorDestinations(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos)
{
std::vector<MWWorld::ConstPtr> teleportDoors;
for (CellStoreCollection::const_iterator iter (mActiveCells.begin());
@ -703,11 +714,11 @@ namespace MWWorld
}
}
const MWWorld::ConstPtr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
for (std::vector<MWWorld::ConstPtr>::iterator it = teleportDoors.begin(); it != teleportDoors.end(); ++it)
{
const MWWorld::ConstPtr& door = *it;
float sqrDistToPlayer = (player.getRefData().getPosition().asVec3() - door.getRefData().getPosition().asVec3()).length2();
float sqrDistToPlayer = (playerPos - door.getRefData().getPosition().asVec3()).length2();
sqrDistToPlayer = std::min(sqrDistToPlayer, (predictedPos - door.getRefData().getPosition().asVec3()).length2());
if (sqrDistToPlayer < mPreloadDistance*mPreloadDistance)
{
@ -730,15 +741,13 @@ namespace MWWorld
}
}
void Scene::preloadExteriorGrid()
void Scene::preloadExteriorGrid(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos)
{
if (!MWBase::Environment::get().getWorld()->isCellExterior())
return;
int halfGridSizePlusOne = mHalfGridSize + 1;
const MWWorld::ConstPtr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
osg::Vec3f playerPos = player.getRefData().getPosition().asVec3();
int cellX,cellY;
getGridCenter(cellX,cellY);
@ -757,6 +766,7 @@ namespace MWWorld
MWBase::Environment::get().getWorld()->indexToPosition(cellX+dx, cellY+dy, thisCellCenterX, thisCellCenterY, true);
float dist = std::max(std::abs(thisCellCenterX - playerPos.x()), std::abs(thisCellCenterY - playerPos.y()));
dist = std::min(dist,std::max(std::abs(thisCellCenterX - predictedPos.x()), std::abs(thisCellCenterY - predictedPos.y())));
float loadDist = 8192/2 + 8192 - mCellLoadingThreshold + mPreloadDistance;
if (dist < loadDist)
@ -816,7 +826,7 @@ namespace MWWorld
std::vector<ESM::Transport::Dest> mList;
};
void Scene::preloadFastTravelDestinations()
void Scene::preloadFastTravelDestinations(const osg::Vec3f& playerPos, const osg::Vec3f& /*predictedPos*/) // ignore predictedPos here since opening dialogue with travel service takes extra time
{
const MWWorld::ConstPtr player = MWBase::Environment::get().getWorld()->getPlayerPtr();
ListFastTravelDestinationsVisitor listVisitor(mPreloadDistance, player.getRefData().getPosition().asVec3());

@ -68,6 +68,8 @@ namespace MWWorld
bool mPreloadDoors;
bool mPreloadFastTravel;
osg::Vec3f mLastPlayerPos;
void insertCell (CellStore &cell, bool rescale, Loading::Listener* loadingListener);
// Load and unload cells as necessary to create a cell grid with "X" and "Y" in the center
@ -75,12 +77,10 @@ namespace MWWorld
void getGridCenter(int& cellX, int& cellY);
void preloadCells();
void preloadTeleportDoorDestinations();
void preloadExteriorGrid();
void preloadFastTravelDestinations();
void preloadCell(MWWorld::CellStore* cell, bool preloadSurrounding=false);
void preloadCells(float dt);
void preloadTeleportDoorDestinations(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos);
void preloadExteriorGrid(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos);
void preloadFastTravelDestinations(const osg::Vec3f& playerPos, const osg::Vec3f& predictedPos);
public:
@ -88,6 +88,8 @@ namespace MWWorld
~Scene();
void preloadCell(MWWorld::CellStore* cell, bool preloadSurrounding=false);
void unloadCell (CellStoreCollection::iterator iter);
void loadCell (CellStore *cell, Loading::Listener* loadingListener, bool respawn);
@ -111,7 +113,7 @@ namespace MWWorld
///< Move to exterior cell.
/// @param changeEvent Set cellChanged flag?
void changeToVoid();
void clear();
///< Change into a void
void markCellAsUnchanged();

@ -164,6 +164,8 @@ namespace MWWorld
mRendering = new MWRender::RenderingManager(viewer, rootNode, resourceSystem, &mFallback, resourcePath);
mProjectileManager.reset(new ProjectileManager(mRendering->getLightRoot(), resourceSystem, mRendering, mPhysics));
mRendering->preloadCommonAssets();
mEsm.resize(contentFiles.size());
Loading::Listener* listener = MWBase::Environment::get().getWindowManager()->getLoadingScreen();
listener->loadingOn();
@ -303,7 +305,7 @@ namespace MWWorld
mProjectileManager->clear();
mLocalScripts.clear();
mWorldScene->changeToVoid();
mWorldScene->clear();
mStore.clearDynamic();
mStore.setUp();
@ -359,9 +361,9 @@ namespace MWWorld
mStore.write (writer, progress); // dynamic Store must be written (and read) before Cells, so that
// references to custom made records will be recognized
mPlayer->write (writer, progress);
mCells.write (writer, progress);
mGlobalVariables.write (writer, progress);
mPlayer->write (writer, progress);
mWeatherManager->write (writer, progress);
mProjectileManager->write (writer, progress);
@ -387,10 +389,13 @@ namespace MWWorld
reader.getHNT(mTeleportEnabled, "TELE");
reader.getHNT(mLevitationEnabled, "LEVT");
return;
case ESM::REC_PLAY:
mPlayer->readRecord(reader, type);
mWorldScene->preloadCell(getPlayerPtr().getCell(), true);
break;
default:
if (!mStore.readRecord (reader, type) &&
!mGlobalVariables.readRecord (reader, type) &&
!mPlayer->readRecord (reader, type) &&
!mWeatherManager->readRecord (reader, type) &&
!mCells.readRecord (reader, type, contentFileMap)
&& !mProjectileManager->readRecord (reader, type)
@ -1468,8 +1473,6 @@ namespace MWWorld
}
if(player != results.end())
moveObjectImp(player->first, player->second.x(), player->second.y(), player->second.z(), false);
mPhysics->debugDraw();
}
bool World::castRay (float x1, float y1, float z1, float x2, float y2, float z2)
@ -1643,6 +1646,8 @@ namespace MWWorld
if (!paused)
doPhysics (duration);
mPhysics->debugDraw();
mWorldScene->update (duration, paused);
updateWindowManager ();
@ -2200,6 +2205,8 @@ namespace MWWorld
scaleObject(getPlayerPtr(), 1.f); // apply race height
rotateObject(getPlayerPtr(), 0.f, 0.f, 0.f, true);
MWBase::Environment::get().getMechanicsManager()->add(getPlayerPtr());
MWBase::Environment::get().getMechanicsManager()->watchActor(getPlayerPtr());
@ -3429,9 +3436,4 @@ namespace MWWorld
return mPhysics->getHitDistance(weaponPos, target) - halfExtents.y();
}
void World::preloadCommonAssets()
{
mRendering->preloadCommonAssets();
}
}

@ -191,8 +191,6 @@ namespace MWWorld
virtual void startNewGame (bool bypass);
///< \param bypass Bypass regular game start.
virtual void preloadCommonAssets();
virtual void clear();
virtual int countSavedGameRecords() const;

@ -51,7 +51,7 @@ namespace ESM
esm.writeHNT("VCLR", mColours, 3*LAND_NUM_VERTS);
}
if (mDataTypes & Land::DATA_VTEX) {
static uint16_t vtex[LAND_NUM_TEXTURES];
uint16_t vtex[LAND_NUM_TEXTURES];
transposeTextureData(mTextures, vtex);
esm.writeHNT("VTEX", vtex, sizeof(vtex));
}
@ -202,7 +202,7 @@ namespace ESM
}
if (reader.isNextSub("VHGT")) {
static VHGT vhgt;
VHGT vhgt;
if (condLoad(reader, flags, DATA_VHGT, &vhgt, sizeof(vhgt))) {
float rowOffset = vhgt.mHeightOffset;
for (int y = 0; y < LAND_SIZE; y++) {
@ -227,7 +227,7 @@ namespace ESM
if (reader.isNextSub("VCLR"))
condLoad(reader, flags, DATA_VCLR, mLandData->mColours, 3 * LAND_NUM_VERTS);
if (reader.isNextSub("VTEX")) {
static uint16_t vtex[LAND_NUM_TEXTURES];
uint16_t vtex[LAND_NUM_TEXTURES];
if (condLoad(reader, flags, DATA_VTEX, vtex, sizeof(vtex))) {
LandData::transposeTextureData(vtex, mLandData->mTextures);
}

@ -356,12 +356,24 @@ namespace NifOsg
osg::ref_ptr<TextKeyMapHolder> textkeys (new TextKeyMapHolder);
osg::ref_ptr<osg::Node> created = handleNode(nifNode, NULL, imageManager, std::vector<int>(), 0, 0, false, &textkeys->mTextKeys);
osg::ref_ptr<osg::Node> created = handleNode(nifNode, NULL, imageManager, std::vector<int>(), 0, false, &textkeys->mTextKeys);
if (nif->getUseSkinning())
{
osg::ref_ptr<SceneUtil::Skeleton> skel = new SceneUtil::Skeleton;
skel->addChild(created);
osg::Group* root = created->asGroup();
if (root && root->getDataVariance() == osg::Object::STATIC)
{
skel->setStateSet(root->getStateSet());
skel->setName(root->getName());
for (unsigned int i=0; i<root->getNumChildren(); ++i)
skel->addChild(root->getChild(i));
root->removeChildren(0, root->getNumChildren());
created = skel;
}
else
skel->addChild(created);
created = skel;
}
@ -404,15 +416,6 @@ namespace NifOsg
toSetup->setFunction(boost::shared_ptr<ControllerFunction>(new ControllerFunction(ctrl)));
}
void setupParticleController(const Nif::Controller* ctrl, SceneUtil::Controller* toSetup, int particleflags)
{
bool autoPlay = particleflags & Nif::NiNode::ParticleFlag_AutoPlay;
if (autoPlay)
toSetup->setSource(boost::shared_ptr<SceneUtil::ControllerSource>(new SceneUtil::FrameTimeSource));
toSetup->setFunction(boost::shared_ptr<ControllerFunction>(new ControllerFunction(ctrl)));
}
void optimize (const Nif::Node* nifNode, osg::Group* node, bool skipMeshes)
{
// For nodes with an identity transform, remove the redundant Transform node
@ -547,7 +550,7 @@ namespace NifOsg
}
osg::ref_ptr<osg::Node> handleNode(const Nif::Node* nifNode, osg::Group* parentNode, Resource::ImageManager* imageManager,
std::vector<int> boundTextures, int animflags, int particleflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL)
std::vector<int> boundTextures, int animflags, bool skipMeshes, TextKeyMap* textKeys, osg::Node* rootNode=NULL)
{
osg::ref_ptr<osg::Group> node = new osg::MatrixTransform(nifNode->trafo.toMatrix());
@ -617,10 +620,8 @@ namespace NifOsg
}
}
if (nifNode->recType == Nif::RC_NiBSAnimationNode)
animflags |= nifNode->flags;
if (nifNode->recType == Nif::RC_NiBSParticleNode)
particleflags |= nifNode->flags;
if (nifNode->recType == Nif::RC_NiBSAnimationNode || nifNode->recType == Nif::RC_NiBSParticleNode)
animflags = nifNode->flags;
// Hide collision shapes, but don't skip the subgraph
// We still need to animate the hidden bones so the physics system can access them
@ -663,7 +664,7 @@ namespace NifOsg
}
if(nifNode->recType == Nif::RC_NiAutoNormalParticles || nifNode->recType == Nif::RC_NiRotatingParticles)
handleParticleSystem(nifNode, node, composite, animflags, particleflags, rootNode);
handleParticleSystem(nifNode, node, composite, animflags, rootNode);
if (composite->getNumControllers() > 0)
node->addUpdateCallback(composite);
@ -700,7 +701,7 @@ namespace NifOsg
for(size_t i = 0;i < children.length();++i)
{
if(!children[i].empty())
handleNode(children[i].getPtr(), node, imageManager, boundTextures, animflags, particleflags, skipMeshes, textKeys, rootNode);
handleNode(children[i].getPtr(), node, imageManager, boundTextures, animflags, skipMeshes, textKeys, rootNode);
}
}
@ -965,7 +966,7 @@ namespace NifOsg
return emitter;
}
void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, int animflags, int particleflags, osg::Node* rootNode)
void handleParticleSystem(const Nif::Node *nifNode, osg::Group *parentNode, SceneUtil::CompositeStateSetUpdater* composite, int animflags, osg::Node* rootNode)
{
osg::ref_ptr<ParticleSystem> partsys (new ParticleSystem);
partsys->setSortMode(osgParticle::ParticleSystem::SORT_BACK_TO_FRONT);
@ -986,7 +987,7 @@ namespace NifOsg
return;
}
osgParticle::ParticleProcessor::ReferenceFrame rf = (particleflags & Nif::NiNode::ParticleFlag_LocalSpace)
osgParticle::ParticleProcessor::ReferenceFrame rf = (animflags & Nif::NiNode::ParticleFlag_LocalSpace)
? osgParticle::ParticleProcessor::RELATIVE_RF
: osgParticle::ParticleProcessor::ABSOLUTE_RF;
@ -1032,10 +1033,10 @@ namespace NifOsg
emitterNode->addChild(emitter);
osg::ref_ptr<ParticleSystemController> callback(new ParticleSystemController(partctrl));
setupParticleController(partctrl, callback, particleflags);
setupController(partctrl, callback, animflags);
emitter->setUpdateCallback(callback);
if (!(particleflags & Nif::NiNode::ParticleFlag_AutoPlay))
if (!(animflags & Nif::NiNode::ParticleFlag_AutoPlay))
{
partsys->setFrozen(true);
// HACK: particle system will not render in Frozen state if there was no update
@ -1438,20 +1439,27 @@ namespace NifOsg
}
const Nif::NiTexturingProperty::Texture& tex = texprop->textures[i];
if(tex.texture.empty())
if(tex.texture.empty() && texprop->controller.empty())
{
std::cerr << "Warning: texture layer " << i << " is in use but empty in " << mFilename << std::endl;
continue;
}
const Nif::NiSourceTexture *st = tex.texture.getPtr();
osg::ref_ptr<osg::Image> image = handleSourceTexture(st, imageManager);
// create a new texture, will later attempt to share using the SharedStateManager
osg::ref_ptr<osg::Texture2D> texture2d;
if (!tex.texture.empty())
{
const Nif::NiSourceTexture *st = tex.texture.getPtr();
osg::ref_ptr<osg::Image> image = handleSourceTexture(st, imageManager);
texture2d = new osg::Texture2D(image);
}
else
texture2d = new osg::Texture2D;
unsigned int clamp = static_cast<unsigned int>(tex.clamp);
int wrapT = (clamp) & 0x1;
int wrapS = (clamp >> 1) & 0x1;
// create a new texture, will later attempt to share using the SharedStateManager
osg::ref_ptr<osg::Texture2D> texture2d (new osg::Texture2D(image));
texture2d->setWrap(osg::Texture::WRAP_S, wrapS ? osg::Texture::REPEAT : osg::Texture::CLAMP);
texture2d->setWrap(osg::Texture::WRAP_T, wrapT ? osg::Texture::REPEAT : osg::Texture::CLAMP);

@ -1,7 +1,6 @@
#include "keyframemanager.hpp"
#include <components/vfs/manager.hpp>
#include <components/nifosg/nifloader.hpp>
#include "objectcache.hpp"

@ -4,12 +4,9 @@
#include <osg/ref_ptr>
#include <string>
#include "resourcemanager.hpp"
#include <components/nifosg/nifloader.hpp>
namespace NifOsg
{
class KeyframeHolder;
}
#include "resourcemanager.hpp"
namespace Resource
{

@ -13,6 +13,20 @@
namespace SceneUtil
{
class LightStateCache
{
public:
osg::Light* lastAppliedLight[8];
};
LightStateCache* getLightStateCache(unsigned int contextid)
{
static std::vector<LightStateCache> cacheVector;
if (cacheVector.size() < contextid+1)
cacheVector.resize(contextid+1);
return &cacheVector[contextid];
}
// Resets the modelview matrix to just the view matrix before applying lights.
class LightStateAttribute : public osg::StateAttribute
{
@ -50,8 +64,17 @@ namespace SceneUtil
state.applyModelViewMatrix(state.getInitialViewMatrix());
LightStateCache* cache = getLightStateCache(state.getContextID());
for (unsigned int i=0; i<mLights.size(); ++i)
applyLight((GLenum)((int)GL_LIGHT0 + i + mIndex), mLights[i].get());
{
osg::Light* current = cache->lastAppliedLight[i+mIndex];
if (current != mLights[i].get())
{
applyLight((GLenum)((int)GL_LIGHT0 + i + mIndex), mLights[i].get());
cache->lastAppliedLight[i+mIndex] = mLights[i].get();
}
}
state.applyModelViewMatrix(modelViewMatrix);
}
@ -262,18 +285,64 @@ namespace SceneUtil
return it->second;
}
class DisableLight : public osg::StateAttribute
{
public:
DisableLight() : mIndex(0) {}
DisableLight(int index) : mIndex(index) {}
DisableLight(const DisableLight& copy,const osg::CopyOp& copyop=osg::CopyOp::SHALLOW_COPY)
: osg::StateAttribute(copy,copyop), mIndex(copy.mIndex) {}
virtual osg::Object* cloneType() const { return new DisableLight(mIndex); }
virtual osg::Object* clone(const osg::CopyOp& copyop) const { return new DisableLight(*this,copyop); }
virtual bool isSameKindAs(const osg::Object* obj) const { return dynamic_cast<const DisableLight *>(obj)!=NULL; }
virtual const char* libraryName() const { return "SceneUtil"; }
virtual const char* className() const { return "DisableLight"; }
virtual Type getType() const { return LIGHT; }
unsigned int getMember() const
{
return mIndex;
}
virtual bool getModeUsage(ModeUsage & usage) const
{
usage.usesMode(GL_LIGHT0 + mIndex);
return true;
}
virtual int compare(const StateAttribute &sa) const
{
throw std::runtime_error("DisableLight::compare: unimplemented");
}
virtual void apply(osg::State& state) const
{
int lightNum = GL_LIGHT0 + mIndex;
glLightfv( lightNum, GL_AMBIENT, mNull.ptr() );
glLightfv( lightNum, GL_DIFFUSE, mNull.ptr() );
glLightfv( lightNum, GL_SPECULAR, mNull.ptr() );
LightStateCache* cache = getLightStateCache(state.getContextID());
cache->lastAppliedLight[mIndex] = NULL;
}
private:
unsigned int mIndex;
osg::Vec4f mNull;
};
void LightManager::setStartLight(int start)
{
mStartLight = start;
// Set default light state to zero
// This is necessary because shaders don't respect glDisable(GL_LIGHTX) so in addition to disabling
// we'll have to set a light state that has no visible effect
for (int i=start; i<8; ++i)
{
osg::ref_ptr<osg::Light> defaultLight (new osg::Light(i));
defaultLight->setAmbient(osg::Vec4());
defaultLight->setDiffuse(osg::Vec4());
defaultLight->setSpecular(osg::Vec4());
defaultLight->setConstantAttenuation(0.f);
osg::ref_ptr<DisableLight> defaultLight (new DisableLight(i));
getOrCreateStateSet()->setAttributeAndModes(defaultLight, osg::StateAttribute::OFF);
}
}
@ -299,7 +368,7 @@ namespace SceneUtil
mId = sLightId++;
for (int i=0; i<2; ++i)
mLight[i] = osg::clone(copy.mLight[i].get(), copyop);
mLight[i] = new osg::Light(*copy.mLight[i].get(), copyop);
}

@ -64,7 +64,7 @@ namespace SceneUtil
void setLight(osg::Light* light)
{
mLight[0] = light;
mLight[1] = osg::clone(light);
mLight[1] = new osg::Light(*light);
}
/// Get the unique ID for this light source.

@ -15,7 +15,7 @@ namespace SceneUtil
for (int i=0; i<2; ++i) // Using SHALLOW_COPY for StateAttributes, if users want to modify it is their responsibility to set a non-shared one first
// This can be done conveniently in user implementations of the setDefaults() method
{
mStateSets[i] = osg::clone(src, osg::CopyOp::SHALLOW_COPY);
mStateSets[i] = new osg::StateSet(*src, osg::CopyOp::SHALLOW_COPY);
setDefaults(mStateSets[i]);
}
}

@ -31,6 +31,9 @@ namespace SceneUtil
/// Internal use by the WorkQueue.
void signalDone();
/// Set abort flag in order to return from doWork() as soon as possible. May not be respected by all WorkItems.
virtual void abort() {}
protected:
OpenThreads::Atomic mDone;
OpenThreads::Mutex mMutex;

@ -85,7 +85,7 @@ namespace Shader
if (!node.getStateSet())
return node.getOrCreateStateSet();
osg::ref_ptr<osg::StateSet> newStateSet = osg::clone(node.getStateSet(), osg::CopyOp::SHALLOW_COPY);
osg::ref_ptr<osg::StateSet> newStateSet = new osg::StateSet(*node.getStateSet(), osg::CopyOp::SHALLOW_COPY);
node.setStateSet(newStateSet);
return newStateSet.get();
}
@ -152,7 +152,7 @@ namespace Shader
}
}
if (mAutoUseNormalMaps && diffuseMap != NULL && normalMap == NULL)
if (mAutoUseNormalMaps && diffuseMap != NULL && normalMap == NULL && diffuseMap->getImage(0))
{
std::string normalMapFileName = diffuseMap->getImage(0)->getFileName();
@ -194,7 +194,7 @@ namespace Shader
mRequirements.back().mNormalHeight = normalHeight;
}
}
if (mAutoUseSpecularMaps && diffuseMap != NULL && specularMap == NULL)
if (mAutoUseSpecularMaps && diffuseMap != NULL && specularMap == NULL && diffuseMap->getImage(0))
{
std::string specularMapFileName = diffuseMap->getImage(0)->getFileName();
boost::replace_last(specularMapFileName, ".", mSpecularMapPattern + ".");
@ -272,6 +272,9 @@ namespace Shader
{
switch (reqs.mVertexColorMode)
{
case GL_AMBIENT:
defineMap["colorMode"] = "3";
break;
default:
case GL_AMBIENT_AND_DIFFUSE:
defineMap["colorMode"] = "2";

@ -59,7 +59,7 @@
<Widget type="Button" skin="" position="82 146 36 41" align="Left Bottom" name="WeapBox">
<Widget type="Widget" skin="HUD_Box" position="0 0 36 36">
<Property key="NeedMouse" value="false"/>
<Widget type="ItemWidget" skin="MW_ItemIcon" position="-3 -3 42 42" align="Left Top" name="WeapImage">
<Widget type="ItemWidget" skin="MW_ItemIconNoShadow" position="-3 -3 42 42" align="Left Top" name="WeapImage">
<Property key="NeedMouse" value="false"/>
</Widget>
</Widget>
@ -71,7 +71,7 @@
<!-- Selected spell box -->
<Widget type="Button" position="122 146 36 41" align="Left Bottom" name="SpellBox">
<Widget type="Widget" skin="HUD_Box" position="0 0 36 36">
<Widget type="ItemWidget" skin="MW_ItemIcon" position="-3 -3 42 42" align="Left Top" name="SpellImage"/>
<Widget type="ItemWidget" skin="MW_ItemIconNoShadow" position="-3 -3 42 42" align="Left Top" name="SpellImage"/>
<Property key="NeedMouse" value="false"/>
</Widget>
<Widget type="ProgressBar" skin="MW_EnergyBar_Magic" position="0 36 36 6" align="Left Bottom" name="SpellStatus">

@ -128,6 +128,18 @@
</Widget>
</Resource>
<Resource type="ResourceLayout" name="MW_ItemIconNoShadow" version="3.2.0">
<Widget type="Widget" skin="" position="0 0 42 42" name="Root">
<Widget type="ImageBox" skin="ImageBox" position="0 0 42 42" align="Stretch" name="Frame">
<Widget type="TextBox" skin="CountText" position="5 19 32 18" align="Right Bottom" name="Text">
<Property key="TextAlign" value="Right"/>
<Property key="TextShadow" value="true"/>
</Widget>
<Widget type="ImageBox" skin="ImageBox" position="5 5 32 32" align="Stretch" name="Item"/>
</Widget>
</Widget>
</Resource>
<Resource type="ResourceLayout" name="MW_ItemIconSmall" version="3.2.0">
<Widget type="Widget" skin="" position="0 0 32 32" name="Root">
<Widget type="ImageBox" skin="ImageBox" position="0 0 32 32" align="Stretch" name="Frame">

@ -5,7 +5,10 @@ vec4 doLighting(vec3 viewPos, vec3 viewNormal, vec4 vertexColor)
vec3 lightDir;
float d;
#if @colorMode == 2
#if @colorMode == 3
vec4 diffuse = gl_FrontMaterial.diffuse;
vec3 ambient = vertexColor.xyz;
#elif @colorMode == 2
vec4 diffuse = vertexColor;
vec3 ambient = vertexColor.xyz;
#else

Loading…
Cancel
Save