1
0
Fork 0
mirror of https://github.com/OpenMW/openmw.git synced 2025-02-21 06:09:42 +00:00

Merge remote-tracking branch 'zini/master' into nifogre

This commit is contained in:
Chris Robinson 2013-04-09 15:12:19 -07:00
commit 9d29921913
29 changed files with 367 additions and 68 deletions

View file

@ -36,7 +36,7 @@ opencs_units (model/tools
opencs_units_noqt (model/tools
stage verifier mandatoryid skillcheck classcheck factioncheck racecheck soundcheck regioncheck
birthsigncheck
birthsigncheck spellcheck
)

View file

@ -0,0 +1,35 @@
#include "spellcheck.hpp"
#include <sstream>
#include <map>
#include <components/esm/loadspel.hpp>
#include "../world/universalid.hpp"
CSMTools::SpellCheckStage::SpellCheckStage (const CSMWorld::IdCollection<ESM::Spell>& spells)
: mSpells (spells)
{}
int CSMTools::SpellCheckStage::setup()
{
return mSpells.getSize();
}
void CSMTools::SpellCheckStage::perform (int stage, std::vector<std::string>& messages)
{
const ESM::Spell& spell = mSpells.getRecord (stage).get();
CSMWorld::UniversalId id (CSMWorld::UniversalId::Type_Spell, spell.mId);
// test for empty name and description
if (spell.mName.empty())
messages.push_back (id.toString() + "|" + spell.mId + " has an empty name");
// test for invalid cost values
if (spell.mData.mCost<0)
messages.push_back (id.toString() + "|" + spell.mId + " has a negative spell costs");
/// \todo check data members that can't be edited in the table view
}

View file

@ -0,0 +1,29 @@
#ifndef CSM_TOOLS_SPELLCHECK_H
#define CSM_TOOLS_SPELLCHECK_H
#include <components/esm/loadspel.hpp>
#include "../world/idcollection.hpp"
#include "stage.hpp"
namespace CSMTools
{
/// \brief VerifyStage: make sure that spell records are internally consistent
class SpellCheckStage : public Stage
{
const CSMWorld::IdCollection<ESM::Spell>& mSpells;
public:
SpellCheckStage (const CSMWorld::IdCollection<ESM::Spell>& spells);
virtual int setup();
///< \return number of steps
virtual void perform (int stage, std::vector<std::string>& messages);
///< Messages resulting from this tage will be appended to \a messages.
};
}
#endif

View file

@ -19,6 +19,7 @@
#include "soundcheck.hpp"
#include "regioncheck.hpp"
#include "birthsigncheck.hpp"
#include "spellcheck.hpp"
CSMTools::Operation *CSMTools::Tools::get (int type)
{
@ -72,6 +73,8 @@ CSMTools::Verifier *CSMTools::Tools::getVerifier()
mVerifier->appendStage (new RegionCheckStage (mData.getRegions()));
mVerifier->appendStage (new BirthsignCheckStage (mData.getBirthsigns()));
mVerifier->appendStage (new SpellCheckStage (mData.getSpells()));
}
return mVerifier;

View file

@ -34,7 +34,8 @@ namespace CSMWorld
Display_GlobalVarType,
Display_Specialisation,
Display_Attribute,
Display_Boolean
Display_Boolean,
Display_SpellType
};
std::string mTitle;

View file

@ -675,6 +675,54 @@ namespace CSMWorld
return true;
}
};
template<typename ESXRecordT>
struct SpellTypeColumn : public Column<ESXRecordT>
{
SpellTypeColumn() : Column<ESXRecordT> ("Type", ColumnBase::Display_SpellType) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mData.mType;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mData.mType = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
template<typename ESXRecordT>
struct CostColumn : public Column<ESXRecordT>
{
CostColumn() : Column<ESXRecordT> ("Cost", ColumnBase::Display_Integer) {}
virtual QVariant get (const Record<ESXRecordT>& record) const
{
return record.get().mData.mCost;
}
virtual void set (Record<ESXRecordT>& record, const QVariant& data)
{
ESXRecordT record2 = record.get();
record2.mData.mCost = data.toInt();
record.setModified (record2);
}
virtual bool isEditable() const
{
return true;
}
};
}
#endif

View file

@ -99,6 +99,15 @@ CSMWorld::Data::Data()
mBirthsigns.addColumn (new TextureColumn<ESM::BirthSign>);
mBirthsigns.addColumn (new DescriptionColumn<ESM::BirthSign>);
mSpells.addColumn (new StringIdColumn<ESM::Spell>);
mSpells.addColumn (new RecordStateColumn<ESM::Spell>);
mSpells.addColumn (new NameColumn<ESM::Spell>);
mSpells.addColumn (new SpellTypeColumn<ESM::Spell>);
mSpells.addColumn (new CostColumn<ESM::Spell>);
mSpells.addColumn (new FlagColumn<ESM::Spell> ("Autocalc", 0x1));
mSpells.addColumn (new FlagColumn<ESM::Spell> ("Starter Spell", 0x2));
mSpells.addColumn (new FlagColumn<ESM::Spell> ("Always Succeeds", 0x4));
addModel (new IdTable (&mGlobals), UniversalId::Type_Globals, UniversalId::Type_Global);
addModel (new IdTable (&mGmsts), UniversalId::Type_Gmsts, UniversalId::Type_Gmst);
addModel (new IdTable (&mSkills), UniversalId::Type_Skills, UniversalId::Type_Skill);
@ -109,6 +118,7 @@ CSMWorld::Data::Data()
addModel (new IdTable (&mScripts), UniversalId::Type_Scripts, UniversalId::Type_Script);
addModel (new IdTable (&mRegions), UniversalId::Type_Regions, UniversalId::Type_Region);
addModel (new IdTable (&mBirthsigns), UniversalId::Type_Birthsigns, UniversalId::Type_Birthsign);
addModel (new IdTable (&mSpells), UniversalId::Type_Spells, UniversalId::Type_Spell);
}
CSMWorld::Data::~Data()
@ -217,6 +227,16 @@ CSMWorld::IdCollection<ESM::BirthSign>& CSMWorld::Data::getBirthsigns()
return mBirthsigns;
}
const CSMWorld::IdCollection<ESM::Spell>& CSMWorld::Data::getSpells() const
{
return mSpells;
}
CSMWorld::IdCollection<ESM::Spell>& CSMWorld::Data::getSpells()
{
return mSpells;
}
QAbstractItemModel *CSMWorld::Data::getTableModel (const UniversalId& id)
{
std::map<UniversalId::Type, QAbstractItemModel *>::iterator iter = mModelIndex.find (id.getType());
@ -261,6 +281,7 @@ void CSMWorld::Data::loadFile (const boost::filesystem::path& path, bool base)
case ESM::REC_SCPT: mScripts.load (reader, base); break;
case ESM::REC_REGN: mRegions.load (reader, base); break;
case ESM::REC_BSGN: mBirthsigns.load (reader, base); break;
case ESM::REC_SPEL: mSpells.load (reader, base); break;
default:

View file

@ -16,6 +16,7 @@
#include <components/esm/loadscpt.hpp>
#include <components/esm/loadregn.hpp>
#include <components/esm/loadbsgn.hpp>
#include <components/esm/loadspel.hpp>
#include "idcollection.hpp"
#include "universalid.hpp"
@ -36,6 +37,7 @@ namespace CSMWorld
IdCollection<ESM::Script> mScripts;
IdCollection<ESM::Region> mRegions;
IdCollection<ESM::BirthSign> mBirthsigns;
IdCollection<ESM::Spell> mSpells;
std::vector<QAbstractItemModel *> mModels;
std::map<UniversalId::Type, QAbstractItemModel *> mModelIndex;
@ -92,6 +94,10 @@ namespace CSMWorld
IdCollection<ESM::BirthSign>& getBirthsigns();
const IdCollection<ESM::Spell>& getSpells() const;
IdCollection<ESM::Spell>& getSpells();
QAbstractItemModel *getTableModel (const UniversalId& id);
///< If no table model is available for \a id, an exception is thrown.
///

View file

@ -27,6 +27,7 @@ namespace
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Scripts, "Scripts" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Regions, "Regions" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Birthsigns, "Birthsigns" },
{ CSMWorld::UniversalId::Class_RecordList, CSMWorld::UniversalId::Type_Spells, "Spells" },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
};
@ -43,6 +44,7 @@ namespace
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Script, "Script" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Region, "Region" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Birthsign, "Birthsign" },
{ CSMWorld::UniversalId::Class_Record, CSMWorld::UniversalId::Type_Spell, "Spell" },
{ CSMWorld::UniversalId::Class_None, CSMWorld::UniversalId::Type_None, 0 } // end marker
};

View file

@ -53,7 +53,9 @@ namespace CSMWorld
Type_Regions,
Type_Region,
Type_Birthsigns,
Type_Birthsign
Type_Birthsign,
Type_Spells,
Type_Spell
};
private:

View file

@ -121,6 +121,10 @@ void CSVDoc::View::setupWorldMenu()
QAction *birthsigns = new QAction (tr ("Birthsigns"), this);
connect (birthsigns, SIGNAL (triggered()), this, SLOT (addBirthsignsSubView()));
world->addAction (birthsigns);
QAction *spells = new QAction (tr ("Spells"), this);
connect (spells, SIGNAL (triggered()), this, SLOT (addSpellsSubView()));
world->addAction (spells);
}
void CSVDoc::View::setupUi()
@ -316,6 +320,11 @@ void CSVDoc::View::addBirthsignsSubView()
addSubView (CSMWorld::UniversalId::Type_Birthsigns);
}
void CSVDoc::View::addSpellsSubView()
{
addSubView (CSMWorld::UniversalId::Type_Spells);
}
void CSVDoc::View::abortOperation (int type)
{
mDocument->abortOperation (type);

View file

@ -131,6 +131,8 @@ namespace CSVDoc
void addRegionsSubView();
void addBirthsignsSubView();
void addSpellsSubView();
};
}

View file

@ -49,6 +49,11 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
"Luck", 0
};
static const char *sSpellTypes[] =
{
"Spell", "Ability", "Blight", "Disease", "Curse", "Power", 0
};
mDelegateFactories = new CSVWorld::CommandDelegateFactoryCollection;
mDelegateFactories->add (CSMWorld::ColumnBase::Display_GmstVarType,
@ -62,6 +67,9 @@ CSVDoc::ViewManager::ViewManager (CSMDoc::DocumentManager& documentManager)
mDelegateFactories->add (CSMWorld::ColumnBase::Display_Attribute,
new CSVWorld::EnumDelegateFactory (sAttributes, true));
mDelegateFactories->add (CSMWorld::ColumnBase::Display_SpellType,
new CSVWorld::EnumDelegateFactory (sSpellTypes));
}
CSVDoc::ViewManager::~ViewManager()

View file

@ -24,6 +24,7 @@ void CSVWorld::addSubViewFactories (CSVDoc::SubViewFactoryManager& manager)
CSMWorld::UniversalId::Type_Scripts,
CSMWorld::UniversalId::Type_Regions,
CSMWorld::UniversalId::Type_Birthsigns,
CSMWorld::UniversalId::Type_Spells,
CSMWorld::UniversalId::Type_None // end marker
};

View file

@ -319,6 +319,7 @@ namespace MWBase
virtual void allowVanityMode(bool allow) = 0;
virtual void togglePlayerLooking(bool enable) = 0;
virtual void changeVanityModeScale(float factor) = 0;
virtual bool vanityRotateCamera(float * rot) = 0;
virtual void renderPlayer() = 0;

View file

@ -236,9 +236,7 @@ namespace MWGui
mReflectTerrainButton->setCaptionWithReplacing(Settings::Manager::getBool("reflect terrain", "Water") ? "#{sOn}" : "#{sOff}");
mShadowsTextureSize->setCaption (Settings::Manager::getString ("texture size", "Shadows"));
//mShadowsLargeDistance->setCaptionWithReplacing(Settings::Manager::getBool("split", "Shadows") ? "#{sOn}" : "#{sOff}");
mShadowsLargeDistance->setCaptionWithReplacing("#{sOff}");
mShadowsLargeDistance->setEnabled (false);
mShadowsLargeDistance->setCaptionWithReplacing(Settings::Manager::getBool("split", "Shadows") ? "#{sOn}" : "#{sOff}");
mShadowsEnabledButton->setCaptionWithReplacing(Settings::Manager::getBool("enabled", "Shadows") ? "#{sOn}" : "#{sOff}");
mActorShadows->setCaptionWithReplacing(Settings::Manager::getBool("actor shadows", "Shadows") ? "#{sOn}" : "#{sOff}");

View file

@ -533,8 +533,17 @@ namespace MWInput
float scale = MWBase::Environment::get().getFrameDuration();
if(scale <= 0.0f) scale = 1.0f;
mPlayer.setYaw(x/scale);
mPlayer.setPitch(-y/scale);
float rot[3];
rot[0] = -y;
rot[1] = 0.0f;
rot[2] = x;
// Only actually turn player when we're not in vanity mode
if(!MWBase::Environment::get().getWorld()->vanityRotateCamera(rot))
{
mPlayer.setYaw(x/scale);
mPlayer.setPitch(-y/scale);
}
if (arg.state.Z.rel)
MWBase::Environment::get().getWorld()->changeVanityModeScale(arg.state.Z.rel);

View file

@ -891,6 +891,16 @@ void RenderingManager::getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float
mPlayer->getSightAngles(pitch, yaw);
}
bool RenderingManager::vanityRotateCamera(float* rot)
{
if(!mPlayer->isVanityOrPreviewModeEnabled())
return false;
Ogre::Vector3 vRot(rot);
mPlayer->rotateCamera(vRot, true);
return true;
}
void RenderingManager::getInteriorMapPosition (Ogre::Vector2 position, float& nX, float& nY, int &x, int& y)
{
return mLocalMap->getInteriorMapPosition (position, nX, nY, x, y);

View file

@ -88,6 +88,8 @@ class RenderingManager: private RenderingInterface, public Ogre::WindowEventList
mPlayer->setCameraDistance(-factor/120.f*10, true, true);
}
bool vanityRotateCamera(float* rot);
void getPlayerData(Ogre::Vector3 &eyepos, float &pitch, float &yaw);
void attachCameraTo(const MWWorld::Ptr &ptr);

View file

@ -28,10 +28,7 @@ void Shadows::recreate()
{
bool enabled = Settings::Manager::getBool("enabled", "Shadows");
// Split shadow maps are currently disabled because the terrain cannot cope with them
// (Too many texture units) Solution would be a multi-pass terrain material
//bool split = Settings::Manager::getBool("split", "Shadows");
const bool split = false;
bool split = Settings::Manager::getBool("split", "Shadows");
sh::Factory::getInstance ().setGlobalSetting ("shadows", enabled && !split ? "true" : "false");
sh::Factory::getInstance ().setGlobalSetting ("shadows_pssm", enabled && split ? "true" : "false");

View file

@ -68,59 +68,113 @@ namespace MWRender
Ogre::MaterialManager::getSingleton().remove(matName);
mMaterial = sh::Factory::getInstance().createMaterialInstance (matName);
mMaterial->setProperty ("allow_fixed_function", sh::makeProperty<sh::BooleanValue>(new sh::BooleanValue(false)));
sh::MaterialInstancePass* p = mMaterial->createPass ();
int numPasses = getRequiredPasses(terrain);
int maxLayersInOnePass = getMaxLayersPerPass(terrain);
p->setProperty ("vertex_program", sh::makeProperty<sh::StringValue>(new sh::StringValue("terrain_vertex")));
p->setProperty ("fragment_program", sh::makeProperty<sh::StringValue>(new sh::StringValue("terrain_fragment")));
p->mShaderProperties.setProperty ("colour_map", sh::makeProperty<sh::BooleanValue>(new sh::BooleanValue(mGlobalColourMap)));
// global colour map
sh::MaterialInstanceTextureUnit* colourMap = p->createTextureUnit ("colourMap");
colourMap->setProperty ("texture_alias", sh::makeProperty<sh::StringValue> (new sh::StringValue(mMaterial->getName() + "_colourMap")));
colourMap->setProperty ("tex_address_mode", sh::makeProperty<sh::StringValue> (new sh::StringValue("clamp")));
// global normal map
sh::MaterialInstanceTextureUnit* normalMap = p->createTextureUnit ("normalMap");
normalMap->setProperty ("direct_texture", sh::makeProperty<sh::StringValue> (new sh::StringValue(terrain->getTerrainNormalMap ()->getName())));
normalMap->setProperty ("tex_address_mode", sh::makeProperty<sh::StringValue> (new sh::StringValue("clamp")));
Ogre::uint maxLayers = getMaxLayers(terrain);
Ogre::uint numBlendTextures = std::min(terrain->getBlendTextureCount(maxLayers), terrain->getBlendTextureCount());
Ogre::uint numLayers = std::min(maxLayers, static_cast<Ogre::uint>(terrain->getLayerCount()));
p->mShaderProperties.setProperty ("num_layers", sh::makeProperty<sh::StringValue>(new sh::StringValue(Ogre::StringConverter::toString(numLayers))));
p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty<sh::StringValue>(new sh::StringValue(Ogre::StringConverter::toString(numBlendTextures))));
// blend maps
for (Ogre::uint i = 0; i < numBlendTextures; ++i)
for (int pass=0; pass<numPasses; ++pass)
{
sh::MaterialInstanceTextureUnit* blendTex = p->createTextureUnit ("blendMap" + Ogre::StringConverter::toString(i));
blendTex->setProperty ("direct_texture", sh::makeProperty<sh::StringValue> (new sh::StringValue(terrain->getBlendTextureName(i))));
blendTex->setProperty ("tex_address_mode", sh::makeProperty<sh::StringValue> (new sh::StringValue("clamp")));
}
int layerOffset = maxLayersInOnePass * pass;
int blendmapOffset = (pass == 0) ? 1 : 0; // the first layer of the first pass is the base layer and does not need a blend map
// layer maps
for (Ogre::uint i = 0; i < numLayers; ++i)
{
sh::MaterialInstanceTextureUnit* diffuseTex = p->createTextureUnit ("diffuseMap" + Ogre::StringConverter::toString(i));
diffuseTex->setProperty ("direct_texture", sh::makeProperty<sh::StringValue> (new sh::StringValue(terrain->getLayerTextureName(i, 0))));
p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i),
sh::makeProperty<sh::StringValue>(new sh::StringValue(Ogre::StringConverter::toString(int((i-1) / 4)) + "." + getComponent(int((i-1) % 4)))));
}
sh::MaterialInstancePass* p = mMaterial->createPass ();
// shadow
for (Ogre::uint i = 0; i < 3; ++i)
{
sh::MaterialInstanceTextureUnit* shadowTex = p->createTextureUnit ("shadowMap" + Ogre::StringConverter::toString(i));
shadowTex->setProperty ("content_type", sh::makeProperty<sh::StringValue> (new sh::StringValue("shadow")));
}
p->setProperty ("vertex_program", sh::makeProperty<sh::StringValue>(new sh::StringValue("terrain_vertex")));
p->setProperty ("fragment_program", sh::makeProperty<sh::StringValue>(new sh::StringValue("terrain_fragment")));
if (pass != 0)
{
p->setProperty ("scene_blend", sh::makeProperty(new sh::StringValue("alpha_blend")));
// Only write if depth is equal to the depth value written by the previous pass.
p->setProperty ("depth_func", sh::makeProperty(new sh::StringValue("equal")));
}
p->mShaderProperties.setProperty ("shadowtexture_offset", sh::makeProperty<sh::StringValue>(new sh::StringValue(
Ogre::StringConverter::toString(numBlendTextures + numLayers + 2))));
p->mShaderProperties.setProperty ("colour_map", sh::makeProperty(new sh::BooleanValue(mGlobalColourMap)));
p->mShaderProperties.setProperty ("is_first_pass", sh::makeProperty(new sh::BooleanValue(pass == 0)));
// global colour map
sh::MaterialInstanceTextureUnit* colourMap = p->createTextureUnit ("colourMap");
colourMap->setProperty ("texture_alias", sh::makeProperty<sh::StringValue> (new sh::StringValue(mMaterial->getName() + "_colourMap")));
colourMap->setProperty ("tex_address_mode", sh::makeProperty<sh::StringValue> (new sh::StringValue("clamp")));
// global normal map
sh::MaterialInstanceTextureUnit* normalMap = p->createTextureUnit ("normalMap");
normalMap->setProperty ("direct_texture", sh::makeProperty<sh::StringValue> (new sh::StringValue(terrain->getTerrainNormalMap ()->getName())));
normalMap->setProperty ("tex_address_mode", sh::makeProperty<sh::StringValue> (new sh::StringValue("clamp")));
Ogre::uint numLayersInThisPass = std::min(maxLayersInOnePass, terrain->getLayerCount()-layerOffset);
// HACK: Terrain::getLayerBlendTextureIndex should be const, but it is not.
// Remove this once ogre got fixed.
Ogre::Terrain* nonconstTerrain = const_cast<Ogre::Terrain*>(terrain);
// a blend map might be shared between two passes
// so we can't just use terrain->getBlendTextureCount()
Ogre::uint numBlendTextures=0;
std::vector<std::string> blendTextures;
for (unsigned int layer=blendmapOffset; layer<numLayersInThisPass; ++layer)
{
std::string blendTextureName = terrain->getBlendTextureName(nonconstTerrain->getLayerBlendTextureIndex(
static_cast<Ogre::uint8>(layerOffset+layer)).first);
if (std::find(blendTextures.begin(), blendTextures.end(), blendTextureName) == blendTextures.end())
{
blendTextures.push_back(blendTextureName);
++numBlendTextures;
}
}
p->mShaderProperties.setProperty ("num_layers", sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(numLayersInThisPass))));
p->mShaderProperties.setProperty ("num_blendmaps", sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(numBlendTextures))));
// blend maps
// the index of the first blend map used in this pass
int blendmapStart;
if (terrain->getLayerCount() == 1) // special case. if there's only one layer, we don't need blend maps at all
blendmapStart = 0;
else
blendmapStart = nonconstTerrain->getLayerBlendTextureIndex(static_cast<Ogre::uint8>(layerOffset+blendmapOffset)).first;
for (Ogre::uint i = 0; i < numBlendTextures; ++i)
{
sh::MaterialInstanceTextureUnit* blendTex = p->createTextureUnit ("blendMap" + Ogre::StringConverter::toString(i));
blendTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getBlendTextureName(blendmapStart+i))));
blendTex->setProperty ("tex_address_mode", sh::makeProperty (new sh::StringValue("clamp")));
}
// layer maps
for (Ogre::uint i = 0; i < numLayersInThisPass; ++i)
{
sh::MaterialInstanceTextureUnit* diffuseTex = p->createTextureUnit ("diffuseMap" + Ogre::StringConverter::toString(i));
diffuseTex->setProperty ("direct_texture", sh::makeProperty (new sh::StringValue(terrain->getLayerTextureName(layerOffset+i, 0))));
if (i+layerOffset > 0)
{
int blendTextureIndex = nonconstTerrain->getLayerBlendTextureIndex(static_cast<Ogre::uint8>(layerOffset+i)).first;
int blendTextureComponent = nonconstTerrain->getLayerBlendTextureIndex(static_cast<Ogre::uint8>(layerOffset+i)).second;
p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i),
sh::makeProperty (new sh::StringValue(Ogre::StringConverter::toString(blendTextureIndex-blendmapStart) + "." + getComponent(blendTextureComponent))));
}
else
{
// just to make it shut up about blendmap_component_0 not existing in the first pass.
// it might be retrieved, but will never survive the preprocessing step.
p->mShaderProperties.setProperty ("blendmap_component_" + Ogre::StringConverter::toString(i),
sh::makeProperty (new sh::StringValue("")));
}
}
// shadow
for (Ogre::uint i = 0; i < 3; ++i)
{
sh::MaterialInstanceTextureUnit* shadowTex = p->createTextureUnit ("shadowMap" + Ogre::StringConverter::toString(i));
shadowTex->setProperty ("content_type", sh::makeProperty<sh::StringValue> (new sh::StringValue("shadow")));
}
p->mShaderProperties.setProperty ("shadowtexture_offset", sh::makeProperty (new sh::StringValue(
Ogre::StringConverter::toString(numBlendTextures + numLayersInThisPass + 2))));
// make sure the pass index is fed to the permutation handler, because blendmap components may be different
p->mShaderProperties.setProperty ("pass_index", sh::makeProperty(new sh::IntValue(pass)));
}
return Ogre::MaterialManager::getSingleton().getByName(matName);
}
@ -142,6 +196,11 @@ namespace MWRender
}
Ogre::uint8 TerrainMaterial::Profile::getMaxLayers(const Ogre::Terrain* terrain) const
{
return 255;
}
int TerrainMaterial::Profile::getMaxLayersPerPass (const Ogre::Terrain* terrain)
{
// count the texture units free
Ogre::uint8 freeTextureUnits = 16;
@ -151,11 +210,21 @@ namespace MWRender
--freeTextureUnits;
// shadow
--freeTextureUnits;
--freeTextureUnits;
--freeTextureUnits;
// each layer needs 1.25 units (1xdiffusespec, 0.25xblend)
return static_cast<Ogre::uint8>(freeTextureUnits / (1.25f));
}
int TerrainMaterial::Profile::getRequiredPasses (const Ogre::Terrain* terrain)
{
int maxLayersPerPass = getMaxLayersPerPass(terrain);
assert(terrain->getLayerCount());
assert(maxLayersPerPass);
return std::ceil(static_cast<float>(terrain->getLayerCount()) / maxLayersPerPass);
}
void TerrainMaterial::Profile::updateParams(const Ogre::MaterialPtr& mat, const Ogre::Terrain* terrain)
{
}

View file

@ -72,6 +72,9 @@ namespace MWRender
private:
sh::MaterialInstance* mMaterial;
int getRequiredPasses (const Ogre::Terrain* terrain);
int getMaxLayersPerPass (const Ogre::Terrain* terrain);
bool mGlobalColourMap;
};

View file

@ -118,6 +118,7 @@ namespace MWWorld
float verts = ESM::Land::LAND_SIZE;
float worldsize = ESM::Land::REAL_SIZE;
// Load terrain physics first...
if (cell->mCell->isExterior())
{
ESM::Land* land =
@ -137,6 +138,7 @@ namespace MWWorld
}
}
// ... then references. This is important for adjustPosition to work correctly.
/// \todo rescale depending on the state of a new GMST
insertCell (*cell, true);
@ -439,7 +441,6 @@ namespace MWWorld
insertCellRefList(mRendering, cell.mBooks, cell, *mPhysics, rescale);
insertCellRefList(mRendering, cell.mClothes, cell, *mPhysics, rescale);
insertCellRefList(mRendering, cell.mContainers, cell, *mPhysics, rescale);
insertCellRefList(mRendering, cell.mCreatures, cell, *mPhysics, rescale);
insertCellRefList(mRendering, cell.mDoors, cell, *mPhysics, rescale);
insertCellRefList(mRendering, cell.mIngreds, cell, *mPhysics, rescale);
insertCellRefList(mRendering, cell.mCreatureLists, cell, *mPhysics, rescale);
@ -447,11 +448,13 @@ namespace MWWorld
insertCellRefList(mRendering, cell.mLights, cell, *mPhysics, rescale);
insertCellRefList(mRendering, cell.mLockpicks, cell, *mPhysics, rescale);
insertCellRefList(mRendering, cell.mMiscItems, cell, *mPhysics, rescale);
insertCellRefList(mRendering, cell.mNpcs, cell, *mPhysics, rescale);
insertCellRefList(mRendering, cell.mProbes, cell, *mPhysics, rescale);
insertCellRefList(mRendering, cell.mRepairs, cell, *mPhysics, rescale);
insertCellRefList(mRendering, cell.mStatics, cell, *mPhysics, rescale);
insertCellRefList(mRendering, cell.mWeapons, cell, *mPhysics, rescale);
// Load NPCs and creatures _after_ everything else (important for adjustPosition to work correctly)
insertCellRefList(mRendering, cell.mCreatures, cell, *mPhysics, rescale);
insertCellRefList(mRendering, cell.mNpcs, cell, *mPhysics, rescale);
}
void Scene::addObjectToScene (const Ptr& ptr)

View file

@ -1364,6 +1364,11 @@ namespace MWWorld
return physactor && physactor->getOnGround();
}
bool World::vanityRotateCamera(float * rot)
{
return mRendering->vanityRotateCamera(rot);
}
void World::renderPlayer()
{
mRendering->renderPlayer(mPlayer->getPlayer());

View file

@ -361,6 +361,8 @@ namespace MWWorld
mRendering->changeVanityModeScale(factor);
}
virtual bool vanityRotateCamera(float * rot);
virtual void renderPlayer();
virtual void setupExternalRendering (MWRender::ExternalRendering& rendering);

View file

@ -20,4 +20,14 @@ void Spell::save(ESMWriter &esm)
mEffects.save(esm);
}
void Spell::blank()
{
mData.mType = 0;
mData.mCost = 0;
mData.mFlags = 0;
mName.clear();
mEffects.mList.clear();
}
}

View file

@ -43,6 +43,9 @@ struct Spell
void load(ESMReader &esm);
void save(ESMWriter &esm);
void blank();
///< Set record to default state (does not touch the ID/index).
};
}
#endif

View file

@ -45,8 +45,7 @@
// use alpha channel of the first texture
float alpha = shSample(texture1, UV).a;
// discard if alpha is less than 0.5
if (alpha < 1.0)
if (alpha < 0.5)
discard;
#endif

View file

@ -1,6 +1,6 @@
#include "core.h"
#define IS_FIRST_PASS 1
#define IS_FIRST_PASS (@shPropertyString(pass_index) == 0)
#define FOG @shGlobalSettingBool(fog)
@ -23,6 +23,9 @@
#define VIEWPROJ_FIX @shGlobalSettingBool(viewproj_fix)
#if !IS_FIRST_PASS
// This is not the first pass.
#endif
#if NEED_DEPTH
@shAllocatePassthrough(1, depth)
@ -222,7 +225,11 @@
float3 waterEyePos = intercept(worldPos, cameraPos.xyz - worldPos, float3(0,0,1), waterLevel);
#endif
#if !IS_FIRST_PASS
float combinedAlpha = 0.f;
#endif
// Layer calculations
@shForeach(@shPropertyString(num_blendmaps))
float4 blendValues@shIterator = shSample(blendMap@shIterator, UV);
@ -232,12 +239,20 @@
@shForeach(@shPropertyString(num_layers))
#if IS_FIRST_PASS == 1 && @shIterator == 0
// first layer of first pass doesn't need a blend map
#if IS_FIRST_PASS
#if @shIterator == 0
// first layer of first pass is the base layer and doesn't need a blend map
albedo = shSample(diffuseMap0, UV * 10).rgb;
#else
#else
albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator));
#endif
#else
#if @shIterator == 0
albedo = shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator);
#else
albedo = shLerp(albedo, shSample(diffuseMap@shIterator, UV * 10).rgb, blendValues@shPropertyString(blendmap_component_@shIterator));
#endif
combinedAlpha += blendValues@shPropertyString(blendmap_component_@shIterator);
#endif
@shEndForeach
@ -325,6 +340,12 @@
// prevent negative colour output (for example with negative lights)
shOutputColour(0).xyz = max(shOutputColour(0).xyz, float3(0,0,0));
#if IS_FIRST_PASS
shOutputColour(0).a = 1;
#else
shOutputColour(0).a = min(combinedAlpha, 1.f);
#endif
}
#endif