Add glow effect for enchanted items

pull/136/head
scrawl 11 years ago
parent 0b9676aaa3
commit 3452bd2e0b

@ -17,6 +17,8 @@
#include "../mwbase/soundmanager.hpp"
#include "../mwbase/world.hpp"
#include <extern/shiny/Main/Factory.hpp>
#include "../mwmechanics/character.hpp"
#include "../mwmechanics/creaturestats.hpp"
#include "../mwworld/class.hpp"
@ -24,6 +26,7 @@
#include "renderconst.hpp"
namespace MWRender
{
@ -166,8 +169,37 @@ void Animation::setObjectRoot(const std::string &model, bool baseonly)
}
}
struct AddGlow
{
Ogre::Vector3* mColor;
AddGlow(Ogre::Vector3* col) : mColor(col) {}
// TODO: integrate this with material controllers?
void operator()(Ogre::Entity* entity) const
{
unsigned int numsubs = entity->getNumSubEntities();
for(unsigned int i = 0;i < numsubs;++i)
{
unsigned int numsubs = entity->getNumSubEntities();
for(unsigned int i = 0;i < numsubs;++i)
{
Ogre::SubEntity* subEnt = entity->getSubEntity(i);
std::string newName = subEnt->getMaterialName() + "@fx";
if (sh::Factory::getInstance().searchInstance(newName) == NULL)
{
sh::MaterialInstance* instance =
sh::Factory::getInstance().createMaterialInstance(newName, subEnt->getMaterialName());
instance->setProperty("env_map", sh::makeProperty(new sh::BooleanValue(true)));
instance->setProperty("env_map_color", sh::makeProperty(new sh::Vector3(mColor->x, mColor->y, mColor->z)));
}
subEnt->setMaterialName(newName);
}
}
}
};
class VisQueueSet {
class VisQueueSet
{
Ogre::uint32 mVisFlags;
Ogre::uint8 mSolidQueue, mTransQueue;
Ogre::Real mDist;
@ -201,12 +233,16 @@ public:
}
};
void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue, Ogre::Real dist)
void Animation::setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue, Ogre::Real dist, bool enchantedGlow, Ogre::Vector3* glowColor)
{
std::for_each(objlist.mEntities.begin(), objlist.mEntities.end(),
VisQueueSet(visflags, solidqueue, transqueue, dist));
std::for_each(objlist.mParticles.begin(), objlist.mParticles.end(),
VisQueueSet(visflags, solidqueue, transqueue, dist));
if (enchantedGlow)
std::for_each(objlist.mEntities.begin(), objlist.mEntities.end(),
AddGlow(glowColor));
}
@ -1116,6 +1152,23 @@ void Animation::updateEffects(float duration)
}
}
// TODO: Should not be here
Ogre::Vector3 Animation::getEnchantmentColor(MWWorld::Ptr item)
{
Ogre::Vector3 result(1,1,1);
std::string enchantmentName = item.getClass().getEnchantment(item);
if (enchantmentName.empty())
return result;
const ESM::Enchantment* enchantment = MWBase::Environment::get().getWorld()->getStore().get<ESM::Enchantment>().find(enchantmentName);
assert (enchantment->mEffects.mList.size());
const ESM::MagicEffect* magicEffect = MWBase::Environment::get().getWorld()->getStore().get<ESM::MagicEffect>().find(
enchantment->mEffects.mList.front().mEffectID);
result.x = magicEffect->mData.mRed / 255.f;
result.y = magicEffect->mData.mGreen / 255.f;
result.z = magicEffect->mData.mBlue / 255.f;
return result;
}
ObjectAnimation::ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &model)
: Animation(ptr, ptr.getRefData().getBaseNode())
@ -1132,9 +1185,10 @@ ObjectAnimation::ObjectAnimation(const MWWorld::Ptr& ptr, const std::string &mod
small = false;
float dist = small ? Settings::Manager::getInt("small object distance", "Viewing distance") : 0.0f;
Ogre::Vector3 col = getEnchantmentColor(ptr);
setRenderProperties(mObjectRoot, (mPtr.getTypeName() == typeid(ESM::Static).name()) ?
(small ? RV_StaticsSmall : RV_Statics) : RV_Misc,
RQG_Main, RQG_Alpha, dist);
RQG_Main, RQG_Alpha, dist, !ptr.getClass().getEnchantment(ptr).empty(), &col);
}
void ObjectAnimation::addLight(const ESM::Light *light)

@ -191,10 +191,15 @@ protected:
static void destroyObjectList(Ogre::SceneManager *sceneMgr, NifOgre::ObjectList &objects);
static void setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue, Ogre::uint8 transqueue, Ogre::Real dist=0.0f);
static void setRenderProperties(const NifOgre::ObjectList &objlist, Ogre::uint32 visflags, Ogre::uint8 solidqueue,
Ogre::uint8 transqueue, Ogre::Real dist=0.0f,
bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL);
void clearAnimSources();
// TODO: Should not be here
Ogre::Vector3 getEnchantmentColor(MWWorld::Ptr item);
public:
Animation(const MWWorld::Ptr &ptr, Ogre::SceneNode *node);
virtual ~Animation();

@ -208,17 +208,19 @@ void NpcAnimation::updateParts()
removeIndividualPart(ESM::PRT_Hair);
int prio = 1;
bool enchantedGlow = !store->getClass().getEnchantment(*store).empty();
Ogre::Vector3 glowColor = getEnchantmentColor(*store);
if(store->getTypeName() == typeid(ESM::Clothing).name())
{
prio = ((slotlist[i].mBasePriority+1)<<1) + 0;
const ESM::Clothing *clothes = store->get<ESM::Clothing>()->mBase;
addPartGroup(slotlist[i].mSlot, prio, clothes->mParts.mParts);
addPartGroup(slotlist[i].mSlot, prio, clothes->mParts.mParts, enchantedGlow, &glowColor);
}
else if(store->getTypeName() == typeid(ESM::Armor).name())
{
prio = ((slotlist[i].mBasePriority+1)<<1) + 1;
const ESM::Armor *armor = store->get<ESM::Armor>()->mBase;
addPartGroup(slotlist[i].mSlot, prio, armor->mParts.mParts);
addPartGroup(slotlist[i].mSlot, prio, armor->mParts.mParts, enchantedGlow, &glowColor);
}
if(slotlist[i].mSlot == MWWorld::InventoryStore::Slot_Robe)
@ -389,10 +391,11 @@ public:
}
};
NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename)
NifOgre::ObjectList NpcAnimation::insertBoundedPart(const std::string &model, int group, const std::string &bonename, bool enchantedGlow, Ogre::Vector3* glowColor)
{
NifOgre::ObjectList objects = NifOgre::Loader::createObjects(mSkelBase, bonename, mInsert, model);
setRenderProperties(objects, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha);
setRenderProperties(objects, (mViewMode == VM_FirstPerson) ? RV_FirstPerson : mVisibilityFlags, RQG_Main, RQG_Alpha, 0,
enchantedGlow, glowColor);
std::for_each(objects.mEntities.begin(), objects.mEntities.end(), SetObjectGroup(group));
std::for_each(objects.mParticles.begin(), objects.mParticles.end(), SetObjectGroup(group));
@ -475,7 +478,7 @@ void NpcAnimation::removePartGroup(int group)
}
}
bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority, const std::string &mesh)
bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority, const std::string &mesh, bool enchantedGlow, Ogre::Vector3* glowColor)
{
if(priority <= mPartPriorities[type])
return false;
@ -484,7 +487,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g
mPartslots[type] = group;
mPartPriorities[type] = priority;
mObjectParts[type] = insertBoundedPart(mesh, group, sPartList.at(type));
mObjectParts[type] = insertBoundedPart(mesh, group, sPartList.at(type), enchantedGlow, glowColor);
if(mObjectParts[type].mSkelBase)
{
Ogre::SkeletonInstance *skel = mObjectParts[type].mSkelBase->getSkeleton();
@ -521,7 +524,7 @@ bool NpcAnimation::addOrReplaceIndividualPart(ESM::PartReferenceType type, int g
return true;
}
void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts)
void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts, bool enchantedGlow, Ogre::Vector3* glowColor)
{
const MWWorld::ESMStore &store = MWBase::Environment::get().getWorld()->getStore();
const MWWorld::Store<ESM::BodyPart> &partStore = store.get<ESM::BodyPart>();
@ -559,7 +562,7 @@ void NpcAnimation::addPartGroup(int group, int priority, const std::vector<ESM::
}
if(bodypart)
addOrReplaceIndividualPart((ESM::PartReferenceType)part->mPart, group, priority, "meshes\\"+bodypart->mModel);
addOrReplaceIndividualPart((ESM::PartReferenceType)part->mPart, group, priority, "meshes\\"+bodypart->mModel, enchantedGlow, glowColor);
else
reserveIndividualPart((ESM::PartReferenceType)part->mPart, group, priority);
}
@ -574,8 +577,10 @@ void NpcAnimation::showWeapons(bool showWeapon)
MWWorld::ContainerStoreIterator weapon = inv.getSlot(MWWorld::InventoryStore::Slot_CarriedRight);
if(weapon != inv.end()) // special case for weapons
{
Ogre::Vector3 glowColor = getEnchantmentColor(*weapon);
std::string mesh = MWWorld::Class::get(*weapon).getModel(*weapon);
addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1, mesh);
addOrReplaceIndividualPart(ESM::PRT_Weapon, MWWorld::InventoryStore::Slot_CarriedRight, 1,
mesh, !weapon->getClass().getEnchantment(*weapon).empty(), &glowColor);
}
}
else

@ -51,14 +51,17 @@ private:
void updateNpcBase();
NifOgre::ObjectList insertBoundedPart(const std::string &model, int group, const std::string &bonename);
NifOgre::ObjectList insertBoundedPart(const std::string &model, int group, const std::string &bonename,
bool enchantedGlow, Ogre::Vector3* glowColor=NULL);
void removeIndividualPart(ESM::PartReferenceType type);
void reserveIndividualPart(ESM::PartReferenceType type, int group, int priority);
bool addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority, const std::string &mesh);
bool addOrReplaceIndividualPart(ESM::PartReferenceType type, int group, int priority, const std::string &mesh,
bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL);
void removePartGroup(int group);
void addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts);
void addPartGroup(int group, int priority, const std::vector<ESM::PartReference> &parts,
bool enchantedGlow=false, Ogre::Vector3* glowColor=NULL);
public:
/**

@ -33,6 +33,8 @@ class Objects{
void insertBegin(const MWWorld::Ptr& ptr);
public:
Objects(OEngine::Render::OgreRenderer &renderer)
: mRenderer(renderer)

@ -49,8 +49,9 @@ struct MagicEffect
int mSchool; // SpellSchool, see defs.hpp
float mBaseCost;
int mFlags;
// Properties of the fired magic 'ball' I think
int mRed, mBlue, mGreen;
// Glow color for enchanted items with this effect
int mRed, mGreen, mBlue;
// Properties of the fired magic 'ball'
float mSpeed, mSize, mSizeCap;
}; // 36 bytes

@ -259,8 +259,9 @@ namespace sh
Platform* mPlatform;
MaterialInstance* findInstance (const std::string& name);
public:
MaterialInstance* searchInstance (const std::string& name);
private:
/// @return was anything removed?
bool removeCache (const std::string& pattern);

@ -1,5 +1,8 @@
#include "OgreTextureUnitState.hpp"
#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>
#include "OgrePass.hpp"
#include "OgrePlatform.hpp"
#include "OgreMaterialSerializer.hpp"
@ -28,6 +31,32 @@ namespace sh
setTextureName (retrieveValue<StringValue>(value, context).get());
return true;
}
else if (name == "anim_texture2")
{
std::string val = retrieveValue<StringValue>(value, context).get();
std::vector<std::string> tokens;
boost::split(tokens, val, boost::is_any_of(" "));
assert(tokens.size() == 3);
std::string texture = tokens[0];
int frames = boost::lexical_cast<int>(tokens[1]);
float duration = boost::lexical_cast<float>(tokens[2]);
std::vector<Ogre::String> frameTextures;
for (int i=0; i<frames; ++i)
{
std::stringstream stream;
stream << std::setw(2);
stream << std::setfill('0');
stream << i;
stream << '.';
std::string tex = texture;
boost::replace_last(tex, ".", stream.str());
frameTextures.push_back(tex);
}
mTextureUnitState->setAnimatedTextureName(&frameTextures[0], frames, duration);
return true;
}
else if (name == "create_in_ffp")
return true; // handled elsewhere

@ -19,6 +19,8 @@ material openmw_objects_base
alpha_rejection default
transparent_sorting default
polygon_mode default
env_map false
env_map_color 1 1 1
pass
{
@ -33,6 +35,8 @@ material openmw_objects_base
detailMapUVSet $detailMapUVSet
emissiveMap $emissiveMap
detailMap $detailMap
env_map $env_map
env_map_color $env_map_color
}
diffuse $diffuse
@ -76,6 +80,14 @@ material openmw_objects_base
tex_coord_set $detailMapUVSet
}
texture_unit envMap
{
create_in_ffp $env_map
env_map spherical
anim_texture2 textures\magicitem\caust.dds 32 2
colour_op add
}
texture_unit shadowMap0
{
content_type shadow

@ -30,6 +30,8 @@
#define VIEWPROJ_FIX @shGlobalSettingBool(viewproj_fix)
#define ENV_MAP @shPropertyBool(env_map)
#ifdef SH_VERTEX_SHADER
// ------------------------------------- VERTEX ---------------------------------------
@ -61,7 +63,7 @@
shOutput(float3, tangentPassthrough)
#endif
#if !VERTEX_LIGHTING
#if !VERTEX_LIGHTING || ENV_MAP
shOutput(float3, normalPassthrough)
#endif
@ -79,12 +81,15 @@
shOutput(float4, colourPassthrough)
#endif
#if ENV_MAP || VERTEX_LIGHTING
shUniform(float4x4, worldView) @shAutoConstant(worldView, worldview_matrix)
#endif
#if VERTEX_LIGHTING
shUniform(float4, lightPosition[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightPosition, light_position_view_space_array, @shGlobalSettingString(num_lights))
shUniform(float4, lightDiffuse[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightDiffuse, light_diffuse_colour_array, @shGlobalSettingString(num_lights))
shUniform(float4, lightAttenuation[@shGlobalSettingString(num_lights)]) @shAutoConstant(lightAttenuation, light_attenuation_array, @shGlobalSettingString(num_lights))
shUniform(float4, lightAmbient) @shAutoConstant(lightAmbient, ambient_light_colour)
shUniform(float4x4, worldView) @shAutoConstant(worldView, worldview_matrix)
#if VERTEXCOLOR_MODE != 2
shUniform(float4, materialAmbient) @shAutoConstant(materialAmbient, surface_ambient_colour)
#endif
@ -125,10 +130,23 @@
UV.zw = uv1;
#endif
#if ENV_MAP || VERTEX_LIGHTING
float3 viewNormal = normalize(shMatrixMult(worldView, float4(normal.xyz, 0)).xyz);
#endif
#if ENV_MAP
float3 viewVec = normalize( shMatrixMult(worldView, shInputPosition).xyz);
float3 r = reflect( viewVec, viewNormal );
float m = 2.0 * sqrt( r.x*r.x + r.y*r.y + (r.z+1.0)*(r.z+1.0) );
UV.z = r.x/m + 0.5;
UV.w = r.y/m + 0.5;
#endif
#if NORMAL_MAP
tangentPassthrough = tangent.xyz;
#endif
#if !VERTEX_LIGHTING
#if !VERTEX_LIGHTING || ENV_MAP
normalPassthrough = normal.xyz;
#endif
#if VERTEXCOLOR_MODE != 0 && !VERTEX_LIGHTING
@ -173,7 +191,6 @@
#if VERTEX_LIGHTING
float3 viewPos = shMatrixMult(worldView, shInputPosition).xyz;
float3 viewNormal = normalize(shMatrixMult(worldView, float4(normal.xyz, 0)).xyz);
float3 lightDir;
float d;
@ -242,12 +259,18 @@
shSampler2D(detailMap)
#endif
#if ENV_MAP
shSampler2D(envMap)
shUniform(float3, env_map_color) @shUniformProperty3f(env_map_color, env_map_color)
shUniform(float3, cameraPosObjSpace) @shAutoConstant(cameraPosObjSpace, camera_position_object_space)
#endif
shInput(float4, UV)
#if NORMAL_MAP
shInput(float3, tangentPassthrough)
#endif
#if !VERTEX_LIGHTING
#if !VERTEX_LIGHTING || ENV_MAP
shInput(float3, normalPassthrough)
#endif
@ -327,8 +350,11 @@
#endif
#endif
#if NORMAL_MAP
#if !VERTEX_LIGHTING || ENV_MAP
float3 normal = normalPassthrough;
#endif
#if NORMAL_MAP
float3 binormal = cross(tangentPassthrough.xyz, normal.xyz);
float3x3 tbn = float3x3(tangentPassthrough.xyz, binormal, normal.xyz);
@ -420,6 +446,23 @@
shOutputColour(0) *= lightResult;
#endif
#if EMISSIVE_MAP
#if @shPropertyString(emissiveMapUVSet)
shOutputColour(0).xyz += shSample(emissiveMap, UV.zw).xyz;
#else
shOutputColour(0).xyz += shSample(emissiveMap, UV.xy).xyz;
#endif
#endif
#if ENV_MAP
// Everything looks better with fresnel
float3 eyeDir = normalize(cameraPosObjSpace.xyz - objSpacePositionPassthrough.xyz);
float facing = 1.0 - max(abs(dot(-eyeDir, normal)), 0);
float envFactor = shSaturate(0.25 + 0.75 * pow(facing, 1));
shOutputColour(0).xyz += shSample(envMap, UV.zw).xyz * envFactor * env_map_color;
#endif
#if FOG
float fogValue = shSaturate((depthPassthrough - fogParams.y) * fogParams.w);
@ -430,14 +473,6 @@
shOutputColour(0).xyz = shLerp (shOutputColour(0).xyz, fogColour, fogValue);
#endif
#endif
#if EMISSIVE_MAP
#if @shPropertyString(emissiveMapUVSet)
shOutputColour(0).xyz += shSample(emissiveMap, UV.zw).xyz;
#else
shOutputColour(0).xyz += shSample(emissiveMap, UV.xy).xyz;
#endif
#endif
// prevent negative colour output (for example with negative lights)

Loading…
Cancel
Save