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/StdMeshLoaderBinaryChunks.h
src/lib/StdMeshLoaderBinary.cpp src/lib/StdMeshLoaderBinary.cpp
src/lib/StdMeshLoaderDataStream.h src/lib/StdMeshLoaderDataStream.h
src/lib/StdMeshLoader.cpp
src/lib/StdMeshLoader.h src/lib/StdMeshLoader.h
src/lib/StdMeshLoaderXml.cpp src/lib/StdMeshLoaderXml.cpp
src/lib/StdMeshMaterial.cpp src/lib/StdMeshMaterial.cpp

View File

@ -193,7 +193,7 @@ static const Pyrit_Hammer_SwingTime = 40;
func Dlg_Pyrit_Init(object clonk) func Dlg_Pyrit_Init(object clonk)
{ {
// Pyit has a red hat! // 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 moves slowly.
clonk.ActMap = { Prototype = Clonk.ActMap, Walk = { Prototype = Clonk.ActMap.Walk } }; clonk.ActMap = { Prototype = Clonk.ActMap, Walk = { Prototype = Clonk.ActMap.Walk } };
clonk.ActMap.Walk.Speed /= 3; clonk.ActMap.Walk.Speed /= 3;

View File

@ -31,8 +31,8 @@ func Intro_Init(object flagpole)
this.pilot->SetObjectLayer(this.pilot); this.pilot->SetObjectLayer(this.pilot);
// Pyit has a red hat! // 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 // Dialogue object also used as helper container for clonks
this.dialogue = this.pilot->SetDialogue("Pyrit"); this.dialogue = this.pilot->SetDialogue("Pyrit");
this.dialogue->SetInteraction(false); this.dialogue->SetInteraction(false);

View File

@ -489,7 +489,7 @@ func AttachBackpack()
{ {
//Places a backpack onto the clonk //Places a backpack onto the clonk
backpack = AttachMesh(BackpackGraphic, "skeleton_body", "main", 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() func RemoveBackpack()

View File

@ -82,7 +82,7 @@ protected func FxFlagCarriedStart(object target, effect, int temp)
effect.x=target->GetX(); effect.x=target->GetX();
effect.y=target->GetY(); 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); effect.mesh_id = target->AttachMesh(this, "pos_back1", "main", trans);
this.Visibility = VIS_None; this.Visibility = VIS_None;

View File

@ -28,9 +28,9 @@ public func GetCarryTransform()
{ {
var act = Contained()->GetAction(); var act = Contained()->GetAction();
if(act != "Walk" && act != "Jump") 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) public func GetCarrySpecial(clonk)
{ {
@ -377,4 +377,4 @@ local Name = "$Name$";
local Description = "$Description$"; local Description = "$Description$";
local UsageHelp = "$UsageHelp$"; local UsageHelp = "$UsageHelp$";
local Rebuy = true; local Rebuy = true;
local ChopStrength = 10; local ChopStrength = 10;

View File

@ -13,9 +13,9 @@ local iVolume;
public func GetCarryTransform(clonk) public func GetCarryTransform(clonk)
{ {
if(GetCarrySpecial(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() public func GetCarryPhase()
{ {

View File

@ -26,9 +26,9 @@ public func GetCarryPhase() { return 700; }
public func GetCarryTransform(clonk) public func GetCarryTransform(clonk)
{ {
if(GetCarrySpecial(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() protected func Construction()
@ -174,7 +174,7 @@ public func OnMount(clonk)
var iDir = 1; var iDir = 1;
if(clonk->GetDir() == 1) iDir = -1; if(clonk->GetDir() == 1) iDir = -1;
clonk->PlayAnimation("PosRocket", 10, Anim_Const(0), Anim_Const(1000)); 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 //Modify picture transform to fit icon on clonk mount
//clean pic transform rotations //clean pic transform rotations

View File

@ -15,7 +15,7 @@ public func GetCarryMode() { return CARRY_HandBack; }
public func GetCarryBone() { return "main"; } public func GetCarryBone() { return "main"; }
public func GetCarryTransform() 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) public func ControlUse(object clonk, int iX, int iY)
@ -250,4 +250,4 @@ protected func Definition(def)
local Name = "$Name$"; local Name = "$Name$";
local Description = "$Description$"; local Description = "$Description$";
local UsageHelp = "$UsageHelp$"; local UsageHelp = "$UsageHelp$";
local Collectible = true; local Collectible = true;

View File

@ -15,9 +15,9 @@ public func GetCarryPhase() { return 800; }
public func GetCarryTransform(clonk) public func GetCarryTransform(clonk)
{ {
if(GetCarrySpecial(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() protected func Construction()
@ -73,4 +73,4 @@ func Hit()
local Name = "$Name$"; local Name = "$Name$";
local Collectible = false; local Collectible = false;
local ContainBlast = true; 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 GetCarryMode() { return CARRY_HandBack; }
public func GetCarryBone() { return "main"; } 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 IsTool() { return true; }
public func IsToolProduct() { 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 GetCarryBone() { return "main"; }
public func GetCarryTransform() public func GetCarryTransform()
{ {
return Trans_Rotate(-90,0,0,1); return Trans_Rotate(-90,0,1,0);
} }
private func Definition(def) private func Definition(def)
{ {
@ -70,4 +70,4 @@ public func IsToolProduct() { return true; }
local Name = "$Name$"; local Name = "$Name$";
local Description = "$Description$"; local Description = "$Description$";
local UsageHelp = "$UsageHelp$"; 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 GetCarrySpecial(clonk) { if(using == 1) return "pos_hand2"; }
public func GetCarryTransform() 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) public func GetCarryTransform(clonk)
{ {
if(GetCarrySpecial(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; } public func GetCarryPhase() { return 900; }

View File

@ -12,7 +12,7 @@ private func Hit()
public func GetCarryMode() { return CARRY_HandBack; } public func GetCarryMode() { return CARRY_HandBack; }
public func GetCarryBone() { return "main"; } 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) public func ControlUseStart(object clonk, int x, int y)
{ {
@ -61,4 +61,4 @@ local Collectible = 1;
local Name = "$Name$"; local Name = "$Name$";
local Description = "$Description$"; local Description = "$Description$";
local UsageHelp = "$UsageHelp$"; local UsageHelp = "$UsageHelp$";
local Rebuy = true; local Rebuy = true;

View File

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

View File

@ -25,7 +25,7 @@ public func GetCarryMode(clonk) { return CARRY_Musket; }
public func GetCarryTransform() 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; } 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 GetCarryBone() { return "main"; }
public func GetCarryTransform() 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; local animation_set;

View File

@ -32,7 +32,7 @@ local aiming;
public func GetCarryMode(clonk) { if(aiming >= 0) return CARRY_HandBack; } public func GetCarryMode(clonk) { if(aiming >= 0) return CARRY_HandBack; }
public func GetCarryBone() { return "Javelin"; } public func GetCarryBone() { return "Javelin"; }
public func GetCarrySpecial(clonk) { if(aiming > 0) return "pos_hand2"; } 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) 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 GetCarryBone() { return "main"; }
public func GetCarryTransform() public func GetCarryTransform()
{ {
return Trans_Rotate(-90, 0, 1, 0); return Trans_Rotate(90, 1, 0, 0);
} }
local animation_set; local animation_set;

View File

@ -280,18 +280,18 @@ public func GetCarryMode() { return CARRY_HandBack; }
public func GetCarrySpecial(clonk) { return carry_bone; } public func GetCarrySpecial(clonk) { return carry_bone; }
public func GetCarryTransform(clonk, sec, back) 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,0,1,0),Trans_Rotate(90,0,1,0));
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,0,1), Trans_Rotate(90,0,1,1));
if(mTrans != nil) return mTrans; if(mTrans != nil) return mTrans;
if(!sec) 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; 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)); 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,1,0,0); return Trans_Rotate(180,0,0,1);
} }
public func IsWeapon() { return true; } 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 GetCarrySpecial(clonk) { return carry_bone; }
public func GetCarryTransform(clonk, sec, back) 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)); 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, 0, 1, 0); return Trans_Rotate(-90, 1, 0, 0);
} }
local magic_number; local magic_number;

View File

@ -81,7 +81,7 @@ func AddLeaves(bool fullyGrown)
// add two leaves // add two leaves
for(var i = 1; i <= 2; ++i) 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); var matrix = Trans_Mul(Trans_Scale(1, 1, 1), rtrans);
if(fullyGrown) if(fullyGrown)
matrix = rtrans; matrix = rtrans;

View File

@ -345,7 +345,7 @@ public func PlaneMount(object clonk)
{ {
SetOwner(clonk->GetController()); SetOwner(clonk->GetController());
clonk->PlayAnimation("Stand", 15, nil, Anim_Const(1000)); 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; return true;
} }

View File

@ -196,7 +196,7 @@ public func ActivateEntrance(object clonk)
SetAnimationPosition(aim_anim, Anim_Const(150)); SetAnimationPosition(aim_anim, Anim_Const(150));
clonk->Enter(this); clonk->Enter(this);
SetOwner(clonk->GetController()); 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)); clonk->PlayAnimation("CatapultSit", 5, Anim_Const(0), Anim_Const(1000));
} }
} }

View File

@ -42,9 +42,6 @@ extern "C" {
// Global access pointer // Global access pointer
C4Draw *pDraw=NULL; 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) inline DWORD GetTextShadowClr(DWORD dwTxtClr)
{ {
return RGBA(((dwTxtClr >> 0) % 256) / 3, ((dwTxtClr >> 8) % 256) / 3, ((dwTxtClr >> 16) % 256) / 3, (dwTxtClr >> 24) % 256); 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) // 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) // 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; if(MeshTransform) mat = *MeshTransform * mat;
instance.ReorderFaces(&mat); instance.ReorderFaces(&mat);
// Render mesh // Render mesh

View File

@ -156,8 +156,6 @@ class C4FoWRegion;
class C4Draw class C4Draw
{ {
public: public:
static const StdMeshMatrix OgreToClonk;
C4Draw(): MaxTexSize(0) { } C4Draw(): MaxTexSize(0) { }
virtual ~C4Draw() { pDraw=NULL; } virtual ~C4Draw() { pDraw=NULL; }
public: 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 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 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(); const StdMesh& mesh = instance.GetMesh();
bool parity = OgreToClonkParity; bool parity = false;
// Convert bounding box to clonk coordinate system // Convert bounding box to clonk coordinate system
// (TODO: We should cache this, not sure where though) // (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(); const StdMeshBox& box = mesh.GetBoundingBox();
StdMeshVector v1, v2; StdMeshVector v1, v2;
v1.x = box.x1; v1.y = box.y1; v1.z = box.z1; v1.x = box.x1; v1.y = box.y1; v1.z = box.z1;
v2.x = box.x2; v2.y = box.y2; v2.z = box.z2; 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 // Vector from origin of mesh to center of mesh
const StdMeshVector MeshCenter = (v1 + v2)/2.0f; const StdMeshVector MeshCenter = (v1 + v2)/2.0f;
@ -1039,9 +1023,6 @@ void CStdGL::PerformMesh(StdMeshInstance &instance, float tx, float ty, float tw
glMultMatrixf(Matrix); glMultMatrixf(Matrix);
} }
// Convert from Ogre to Clonk coordinate system
glMultMatrixf(OgreToClonkGL);
DWORD dwModClr = BlitModulated ? BlitModulateClr : 0xffffffff; DWORD dwModClr = BlitModulated ? BlitModulateClr : 0xffffffff;
const C4Rect clipRect = GetClipRect(); 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) 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 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.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); 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); frame.Transformation.translate = new_inverse_bone_transformation.rotate * (new_inverse_bone_transformation.scale * d);
// TODO: scale // 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 #define INC_StdMeshLoader
#include <stdexcept> #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 class StdMeshLoader
{ {

View File

@ -27,9 +27,6 @@
#include <boost/ptr_container/ptr_map.hpp> #include <boost/ptr_container/ptr_map.hpp>
#include <boost/ptr_container/ptr_vector.hpp> #include <boost/ptr_container/ptr_vector.hpp>
#include <C4DefList.h>
#include <C4Def.h>
namespace namespace
{ {
bool VertexDeclarationIsSane(const boost::ptr_vector<Ogre::Mesh::ChunkGeometryVertexDeclElement> &decl, const char *filename) bool VertexDeclarationIsSane(const boost::ptr_vector<Ogre::Mesh::ChunkGeometryVertexDeclElement> &decl, const char *filename)
@ -174,7 +171,7 @@ namespace
break; break;
} }
} }
vertices.push_back(vertex); vertices.push_back(OgreToClonk::TransformVertex(vertex));
// Advance vertex buffer cursors // Advance vertex buffer cursors
BOOST_FOREACH(const Ogre::Mesh::ChunkGeometryVertexBuffer &buf, geo.vertexBuffers) BOOST_FOREACH(const Ogre::Mesh::ChunkGeometryVertexBuffer &buf, geo.vertexBuffers)
cursors[buf.index] += buf.vertexSize; cursors[buf.index] += buf.vertexSize;
@ -419,6 +416,7 @@ void StdMeshSkeletonLoader::LoadSkeletonBinary(const char* groupname, const char
kf.Transformation.rotate = catkf.rotation; kf.Transformation.rotate = catkf.rotation;
kf.Transformation.scale = catkf.scale; kf.Transformation.scale = catkf.scale;
kf.Transformation.translate = bone.InverseTransformation.rotate * (bone.InverseTransformation.scale * catkf.translation); 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) BOOST_FOREACH(StdMeshBone *bone, Skeleton->Bones)
{ {
if (bone->Parent) if (bone->Parent)
{ bone->Transformation = bone->Parent->Transformation * OgreToClonk::TransformTransformation(bone->Transformation);
bone->Transformation = bone->Parent->Transformation * bone->Transformation; else
bone->InverseTransformation = StdMeshTransformation::Inverse(bone->Transformation); bone->Transformation = OgreToClonk::TransformTransformation(bone->Transformation);
}
bone->InverseTransformation = StdMeshTransformation::Inverse(bone->Transformation);
} }
StoreSkeleton(groupname, filename, Skeleton); StoreSkeleton(groupname, filename, Skeleton);
@ -454,13 +453,6 @@ StdMesh *StdMeshLoader::LoadMeshBinary(const char *sourcefile, size_t length, co
// Generate mesh from data // Generate mesh from data
Ogre::Mesh::ChunkMesh &cmesh = *static_cast<Ogre::Mesh::ChunkMesh*>(root.get()); Ogre::Mesh::ChunkMesh &cmesh = *static_cast<Ogre::Mesh::ChunkMesh*>(root.get());
std::unique_ptr<StdMesh> mesh(new StdMesh); 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 // if the mesh has a skeleton, then try loading
// it from the loader by the definition name // 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; 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(); 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].x = RequireFloatAttribute(position_elem, "x");
vertices[i].y = RequireFloatAttribute(position_elem, "y"); vertices[i].y = RequireFloatAttribute(position_elem, "y");
vertices[i].z = RequireFloatAttribute(position_elem, "z"); 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 const float d = std::sqrt(vertices[i].x*vertices[i].x
+ vertices[i].y*vertices[i].y + vertices[i].y*vertices[i].y
+ vertices[i].z*vertices[i].z); + vertices[i].z*vertices[i].z);
// Construct BoundingBox // Construct BoundingBox
StdMeshBox& BoundingBox = mesh.BoundingBox; StdMeshBox& BoundingBox = mesh.BoundingBox;
@ -168,24 +191,6 @@ void StdMeshLoader::StdMeshXML::LoadGeometry(StdMesh& mesh, std::vector<StdSubMe
mesh.BoundingRadius = Max(mesh.BoundingRadius, d); 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) 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. // 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); xml.Error(StdCopyStrBuf("Bounding box is empty"), mesh_elem);
// Read skeleton, if any // Read skeleton, if any
@ -528,6 +533,7 @@ void StdMeshSkeletonLoader::LoadSkeletonXml(const char* groupname, const char* f
frame.Transformation.scale = s; frame.Transformation.scale = s;
frame.Transformation.rotate = StdMeshQuaternion::AngleAxis(angle, r); frame.Transformation.rotate = StdMeshQuaternion::AngleAxis(angle, r);
frame.Transformation.translate = bone->InverseTransformation.rotate * (bone->InverseTransformation.scale * d); 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. // transformations, not bone+parent.
for (unsigned int i = 0; i < Skeleton->GetNumBones(); ++i) for (unsigned int i = 0; i < Skeleton->GetNumBones(); ++i)
{ {
// Apply parent transformation
if (Skeleton->Bones[i]->Parent) if (Skeleton->Bones[i]->Parent)
{ Skeleton->Bones[i]->Transformation = Skeleton->Bones[i]->Parent->Transformation * OgreToClonk::TransformTransformation(Skeleton->Bones[i]->Transformation);
// Apply parent transformation else
Skeleton->Bones[i]->Transformation = Skeleton->Bones[i]->Parent->Transformation * Skeleton->Bones[i]->Transformation; Skeleton->Bones[i]->Transformation = OgreToClonk::TransformTransformation(Skeleton->Bones[i]->Transformation);
// Update inverse
Skeleton->Bones[i]->InverseTransformation = StdMeshTransformation::Inverse(Skeleton->Bones[i]->Transformation); // Update inverse
} Skeleton->Bones[i]->InverseTransformation = StdMeshTransformation::Inverse(Skeleton->Bones[i]->Transformation);
} }
StoreSkeleton(groupname, filename, Skeleton); 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; } else { dir.x = dir.y = dir.z = 0.0f; }
// Apply the bone transformation to them, to go from bone coordinates // Apply the bone transformation to them, to go from bone coordinates
// to mesh coordinates (note that bone coordinates use the OGRE // to mesh coordinates.
// coordinate system, so they need to be transformed to Clonk coordinates).
const StdMeshMatrix ClonkToOgre = StdMeshMatrix::Inverse(C4Draw::OgreToClonk);
// This is a good example why we should have different types for // This is a good example why we should have different types for
// position vectors and displacement vectors. TODO. // 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.x += transform(0,3);
transformed_x.y += transform(1,3); transformed_x.y += transform(1,3);
transformed_x.z += transform(2,3); transformed_x.z += transform(2,3);
x = C4Draw::OgreToClonk * transformed_x; x = transformed_x;
dir = C4Draw::OgreToClonk * (transform * (ClonkToOgre * dir)); dir = transform * dir;
// Apply MeshTransformation in the mesh reference frame // Apply MeshTransformation in the mesh reference frame
C4Value value; C4Value value;
Obj->GetProperty(P_MeshTransformation, &value); Obj->GetProperty(P_MeshTransformation, &value);
@ -2310,8 +2308,6 @@ static bool FnCreateParticleAtBone(C4Object* Obj, C4String* szName, C4String* sz
StdMeshVector v1, v2; StdMeshVector v1, v2;
v1.x = box.x1; v1.y = box.y1; v1.z = box.z1; v1.x = box.x1; v1.y = box.y1; v1.z = box.z1;
v2.x = box.x2; v2.y = box.y2; v2.z = box.z2; 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 tx = fixtof(Obj->fix_x) + Obj->Def->Shape.GetX();
const float ty = fixtof(Obj->fix_y) + Obj->Def->Shape.GetY(); const float ty = fixtof(Obj->fix_y) + Obj->Def->Shape.GetY();
const float twdt = Obj->Def->Shape.Wdt; const float twdt = Obj->Def->Shape.Wdt;