Transform all mesh data to Clonk reference frame on load

Instead of doing the transformation when drawing a mesh. This allows making
the OpenGL normal matrix more consistent, since it does not include the
Ogre-To-Clonk transformation, and so that the transformation does not need
to be inverted in the shader.

As a side effect, all Attach transformations were updated, since before
they were specified in the OGRE reference frame, not the Clonk reference
frame.
lights3
Armin Burgmeier 2015-08-04 23:16:36 -04:00
parent 035cbb01b2
commit 0cdafc278b
34 changed files with 306 additions and 122 deletions

View File

@ -370,6 +370,7 @@ set(OC_CLONK_SOURCES
src/lib/StdMeshLoaderBinaryChunks.h
src/lib/StdMeshLoaderBinary.cpp
src/lib/StdMeshLoaderDataStream.h
src/lib/StdMeshLoader.cpp
src/lib/StdMeshLoader.h
src/lib/StdMeshLoaderXml.cpp
src/lib/StdMeshMaterial.cpp

View File

@ -193,7 +193,7 @@ static const Pyrit_Hammer_SwingTime = 40;
func Dlg_Pyrit_Init(object clonk)
{
// Pyit has a red hat!
clonk->AttachMesh(Hat, "skeleton_head", "main", Trans_Translate(0,5500));
clonk->AttachMesh(Hat, "skeleton_head", "main", Trans_Translate(5500, 0, 0));
// Clonk moves slowly.
clonk.ActMap = { Prototype = Clonk.ActMap, Walk = { Prototype = Clonk.ActMap.Walk } };
clonk.ActMap.Walk.Speed /= 3;

View File

@ -31,8 +31,8 @@ func Intro_Init(object flagpole)
this.pilot->SetObjectLayer(this.pilot);
// Pyit has a red hat!
this.pilot->AttachMesh(Hat, "skeleton_head", "main", Trans_Translate(0,5500));
this.pilot->AttachMesh(Hat, "skeleton_head", "main", Trans_Translate(5500, 0, 0));
// Dialogue object also used as helper container for clonks
this.dialogue = this.pilot->SetDialogue("Pyrit");
this.dialogue->SetInteraction(false);

View File

@ -489,7 +489,7 @@ func AttachBackpack()
{
//Places a backpack onto the clonk
backpack = AttachMesh(BackpackGraphic, "skeleton_body", "main",
Trans_Mul(Trans_Rotate(180,0,1,0), Trans_Scale(700,700,400), Trans_Translate(0,4000,1000)));
Trans_Mul(Trans_Rotate(180,1,0,0), Trans_Scale(700,400,700), Trans_Translate(4000,-1000,0)));
}
func RemoveBackpack()

View File

@ -82,7 +82,7 @@ protected func FxFlagCarriedStart(object target, effect, int temp)
effect.x=target->GetX();
effect.y=target->GetY();
var trans = Trans_Mul(Trans_Translate(0, -17000, 0), Trans_Rotate(-90, 0, 1, 0));
var trans = Trans_Mul(Trans_Translate(-17000, 0, 0), Trans_Rotate(90, 1, 0, 0));
effect.mesh_id = target->AttachMesh(this, "pos_back1", "main", trans);
this.Visibility = VIS_None;

View File

@ -28,9 +28,9 @@ public func GetCarryTransform()
{
var act = Contained()->GetAction();
if(act != "Walk" && act != "Jump")
return Trans_Mul(Trans_Translate(0,4500,0), Trans_Rotate(-90,0,1,0), Trans_Rotate(180,0,0,1) );
return Trans_Mul(Trans_Translate(4500,0,0), Trans_Rotate(90,1,0,0), Trans_Rotate(180,0,1,0) );
return Trans_Rotate(90, 0, 1, 0);
return Trans_Rotate(-90, 1, 0, 0);
}
public func GetCarrySpecial(clonk)
{
@ -377,4 +377,4 @@ local Name = "$Name$";
local Description = "$Description$";
local UsageHelp = "$UsageHelp$";
local Rebuy = true;
local ChopStrength = 10;
local ChopStrength = 10;

View File

@ -13,9 +13,9 @@ local iVolume;
public func GetCarryTransform(clonk)
{
if(GetCarrySpecial(clonk))
return Trans_Translate(0, 1000, -6500);
return Trans_Translate(1000, 6500, 0);
return Trans_Translate(-1500, 1500, 0);
return Trans_Translate(1500, 0, -1500);
}
public func GetCarryPhase()
{

View File

@ -26,9 +26,9 @@ public func GetCarryPhase() { return 700; }
public func GetCarryTransform(clonk)
{
if(GetCarrySpecial(clonk))
return Trans_Translate(0, 0, -6500);
return Trans_Translate(0, 6500, 0);
return Trans_Translate(-1500, 0, 0);
return Trans_Translate(0, 0, -1500);
}
protected func Construction()
@ -174,7 +174,7 @@ public func OnMount(clonk)
var iDir = 1;
if(clonk->GetDir() == 1) iDir = -1;
clonk->PlayAnimation("PosRocket", 10, Anim_Const(0), Anim_Const(1000));
riderattach = AttachMesh(clonk, "main", "pos_tool1", Trans_Mul(Trans_Translate(2000, -1000, -2000*iDir), Trans_Rotate(90*iDir,0,1,0)));
riderattach = AttachMesh(clonk, "main", "pos_tool1", Trans_Mul(Trans_Translate(-1000,2000*iDir,2000), Trans_Rotate(-90*iDir,1,0,0)));
//Modify picture transform to fit icon on clonk mount
//clean pic transform rotations

View File

@ -15,7 +15,7 @@ public func GetCarryMode() { return CARRY_HandBack; }
public func GetCarryBone() { return "main"; }
public func GetCarryTransform()
{
return Trans_Mul(Trans_Rotate(-90, 0, 0, 1), Trans_Translate(-4000,3500));
return Trans_Mul(Trans_Rotate(90, 0, 1, 0), Trans_Translate(3500, 0, -4000));
}
public func ControlUse(object clonk, int iX, int iY)
@ -250,4 +250,4 @@ protected func Definition(def)
local Name = "$Name$";
local Description = "$Description$";
local UsageHelp = "$UsageHelp$";
local Collectible = true;
local Collectible = true;

View File

@ -15,9 +15,9 @@ public func GetCarryPhase() { return 800; }
public func GetCarryTransform(clonk)
{
if(GetCarrySpecial(clonk))
return Trans_Translate(0, 3500, -6500);
return Trans_Translate(3500, 6500, 0);
return Trans_Translate(-1500, 0, 0);
return Trans_Translate(0, 0, -1500);
}
protected func Construction()
@ -73,4 +73,4 @@ func Hit()
local Name = "$Name$";
local Collectible = false;
local ContainBlast = true;
local Touchable = 2;
local Touchable = 2;

View File

@ -10,7 +10,7 @@ private func Hit(int x, int y)
public func GetCarryMode() { return CARRY_HandBack; }
public func GetCarryBone() { return "main"; }
public func GetCarryTransform() { return Trans_Rotate(90,0,1,0); }
public func GetCarryTransform() { return Trans_Rotate(-90,1,0,0); }
public func IsTool() { return true; }
public func IsToolProduct() { return true; }

View File

@ -55,7 +55,7 @@ public func GetCarryMode() { return CARRY_HandBack; }
public func GetCarryBone() { return "main"; }
public func GetCarryTransform()
{
return Trans_Rotate(-90,0,0,1);
return Trans_Rotate(-90,0,1,0);
}
private func Definition(def)
{
@ -70,4 +70,4 @@ public func IsToolProduct() { return true; }
local Name = "$Name$";
local Description = "$Description$";
local UsageHelp = "$UsageHelp$";
local Collectible = true;
local Collectible = true;

View File

@ -15,7 +15,7 @@ public func GetCarryBone() { return "main"; }
public func GetCarrySpecial(clonk) { if(using == 1) return "pos_hand2"; }
public func GetCarryTransform()
{
return Trans_Rotate(-90, 0, 1, 0);
return Trans_Rotate(90, 1, 0, 0);
}

View File

@ -12,9 +12,9 @@ local count;
public func GetCarryTransform(clonk)
{
if(GetCarrySpecial(clonk))
return Trans_Translate(0, 1000, -6500);
return Trans_Translate(1000, -6500, 0);
return Trans_Mul(Trans_Translate(-1500,1500,0),Trans_Rotate(180,0,1,0));
return Trans_Mul(Trans_Translate(1500, 0, -1500),Trans_Rotate(180,1,0,0));
}
public func GetCarryPhase() { return 900; }

View File

@ -12,7 +12,7 @@ private func Hit()
public func GetCarryMode() { return CARRY_HandBack; }
public func GetCarryBone() { return "main"; }
public func GetCarryTransform() { return Trans_Rotate(270,0,1,0); }
public func GetCarryTransform() { return Trans_Rotate(90,1,0,0); }
public func ControlUseStart(object clonk, int x, int y)
{
@ -61,4 +61,4 @@ local Collectible = 1;
local Name = "$Name$";
local Description = "$Description$";
local UsageHelp = "$UsageHelp$";
local Rebuy = true;
local Rebuy = true;

View File

@ -31,8 +31,8 @@ public func GetCarryBone() { return "main"; }
public func GetCarryTransform()
{
//Left hand's bone is different? I don't know, but this is a work-around.
if(carry_bone == "pos_hand1") return Trans_Rotate(180,0,0,1);
return Trans_Rotate(-90,0,0,1);
if(carry_bone == "pos_hand1") return Trans_Rotate(180,0,1,0);
return Trans_Rotate(-90,0,1,0);
}
protected func HoldingEnabled() { return true; }

View File

@ -25,7 +25,7 @@ public func GetCarryMode(clonk) { return CARRY_Musket; }
public func GetCarryTransform()
{
return Trans_Mul(Trans_Rotate(220, 0, 0, 1), Trans_Rotate(-30, 1, 0, 0), Trans_Rotate(26, 0, 1, 0));
return Trans_Mul(Trans_Rotate(220, 0, 1, 0), Trans_Rotate(30, 0, 0, 1), Trans_Rotate(-26, 1, 0, 0));
}
public func GetCarryPhase() { return 600; }

View File

@ -21,7 +21,7 @@ public func GetCarrySpecial(clonk) { if(fAiming > 0) return "pos_hand2"; }
public func GetCarryBone() { return "main"; }
public func GetCarryTransform()
{
return Trans_Mul(Trans_Rotate(-90,0,1,0), Trans_Rotate(10,1,0,0));
return Trans_Mul(Trans_Rotate(90,1,0,0), Trans_Rotate(-10,0,0,1));
}
local animation_set;

View File

@ -32,7 +32,7 @@ local aiming;
public func GetCarryMode(clonk) { if(aiming >= 0) return CARRY_HandBack; }
public func GetCarryBone() { return "Javelin"; }
public func GetCarrySpecial(clonk) { if(aiming > 0) return "pos_hand2"; }
public func GetCarryTransform() { if(aiming == 1) return Trans_Rotate(180, 1, 0, 0); }
public func GetCarryTransform() { if(aiming == 1) return Trans_Rotate(180, 0, 0, 1); }
public func ControlUseStart(object clonk, int x, int y)
{

View File

@ -21,7 +21,7 @@ public func GetCarrySpecial(clonk) { if(fAiming > 0) return "pos_hand2"; }
public func GetCarryBone() { return "main"; }
public func GetCarryTransform()
{
return Trans_Rotate(-90, 0, 1, 0);
return Trans_Rotate(90, 1, 0, 0);
}
local animation_set;

View File

@ -280,18 +280,18 @@ public func GetCarryMode() { return CARRY_HandBack; }
public func GetCarrySpecial(clonk) { return carry_bone; }
public func GetCarryTransform(clonk, sec, back)
{
if(aim_anim && !sec) return Trans_Mul(Trans_Rotate(180,0,0,1),Trans_Rotate(90,0,0,1));
if(aim_anim && sec) return Trans_Mul(Trans_Rotate(180,1,0,0), Trans_Rotate(90,0,0,1));
if(aim_anim && !sec) return Trans_Mul(Trans_Rotate(180,0,1,0),Trans_Rotate(90,0,1,0));
if(aim_anim && sec) return Trans_Mul(Trans_Rotate(180,0,0,1), Trans_Rotate(90,0,1,1));
if(mTrans != nil) return mTrans;
if(!sec)
{
if(back) return Trans_Mul(Trans_Rotate(-90, 0, 0, 1),Trans_Translate(0,0,400));
if(back) return Trans_Mul(Trans_Rotate(-90, 0, 1, 0),Trans_Translate(0,-400,0));
return nil;
}
if(back) return Trans_Mul(Trans_Mul(Trans_Rotate(90, 0, 0, 1),Trans_Rotate(180, 0, 1)),Trans_Translate(0,0,400));
return Trans_Rotate(180,1,0,0);
if(back) return Trans_Mul(Trans_Mul(Trans_Rotate(90, 0, 1, 0),Trans_Rotate(180, 1, 0, 0)),Trans_Translate(0,-400,0));
return Trans_Rotate(180,0,0,1);
}
public func IsWeapon() { return true; }

View File

@ -20,8 +20,8 @@ public func GetCarryBone() { return "main"; }
public func GetCarrySpecial(clonk) { return carry_bone; }
public func GetCarryTransform(clonk, sec, back)
{
if(back) return Trans_Mul(Trans_Rotate(180,0,0,1), Trans_Rotate(90,0,1,0), Trans_Translate(0,-7000,0));
return Trans_Rotate(90, 0, 1, 0);
if(back) return Trans_Mul(Trans_Rotate(180,0,1,0), Trans_Rotate(-90,1,0,0), Trans_Translate(-7000,0,0));
return Trans_Rotate(-90, 1, 0, 0);
}
local magic_number;

View File

@ -81,7 +81,7 @@ func AddLeaves(bool fullyGrown)
// add two leaves
for(var i = 1; i <= 2; ++i)
{
var rtrans = Trans_Rotate(Random(360), 0, 1, 0);
var rtrans = Trans_Rotate(Random(360), 1, 0, 0);
var matrix = Trans_Mul(Trans_Scale(1, 1, 1), rtrans);
if(fullyGrown)
matrix = rtrans;

View File

@ -345,7 +345,7 @@ public func PlaneMount(object clonk)
{
SetOwner(clonk->GetController());
clonk->PlayAnimation("Stand", 15, nil, Anim_Const(1000));
clonkmesh = AttachMesh(clonk,"pilot","skeleton_body",Trans_Mul(Trans_Rotate(180,0,1,0), Trans_Translate(0,-3000,-1000)),AM_DrawBefore);
clonkmesh = AttachMesh(clonk,"pilot","skeleton_body",Trans_Mul(Trans_Rotate(180, 1, 0, 0), Trans_Translate(-3000, 1000, 0)),AM_DrawBefore);
return true;
}

View File

@ -196,7 +196,7 @@ public func ActivateEntrance(object clonk)
SetAnimationPosition(aim_anim, Anim_Const(150));
clonk->Enter(this);
SetOwner(clonk->GetController());
clonkmesh = AttachMesh(clonk,"shot","skeleton_body",Trans_Mul(Trans_Rotate(180,0,1,0), Trans_Translate(0,-3000,-1000)),AM_DrawBefore);
clonkmesh = AttachMesh(clonk,"shot","skeleton_body",Trans_Mul(Trans_Rotate(180, 1, 0, 0), Trans_Translate(-3000, 1000, 0)),AM_DrawBefore);
clonk->PlayAnimation("CatapultSit", 5, Anim_Const(0), Anim_Const(1000));
}
}

View File

@ -42,9 +42,6 @@ extern "C" {
// Global access pointer
C4Draw *pDraw=NULL;
// Transformation matrix to convert meshes from Ogre to Clonk coordinate system
const StdMeshMatrix C4Draw::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 DWORD GetTextShadowClr(DWORD dwTxtClr)
{
return RGBA(((dwTxtClr >> 0) % 256) / 3, ((dwTxtClr >> 8) % 256) / 3, ((dwTxtClr >> 16) % 256) / 3, (dwTxtClr >> 24) % 256);
@ -498,7 +495,7 @@ bool C4Draw::RenderMesh(StdMeshInstance &instance, C4Surface * sfcTarget, float
// Update bone matrices and vertex data (note this also updates attach transforms and child transforms)
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;
StdMeshMatrix mat = StdMeshMatrix::Identity();
if(MeshTransform) mat = *MeshTransform * mat;
instance.ReorderFaces(&mat);
// Render mesh

View File

@ -156,8 +156,6 @@ class C4FoWRegion;
class C4Draw
{
public:
static const StdMeshMatrix OgreToClonk;
C4Draw(): MaxTexSize(0) { }
virtual ~C4Draw() { pDraw=NULL; }
public:

View File

@ -841,32 +841,16 @@ void CStdGL::PerformMesh(StdMeshInstance &instance, float tx, float ty, float tw
static const float FOV = 60.0f;
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 C4Draw::OgreToClonk was
// initialized - is this guaranteed at this position?
static const float OgreToClonkGL[16] =
{
C4Draw::OgreToClonk(0,0), C4Draw::OgreToClonk(1,0), C4Draw::OgreToClonk(2,0), 0,
C4Draw::OgreToClonk(0,1), C4Draw::OgreToClonk(1,1), C4Draw::OgreToClonk(2,1), 0,
C4Draw::OgreToClonk(0,2), C4Draw::OgreToClonk(1,2), C4Draw::OgreToClonk(2,2), 0,
C4Draw::OgreToClonk(0,3), C4Draw::OgreToClonk(1,3), C4Draw::OgreToClonk(2,3), 1
};
static const bool OgreToClonkParity = C4Draw::OgreToClonk.Determinant() > 0.0f;
const StdMesh& mesh = instance.GetMesh();
bool parity = OgreToClonkParity;
bool parity = false;
// Convert bounding box to clonk coordinate system
// (TODO: We should cache this, not sure where though)
// TODO: Note that this does not generally work with an arbitrary transformation this way
const StdMeshBox& box = mesh.GetBoundingBox();
StdMeshVector v1, v2;
v1.x = box.x1; v1.y = box.y1; v1.z = box.z1;
v2.x = box.x2; v2.y = box.y2; v2.z = box.z2;
v1 = OgreToClonk * v1; // TODO: Include translation
v2 = OgreToClonk * v2; // TODO: Include translation
// Vector from origin of mesh to center of mesh
const StdMeshVector MeshCenter = (v1 + v2)/2.0f;
@ -1039,9 +1023,6 @@ void CStdGL::PerformMesh(StdMeshInstance &instance, float tx, float ty, float tw
glMultMatrixf(Matrix);
}
// Convert from Ogre to Clonk coordinate system
glMultMatrixf(OgreToClonkGL);
DWORD dwModClr = BlitModulated ? BlitModulateClr : 0xffffffff;
const C4Rect clipRect = GetClipRect();

View File

@ -261,15 +261,15 @@ namespace
}
}
// Mirror is wrt X axis
// Mirror is wrt Z axis
void MirrorKeyFrame(StdMeshKeyFrame& frame, const StdMeshTransformation& old_bone_transformation, const StdMeshTransformation& new_inverse_bone_transformation)
{
// frame was a keyframe of a track for old_bone and was now transplanted to new_bone.
frame.Transformation.rotate.x = -frame.Transformation.rotate.x;
frame.Transformation.rotate.y = -frame.Transformation.rotate.y;
frame.Transformation.rotate.z = -frame.Transformation.rotate.z;
StdMeshVector d = old_bone_transformation.scale * (old_bone_transformation.rotate * frame.Transformation.translate);
d.x = -d.x;
d.z = -d.z;
frame.Transformation.translate = new_inverse_bone_transformation.rotate * (new_inverse_bone_transformation.scale * d);
// TODO: scale

View File

@ -0,0 +1,152 @@
/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2010-2015, The OpenClonk Team and contributors
*
* Distributed under the terms of the ISC license; see accompanying file
* "COPYING" for details.
*
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
* See accompanying file "TRADEMARK" for details.
*
* To redistribute this file separately, substitute the full license texts
* for the above references.
*/
// A loader for the OGRE .mesh binary file format
#include <C4Include.h>
#include <StdMeshLoader.h>
namespace
{
// Transpose a StdMeshMatrix. The translate component of
// the input matrix must be 0.
StdMeshMatrix Transpose(const StdMeshMatrix& matrix)
{
assert(fabs(matrix(0,3)) < 1e-6);
assert(fabs(matrix(1,3)) < 1e-6);
assert(fabs(matrix(2,3)) < 1e-6);
StdMeshMatrix result;
result(0,0) = matrix(0,0);
result(0,1) = matrix(1,0);
result(0,2) = matrix(2,0);
result(0,3) = 0.0f;
result(1,0) = matrix(0,1);
result(1,1) = matrix(1,1);
result(1,2) = matrix(2,1);
result(1,3) = 0.0f;
result(2,0) = matrix(0,2);
result(2,1) = matrix(1,2);
result(2,2) = matrix(2,2);
result(2,3) = 0.0f;
return result;
}
// Transformation matrix to convert meshes from Ogre to Clonk coordinate system
const StdMeshMatrix OgreToClonkMatrix = 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);
const StdMeshMatrix OgreToClonkInverse = StdMeshMatrix::Inverse(OgreToClonkMatrix);
const StdMeshMatrix OgreToClonkInverseTranspose = Transpose(OgreToClonkInverse);
const float OgreToClonkDeterminant = OgreToClonkMatrix.Determinant();
}
namespace OgreToClonk
{
StdMeshVector TransformVector(const StdMeshVector& vector)
{
return OgreToClonkMatrix * vector;
}
StdMeshVector TransformPseudoVector(const StdMeshVector& vector)
{
// TODO: This works only for improper rotations... otherwise it might be better
// to write vector as an antisymmetric tensor and do the matrix transform.
return OgreToClonkDeterminant * (OgreToClonkMatrix * vector);
}
StdMeshVector TransformNormalVector(const StdMeshVector& vector)
{
return OgreToClonkInverseTranspose * vector;
}
StdMeshVector TransformScaleVector(const StdMeshVector& vector)
{
// TODO: Check we didn't introduce shear components
StdMeshMatrix scale = StdMeshMatrix::Scale(vector.x, vector.y, vector.z);
StdMeshMatrix transformed = OgreToClonkMatrix * scale * OgreToClonkInverse;
StdMeshVector result;
result.x = transformed(0,0);
result.y = transformed(1,1);
result.z = transformed(2,2);
return result;
}
StdMeshQuaternion TransformQuaternion(const StdMeshQuaternion& quaternion)
{
StdMeshVector axis;
axis.x = quaternion.x;
axis.y = quaternion.y;
axis.z = quaternion.z;
StdMeshVector transformed = TransformPseudoVector(axis);
StdMeshQuaternion result;
result.w = quaternion.w;
result.x = transformed.x;
result.y = transformed.y;
result.z = transformed.z;
return result;
}
StdSubMesh::Vertex TransformVertex(const StdSubMesh::Vertex& vertex)
{
StdMeshVector pos, normal;
pos.x = vertex.x;
pos.y = vertex.y;
pos.z = vertex.z;
normal.x = vertex.nx;
normal.y = vertex.ny;
normal.z = vertex.nz;
pos = TransformVector(pos);
normal = TransformNormalVector(normal);
StdSubMesh::Vertex result = vertex;
result.x = pos.x;
result.y = pos.y;
result.z = pos.z;
result.nx = normal.x;
result.ny = normal.y;
result.nz = normal.z;
return result;
}
StdMeshTransformation TransformTransformation(const StdMeshTransformation& trans)
{
StdMeshTransformation result;
result.scale = TransformScaleVector(trans.scale);
result.rotate = TransformQuaternion(trans.rotate);
result.translate = TransformVector(trans.translate);
// Consistency check:
/*StdMeshMatrix matrix = StdMeshMatrix::Transform(trans);
matrix = OgreToClonk * matrix * OgreToClonkInverse;
StdMeshMatrix matrix2 = StdMeshMatrix::Transform(result);
for(int i = 0; i < 3; ++i)
for(int j = 0; j < 4; ++j)
assert(fabs(matrix(i,j) - matrix2(i,j)) < 1e-3);*/
return result;
}
}

View File

@ -20,6 +20,16 @@
#define INC_StdMeshLoader
#include <stdexcept>
namespace OgreToClonk
{
StdMeshVector TransformVector(const StdMeshVector& vector);
StdMeshVector TransformPseudoVector(const StdMeshVector& vector);
StdMeshVector TransformNormalVector(const StdMeshVector& vector);
StdMeshVector TransformScaleVector(const StdMeshVector& vector);
StdMeshQuaternion TransformQuaternion(const StdMeshQuaternion& quaternion);
StdSubMesh::Vertex TransformVertex(const StdSubMesh::Vertex& vertex);
StdMeshTransformation TransformTransformation(const StdMeshTransformation& transformation);
}
class StdMeshLoader
{

View File

@ -27,9 +27,6 @@
#include <boost/ptr_container/ptr_map.hpp>
#include <boost/ptr_container/ptr_vector.hpp>
#include <C4DefList.h>
#include <C4Def.h>
namespace
{
bool VertexDeclarationIsSane(const boost::ptr_vector<Ogre::Mesh::ChunkGeometryVertexDeclElement> &decl, const char *filename)
@ -174,7 +171,7 @@ namespace
break;
}
}
vertices.push_back(vertex);
vertices.push_back(OgreToClonk::TransformVertex(vertex));
// Advance vertex buffer cursors
BOOST_FOREACH(const Ogre::Mesh::ChunkGeometryVertexBuffer &buf, geo.vertexBuffers)
cursors[buf.index] += buf.vertexSize;
@ -419,6 +416,7 @@ void StdMeshSkeletonLoader::LoadSkeletonBinary(const char* groupname, const char
kf.Transformation.rotate = catkf.rotation;
kf.Transformation.scale = catkf.scale;
kf.Transformation.translate = bone.InverseTransformation.rotate * (bone.InverseTransformation.scale * catkf.translation);
kf.Transformation = OgreToClonk::TransformTransformation(kf.Transformation);
}
}
}
@ -427,10 +425,11 @@ void StdMeshSkeletonLoader::LoadSkeletonBinary(const char* groupname, const char
BOOST_FOREACH(StdMeshBone *bone, Skeleton->Bones)
{
if (bone->Parent)
{
bone->Transformation = bone->Parent->Transformation * bone->Transformation;
bone->InverseTransformation = StdMeshTransformation::Inverse(bone->Transformation);
}
bone->Transformation = bone->Parent->Transformation * OgreToClonk::TransformTransformation(bone->Transformation);
else
bone->Transformation = OgreToClonk::TransformTransformation(bone->Transformation);
bone->InverseTransformation = StdMeshTransformation::Inverse(bone->Transformation);
}
StoreSkeleton(groupname, filename, Skeleton);
@ -454,13 +453,6 @@ StdMesh *StdMeshLoader::LoadMeshBinary(const char *sourcefile, size_t length, co
// Generate mesh from data
Ogre::Mesh::ChunkMesh &cmesh = *static_cast<Ogre::Mesh::ChunkMesh*>(root.get());
std::unique_ptr<StdMesh> mesh(new StdMesh);
mesh->BoundingBox = cmesh.bounds;
mesh->BoundingRadius = cmesh.radius;
// We allow bounding box to be empty if it's only due to X direction since
// this is what goes inside the screen in Clonk.
if(mesh->BoundingBox.y1 == mesh->BoundingBox.y2 || mesh->BoundingBox.z1 == mesh->BoundingBox.z2)
throw Ogre::Mesh::EmptyBoundingBox();
// if the mesh has a skeleton, then try loading
// it from the loader by the definition name
@ -553,6 +545,56 @@ StdMesh *StdMeshLoader::LoadMeshBinary(const char *sourcefile, size_t length, co
vertex.bone_weight[0] = 1.0f;
}
}
// Construct bounding box. Don't use bounds and radius from cmesh
// because they are in a different coordinate frame.
//mesh->BoundingBox = cmesh.bounds;
//mesh->BoundingRadius = cmesh.radius;
bool first = true;
for (unsigned int i = 0; i < mesh->SubMeshes.size() + 1; ++i)
{
const std::vector<StdSubMesh::Vertex>* vertices = NULL;
if (i < mesh->SubMeshes.size())
vertices = &mesh->SubMeshes[i].Vertices;
else
vertices = &mesh->SharedVertices;
for (unsigned int j = 0; j < vertices->size(); ++j)
{
const StdMeshVertex& vertex = (*vertices)[j];
const float d = std::sqrt(vertex.x*vertex.x
+ vertex.y*vertex.y
+ vertex.z*vertex.z);
// First vertex
if (first)
{
mesh->BoundingBox.x1 = mesh->BoundingBox.x2 = vertex.x;
mesh->BoundingBox.y1 = mesh->BoundingBox.y2 = vertex.y;
mesh->BoundingBox.z1 = mesh->BoundingBox.z2 = vertex.z;
mesh->BoundingRadius = d;
first = false;
}
else
{
mesh->BoundingBox.x1 = Min(vertex.x, mesh->BoundingBox.x1);
mesh->BoundingBox.x2 = Max(vertex.x, mesh->BoundingBox.x2);
mesh->BoundingBox.y1 = Min(vertex.y, mesh->BoundingBox.y1);
mesh->BoundingBox.y2 = Max(vertex.y, mesh->BoundingBox.y2);
mesh->BoundingBox.z1 = Min(vertex.z, mesh->BoundingBox.z1);
mesh->BoundingBox.z2 = Max(vertex.z, mesh->BoundingBox.z2);
mesh->BoundingRadius = Max(mesh->BoundingRadius, d);
}
}
}
// We allow bounding box to be empty if it's only due to Z direction since
// this is what goes inside the screen in Clonk.
if(mesh->BoundingBox.x1 == mesh->BoundingBox.x2 || mesh->BoundingBox.y1 == mesh->BoundingBox.y2)
throw Ogre::Mesh::EmptyBoundingBox();
return mesh.release();
}

View File

@ -142,10 +142,33 @@ void StdMeshLoader::StdMeshXML::LoadGeometry(StdMesh& mesh, std::vector<StdSubMe
vertices[i].x = RequireFloatAttribute(position_elem, "x");
vertices[i].y = RequireFloatAttribute(position_elem, "y");
vertices[i].z = RequireFloatAttribute(position_elem, "z");
}
if(attributes & NORMALS)
{
TiXmlElement* normal_elem = RequireFirstChild(vertex_elem, "normal");
vertices[i].nx = RequireFloatAttribute(normal_elem, "x");
vertices[i].ny = RequireFloatAttribute(normal_elem, "y");
vertices[i].nz = RequireFloatAttribute(normal_elem, "z");
}
if(attributes & TEXCOORDS)
{
// FIXME: The Ogre format supports denoting multiple texture coordinates, but the rendering code only supports one
// currently only the first set is read, any additional ones are ignored
TiXmlElement* texcoord_elem = RequireFirstChild(vertex_elem, "texcoord");
vertices[i].u = RequireFloatAttribute(texcoord_elem, "u");
vertices[i].v = RequireFloatAttribute(texcoord_elem, "v");
}
vertices[i] = OgreToClonk::TransformVertex(vertices[i]);
if (attributes & POSITIONS)
{
const float d = std::sqrt(vertices[i].x*vertices[i].x
+ vertices[i].y*vertices[i].y
+ vertices[i].z*vertices[i].z);
+ vertices[i].y*vertices[i].y
+ vertices[i].z*vertices[i].z);
// Construct BoundingBox
StdMeshBox& BoundingBox = mesh.BoundingBox;
@ -168,24 +191,6 @@ void StdMeshLoader::StdMeshXML::LoadGeometry(StdMesh& mesh, std::vector<StdSubMe
mesh.BoundingRadius = Max(mesh.BoundingRadius, d);
}
}
if(attributes & NORMALS)
{
TiXmlElement* normal_elem = RequireFirstChild(vertex_elem, "normal");
vertices[i].nx = RequireFloatAttribute(normal_elem, "x");
vertices[i].ny = RequireFloatAttribute(normal_elem, "y");
vertices[i].nz = RequireFloatAttribute(normal_elem, "z");
}
if(attributes & TEXCOORDS)
{
// FIXME: The Ogre format supports denoting multiple texture coordinates, but the rendering code only supports one
// currently only the first set is read, any additional ones are ignored
TiXmlElement* texcoord_elem = RequireFirstChild(vertex_elem, "texcoord");
vertices[i].u = RequireFloatAttribute(texcoord_elem, "u");
vertices[i].v = RequireFloatAttribute(texcoord_elem, "v");
}
}
if(vertex_elem != NULL)
@ -317,9 +322,9 @@ StdMesh *StdMeshLoader::LoadMeshXml(const char* xml_data, size_t size, const Std
}
}
// We allow bounding box to be empty if it's only due to X direction since
// We allow bounding box to be empty if it's only due to Z direction since
// this is what goes inside the screen in Clonk.
if(mesh->BoundingBox.y1 == mesh->BoundingBox.y2 || mesh->BoundingBox.z1 == mesh->BoundingBox.z2)
if(mesh->BoundingBox.x1 == mesh->BoundingBox.x2 || mesh->BoundingBox.y1 == mesh->BoundingBox.y2)
xml.Error(StdCopyStrBuf("Bounding box is empty"), mesh_elem);
// Read skeleton, if any
@ -528,6 +533,7 @@ void StdMeshSkeletonLoader::LoadSkeletonXml(const char* groupname, const char* f
frame.Transformation.scale = s;
frame.Transformation.rotate = StdMeshQuaternion::AngleAxis(angle, r);
frame.Transformation.translate = bone->InverseTransformation.rotate * (bone->InverseTransformation.scale * d);
frame.Transformation = OgreToClonk::TransformTransformation(frame.Transformation);
}
}
}
@ -541,13 +547,14 @@ void StdMeshSkeletonLoader::LoadSkeletonXml(const char* groupname, const char* f
// transformations, not bone+parent.
for (unsigned int i = 0; i < Skeleton->GetNumBones(); ++i)
{
// Apply parent transformation
if (Skeleton->Bones[i]->Parent)
{
// Apply parent transformation
Skeleton->Bones[i]->Transformation = Skeleton->Bones[i]->Parent->Transformation * Skeleton->Bones[i]->Transformation;
// Update inverse
Skeleton->Bones[i]->InverseTransformation = StdMeshTransformation::Inverse(Skeleton->Bones[i]->Transformation);
}
Skeleton->Bones[i]->Transformation = Skeleton->Bones[i]->Parent->Transformation * OgreToClonk::TransformTransformation(Skeleton->Bones[i]->Transformation);
else
Skeleton->Bones[i]->Transformation = OgreToClonk::TransformTransformation(Skeleton->Bones[i]->Transformation);
// Update inverse
Skeleton->Bones[i]->InverseTransformation = StdMeshTransformation::Inverse(Skeleton->Bones[i]->Transformation);
}
StoreSkeleton(groupname, filename, Skeleton);

View File

@ -2280,17 +2280,15 @@ static bool FnCreateParticleAtBone(C4Object* Obj, C4String* szName, C4String* sz
}
else { dir.x = dir.y = dir.z = 0.0f; }
// Apply the bone transformation to them, to go from bone coordinates
// to mesh coordinates (note that bone coordinates use the OGRE
// coordinate system, so they need to be transformed to Clonk coordinates).
const StdMeshMatrix ClonkToOgre = StdMeshMatrix::Inverse(C4Draw::OgreToClonk);
// to mesh coordinates.
// This is a good example why we should have different types for
// position vectors and displacement vectors. TODO.
StdMeshVector transformed_x = transform * (ClonkToOgre * x);
StdMeshVector transformed_x = transform * x;
transformed_x.x += transform(0,3);
transformed_x.y += transform(1,3);
transformed_x.z += transform(2,3);
x = C4Draw::OgreToClonk * transformed_x;
dir = C4Draw::OgreToClonk * (transform * (ClonkToOgre * dir));
x = transformed_x;
dir = transform * dir;
// Apply MeshTransformation in the mesh reference frame
C4Value value;
Obj->GetProperty(P_MeshTransformation, &value);
@ -2310,8 +2308,6 @@ static bool FnCreateParticleAtBone(C4Object* Obj, C4String* szName, C4String* sz
StdMeshVector v1, v2;
v1.x = box.x1; v1.y = box.y1; v1.z = box.z1;
v2.x = box.x2; v2.y = box.y2; v2.z = box.z2;
v1 = C4Draw::OgreToClonk * v1; // TODO: Include translation
v2 = C4Draw::OgreToClonk * v2; // TODO: Include translation
const float tx = fixtof(Obj->fix_x) + Obj->Def->Shape.GetX();
const float ty = fixtof(Obj->fix_y) + Obj->Def->Shape.GetY();
const float twdt = Obj->Def->Shape.Wdt;