Add support for scene_blend in material scripts (#303)

stable-5.1
Armin Burgmeier 2010-06-09 00:55:34 +02:00
parent 6729c0ca64
commit e282de55f1
11 changed files with 207 additions and 83 deletions

View File

@ -6,6 +6,7 @@ material RopeBalloon
pass pass
{ {
cull_hardware none cull_hardware none
scene_blend src_alpha one_minus_src_alpha
ambient 1.500000 1.500000 1.500000 1.000000 ambient 1.500000 1.500000 1.500000 1.000000
diffuse 0.640000 0.640000 0.640000 1.000000 diffuse 0.640000 0.640000 0.640000 1.000000

View File

@ -996,12 +996,7 @@ void C4GraphicsOverlay::Draw(C4TargetFacet &cgo, C4Object *pForObj, int32_t iByP
if (dwClrModulation != 0xffffff) Application.DDraw->ActivateBlitModulation(dwClrModulation); if (dwClrModulation != 0xffffff) Application.DDraw->ActivateBlitModulation(dwClrModulation);
if (pMeshInstance) if (pMeshInstance)
{ pMeshInstance->SetFaceOrderingForClrModulation(dwClrModulation);
if ( ((dwClrModulation >> 24) & 0xff) != 0xff)
pMeshInstance->SetFaceOrdering(StdMeshInstance::FO_NearestToFarthest);
else
pMeshInstance->SetFaceOrdering(StdMeshInstance::FO_Fixed);
}
} }
if (eMode == MODE_Rank) if (eMode == MODE_Rank)
{ {
@ -1174,12 +1169,7 @@ void C4GraphicsOverlay::DrawPicture(C4Facet &cgo, C4Object *pForObj)
if (dwClrModulation != 0xffffff) Application.DDraw->ActivateBlitModulation(dwClrModulation); if (dwClrModulation != 0xffffff) Application.DDraw->ActivateBlitModulation(dwClrModulation);
if (pMeshInstance) if (pMeshInstance)
{ pMeshInstance->SetFaceOrderingForClrModulation(dwClrModulation);
if ( ((dwClrModulation >> 24) & 0xff) != 0xff)
pMeshInstance->SetFaceOrdering(StdMeshInstance::FO_NearestToFarthest);
else
pMeshInstance->SetFaceOrdering(StdMeshInstance::FO_Fixed);
}
} }
// draw at given rect // draw at given rect
if (!pMeshInstance) if (!pMeshInstance)

View File

@ -251,8 +251,7 @@ bool C4Object::Init(C4PropList *pDef, C4Object *pCreator,
if (pGraphics->Type == C4DefGraphics::TYPE_Mesh) if (pGraphics->Type == C4DefGraphics::TYPE_Mesh)
{ {
pMeshInstance = new StdMeshInstance(*pGraphics->Mesh); pMeshInstance = new StdMeshInstance(*pGraphics->Mesh);
if ( ((ColorMod >> 24) & 0xff) != 0xff) // Sort faces if the object is transparent pMeshInstance->SetFaceOrderingForClrModulation(ColorMod);
pMeshInstance->SetFaceOrdering(StdMeshInstance::FO_NearestToFarthest);
} }
else else
{ {
@ -486,8 +485,7 @@ void C4Object::UpdateGraphics(bool fGraphicsChanged, bool fTemp)
if (pGraphics->Type == C4DefGraphics::TYPE_Mesh) if (pGraphics->Type == C4DefGraphics::TYPE_Mesh)
{ {
pMeshInstance = new StdMeshInstance(*pGraphics->Mesh); pMeshInstance = new StdMeshInstance(*pGraphics->Mesh);
if ( ((ColorMod >> 24) & 0xff) != 0xff) // Sort faces if the object is transparent pMeshInstance->SetFaceOrderingForClrModulation(ColorMod);
pMeshInstance->SetFaceOrdering(StdMeshInstance::FO_NearestToFarthest);
} }
else else
{ {
@ -2847,12 +2845,11 @@ void C4Object::CompileFunc(StdCompiler *pComp)
Action.PhaseDelay=iPhaseDelay; Action.PhaseDelay=iPhaseDelay;
}*/ }*/
// Set Action animation by slot 0
if (pMeshInstance) if (pMeshInstance)
{ {
// Set Action animation by slot 0
Action.Animation = pMeshInstance->GetRootAnimationForSlot(0); Action.Animation = pMeshInstance->GetRootAnimationForSlot(0);
if ( ((ColorMod >> 24) & 0xff) != 0xff) // Sort faces if the object is transparent pMeshInstance->SetFaceOrderingForClrModulation(ColorMod);
pMeshInstance->SetFaceOrdering(StdMeshInstance::FO_NearestToFarthest);
} }
// if on fire but no effect is present (old-style savegames), re-incinerate // if on fire but no effect is present (old-style savegames), re-incinerate

View File

@ -3421,12 +3421,7 @@ static bool FnSetClrModulation(C4AulObjectContext *cthr, Nillable<long> dwClr, l
// set it // set it
cthr->Obj->ColorMod=clr; cthr->Obj->ColorMod=clr;
if (cthr->Obj->pMeshInstance) if (cthr->Obj->pMeshInstance)
{ cthr->Obj->pMeshInstance->SetFaceOrderingForClrModulation(clr);
if ( ((clr >> 24) & 0xff) != 0xff)
cthr->Obj->pMeshInstance->SetFaceOrdering(StdMeshInstance::FO_NearestToFarthest);
else
cthr->Obj->pMeshInstance->SetFaceOrdering(StdMeshInstance::FO_Fixed);
}
} }
// success // success
return true; return true;

View File

@ -40,6 +40,9 @@ CStdDDraw *lpDDraw=NULL;
CStdPalette *lpDDrawPal=NULL; CStdPalette *lpDDrawPal=NULL;
int iGfxEngine=-1; int iGfxEngine=-1;
// Transformation matrix to convert meshes from Ogre to Clonk coordinate system
const StdMeshMatrix CStdDDraw::OgreToClonk = StdMeshMatrix::Scale(-1.0f, 1.0f, 1.0f) * StdMeshMatrix::Rotate(float(M_PI)/2.0f, 1.0f, 0.0f, 0.0f) * StdMeshMatrix::Rotate(float(M_PI)/2.0f, 0.0f, 0.0f, 1.0f);
inline void SetRect(RECT &rect, int left, int top, int right, int bottom) inline void SetRect(RECT &rect, int left, int top, int right, int bottom)
{ {
rect.left=left; rect.top=top; rect.bottom=bottom; rect.right=right; rect.left=left; rect.top=top; rect.bottom=bottom; rect.right=right;
@ -702,6 +705,10 @@ bool CStdDDraw::RenderMesh(StdMeshInstance &instance, SURFACE sfcTarget, float t
if (!PrepareRendering(sfcTarget)) return false; if (!PrepareRendering(sfcTarget)) return false;
// Update bone matrices and vertex data (note this also updates attach transforms and child transforms) // Update bone matrices and vertex data (note this also updates attach transforms and child transforms)
instance.UpdateBoneTransforms(); instance.UpdateBoneTransforms();
// Order faces according to MeshTransformation (note pTransform does not affect Z coordinate, so does not need to be taken into account for correct ordering)
StdMeshMatrix mat = OgreToClonk;
if(MeshTransform) mat = *MeshTransform * mat;
instance.ReorderFaces(&mat);
// Render mesh // Render mesh
PerformMesh(instance, tx, ty, twdt, thgt, dwPlayerColor, pTransform); PerformMesh(instance, tx, ty, twdt, thgt, dwPlayerColor, pTransform);
// success // success

View File

@ -210,6 +210,8 @@ struct ZoomData
class CStdDDraw class CStdDDraw
{ {
public: public:
static const StdMeshMatrix OgreToClonk;
CStdDDraw(): MaxTexSize(0), Saturation(255) { lpDDrawPal=&Pal; } CStdDDraw(): MaxTexSize(0), Saturation(255) { lpDDrawPal=&Pal; }
virtual ~CStdDDraw() { lpDDraw=NULL; } virtual ~CStdDDraw() { lpDDraw=NULL; }
public: public:

View File

@ -677,7 +677,25 @@ namespace
glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, Color); glTexEnvfv(GL_TEXTURE_ENV, GL_TEXTURE_ENV_COLOR, Color);
} }
void RenderSubMeshImpl(const StdSubMeshInstance& instance, DWORD dwModClr, bool fMod2, DWORD dwPlayerColor, bool parity) inline GLenum OgreBlendTypeToGL(StdMeshMaterialPass::SceneBlendType blend)
{
switch(blend)
{
case StdMeshMaterialPass::SB_One: return GL_ONE;
case StdMeshMaterialPass::SB_Zero: return GL_ZERO;
case StdMeshMaterialPass::SB_DestColor: return GL_DST_COLOR;
case StdMeshMaterialPass::SB_SrcColor: return GL_SRC_COLOR;
case StdMeshMaterialPass::SB_OneMinusDestColor: return GL_ONE_MINUS_DST_COLOR;
case StdMeshMaterialPass::SB_OneMinusSrcColor: return GL_ONE_MINUS_SRC_COLOR;
case StdMeshMaterialPass::SB_DestAlpha: return GL_DST_ALPHA;
case StdMeshMaterialPass::SB_SrcAlpha: return GL_SRC_ALPHA;
case StdMeshMaterialPass::SB_OneMinusDestAlpha: return GL_ONE_MINUS_DST_ALPHA;
case StdMeshMaterialPass::SB_OneMinusSrcAlpha: return GL_ONE_MINUS_SRC_ALPHA;
default: assert(false); return GL_ZERO;
}
}
void RenderSubMeshImpl(const StdSubMeshInstance& instance, DWORD dwModClr, DWORD dwBlitMode, DWORD dwPlayerColor, bool parity)
{ {
const StdMeshMaterial& material = instance.GetMaterial(); const StdMeshMaterial& material = instance.GetMaterial();
assert(material.BestTechniqueIndex != -1); assert(material.BestTechniqueIndex != -1);
@ -697,7 +715,7 @@ namespace
// clrmodmap texture needs to be the last texture in that case... we should // clrmodmap texture needs to be the last texture in that case... we should
// change the index to maxtextures-1 instead of 3. // change the index to maxtextures-1 instead of 3.
if(!fMod2 && dwModClr == 0xffffffff) if(!(dwBlitMode & C4GFXBLIT_MOD2) && dwModClr == 0xffffffff)
{ {
// Fastpath for the easy case // Fastpath for the easy case
glMaterialfv(GL_FRONT, GL_AMBIENT, pass.Ambient); glMaterialfv(GL_FRONT, GL_AMBIENT, pass.Ambient);
@ -719,7 +737,7 @@ namespace
// TODO: We could also consider applying dwmod using an additional // TODO: We could also consider applying dwmod using an additional
// texture unit, maybe we can even re-use the one which is reserved for // texture unit, maybe we can even re-use the one which is reserved for
// the clrmodmap texture anyway (+adapt the shader). // the clrmodmap texture anyway (+adapt the shader).
if(!fMod2) if(!(dwBlitMode & C4GFXBLIT_MOD2))
{ {
Ambient[0] = pass.Ambient[0] * dwMod[0]; Ambient[0] = pass.Ambient[0] * dwMod[0];
Ambient[1] = pass.Ambient[1] * dwMod[1]; Ambient[1] = pass.Ambient[1] * dwMod[1];
@ -786,6 +804,16 @@ namespace
break; break;
} }
if(!(dwBlitMode & C4GFXBLIT_ADDITIVE))
{
glBlendFunc(OgreBlendTypeToGL(pass.SceneBlendFactors[0]),
OgreBlendTypeToGL(pass.SceneBlendFactors[1]));
}
else
{
glBlendFunc(OgreBlendTypeToGL(pass.SceneBlendFactors[0]), GL_ONE);
}
// TODO: Use vbo if available. // TODO: Use vbo if available.
// Note that we need to do this before we do glTexCoordPointer for the // Note that we need to do this before we do glTexCoordPointer for the
// texture units below, otherwise the texcoordpointer is reset by this // texture units below, otherwise the texcoordpointer is reset by this
@ -968,13 +996,13 @@ namespace
} }
} }
void RenderMeshImpl(StdMeshInstance& instance, DWORD dwModClr, bool fMod2, DWORD dwPlayerColor, bool parity) void RenderMeshImpl(StdMeshInstance& instance, DWORD dwModClr, DWORD dwBlitMode, DWORD dwPlayerColor, bool parity)
{ {
const StdMesh& mesh = instance.Mesh; const StdMesh& mesh = instance.Mesh;
// Render each submesh // Render each submesh
for (unsigned int i = 0; i < mesh.GetNumSubMeshes(); ++i) for (unsigned int i = 0; i < mesh.GetNumSubMeshes(); ++i)
RenderSubMeshImpl(instance.GetSubMesh(i), dwModClr, fMod2, dwPlayerColor, parity); RenderSubMeshImpl(instance.GetSubMesh(i), dwModClr, dwBlitMode, dwPlayerColor, parity);
#if 0 #if 0
// Draw attached bone // Draw attached bone
@ -1015,7 +1043,7 @@ namespace
// TODO: Take attach transform's parity into account // TODO: Take attach transform's parity into account
glPushMatrix(); glPushMatrix();
glMultMatrixf(attach_trans_gl); glMultMatrixf(attach_trans_gl);
RenderMeshImpl(*attach->Child, dwModClr, fMod2, dwPlayerColor, parity); RenderMeshImpl(*attach->Child, dwModClr, dwBlitMode, dwPlayerColor, parity);
glPopMatrix(); glPopMatrix();
#if 0 #if 0
@ -1068,29 +1096,25 @@ namespace
} }
} }
namespace
{
// Generate matrix to convert the mesh from Ogre coordinate system to Clonk coordinate system.
const StdMeshMatrix OgreToClonk = StdMeshMatrix::Scale(-1.0f, 1.0f, 1.0f) * StdMeshMatrix::Rotate(float(M_PI)/2.0f, 1.0f, 0.0f, 0.0f) * StdMeshMatrix::Rotate(float(M_PI)/2.0f, 0.0f, 0.0f, 1.0f);
// Convert to column-major order
const float OgreToClonkGL[16] =
{
OgreToClonk(0,0), OgreToClonk(1,0), OgreToClonk(2,0), 0,
OgreToClonk(0,1), OgreToClonk(1,1), OgreToClonk(2,1), 0,
OgreToClonk(0,2), OgreToClonk(1,2), OgreToClonk(2,2), 0,
OgreToClonk(0,3), OgreToClonk(1,3), OgreToClonk(2,3), 1
};
const bool OgreToClonkParity = OgreToClonk.Determinant() > 0.0f;
}
void CStdGL::PerformMesh(StdMeshInstance &instance, float tx, float ty, float twdt, float thgt, DWORD dwPlayerColor, CBltTransform* pTransform) void CStdGL::PerformMesh(StdMeshInstance &instance, float tx, float ty, float twdt, float thgt, DWORD dwPlayerColor, CBltTransform* pTransform)
{ {
// Field of View for perspective projection, in degrees // Field of View for perspective projection, in degrees
static const float FOV = 60.0f; static const float FOV = 60.0f;
static const float TAN_FOV = tan(FOV / 2.0f / 180.0f * M_PI); static const float TAN_FOV = tan(FOV / 2.0f / 180.0f * M_PI);
// Convert OgreToClonk matrix to column-major order
// TODO: This must be executed after CStdDDraw::OgreToClonk was
// initialized - is this guaranteed at this position?
static const float OgreToClonkGL[16] =
{
CStdDDraw::OgreToClonk(0,0), CStdDDraw::OgreToClonk(1,0), CStdDDraw::OgreToClonk(2,0), 0,
CStdDDraw::OgreToClonk(0,1), CStdDDraw::OgreToClonk(1,1), CStdDDraw::OgreToClonk(2,1), 0,
CStdDDraw::OgreToClonk(0,2), CStdDDraw::OgreToClonk(1,2), CStdDDraw::OgreToClonk(2,2), 0,
CStdDDraw::OgreToClonk(0,3), CStdDDraw::OgreToClonk(1,3), CStdDDraw::OgreToClonk(2,3), 1
};
static const bool OgreToClonkParity = CStdDDraw::OgreToClonk.Determinant() > 0.0f;
const StdMesh& mesh = instance.Mesh; const StdMesh& mesh = instance.Mesh;
bool parity = OgreToClonkParity; bool parity = OgreToClonkParity;
@ -1112,8 +1136,12 @@ void CStdGL::PerformMesh(StdMeshInstance &instance, float tx, float ty, float tw
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
glEnable(GL_LIGHTING); glEnable(GL_LIGHTING);
glEnable(GL_BLEND); // TODO: Shouldn't this always be enabled? - blending does not work for meshes without this though. glEnable(GL_BLEND); // TODO: Shouldn't this always be enabled? - blending does not work for meshes without this though.
int iAdditive = dwBlitMode & C4GFXBLIT_ADDITIVE;
glBlendFunc(GL_SRC_ALPHA, iAdditive ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA); // TODO: We ignore the additive drawing flag for meshes but instead
// set the blending mode of the corresponding material. I'm not sure
// how the two could be combined.
//int iAdditive = dwBlitMode & C4GFXBLIT_ADDITIVE;
//glBlendFunc(GL_SRC_ALPHA, iAdditive ? GL_ONE : GL_ONE_MINUS_SRC_ALPHA);
// Set up projection matrix first. We do transform and Zoom with the // Set up projection matrix first. We do transform and Zoom with the
// projection matrix, so that lighting is applied to the untransformed/unzoomed // projection matrix, so that lighting is applied to the untransformed/unzoomed
@ -1301,7 +1329,7 @@ void CStdGL::PerformMesh(StdMeshInstance &instance, float tx, float ty, float tw
ModulateClr(dwModClr, c); ModulateClr(dwModClr, c);
} }
RenderMeshImpl(instance, dwModClr, !!(dwBlitMode & C4GFXBLIT_MOD2), dwPlayerColor, parity); RenderMeshImpl(instance, dwModClr, dwBlitMode, dwPlayerColor, parity);
glMatrixMode(GL_PROJECTION); glMatrixMode(GL_PROJECTION);
glPopMatrix(); glPopMatrix();

View File

@ -30,18 +30,15 @@ std::vector<StdMeshInstance::SerializableValueProvider::IDBase*>* StdMeshInstanc
namespace namespace
{ {
// TODO: Avoid duplication with StdGL.cpp. This should not be here but possibly a parameter to ReorderFaces(),
// which should then be called from StdDDraw::RenderMesh. That way it can also include MeshTransformation.
const StdMeshMatrix OgreToClonk = StdMeshMatrix::Scale(-1.0f, 1.0f, 1.0f) * StdMeshMatrix::Rotate(float(M_PI)/2.0f, 1.0f, 0.0f, 0.0f) * StdMeshMatrix::Rotate(float(M_PI)/2.0f, 0.0f, 0.0f, 1.0f);
// Helper to sort faces for FaceOrdering // Helper to sort faces for FaceOrdering
struct StdMeshInstanceFaceOrderingCmpPred struct StdMeshInstanceFaceOrderingCmpPred
{ {
const StdMeshInstance& m_inst; const StdMeshInstance& m_inst;
const StdMeshVertex* m_vertices; const StdMeshVertex* m_vertices;
const StdMeshMatrix& m_global_trans;
StdMeshInstanceFaceOrderingCmpPred(const StdMeshInstance& inst, unsigned int submesh): StdMeshInstanceFaceOrderingCmpPred(const StdMeshInstance& inst, unsigned int submesh, const StdMeshMatrix& global_trans):
m_inst(inst), m_vertices(m_inst.GetSubMesh(submesh).GetVertices()) {} m_inst(inst), m_vertices(m_inst.GetSubMesh(submesh).GetVertices()), m_global_trans(global_trans) {}
bool operator()(const StdMeshFace& face1, const StdMeshFace& face2) const bool operator()(const StdMeshFace& face1, const StdMeshFace& face2) const
{ {
@ -54,8 +51,9 @@ namespace
case StdMeshInstance::FO_FarthestToNearest: case StdMeshInstance::FO_FarthestToNearest:
case StdMeshInstance::FO_NearestToFarthest: case StdMeshInstance::FO_NearestToFarthest:
{ {
float z1 = (OgreToClonk*(m_vertices[face1.Vertices[0]] + m_vertices[face1.Vertices[1]] + m_vertices[face1.Vertices[2]])).z; float z1 = (m_global_trans*(m_vertices[face1.Vertices[0]] + m_vertices[face1.Vertices[1]] + m_vertices[face1.Vertices[2]])).z;
float z2 = (OgreToClonk*(m_vertices[face2.Vertices[0]] + m_vertices[face2.Vertices[1]] + m_vertices[face2.Vertices[2]])).z; float z2 = (m_global_trans*(m_vertices[face2.Vertices[0]] + m_vertices[face2.Vertices[1]] + m_vertices[face2.Vertices[2]])).z;
if (m_inst.GetFaceOrdering() == StdMeshInstance::FO_FarthestToNearest) if (m_inst.GetFaceOrdering() == StdMeshInstance::FO_FarthestToNearest)
return z1 < z2; return z1 < z2;
else else
@ -534,6 +532,12 @@ StdMeshMatrix operator*(const StdMeshMatrix& lhs, float rhs)
return rhs * lhs; return rhs * lhs;
} }
StdMeshMatrix& operator*=(StdMeshMatrix& lhs, const StdMeshMatrix& rhs)
{
lhs = lhs * rhs;
return lhs;
}
StdMeshMatrix operator+(const StdMeshMatrix& lhs, const StdMeshMatrix& rhs) StdMeshMatrix operator+(const StdMeshMatrix& lhs, const StdMeshMatrix& rhs)
{ {
StdMeshMatrix m; StdMeshMatrix m;
@ -1195,7 +1199,7 @@ void StdMeshInstance::SetFaceOrdering(FaceOrdering ordering)
} }
} }
BoneTransformsDirty = true; //BoneTransformsDirty = true;
// Update attachments (only own meshes for now... others might be displayed both attached and non-attached...) // Update attachments (only own meshes for now... others might be displayed both attached and non-attached...)
// still not optimal. // still not optimal.
@ -1205,6 +1209,23 @@ void StdMeshInstance::SetFaceOrdering(FaceOrdering ordering)
} }
} }
void StdMeshInstance::SetFaceOrderingForClrModulation(uint32_t clrmod)
{
// TODO: This could do face ordering only for non-opaque submeshes
bool opaque = true;
for(unsigned int i = 0; i < SubMeshInstances.size(); ++i)
if(!SubMeshInstances[i]->Material->IsOpaque())
{ opaque = false; break; }
if(!opaque)
SetFaceOrdering(FO_FarthestToNearest);
else if( ((clrmod >> 24) & 0xff) != 0xff)
SetFaceOrdering(FO_NearestToFarthest);
else
SetFaceOrdering(FO_Fixed);
}
StdMeshInstance::AnimationNode* StdMeshInstance::PlayAnimation(const StdStrBuf& animation_name, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight) StdMeshInstance::AnimationNode* StdMeshInstance::PlayAnimation(const StdStrBuf& animation_name, int slot, AnimationNode* sibling, ValueProvider* position, ValueProvider* weight)
{ {
const StdMeshAnimation* animation = Mesh.GetAnimationByName(animation_name); const StdMeshAnimation* animation = Mesh.GetAnimationByName(animation_name);
@ -1483,8 +1504,10 @@ StdMeshInstance::AttachedMesh* StdMeshInstance::GetAttachedMeshByNumber(unsigned
return NULL; return NULL;
} }
void StdMeshInstance::UpdateBoneTransforms() bool StdMeshInstance::UpdateBoneTransforms()
{ {
bool was_dirty = BoneTransformsDirty;
// Nothing changed since last time // Nothing changed since last time
if (BoneTransformsDirty) if (BoneTransformsDirty)
{ {
@ -1558,9 +1581,6 @@ void StdMeshInstance::UpdateBoneTransforms()
} }
} }
} }
if (CurrentFaceOrdering != FO_Fixed)
ReorderFaces();
} }
// Update attachment's attach transformations. Note this is done recursively. // Update attachment's attach transformations. Note this is done recursively.
@ -1572,6 +1592,8 @@ void StdMeshInstance::UpdateBoneTransforms()
if (BoneTransformsDirty || ChildBoneTransformsDirty || attach->FinalTransformDirty) if (BoneTransformsDirty || ChildBoneTransformsDirty || attach->FinalTransformDirty)
{ {
was_dirty = true;
// Compute matrix to change the coordinate system to the one of the attached bone: // Compute matrix to change the coordinate system to the one of the attached bone:
// The idea is that a vertex at the child bone's position transforms to the parent bone's position. // The idea is that a vertex at the child bone's position transforms to the parent bone's position.
// Therefore (read from right to left) we first apply the inverse of the child bone transformation, // Therefore (read from right to left) we first apply the inverse of the child bone transformation,
@ -1594,6 +1616,21 @@ void StdMeshInstance::UpdateBoneTransforms()
} }
BoneTransformsDirty = false; BoneTransformsDirty = false;
return was_dirty;
}
void StdMeshInstance::ReorderFaces(StdMeshMatrix* global_trans)
{
if(CurrentFaceOrdering != FO_Fixed)
{
for (unsigned int i = 0; i < SubMeshInstances.size(); ++i)
{
StdMeshInstanceFaceOrderingCmpPred pred(*this, i, global_trans ? *global_trans : StdMeshMatrix::Identity());
std::sort(SubMeshInstances[i]->Faces.begin(), SubMeshInstances[i]->Faces.end(), pred);
}
}
// TODO: Also reorder submeshes, attached meshes and include AttachTransformation for attached meshes...
} }
void StdMeshInstance::CompileFunc(StdCompiler* pComp, AttachedMesh::DenumeratorFactoryFunc Factory) void StdMeshInstance::CompileFunc(StdCompiler* pComp, AttachedMesh::DenumeratorFactoryFunc Factory)
@ -1779,16 +1816,3 @@ bool StdMeshInstance::ExecuteAnimationNode(AnimationNode* node)
return true; return true;
} }
void StdMeshInstance::ReorderFaces()
{
for (unsigned int i = 0; i < SubMeshInstances.size(); ++i)
{
StdMeshInstanceFaceOrderingCmpPred pred(*this, i);
std::sort(SubMeshInstances[i]->Faces.begin(), SubMeshInstances[i]->Faces.end(), pred);
}
// TODO: Also reorder submeshes and attached meshes... maybe this face ordering
// is not a good idea after all. Another possibility to obtain the effect would be
// to first render to an offscreen texture, then render to screen (only for meshes
// with halftransparent clrmod applied)
}

View File

@ -108,6 +108,7 @@ private:
StdMeshMatrix operator*(const StdMeshMatrix& lhs, const StdMeshMatrix& rhs); StdMeshMatrix operator*(const StdMeshMatrix& lhs, const StdMeshMatrix& rhs);
StdMeshMatrix operator*(float lhs, const StdMeshMatrix& rhs); StdMeshMatrix operator*(float lhs, const StdMeshMatrix& rhs);
StdMeshMatrix operator*(const StdMeshMatrix& lhs, float rhs); StdMeshMatrix operator*(const StdMeshMatrix& lhs, float rhs);
StdMeshMatrix& operator*=(StdMeshMatrix& lhs, const StdMeshMatrix& rhs);
StdMeshMatrix operator+(const StdMeshMatrix& lhs, const StdMeshMatrix& rhs); StdMeshMatrix operator+(const StdMeshMatrix& lhs, const StdMeshMatrix& rhs);
StdMeshQuaternion operator-(const StdMeshQuaternion& rhs); StdMeshQuaternion operator-(const StdMeshQuaternion& rhs);
StdMeshQuaternion operator*(const StdMeshQuaternion& lhs, const StdMeshQuaternion& rhs); StdMeshQuaternion operator*(const StdMeshQuaternion& lhs, const StdMeshQuaternion& rhs);
@ -357,6 +358,7 @@ public:
FaceOrdering GetFaceOrdering() const { return CurrentFaceOrdering; } FaceOrdering GetFaceOrdering() const { return CurrentFaceOrdering; }
void SetFaceOrdering(FaceOrdering ordering); void SetFaceOrdering(FaceOrdering ordering);
void SetFaceOrderingForClrModulation(uint32_t clrmod);
// Provider for animation position or weight. // Provider for animation position or weight.
class ValueProvider class ValueProvider
@ -584,8 +586,22 @@ public:
// Update bone transformation matrices, vertex positions and final attach transformations of attached children. // Update bone transformation matrices, vertex positions and final attach transformations of attached children.
// This is called recursively for attached children, so there is no need to call it on attached children only // This is called recursively for attached children, so there is no need to call it on attached children only
// which would also not update its attach transformation. Call this once before rendering. // which would also not update its attach transformation. Call this once before rendering. Returns true if the
void UpdateBoneTransforms(); // mesh was deformed since the last execution, or false otherwise.
bool UpdateBoneTransforms();
// Orders faces according to current face ordering. Clal this once before rendering if one of the following is true:
//
// a) the call to UpdateBoneTransforms returns true
// b) a submesh's material was changed
// c) the global transformation changed since previous call to ReorderFaces()
// d) some other obscure state change occurred (?)
//
// global_trans is a global transformation that is applied when rendering the mesh, and this is used
// to correctly do face ordering.
//
// TODO: Should maybe introduce a FaceOrderingDirty flag
void ReorderFaces(StdMeshMatrix* global_trans);
void CompileFunc(StdCompiler* pComp, AttachedMesh::DenumeratorFactoryFunc Factory); void CompileFunc(StdCompiler* pComp, AttachedMesh::DenumeratorFactoryFunc Factory);
void EnumeratePointers(); void EnumeratePointers();
@ -598,7 +614,6 @@ protected:
AnimationNodeList::iterator GetStackIterForSlot(int slot, bool create); AnimationNodeList::iterator GetStackIterForSlot(int slot, bool create);
bool ExecuteAnimationNode(AnimationNode* node); bool ExecuteAnimationNode(AnimationNode* node);
void ReorderFaces();
FaceOrdering CurrentFaceOrdering; FaceOrdering CurrentFaceOrdering;

View File

@ -126,7 +126,8 @@ namespace
{ "scroll_y", StdMeshMaterialTextureUnit::Transformation::XF_SCROLL_Y }, { "scroll_y", StdMeshMaterialTextureUnit::Transformation::XF_SCROLL_Y },
{ "rotate", StdMeshMaterialTextureUnit::Transformation::XF_ROTATE }, { "rotate", StdMeshMaterialTextureUnit::Transformation::XF_ROTATE },
{ "scale_x", StdMeshMaterialTextureUnit::Transformation::XF_SCALE_X }, { "scale_x", StdMeshMaterialTextureUnit::Transformation::XF_SCALE_X },
{ "scale_y", StdMeshMaterialTextureUnit::Transformation::XF_SCALE_Y } { "scale_y", StdMeshMaterialTextureUnit::Transformation::XF_SCALE_Y },
{ NULL }
}; };
const Enumerator<StdMeshMaterialTextureUnit::Transformation::WaveType> WaveTypeEnumerators[] = const Enumerator<StdMeshMaterialTextureUnit::Transformation::WaveType> WaveTypeEnumerators[] =
@ -135,14 +136,40 @@ namespace
{ "triangle", StdMeshMaterialTextureUnit::Transformation::W_TRIANGLE }, { "triangle", StdMeshMaterialTextureUnit::Transformation::W_TRIANGLE },
{ "square", StdMeshMaterialTextureUnit::Transformation::W_SQUARE }, { "square", StdMeshMaterialTextureUnit::Transformation::W_SQUARE },
{ "sawtooth", StdMeshMaterialTextureUnit::Transformation::W_SAWTOOTH }, { "sawtooth", StdMeshMaterialTextureUnit::Transformation::W_SAWTOOTH },
{ "inverse_sawtooth", StdMeshMaterialTextureUnit::Transformation::W_INVERSE_SAWTOOTH } { "inverse_sawtooth", StdMeshMaterialTextureUnit::Transformation::W_INVERSE_SAWTOOTH },
{ NULL }
}; };
const Enumerator<StdMeshMaterialPass::CullHardwareType> CullHardwareEnumerators[] = const Enumerator<StdMeshMaterialPass::CullHardwareType> CullHardwareEnumerators[] =
{ {
{ "clockwise", StdMeshMaterialPass::CH_Clockwise }, { "clockwise", StdMeshMaterialPass::CH_Clockwise },
{ "anticlockwise", StdMeshMaterialPass::CH_CounterClockwise }, { "anticlockwise", StdMeshMaterialPass::CH_CounterClockwise },
{ "none", StdMeshMaterialPass::CH_None } { "none", StdMeshMaterialPass::CH_None },
{ NULL }
};
const Enumerator<StdMeshMaterialPass::SceneBlendType> SceneBlendEnumerators[] =
{
{ "one", StdMeshMaterialPass::SB_One },
{ "zero", StdMeshMaterialPass::SB_Zero },
{ "dest_colour", StdMeshMaterialPass::SB_DestColor },
{ "src_colour", StdMeshMaterialPass::SB_SrcColor },
{ "one_minus_dest_colour", StdMeshMaterialPass::SB_OneMinusDestColor },
{ "one_minus_src_colour", StdMeshMaterialPass::SB_OneMinusSrcColor },
{ "dest_alpha", StdMeshMaterialPass::SB_DestAlpha },
{ "src_alpha", StdMeshMaterialPass::SB_SrcAlpha },
{ "one_minus_dest_alpha", StdMeshMaterialPass::SB_OneMinusDestAlpha },
{ "one_minus_src_alpha", StdMeshMaterialPass::SB_OneMinusSrcAlpha },
{ NULL }
};
const EnumeratorShortcut<2, StdMeshMaterialPass::SceneBlendType> SceneBlendShortcuts[] =
{
{ "add", { StdMeshMaterialPass::SB_One, StdMeshMaterialPass::SB_One } },
{ "modulate", { StdMeshMaterialPass::SB_DestColor, StdMeshMaterialPass::SB_Zero } },
{ "colour_blend", { StdMeshMaterialPass::SB_SrcColor, StdMeshMaterialPass::SB_OneMinusSrcColor } },
{ "alpha_blend", { StdMeshMaterialPass::SB_SrcAlpha, StdMeshMaterialPass::SB_OneMinusSrcAlpha } },
{ NULL }
}; };
} }
@ -802,6 +829,7 @@ StdMeshMaterialPass::StdMeshMaterialPass():
Specular[0] = Specular[1] = Specular[2] = 0.0f; Specular[3] = 0.0f; Specular[0] = Specular[1] = Specular[2] = 0.0f; Specular[3] = 0.0f;
Emissive[0] = Emissive[1] = Emissive[2] = 0.0f; Emissive[3] = 0.0f; Emissive[0] = Emissive[1] = Emissive[2] = 0.0f; Emissive[3] = 0.0f;
Shininess = 0.0f; Shininess = 0.0f;
SceneBlendFactors[0] = SB_One; SceneBlendFactors[1] = SB_Zero;
} }
void StdMeshMaterialPass::Load(StdMeshMaterialParserCtx& ctx) void StdMeshMaterialPass::Load(StdMeshMaterialParserCtx& ctx)
@ -855,6 +883,10 @@ void StdMeshMaterialPass::Load(StdMeshMaterialParserCtx& ctx)
{ {
CullHardware = ctx.AdvanceEnum(CullHardwareEnumerators); CullHardware = ctx.AdvanceEnum(CullHardwareEnumerators);
} }
else if (token_name == "scene_blend")
{
ctx.AdvanceEnums<2, StdMeshMaterialPass::SceneBlendType>(SceneBlendEnumerators, SceneBlendShortcuts, SceneBlendFactors);
}
else else
ctx.ErrorUnexpectedIdentifier(token_name); ctx.ErrorUnexpectedIdentifier(token_name);
} }
@ -887,6 +919,18 @@ void StdMeshMaterialTechnique::Load(StdMeshMaterialParserCtx& ctx)
ctx.Error(StdCopyStrBuf("'") + token_name.getData() + "' unexpected"); ctx.Error(StdCopyStrBuf("'") + token_name.getData() + "' unexpected");
} }
bool StdMeshMaterialTechnique::IsOpaque() const
{
// Technique is opaque if one of the passes is opaque (subsequent
// non-opaque passes will just depend on the opaque value drawn in
// the previous pass; total result will not depend on original
// frame buffer value).
for(unsigned int i = 0; i < Passes.size(); ++i)
if(Passes[i].IsOpaque())
return true;
return false;
}
StdMeshMaterial::StdMeshMaterial(): StdMeshMaterial::StdMeshMaterial():
Line(0), ReceiveShadows(true), BestTechniqueIndex(-1) Line(0), ReceiveShadows(true), BestTechniqueIndex(-1)
{ {

View File

@ -240,9 +240,25 @@ public:
CH_None CH_None
}; };
enum SceneBlendType
{
SB_One,
SB_Zero,
SB_DestColor,
SB_SrcColor,
SB_OneMinusDestColor,
SB_OneMinusSrcColor,
SB_DestAlpha,
SB_SrcAlpha,
SB_OneMinusDestAlpha,
SB_OneMinusSrcAlpha
};
StdMeshMaterialPass(); StdMeshMaterialPass();
void Load(StdMeshMaterialParserCtx& ctx); void Load(StdMeshMaterialParserCtx& ctx);
bool IsOpaque() const { return SceneBlendFactors[1] == SB_Zero; }
StdCopyStrBuf Name; StdCopyStrBuf Name;
std::vector<StdMeshMaterialTextureUnit> TextureUnits; std::vector<StdMeshMaterialTextureUnit> TextureUnits;
@ -254,6 +270,7 @@ public:
bool DepthWrite; bool DepthWrite;
CullHardwareType CullHardware; CullHardwareType CullHardware;
SceneBlendType SceneBlendFactors[2];
}; };
class StdMeshMaterialTechnique class StdMeshMaterialTechnique
@ -263,6 +280,8 @@ public:
void Load(StdMeshMaterialParserCtx& ctx); void Load(StdMeshMaterialParserCtx& ctx);
bool IsOpaque() const;
StdCopyStrBuf Name; StdCopyStrBuf Name;
std::vector<StdMeshMaterialPass> Passes; std::vector<StdMeshMaterialPass> Passes;
@ -277,6 +296,8 @@ public:
StdMeshMaterial(); StdMeshMaterial();
void Load(StdMeshMaterialParserCtx& ctx); void Load(StdMeshMaterialParserCtx& ctx);
bool IsOpaque() const { assert(BestTechniqueIndex >= 0); return Techniques[BestTechniqueIndex].IsOpaque(); }
// Location the Material was loaded from // Location the Material was loaded from
StdCopyStrBuf FileName; StdCopyStrBuf FileName;
unsigned int Line; unsigned int Line;