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:
commit
9d29921913
29 changed files with 367 additions and 68 deletions
|
@ -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
|
||||
)
|
||||
|
||||
|
||||
|
|
35
apps/opencs/model/tools/spellcheck.cpp
Normal file
35
apps/opencs/model/tools/spellcheck.cpp
Normal 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
|
||||
}
|
29
apps/opencs/model/tools/spellcheck.hpp
Normal file
29
apps/opencs/model/tools/spellcheck.hpp
Normal 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
|
|
@ -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;
|
||||
|
|
|
@ -34,7 +34,8 @@ namespace CSMWorld
|
|||
Display_GlobalVarType,
|
||||
Display_Specialisation,
|
||||
Display_Attribute,
|
||||
Display_Boolean
|
||||
Display_Boolean,
|
||||
Display_SpellType
|
||||
};
|
||||
|
||||
std::string mTitle;
|
||||
|
|
|
@ -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
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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.
|
||||
///
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -53,7 +53,9 @@ namespace CSMWorld
|
|||
Type_Regions,
|
||||
Type_Region,
|
||||
Type_Birthsigns,
|
||||
Type_Birthsign
|
||||
Type_Birthsign,
|
||||
Type_Spells,
|
||||
Type_Spell
|
||||
};
|
||||
|
||||
private:
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -131,6 +131,8 @@ namespace CSVDoc
|
|||
void addRegionsSubView();
|
||||
|
||||
void addBirthsignsSubView();
|
||||
|
||||
void addSpellsSubView();
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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}");
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
}
|
||||
|
|
|
@ -72,6 +72,9 @@ namespace MWRender
|
|||
private:
|
||||
sh::MaterialInstance* mMaterial;
|
||||
|
||||
int getRequiredPasses (const Ogre::Terrain* terrain);
|
||||
int getMaxLayersPerPass (const Ogre::Terrain* terrain);
|
||||
|
||||
bool mGlobalColourMap;
|
||||
|
||||
};
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -361,6 +361,8 @@ namespace MWWorld
|
|||
mRendering->changeVanityModeScale(factor);
|
||||
}
|
||||
|
||||
virtual bool vanityRotateCamera(float * rot);
|
||||
|
||||
virtual void renderPlayer();
|
||||
|
||||
virtual void setupExternalRendering (MWRender::ExternalRendering& rendering);
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue