forked from Mirrors/openclonk
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
parent
035cbb01b2
commit
0cdafc278b
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -31,7 +31,7 @@ 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");
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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()
|
||||
{
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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; }
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -156,8 +156,6 @@ class C4FoWRegion;
|
|||
class C4Draw
|
||||
{
|
||||
public:
|
||||
static const StdMeshMatrix OgreToClonk;
|
||||
|
||||
C4Draw(): MaxTexSize(0) { }
|
||||
virtual ~C4Draw() { pDraw=NULL; }
|
||||
public:
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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,11 +425,12 @@ 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->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();
|
||||
}
|
||||
|
||||
|
|
|
@ -142,7 +142,30 @@ 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);
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -540,15 +546,16 @@ void StdMeshSkeletonLoader::LoadSkeletonXml(const char* groupname, const char* f
|
|||
// do this late since animation keyframe computation needs the bone
|
||||
// transformations, not bone+parent.
|
||||
for (unsigned int i = 0; i < Skeleton->GetNumBones(); ++i)
|
||||
{
|
||||
if (Skeleton->Bones[i]->Parent)
|
||||
{
|
||||
// Apply parent transformation
|
||||
Skeleton->Bones[i]->Transformation = Skeleton->Bones[i]->Parent->Transformation * Skeleton->Bones[i]->Transformation;
|
||||
if (Skeleton->Bones[i]->Parent)
|
||||
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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue