Commit 5149128b authored by Jack Andersen's avatar Jack Andersen

DCLN cooking and various bug fixes

parent 4af2d975
......@@ -34,6 +34,7 @@ set(DNACOMMON_SOURCES
BabeDead.hpp BabeDead.cpp
RigInverter.hpp RigInverter.cpp
AROTBuilder.hpp AROTBuilder.cpp
OBBTreeBuilder.hpp OBBTreeBuilder.cpp
Tweaks/ITweak.hpp
Tweaks/TweakWriter.hpp
Tweaks/ITweakGame.hpp
......
......@@ -84,15 +84,39 @@ template void DeafBabeSendToBlender<DNAMP2::DeafBabe>(hecl::BlenderConnection::P
template void DeafBabeSendToBlender<DNAMP1::DCLN::Collision>(hecl::BlenderConnection::PyOutStream& os, const DNAMP1::DCLN::Collision& db, bool isDcln, atInt32 idx);
template<class DEAFBABE>
void DeafBabeBuildFromBlender(DEAFBABE& db, const hecl::BlenderConnection::DataStream::ColMesh& colMesh)
static void PopulateAreaFields(DEAFBABE& db,
const hecl::BlenderConnection::DataStream::ColMesh& colMesh,
const zeus::CAABox& fullAABB,
std::enable_if_t<std::is_same<DEAFBABE, DNAMP1::DeafBabe>::value ||
std::is_same<DEAFBABE, DNAMP2::DeafBabe>::value, int>* = 0)
{
{
AROTBuilder builder;
auto octree = builder.buildCol(colMesh, db.rootNodeType);
static_cast<std::unique_ptr<atUint8[]>&>(db.bspTree) = std::move(octree.first);
db.bspSize = octree.second;
}
AROTBuilder builder;
auto octree = builder.buildCol(colMesh, db.rootNodeType);
static_cast<std::unique_ptr<atUint8[]>&>(db.bspTree) = std::move(octree.first);
db.bspSize = octree.second;
db.unk1 = 0x1000000;
db.length = db.binarySize(0) - 8;
db.magic = 0xDEAFBABE;
db.version = 3;
db.aabb[0] = fullAABB.min;
db.aabb[1] = fullAABB.max;
}
template<class DEAFBABE>
static void PopulateAreaFields(DEAFBABE& db,
const hecl::BlenderConnection::DataStream::ColMesh& colMesh,
const zeus::CAABox& fullAABB,
std::enable_if_t<std::is_same<DEAFBABE, DNAMP1::DCLN::Collision>::value, int>* = 0)
{
db.magic = 0xDEAFBABE;
db.version = 2;
db.memSize = 0;
}
template<class DEAFBABE>
void DeafBabeBuildFromBlender(DEAFBABE& db, const hecl::BlenderConnection::DataStream::ColMesh& colMesh)
{
db.materials.reserve(colMesh.materials.size());
for (const hecl::BlenderConnection::DataStream::ColMesh::Material& mat : colMesh.materials)
{
......@@ -186,15 +210,11 @@ void DeafBabeBuildFromBlender(DEAFBABE& db, const hecl::BlenderConnection::DataS
db.triMatsCount = colMesh.trianges.size();
db.triangleEdgesCount = colMesh.trianges.size() * 3;
db.unk1 = 0x1000000;
db.length = db.binarySize(0) - 8;
db.magic = 0xDEAFBABE;
db.version = 3;
db.aabb[0] = fullAABB.min;
db.aabb[1] = fullAABB.max;
PopulateAreaFields(db, colMesh, fullAABB);
}
template void DeafBabeBuildFromBlender<DNAMP1::DeafBabe>(DNAMP1::DeafBabe& db, const hecl::BlenderConnection::DataStream::ColMesh& colMesh);
template void DeafBabeBuildFromBlender<DNAMP2::DeafBabe>(DNAMP2::DeafBabe& db, const hecl::BlenderConnection::DataStream::ColMesh& colMesh);
template void DeafBabeBuildFromBlender<DNAMP1::DCLN::Collision>(DNAMP1::DCLN::Collision& db, const hecl::BlenderConnection::DataStream::ColMesh& colMesh);
}
#include <athena/Types.hpp>
#include "OBBTreeBuilder.hpp"
#include "zeus/CTransform.hpp"
#include "DataSpec/DNAMP1/DCLN.hpp"
#include "gmm/gmm.h"
namespace DataSpec
{
using ColMesh = hecl::BlenderConnection::DataStream::ColMesh;
struct FittedOBB
{
zeus::CTransform xf;
zeus::CVector3f he;
};
static std::vector<int> MakeRootTriangleIndex(const ColMesh& mesh)
{
std::vector<int> ret;
ret.reserve(mesh.trianges.size());
for (int i = 0; i < mesh.trianges.size(); ++i)
ret.push_back(i);
return ret;
}
static std::unordered_set<uint32_t> GetTriangleVerts(const ColMesh& mesh, int triIdx)
{
const ColMesh::Triangle& T = mesh.trianges[triIdx];
std::unordered_set<uint32_t> verts;
verts.insert(mesh.edges[T.edges[0]].verts[0]);
verts.insert(mesh.edges[T.edges[0]].verts[1]);
verts.insert(mesh.edges[T.edges[1]].verts[0]);
verts.insert(mesh.edges[T.edges[1]].verts[1]);
verts.insert(mesh.edges[T.edges[2]].verts[0]);
verts.insert(mesh.edges[T.edges[2]].verts[1]);
return verts;
}
// method to set the OBB parameters which produce a box oriented according to
// the covariance matrix C, which just containts the points pnts
static FittedOBB BuildFromCovarianceMatrix(gmm::dense_matrix<float>& C,
const ColMesh& mesh, const std::vector<int>& index)
{
FittedOBB ret;
// extract the eigenvalues and eigenvectors from C
gmm::dense_matrix<float> eigvec(3,3);
std::vector<float> eigval(3);
gmm::symmetric_qr_algorithm(C, eigval, eigvec);
// find the right, up and forward vectors from the eigenvectors
zeus::CVector3f r(eigvec(0,0), eigvec(1,0), eigvec(2,0));
zeus::CVector3f u(eigvec(0,1), eigvec(1,1), eigvec(2,1));
zeus::CVector3f f(eigvec(0,2), eigvec(1,2), eigvec(2,2));
r.normalize(); u.normalize(), f.normalize();
// set the rotation matrix using the eigvenvectors
ret.xf.basis[0][0]=r.x; ret.xf.basis[1][0]=u.x; ret.xf.basis[2][0]=f.x;
ret.xf.basis[0][1]=r.y; ret.xf.basis[1][1]=u.y; ret.xf.basis[2][1]=f.y;
ret.xf.basis[0][2]=r.z; ret.xf.basis[1][2]=u.z; ret.xf.basis[2][2]=f.z;
// now build the bounding box extents in the rotated frame
zeus::CVector3f minim(1e10f, 1e10f, 1e10f), maxim(-1e10f, -1e10f, -1e10f);
for (int triIdx : index)
{
std::unordered_set<uint32_t> verts = GetTriangleVerts(mesh, triIdx);
for (uint32_t v : verts)
{
const zeus::CVector3f& p = mesh.verts[v].val;
zeus::CVector3f p_prime(r.dot(p), u.dot(p), f.dot(p));
minim = zeus::min(minim, p_prime);
maxim = zeus::max(maxim, p_prime);
}
}
// set the center of the OBB to be the average of the
// minimum and maximum, and the extents be half of the
// difference between the minimum and maximum
zeus::CVector3f center = (maxim + minim) * 0.5f;
ret.xf.origin = ret.xf.basis * center;
ret.he = (maxim - minim) * 0.5f;
return ret;
}
// builds an OBB from triangles specified as an array of
// points with integer indices into the point array. Forms
// the covariance matrix for the triangles, then uses the
// method build_from_covariance_matrix() method to fit
// the box. ALL points will be fit in the box, regardless
// of whether they are indexed by a triangle or not.
static FittedOBB FitOBB(const ColMesh& mesh, const std::vector<int>& index)
{
float Ai, Am=0.0;
zeus::CVector3f mu, mui;
gmm::dense_matrix<float> C(3,3);
float cxx=0.0, cxy=0.0, cxz=0.0, cyy=0.0, cyz=0.0, czz=0.0;
// loop over the triangles this time to find the
// mean location
for (int i : index)
{
const ColMesh::Triangle& T = mesh.trianges[i];
std::unordered_set<uint32_t> verts = GetTriangleVerts(mesh, i);
auto it = verts.begin();
zeus::CVector3f p = mesh.verts[*it++].val;
zeus::CVector3f q = mesh.verts[*it++].val;
zeus::CVector3f r = mesh.verts[*it++].val;
mui = (p+q+r)/3.f;
Ai = (q-p).cross(r-p).magnitude() / 2.f;
mu += mui*Ai;
Am += Ai;
// these bits set the c terms to Am*E[xx], Am*E[xy], Am*E[xz]....
cxx += ( 9.0*mui.x*mui.x + p.x*p.x + q.x*q.x + r.x*r.x )*(Ai/12.0);
cxy += ( 9.0*mui.x*mui.y + p.x*p.y + q.x*q.y + r.x*r.y )*(Ai/12.0);
cxz += ( 9.0*mui.x*mui.z + p.x*p.z + q.x*q.z + r.x*r.z )*(Ai/12.0);
cyy += ( 9.0*mui.y*mui.y + p.y*p.y + q.y*q.y + r.y*r.y )*(Ai/12.0);
cyz += ( 9.0*mui.y*mui.z + p.y*p.z + q.y*q.z + r.y*r.z )*(Ai/12.0);
}
// divide out the Am fraction from the average position and
// covariance terms
mu = mu / Am;
cxx /= Am; cxy /= Am; cxz /= Am; cyy /= Am; cyz /= Am; czz /= Am;
// now subtract off the E[x]*E[x], E[x]*E[y], ... terms
cxx -= mu.x*mu.x; cxy -= mu.x*mu.y; cxz -= mu.x*mu.z;
cyy -= mu.y*mu.y; cyz -= mu.y*mu.z; czz -= mu.z*mu.z;
// now build the covariance matrix
C(0,0)=cxx; C(0,1)=cxy; C(0,2)=cxz;
C(1,0)=cxy; C(1,1)=cyy; C(1,2)=cyz;
C(2,0)=cxz; C(1,2)=cyz; C(2,2)=czz;
// set the obb parameters from the covariance matrix
return BuildFromCovarianceMatrix(C, mesh, index);
}
template <typename Node>
static void MakeLeaf(const ColMesh& mesh, const std::vector<int>& index, Node& n)
{
n.left.reset();
n.right.reset();
n.isLeaf = true;
n.leafData = std::make_unique<typename Node::LeafData>();
n.leafData->edgeIndexCount = atUint32(index.size() * 3);
n.leafData->edgeIndices.reserve(n.leafData->edgeIndexCount);
for (int i : index)
{
const ColMesh::Triangle& T = mesh.trianges[i];
for (int j = 0; j < 3; ++j)
n.leafData->edgeIndices.push_back(T.edges[j]);
}
}
template <typename Node>
static std::unique_ptr<Node> RecursiveMakeNode(const ColMesh& mesh, const std::vector<int>& index)
{
// calculate root OBB
FittedOBB obb = FitOBB(mesh, index);
// make results row-major and also invert the rotation basis
obb.xf.basis.transpose();
std::unique_ptr<Node> n = std::make_unique<Node>();
for (int i = 0; i < 3; ++i)
{
n->xf[i] = zeus::CVector4f{obb.xf.basis[i]};
n->xf[i].vec[3] = obb.xf.origin[i];
}
n->halfExtent = obb.he;
// terminate branch when volume < 1.0
if (obb.he[0] * obb.he[1] * obb.he[2] < 1.f)
{
MakeLeaf(mesh, index, *n);
return n;
}
n->isLeaf = false;
std::vector<int> indexNeg[3];
std::vector<int> indexPos[3];
for (int c = 0; c < 3; ++c)
{
// subdivide negative side
indexNeg[c].reserve(index.size());
for (int i : index)
{
std::unordered_set<uint32_t> verts = GetTriangleVerts(mesh, i);
for (uint32_t vtx : verts)
{
zeus::CVector3f v = mesh.verts[vtx].val;
v = obb.xf.basis * (v - obb.xf.origin);
if (v[c] < 0.f)
{
indexNeg[c].push_back(i);
break;
}
}
}
// subdivide positive side
indexPos[c].reserve(index.size());
for (int i : index)
{
std::unordered_set<uint32_t> verts = GetTriangleVerts(mesh, i);
for (uint32_t vtx : verts)
{
zeus::CVector3f v = mesh.verts[vtx].val;
v = obb.xf.basis * (v - obb.xf.origin);
if (v[c] >= 0.f)
{
indexPos[c].push_back(i);
break;
}
}
}
}
size_t idxMin = index.size();
int minComp = -1;
for (int c = 0; c < 3; ++c)
{
size_t test = std::max(indexNeg[c].size(), indexPos[c].size());
if (test < idxMin && test < index.size() * 3 / 4)
{
minComp = c;
idxMin = test;
}
}
if (minComp == -1)
{
MakeLeaf(mesh, index, *n);
return n;
}
n->left = RecursiveMakeNode<Node>(mesh, indexNeg[minComp]);
n->right = RecursiveMakeNode<Node>(mesh, indexPos[minComp]);
return n;
}
template <typename Node>
std::unique_ptr<Node> OBBTreeBuilder::buildCol(const ColMesh& mesh)
{
std::vector<int> root = MakeRootTriangleIndex(mesh);
return RecursiveMakeNode<Node>(mesh, root);
}
template std::unique_ptr<DNAMP1::DCLN::Collision::Node>
OBBTreeBuilder::buildCol<DNAMP1::DCLN::Collision::Node>(const ColMesh& mesh);
}
#ifndef DNACOMMON_OBBTREEBUILDER_HPP
#define DNACOMMON_OBBTREEBUILDER_HPP
#include "DNACommon.hpp"
namespace DataSpec
{
struct OBBTreeBuilder
{
using ColMesh = hecl::BlenderConnection::DataStream::ColMesh;
template <typename Node>
static std::unique_ptr<Node> buildCol(const ColMesh& mesh);
};
}
#endif // DNACOMMON_OBBTREEBUILDER_HPP
#ifndef __DNAMP1_DCLN_HPP__
#define __DNAMP1_DCLN_HPP__
#include <athena/Types.hpp>
#include "../DNACommon/DeafBabe.hpp"
#include "../DNACommon/PAK.hpp"
#include "../DNACommon/OBBTreeBuilder.hpp"
#include "DNAMP1.hpp"
#include "DeafBabe.hpp"
......@@ -13,6 +15,8 @@ namespace DNAMP1
struct DCLN : BigDNA
{
using Mesh = hecl::BlenderConnection::DataStream::ColMesh;
DECL_DNA
Value<atUint32> colCount;
struct Collision : BigDNA
......@@ -40,19 +44,20 @@ struct DCLN : BigDNA
Value<atUint32> vertCount;
Vector<atVec3f, DNA_COUNT(vertCount)> verts;
struct LeafData : BigDNA
{
DECL_DNA
Value<atUint32> edgeIndexCount;
Vector<atUint16, DNA_COUNT(edgeIndexCount)> edgeIndices;
size_t getMemoryUsage() const { return (((edgeIndices.size() * 2) + 16) + 3) & ~3; }
};
struct Node : BigDNA
{
Delete _d;
struct LeafData : BigDNA
{
DECL_DNA
Value<atUint32> edgeIndexCount;
Vector<atUint16, DNA_COUNT(edgeIndexCount)> edgeIndices;
size_t getMemoryUsage() const { return (((edgeIndices.size() * 2) + 16) + 3) & ~3; }
};
Value<atVec4f> xf[3];
Value<atVec3f> origin;
Value<atVec3f> halfExtent;
Value<bool> isLeaf;
std::unique_ptr<LeafData> leafData;
std::unique_ptr<Node> left;
......@@ -63,7 +68,7 @@ struct DCLN : BigDNA
xf[0] = __dna_reader.readVec4fBig();
xf[1] = __dna_reader.readVec4fBig();
xf[2] = __dna_reader.readVec4fBig();
origin = __dna_reader.readVec3fBig();
halfExtent = __dna_reader.readVec3fBig();
isLeaf = __dna_reader.readBool();
if (isLeaf)
{
......@@ -84,7 +89,7 @@ struct DCLN : BigDNA
__dna_writer.writeVec4fBig(xf[0]);
__dna_writer.writeVec4fBig(xf[1]);
__dna_writer.writeVec4fBig(xf[2]);
__dna_writer.writeVec3fBig(origin);
__dna_writer.writeVec3fBig(halfExtent);
__dna_writer.writeBool(isLeaf);
if (isLeaf && leafData)
leafData->write(__dna_writer);
......@@ -121,6 +126,30 @@ struct DCLN : BigDNA
return (ret + 3) & ~3;
}
void sendToBlender(hecl::BlenderConnection::PyOutStream& os) const
{
os.format("obj = bpy.data.objects.new('%s', None)\n"
"obj.empty_draw_type = 'CUBE'\n"
"bpy.context.scene.objects.link(obj)\n"
"mtx = Matrix(((%f,%f,%f,%f),(%f,%f,%f,%f),(%f,%f,%f,%f),(0.0,0.0,0.0,1.0)))\n"
"mtxd = mtx.decompose()\n"
"obj.rotation_mode = 'QUATERNION'\n"
"obj.location = mtxd[0]\n"
"obj.rotation_quaternion = mtxd[1]\n"
"obj.scale = (%f,%f,%f)\n", isLeaf ? "leaf" : "branch",
xf[0].vec[0], xf[0].vec[1], xf[0].vec[2], xf[0].vec[3],
xf[1].vec[0], xf[1].vec[1], xf[1].vec[2], xf[1].vec[3],
xf[2].vec[0], xf[2].vec[1], xf[2].vec[2], xf[2].vec[3],
halfExtent.vec[0], halfExtent.vec[1], halfExtent.vec[2]);
if (isLeaf)
os << "obj.show_name = True\n";
if (!isLeaf)
{
left->sendToBlender(os);
right->sendToBlender(os);
}
}
};
Node root;
size_t getMemoryUsage()
......@@ -141,7 +170,8 @@ struct DCLN : BigDNA
hecl::BlenderConnection::PyOutStream os = conn.beginPythonOut(true);
os.format("import bpy\n"
"import bmesh\n"
"from mathutils import Vector\n"
"from mathutils import Vector, Matrix\n"
"\n"
"bpy.context.scene.name = '%s'\n"
"# Clear Scene\n"
......@@ -154,7 +184,10 @@ struct DCLN : BigDNA
DeafBabe::BlenderInit(os);
atInt32 idx = 0;
for (const Collision& col : collision)
{
DeafBabeSendToBlender(os, col, true, idx++);
col.root.sendToBlender(os);
}
os.centerView();
os.close();
}
......@@ -171,12 +204,33 @@ struct DCLN : BigDNA
DCLN dcln;
dcln.read(rs);
hecl::BlenderConnection& conn = btok.getBlenderConnection();
if (!conn.createBlend(outPath, hecl::BlenderConnection::BlendType::Mesh))
if (!conn.createBlend(outPath, hecl::BlenderConnection::BlendType::ColMesh))
return false;
dcln.sendToBlender(conn, pakRouter.getBestEntryName(entry, false));
return conn.saveBlend();
}
static bool Cook(const hecl::ProjectPath& outPath,
const hecl::ProjectPath& inPath,
const std::vector<Mesh>& meshes,
hecl::BlenderConnection* conn = nullptr)
{
DCLN dcln;
dcln.colCount = atUint32(meshes.size());
for (const Mesh& mesh : meshes)
{
dcln.collision.emplace_back();
Collision& colOut = dcln.collision.back();
DeafBabeBuildFromBlender(colOut, mesh);
colOut.root = std::move(*OBBTreeBuilder::buildCol<Collision::Node>(mesh));
colOut.memSize = atUint32(colOut.root.getMemoryUsage());
}
athena::io::FileWriter w(outPath.getAbsolutePath());
dcln.write(w);
return true;
}
};
}
......
......@@ -22,7 +22,7 @@ struct CameraHint : IScriptObject
{
DECL_YAML
Value<atUint32> propertyCount;
Value<bool> unknown1; // 0x1
Value<bool> calculateCamPos; // 0x1
Value<bool> chaseAllowed; // 0x2
Value<bool> boostAllowed; // 0x4
Value<bool> obscureAvoidance; // 0x8
......
......@@ -249,6 +249,12 @@ void SpecBase::doCook(const hecl::ProjectPath& path, const hecl::ProjectPath& co
cookMesh(cookedPath, path, ds, fast, btok, progress);
break;
}
case hecl::BlenderConnection::BlendType::ColMesh:
{
hecl::BlenderConnection::DataStream ds = conn.beginData();
cookColMesh(cookedPath, path, ds, fast, btok, progress);
break;
}
case hecl::BlenderConnection::BlendType::Actor:
{
hecl::BlenderConnection::DataStream ds = conn.beginData();
......
......@@ -71,6 +71,9 @@ struct SpecBase : hecl::Database::IDataSpec
virtual void cookMesh(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
BlendStream& ds, bool fast, hecl::BlenderToken& btok,
FCookProgress progress)=0;
virtual void cookColMesh(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
BlendStream& ds, bool fast, hecl::BlenderToken& btok,
FCookProgress progress)=0;
virtual void cookActor(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
BlendStream& ds, bool fast, hecl::BlenderToken& btok,
FCookProgress progress)=0;
......
......@@ -10,6 +10,7 @@
#include "DNAMP1/STRG.hpp"
#include "DNAMP1/SCAN.hpp"
#include "DNAMP1/CMDL.hpp"
#include "DNAMP1/DCLN.hpp"
#include "DNAMP1/MREA.hpp"
#include "DNAMP1/ANCS.hpp"
#include "DNAMP1/AGSC.hpp"
......@@ -555,6 +556,8 @@ struct SpecMP1 : SpecBase
{
case hecl::BlenderConnection::BlendType::Mesh:
return {SBIG('CMDL'), path.hash().val32()};
case hecl::BlenderConnection::BlendType::ColMesh:
return {SBIG('DCLN'), path.hash().val32()};
case hecl::BlenderConnection::BlendType::Actor:
if (path.getAuxInfo().size())
{
......@@ -728,6 +731,14 @@ struct SpecMP1 : SpecBase
DNAMP1::CMDL::Cook(out, in, mesh);
}
void cookColMesh(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast,
hecl::BlenderToken& btok, FCookProgress progress)
{
std::vector<ColMesh> mesh = ds.compileColMeshes();
ds.close();
DNAMP1::DCLN::Cook(out, in, mesh);
}
void cookActor(const hecl::ProjectPath& out, const hecl::ProjectPath& in, BlendStream& ds, bool fast,
hecl::BlenderToken& btok, FCookProgress progress)
{
......
......@@ -329,6 +329,12 @@ struct SpecMP2 : SpecBase
{
}
void cookColMesh(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
BlendStream& ds, bool fast, hecl::BlenderToken& btok,
FCookProgress progress)
{
}
void cookActor(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
BlendStream& ds, bool fast, hecl::BlenderToken& btok,
FCookProgress progress)
......
......@@ -523,6 +523,12 @@ struct SpecMP3 : SpecBase
{
}
void cookColMesh(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
BlendStream& ds, bool fast, hecl::BlenderToken& btok,
FCookProgress progress)
{
}
void cookActor(const hecl::ProjectPath& out, const hecl::ProjectPath& in,
BlendStream& ds, bool fast, hecl::BlenderToken& btok,
FCookProgress progress)
......
......@@ -37,6 +37,7 @@ void ViewManager::BuildTestPART()
void ViewManager::InitMP1(MP1::CMain& main)
{
main.Init(m_fileStoreManager, m_mainWindow.get(), m_voiceEngine.get(), *m_amuseAllocWrapper);
main.WarmupShaders();
}
void ViewManager::TestGameView::resized(const boo::SWindowRect& root, const boo::SWindowRect& sub)
......
GetFEM++ is free software; you can redistribute it and/or modify it
under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 3 of the License, or
(at your option) any later version along with the GCC Runtime Library
Exception either version 3.1 or (at your option) any later version.
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
License and the GCC Runtime Library Exception for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program (see GNU_GPL_V3, GNU_LGPL_V3 and
GNU_GCC_RUNTIME_EXCEPTION files); if not, write to the Free Software
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA.
\ No newline at end of file
......@@ -2423,9 +2423,9 @@ void CBallCamera::ApplyCameraHint(CStateManager& mgr)
zeus::CVector3f camPos = mgr.GetPlayer().GetBallPosition() + hint->GetHint().GetBallToCam();
if ((hint->GetHint().GetOverrideFlags() & 0x1) != 0)
{
float f30 = hint->GetHint().GetBallToCam().toVec2f().magnitude();
zeus::CVector3f x23c = -zeus::CVector3f(hint->GetHint().GetBallToCam().toVec2f()).normalized();
camPos = FindDesiredPosition(f30, hint->GetHint().GetBallToCam().z, x23c, mgr, false);
float distance = hint->GetHint().GetBallToCam().toVec2f().magnitude();
zeus::CVector3f camToBall = -zeus::CVector3f(hint->GetHint().GetBallToCam().toVec2f()).normalized();
camPos = FindDesiredPosition(distance, hint->GetHint().GetBallToCam().z, camToBall, mgr, false);
}
TeleportCamera(zeus::lookAt(camPos, x1d8_lookPos), mgr);
break;
......
......@@ -53,6 +53,8 @@ public:
class CBooRenderer : public IRenderer
{
friend class CBooModel;
friend class CModel;
friend class CGameArea;
friend class CWorldTransManager;
friend class CMorphBallShadow;
......
......@@ -73,6 +73,7 @@ struct CBooSurface
class CBooModel
{
friend class CModel;
friend class CGameArea;
friend class CBooRenderer;
friend class CMetroidModelInstance;
friend class CSkinnedModel;
......@@ -151,6 +152,8 @@ private:
void DrawNormalSurfaces(const CModelFlags& flags) const;
void DrawSurfaces(const CModelFlags& flags) const;
void DrawSurface(const CBooSurface& surf, const CModelFlags& flags) const;
void WarmupDrawSurfaces() const;
void WarmupDrawSurface(const CBooSurface& surf) const;
static zeus::CVector3f g_PlayerPosition;
static float g_ModSeconds;
......@@ -177,6 +180,7 @@ public:
void RemapMaterialData(SShader& shader);
bool TryLockTextures() const;
void UnlockTextures() const;
void SyncLoadTextures() const;
void Touch(int shaderIdx) const;
void VerifyCurrentShader(int shaderIdx);
boo::IGraphicsBufferD* UpdateUniformData(const CModelFlags& flags,
......@@ -214,15 +218,8 @@ public:
static