2006-12-10
This commit is contained in:
commit
78c27f03c8
12
blockdata.cpp
Normal file
12
blockdata.cpp
Normal file
@ -0,0 +1,12 @@
|
||||
#include "blockdata.h"
|
||||
namespace OpenGTA {
|
||||
float BlockData::slope_raw_data[numBlockTypes][numFaces][4][3] = {
|
||||
#include "slope1_data.h"
|
||||
};
|
||||
float BlockData::slope_tex_data[numBlockTypes][numFaces-1][4][2] = {
|
||||
#include "slope1_tcoords.h"
|
||||
};
|
||||
float BlockData::lid_normal_data[numBlockTypes][3] = {
|
||||
#include "lid_normal_data.h"
|
||||
};
|
||||
}
|
25
blockdata.h
Normal file
25
blockdata.h
Normal file
@ -0,0 +1,25 @@
|
||||
#ifndef OPENGTA_BLOCKDATA
|
||||
#define OPENGTA_BLOCKDATA
|
||||
#include <cstddef>
|
||||
#include "Singleton.h"
|
||||
|
||||
namespace OpenGTA {
|
||||
struct BlockData {
|
||||
static const size_t numBlockTypes = 45;
|
||||
static const size_t numFaces = 5;
|
||||
|
||||
static float slope_raw_data[numBlockTypes][numFaces][4][3];
|
||||
static float slope_tex_data[numBlockTypes][numFaces-1][4][2];
|
||||
static float lid_normal_data[numBlockTypes][3];
|
||||
};
|
||||
|
||||
typedef Loki::SingletonHolder<BlockData, Loki::CreateUsingNew,
|
||||
Loki::DefaultLifetime, Loki::SingleThreaded> BlockDataHolder;
|
||||
}
|
||||
|
||||
#define SLOPE_RAW_DATA BlockDataHolder::Instance().slope_raw_data
|
||||
#define SLOPE_TEX_DATA BlockDataHolder::Instance().slope_tex_data
|
||||
#define LID_NORMAL_DATA BlockDataHolder::Instance().lid_normal_data
|
||||
|
||||
|
||||
#endif
|
281
coldet/box.cpp
Normal file
281
coldet/box.cpp
Normal file
@ -0,0 +1,281 @@
|
||||
/* ColDet - C++ 3D Collision Detection Library
|
||||
* Copyright (C) 2000 Amir Geva
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Any comments, questions and bug reports send to:
|
||||
* photon@photoneffect.com
|
||||
*
|
||||
* Or visit the home page: http://photoneffect.com/coldet/
|
||||
*/
|
||||
#include "sysdep.h"
|
||||
#include "box.h"
|
||||
#include "mytritri.h"
|
||||
|
||||
__CD__BEGIN
|
||||
////////////////////////////////////////////////////
|
||||
// code from here is used in detection process
|
||||
|
||||
int BoxTreeInnerNode::getTrianglesNumber()
|
||||
{
|
||||
return m_Boxes.size();
|
||||
}
|
||||
|
||||
BoxedTriangle* BoxTreeInnerNode::getTriangle(int which)
|
||||
{
|
||||
if (which<0 || which>=getTrianglesNumber()) return NULL;
|
||||
return m_Boxes[which];
|
||||
}
|
||||
|
||||
RotationState::RotationState(const Matrix3D& transform)
|
||||
: t(transform)
|
||||
{
|
||||
N[0]=Vector3D(t._11,t._12,t._13);
|
||||
N[1]=Vector3D(t._21,t._22,t._23);
|
||||
N[2]=Vector3D(t._31,t._32,t._33);
|
||||
}
|
||||
|
||||
inline float DotWithCol(const Vector3D& v, const Matrix3& m, int col)
|
||||
{
|
||||
return v.x*m(0,col) + v.y*m(1,col) + v.z*m(2,col);
|
||||
}
|
||||
|
||||
bool Box::intersect(const Vector3D& O, float radius)
|
||||
{
|
||||
Vector3D mx=m_Pos+m_Size;
|
||||
float dist=0.0f;
|
||||
for(int i=0;i<3;i++)
|
||||
{
|
||||
if (O[i] < m_Pos[i])
|
||||
{
|
||||
float d=O[i]-m_Pos[i];
|
||||
dist+=d*d;
|
||||
}
|
||||
else
|
||||
if (O[i] > mx[i])
|
||||
{
|
||||
float d=O[i]-mx[i];
|
||||
dist+=d*d;
|
||||
}
|
||||
}
|
||||
return (dist <= (radius*radius));
|
||||
}
|
||||
|
||||
bool Box::intersect(const Vector3D& O, const Vector3D& D,
|
||||
float segmax)
|
||||
{
|
||||
if (segmax>3e30f) return intersect(O,D); // infinite ray
|
||||
Vector3D abs_segdir, abs_diff, abs_cross;
|
||||
|
||||
Vector3D segdir=0.5f*segmax*D;
|
||||
Vector3D seg_center=O+segdir;
|
||||
Vector3D diff=seg_center - getCenter();
|
||||
int i;
|
||||
for(i=0;i<3;i++)
|
||||
{
|
||||
abs_segdir[i]=flabs(segdir[i]);
|
||||
abs_diff[i]=flabs(diff[i]);
|
||||
float f=getSize()[i] + abs_segdir[i];
|
||||
if (abs_diff[i] > f) return false;
|
||||
}
|
||||
Vector3D cross=CrossProduct(segdir,diff);
|
||||
int idx[] = {0,1,2,0,1};
|
||||
for(i=0;i<3;i++)
|
||||
{
|
||||
int i1=idx[i+1];
|
||||
int i2=idx[i+2];
|
||||
abs_cross[i] = flabs(cross[i]);
|
||||
float f = getSize()[i1]*abs_segdir[i2] + getSize()[i2]*abs_segdir[i1];
|
||||
if ( abs_cross[i] > f ) return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Box::intersect(const Vector3D& O, const Vector3D& D)
|
||||
{
|
||||
Vector3D abs_segdir, abs_cross;
|
||||
float f;
|
||||
Vector3D diff = O - getCenter();
|
||||
|
||||
for(int i=0;i<3;i++)
|
||||
{
|
||||
abs_segdir[i] = flabs(D[i]);
|
||||
if ( flabs(diff[i])>m_Size[i] && diff[i]*D[i]>=0.0f )
|
||||
return false;
|
||||
}
|
||||
|
||||
Vector3D cross = CrossProduct(D,diff);
|
||||
|
||||
abs_cross[0] = flabs(cross[0]);
|
||||
f = m_Size[1]*abs_segdir[2] + m_Size[2]*abs_segdir[1];
|
||||
if ( abs_cross[0] > f )
|
||||
return false;
|
||||
|
||||
abs_cross[1] = flabs(cross[1]);
|
||||
f = m_Size[0]*abs_segdir[2] + m_Size[2]*abs_segdir[0];
|
||||
if ( abs_cross[1] > f )
|
||||
return false;
|
||||
|
||||
abs_cross[2] = flabs(cross[2]);
|
||||
f = m_Size[0]*abs_segdir[1] + m_Size[1]*abs_segdir[0];
|
||||
if ( abs_cross[2] > f )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Box::intersect(const Box& b, RotationState& rs)
|
||||
{
|
||||
const Vector3D bCenter=Transform(b.getCenter(),rs.t);
|
||||
Vector3D EA=0.5f*getSize();
|
||||
Vector3D EB=0.5f*b.getSize();
|
||||
Vector3D distance=bCenter-getCenter();
|
||||
Matrix3 C,abs_C;
|
||||
float R0,R1,R,R01;
|
||||
int i;
|
||||
|
||||
for(i=0;i<3;i++)
|
||||
{
|
||||
C(i,0)=rs.N[0][i];
|
||||
C(i,1)=rs.N[1][i];
|
||||
C(i,2)=rs.N[2][i];
|
||||
abs_C(i,0)=flabs(C(i,0));
|
||||
abs_C(i,1)=flabs(C(i,1));
|
||||
abs_C(i,2)=flabs(C(i,2));
|
||||
R=flabs(distance[i]);
|
||||
R1=EB*abs_C.baseRow(i);
|
||||
R01=EA[i]+R1;
|
||||
if (R>R01) return false;
|
||||
}
|
||||
for(i=0;i<3;i++)
|
||||
{
|
||||
R=flabs(rs.N[i]*distance);
|
||||
R0=DotWithCol(EA,abs_C,i);
|
||||
R01=R0+EB[i];
|
||||
if (R>R01) return false;
|
||||
}
|
||||
|
||||
R=flabs(distance.z*C(1,0) - distance.y*C(2,0));
|
||||
R0=EA.y*abs_C(2,0) + EA.z*abs_C(1,0);
|
||||
R1=EB.y*abs_C(0,2) + EB.z*abs_C(0,1);
|
||||
R01=R0+R1;
|
||||
if (R>R01) return false;
|
||||
|
||||
R=flabs(distance.z*C(1,1) - distance.y*C(2,1));
|
||||
R0=EA.y*abs_C(2,1) + EA.z*abs_C(1,1);
|
||||
R1=EB.x*abs_C(0,2) + EB.z*abs_C(0,0);
|
||||
R01=R0+R1;
|
||||
if (R>R01) return false;
|
||||
|
||||
R=flabs(distance.z*C(1,2) - distance.y*C(2,2));
|
||||
R0=EA.y*abs_C(2,2) + EA.z*abs_C(1,2);
|
||||
R1=EB.x*abs_C(0,1) + EB.y*abs_C(0,0);
|
||||
R01=R0+R1;
|
||||
if (R>R01) return false;
|
||||
|
||||
R=flabs(distance.x*C(2,0) - distance.z*C(0,0));
|
||||
R0=EA.x*abs_C(2,0) + EA.z*abs_C(0,0);
|
||||
R1=EB.y*abs_C(1,2) + EB.z*abs_C(1,1);
|
||||
R01=R0+R1;
|
||||
if (R>R01) return false;
|
||||
|
||||
R=flabs(distance.x*C(2,1) - distance.z*C(0,1));
|
||||
R0=EA.x*abs_C(2,1) + EA.z*abs_C(0,1);
|
||||
R1=EB.x*abs_C(1,2) + EB.z*abs_C(1,0);
|
||||
R01=R0+R1;
|
||||
if (R>R01) return false;
|
||||
|
||||
R=flabs(distance.x*C(2,2) - distance.z*C(0,2));
|
||||
R0=EA.x*abs_C(2,2) + EA.z*abs_C(0,2);
|
||||
R1=EB.x*abs_C(1,1) + EB.y*abs_C(1,0);
|
||||
R01=R0+R1;
|
||||
if (R>R01) return false;
|
||||
|
||||
R=flabs(distance.y*C(0,0) - distance.x*C(1,0));
|
||||
R0=EA.x*abs_C(1,0) + EA.y*abs_C(0,0);
|
||||
R1=EB.y*abs_C(2,2) + EB.z*abs_C(2,1);
|
||||
R01=R0+R1;
|
||||
if (R>R01) return false;
|
||||
|
||||
R=flabs(distance.y*C(0,1) - distance.x*C(1,1));
|
||||
R0=EA.x*abs_C(1,1) + EA.y*abs_C(0,1);
|
||||
R1=EB.x*abs_C(2,2) + EB.z*abs_C(2,0);
|
||||
R01=R0+R1;
|
||||
if (R>R01) return false;
|
||||
|
||||
R=flabs(distance.y*C(0,2) - distance.x*C(1,2));
|
||||
R0=EA.x*abs_C(1,2) + EA.y*abs_C(0,2);
|
||||
R1=EB.x*abs_C(2,1) + EB.y*abs_C(2,0);
|
||||
R01=R0+R1;
|
||||
if (R>R01) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
int tri_tri_intersect(float V0[3],float V1[3],float V2[3],
|
||||
float U0[3],float U1[3],float U2[3]);
|
||||
};
|
||||
|
||||
Triangle::Triangle(const Vector3D& _1, const Vector3D& _2, const Vector3D& _3)
|
||||
: v1(_1), v2(_2), v3(_3), center((1.0f/3.0f)*(_1+_2+_3))
|
||||
{}
|
||||
|
||||
bool Triangle::intersect(const Vector3D& O, const Vector3D& D, Vector3D& cp,
|
||||
float& tparm, float segmax)
|
||||
{
|
||||
Plane p(v1,v2,v3);
|
||||
float denom=p.normal*D;
|
||||
if (IsZero(denom)) return false;
|
||||
float t=-(p.d+p.normal*O)/denom;
|
||||
if (t<=0.0f) return false;
|
||||
if (t>segmax) return false;
|
||||
TriangleDesc td(*this,p);
|
||||
cp=O+t*D;
|
||||
if (td.pointInTri(cp))
|
||||
{
|
||||
tparm=t;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Triangle::intersect(const Vector3D& O, float radius, Vector3D& cp)
|
||||
{
|
||||
Plane p(v1,v2,v3);
|
||||
float dist=p.Classify(O);
|
||||
if (flabs(dist) > radius) return false;
|
||||
Vector3D point=O-dist*p.normal;
|
||||
TriangleDesc td(*this,p);
|
||||
if (td.pointInTri(point))
|
||||
{
|
||||
cp=point;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Triangle::intersect(const Triangle& t) const
|
||||
{
|
||||
return (tri_tri_intersect((float*)&v1.x,
|
||||
(float*)&v2.x,
|
||||
(float*)&v3.x,
|
||||
(float*)&t.v1.x,
|
||||
(float*)&t.v2.x,
|
||||
(float*)&t.v3.x) != 0);
|
||||
}
|
||||
|
||||
__CD__END
|
205
coldet/box.h
Normal file
205
coldet/box.h
Normal file
@ -0,0 +1,205 @@
|
||||
/* ColDet - C++ 3D Collision Detection Library
|
||||
* Copyright (C) 2000 Amir Geva
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Any comments, questions and bug reports send to:
|
||||
* photon@photoneffect.com
|
||||
*
|
||||
* Or visit the home page: http://photoneffect.com/coldet/
|
||||
*/
|
||||
#ifndef H_BOX
|
||||
#define H_BOX
|
||||
|
||||
#include <vector>
|
||||
#include "math3d.h"
|
||||
#include "sysdep.h"
|
||||
|
||||
__CD__BEGIN
|
||||
|
||||
/** Stores rotation vectors used in the intersection tests,
|
||||
to avoid recalculating them each time. */
|
||||
class RotationState
|
||||
{
|
||||
public:
|
||||
RotationState(const Matrix3D& transform);
|
||||
Vector3D N[3];
|
||||
Matrix3D t;
|
||||
};
|
||||
|
||||
/** AABB class, with support for testing against OBBs. */
|
||||
class Box
|
||||
{
|
||||
public:
|
||||
/** Default constructor */
|
||||
Box() {}
|
||||
/** Construct from scalar corner position and size */
|
||||
Box(float x, float y, float z, float sx, float sy, float sz)
|
||||
: m_Pos(x,y,z), m_Size(sx,sy,sz),
|
||||
m_Center(x+0.5f*sx,y+0.5f*sy,z+0.5f*sz) {}
|
||||
/** Construct from corner position and size */
|
||||
Box(const Vector3D& pos, const Vector3D& size)
|
||||
: m_Pos(pos), m_Size(size), m_Center(pos+0.5f*size) {}
|
||||
/** Copy constructor */
|
||||
Box(const Box& b) : m_Pos(b.m_Pos), m_Size(b.m_Size), m_Center(b.m_Center) {}
|
||||
virtual ~Box() {}
|
||||
/** Returns the box's position */
|
||||
const Vector3D& getPosition() const { return m_Pos; }
|
||||
/** Returns the sizes of the box's edges */
|
||||
const Vector3D& getSize() const { return m_Size; }
|
||||
/** Returns the center position of the box */
|
||||
const Vector3D& getCenter() const { return m_Center; }
|
||||
/** Returns the volume of the box */
|
||||
float getVolume() const { return m_Size.x*m_Size.y*m_Size.z; }
|
||||
/** Ray intersection */
|
||||
bool intersect(const Vector3D& O, const Vector3D& D);
|
||||
/** Line segment intersection */
|
||||
bool intersect(const Vector3D& O, const Vector3D& D, float segmax);
|
||||
/** Sphere intersection */
|
||||
bool intersect(const Vector3D& O, float radius);
|
||||
/** Point in box */
|
||||
bool intersect(const Vector3D& p) const;
|
||||
/** Aligned box intersection */
|
||||
bool intersect(const Box& b);
|
||||
/** Oriented box intersection. */
|
||||
bool intersect(const Box& b, RotationState& rs);
|
||||
|
||||
/** Position of box corner */
|
||||
Vector3D m_Pos;
|
||||
/** Size of box box edges */
|
||||
Vector3D m_Size;
|
||||
/** Position of box center. m_Pos+0.5f*m_Size; */
|
||||
Vector3D m_Center;
|
||||
};
|
||||
|
||||
/** A single triangle in the model */
|
||||
class Triangle
|
||||
{
|
||||
public:
|
||||
/** Default constructor */
|
||||
Triangle() {}
|
||||
/** Constructor to build a triangle from 3 points */
|
||||
Triangle(const Vector3D& _1, const Vector3D& _2, const Vector3D& _3);
|
||||
/** Tests for intersection with another triangle. */
|
||||
bool intersect(const Triangle& t) const;
|
||||
/** Tests for intersection with a ray (O origin, D direction)
|
||||
Returns true if collision occured.
|
||||
Outputs collision point in cp
|
||||
Outputs the distance from the origin to the collision point in tparm
|
||||
This distance is relative to the magnitude of D
|
||||
Allows testing against a finite segment, by specifying
|
||||
the maximum length of the ray in segmax
|
||||
This length is also relative to the magnitude of D
|
||||
*/
|
||||
bool intersect(const Vector3D& O, const Vector3D& D, Vector3D& cp,
|
||||
float& tparm, float segmax);
|
||||
/** Test for intersection with a sphere (O origin)
|
||||
Returns true if collision occured.
|
||||
Outputs collision point in cp
|
||||
*/
|
||||
bool intersect(const Vector3D& O, float radius, Vector3D& cp);
|
||||
|
||||
Vector3D v1,v2,v3;
|
||||
Vector3D center;
|
||||
};
|
||||
|
||||
class BoxedTriangle;
|
||||
|
||||
/** Base class for hierarchy tree nodes. */
|
||||
class BoxTreeNode : public Box
|
||||
{
|
||||
public:
|
||||
/** Default constructor */
|
||||
BoxTreeNode() : Box() {}
|
||||
/** Constructor for a box from position and size */
|
||||
BoxTreeNode(const Vector3D& pos, const Vector3D& size)
|
||||
: Box(pos,size) {}
|
||||
/** Returns true if the node is a leaf node. */
|
||||
virtual bool isLeaf() const = 0;
|
||||
/** Returns the number of sons this node has */
|
||||
virtual int getSonsNumber() = 0;
|
||||
/** Returns a son node, by index */
|
||||
virtual BoxTreeNode* getSon(int which) = 0;
|
||||
/** Returns the number of triangles in this node.
|
||||
Only non-zero for leaf nodes. */
|
||||
virtual int getTrianglesNumber() = 0;
|
||||
/** Returns the boxed triangle contained in this node
|
||||
by its index
|
||||
*/
|
||||
virtual BoxedTriangle* getTriangle(int which) = 0;
|
||||
};
|
||||
|
||||
/** Inner node, containing other nodes. */
|
||||
class BoxTreeInnerNode : public BoxTreeNode
|
||||
{
|
||||
public:
|
||||
BoxTreeInnerNode(const Vector3D& pos, const Vector3D& size, int logdepth)
|
||||
: BoxTreeNode(pos,size), m_First(NULL), m_Second(NULL),
|
||||
m_logdepth(logdepth) {};
|
||||
virtual bool isLeaf() const { return false; }
|
||||
/** Create the sons that will divide this box */
|
||||
int createSons(const Vector3D& center);
|
||||
/** Recalculate the bounds of this box to fully contain
|
||||
all of its triangles
|
||||
*/
|
||||
void recalcBounds(Vector3D& center);
|
||||
/** Recursively divide this box */
|
||||
int divide(int p_depth);
|
||||
|
||||
int getSonsNumber()
|
||||
{
|
||||
int n=0;
|
||||
if (m_First!=NULL) n++;
|
||||
if (m_Second!=NULL) n++;
|
||||
return n;
|
||||
}
|
||||
|
||||
int getTrianglesNumber();
|
||||
BoxedTriangle* getTriangle(int which);
|
||||
|
||||
BoxTreeNode* getSon(int which)
|
||||
{
|
||||
if (which==0) return m_First;
|
||||
if (which==1) return m_Second;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
BoxTreeNode* m_First;
|
||||
BoxTreeNode* m_Second;
|
||||
int m_logdepth;
|
||||
std::vector<BoxedTriangle*> m_Boxes;
|
||||
};
|
||||
|
||||
/** Leaf node, containing 1 triangle. */
|
||||
class BoxedTriangle : public BoxTreeNode, public Triangle
|
||||
{
|
||||
public:
|
||||
BoxedTriangle(const Vector3D& _1, const Vector3D& _2, const Vector3D& _3);
|
||||
virtual bool isLeaf() const { return true; }
|
||||
int getSonsNumber() { return 0; }
|
||||
BoxTreeNode* getSon(int which) { return NULL; }
|
||||
int getTrianglesNumber() { return 1; }
|
||||
BoxedTriangle* getTriangle(int which)
|
||||
{
|
||||
if (which==0) return this;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
__CD__END
|
||||
|
||||
#endif // H_BOX
|
197
coldet/box_bld.cpp
Normal file
197
coldet/box_bld.cpp
Normal file
@ -0,0 +1,197 @@
|
||||
/* ColDet - C++ 3D Collision Detection Library
|
||||
* Copyright (C) 2000 Amir Geva
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Any comments, questions and bug reports send to:
|
||||
* photon@photoneffect.com
|
||||
*
|
||||
* Or visit the home page: http://photoneffect.com/coldet/
|
||||
*/
|
||||
#include "sysdep.h"
|
||||
#include "box.h"
|
||||
|
||||
__CD__BEGIN
|
||||
|
||||
// point in box test
|
||||
bool Box::intersect(const Vector3D& p) const
|
||||
{
|
||||
const Vector3D& pos=getPosition();
|
||||
const Vector3D& s=getSize();
|
||||
if (p.x<pos.x || p.x>(pos.x+s.x)) return false;
|
||||
if (p.y<pos.y || p.y>(pos.y+s.y)) return false;
|
||||
if (p.z<pos.z || p.z>(pos.z+s.z)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
// Non-oriented intersection test
|
||||
bool Box::intersect(const Box& b)
|
||||
{
|
||||
const Vector3D& t1=getPosition();
|
||||
Vector3D t2=getPosition()+getSize();
|
||||
const Vector3D& p1=b.getPosition();
|
||||
Vector3D p2=b.getPosition()+b.getSize();
|
||||
return (Max(p1.x,t1.x) <= Min(p2.x,t2.x) &&
|
||||
Max(p1.y,t1.y) <= Min(p2.y,t2.y) &&
|
||||
Max(p1.z,t1.z) <= Min(p2.z,t2.z));
|
||||
}
|
||||
|
||||
BoxedTriangle::BoxedTriangle(const Vector3D& _1,
|
||||
const Vector3D& _2,
|
||||
const Vector3D& _3)
|
||||
: BoxTreeNode(), Triangle(_1,_2,_3)
|
||||
{
|
||||
m_Pos.x=Min(Min(_1.x,_2.x),_3.x);
|
||||
m_Pos.y=Min(Min(_1.y,_2.y),_3.y);
|
||||
m_Pos.z=Min(Min(_1.z,_2.z),_3.z);
|
||||
Vector3D mx;
|
||||
mx.x=Max(Max(_1.x,_2.x),_3.x);
|
||||
mx.y=Max(Max(_1.y,_2.y),_3.y);
|
||||
mx.z=Max(Max(_1.z,_2.z),_3.z);
|
||||
m_Size=mx-getPosition();
|
||||
m_Center=getPosition()+0.5f*getSize();
|
||||
}
|
||||
|
||||
int BoxTreeInnerNode::createSons(const Vector3D& center)
|
||||
{
|
||||
int longest=0;
|
||||
Vector3D p=getPosition();
|
||||
Vector3D s=getSize();
|
||||
if (1)
|
||||
{
|
||||
Vector3D dist(Vector3D::Zero);
|
||||
for(unsigned i=0;i<m_Boxes.size();i++)
|
||||
{
|
||||
BoxedTriangle* bt=m_Boxes[i];
|
||||
dist.x+=flabs(bt->center.x - center.x);
|
||||
dist.y+=flabs(bt->center.y - center.y);
|
||||
dist.z+=flabs(bt->center.z - center.z);
|
||||
}
|
||||
if (dist.y>dist.x && dist.y>dist.z) longest=1;
|
||||
else
|
||||
if (dist.z>dist.x && dist.z>dist.y) longest=2;
|
||||
}
|
||||
else
|
||||
{
|
||||
int dist[3];
|
||||
dist[0]=dist[1]=dist[2]=0;
|
||||
for(unsigned i=0;i<m_Boxes.size();i++)
|
||||
{
|
||||
BoxedTriangle* bt=m_Boxes[i];
|
||||
for(int j=0;j<3;j++)
|
||||
if (bt->center[j] > center[j]) dist[j]++;
|
||||
else dist[j]--;
|
||||
}
|
||||
for(int j=0;j<3;j++)
|
||||
dist[j]=abs(dist[j]);
|
||||
if (dist[1]<dist[0] && dist[1]<dist[2]) longest=1;
|
||||
else
|
||||
if (dist[2]<dist[0] && dist[2]<dist[1]) longest=2;
|
||||
}
|
||||
float s1=center[longest]-p[longest];
|
||||
float s2=s[longest]-s1;
|
||||
s[longest]=s1;
|
||||
m_First=new BoxTreeInnerNode(p,s,m_logdepth);
|
||||
p[longest]+=s1;
|
||||
s[longest]=s2;
|
||||
m_Second=new BoxTreeInnerNode(p,s,m_logdepth);
|
||||
return longest;
|
||||
}
|
||||
|
||||
void BoxTreeInnerNode::recalcBounds(Vector3D& center)
|
||||
{
|
||||
if (m_Boxes.empty()) return;
|
||||
center=Vector3D::Zero;
|
||||
Vector3D mn(9e9f,9e9f,9e9f),mx(-9e9f,-9e9f,-9e9f);
|
||||
for(unsigned i=0;i<m_Boxes.size();i++)
|
||||
{
|
||||
BoxedTriangle* bt=m_Boxes[i];
|
||||
center+=bt->center;
|
||||
mn.x=Min(Min(Min(bt->v1.x,bt->v2.x),bt->v3.x),mn.x);
|
||||
mn.y=Min(Min(Min(bt->v1.y,bt->v2.y),bt->v3.y),mn.y);
|
||||
mn.z=Min(Min(Min(bt->v1.z,bt->v2.z),bt->v3.z),mn.z);
|
||||
mx.x=Max(Max(Max(bt->v1.x,bt->v2.x),bt->v3.x),mx.x);
|
||||
mx.y=Max(Max(Max(bt->v1.y,bt->v2.y),bt->v3.y),mx.y);
|
||||
mx.z=Max(Max(Max(bt->v1.z,bt->v2.z),bt->v3.z),mx.z);
|
||||
}
|
||||
center/=float(m_Boxes.size());
|
||||
m_Pos=mn;
|
||||
m_Size=mx-mn;
|
||||
if (m_Size.x==0.0f) { m_Size.x=0.002f; m_Pos.x-=0.001f; }
|
||||
if (m_Size.y==0.0f) { m_Size.y=0.002f; m_Pos.y-=0.001f; }
|
||||
if (m_Size.z==0.0f) { m_Size.z=0.002f; m_Pos.z-=0.001f; }
|
||||
m_Center=getPosition()+0.5f*getSize();
|
||||
}
|
||||
|
||||
int BoxTreeInnerNode::divide(int p_depth)
|
||||
{
|
||||
if (m_Boxes.empty()) return 0;
|
||||
Vector3D center;
|
||||
recalcBounds(center);
|
||||
int longest=createSons(center);
|
||||
BoxTreeInnerNode* f=static_cast<BoxTreeInnerNode*>(m_First);
|
||||
BoxTreeInnerNode* s=static_cast<BoxTreeInnerNode*>(m_Second);
|
||||
int depth=1;
|
||||
int bnum=m_Boxes.size();
|
||||
#ifdef _DEBUG
|
||||
int fnum=0;
|
||||
#endif
|
||||
for(unsigned i=0;i<bnum;i++)
|
||||
{
|
||||
BoxedTriangle* bt=m_Boxes[i];
|
||||
if (bt->center[longest]<center[longest])
|
||||
{
|
||||
f->m_Boxes.push_back(bt);
|
||||
#ifdef _DEBUG
|
||||
fnum++;
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
s->m_Boxes.push_back(bt);
|
||||
}
|
||||
}
|
||||
|
||||
int b1num=f->m_Boxes.size();
|
||||
int b2num=s->m_Boxes.size();
|
||||
if ((b1num==bnum || b2num==bnum))// && p_depth>m_logdepth)
|
||||
{
|
||||
delete m_First; m_First=NULL;
|
||||
delete m_Second; m_Second=NULL;
|
||||
return depth+1;
|
||||
}
|
||||
|
||||
m_Boxes.clear();
|
||||
if (f->m_Boxes.empty()) { delete m_First; m_First=NULL; }
|
||||
else
|
||||
if (f->m_Boxes.size()==1)
|
||||
{
|
||||
BoxedTriangle* bt=f->m_Boxes.back();
|
||||
delete m_First;
|
||||
m_First=bt;
|
||||
} else depth=f->divide(p_depth+1);
|
||||
if (s->m_Boxes.empty()) { delete m_Second; m_Second=NULL; }
|
||||
else
|
||||
if (s->m_Boxes.size()==1)
|
||||
{
|
||||
BoxedTriangle* bt=s->m_Boxes.back();
|
||||
delete m_Second;
|
||||
m_Second=bt;
|
||||
} else depth=Max(depth,s->divide(p_depth+1));
|
||||
return depth+1;
|
||||
}
|
||||
|
||||
__CD__BEGIN
|
389
coldet/coldet.cpp
Normal file
389
coldet/coldet.cpp
Normal file
@ -0,0 +1,389 @@
|
||||
/* ColDet - C++ 3D Collision Detection Library
|
||||
* Copyright (C) 2000 Amir Geva
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Any comments, questions and bug reports send to:
|
||||
* photon@photoneffect.com
|
||||
*
|
||||
* Or visit the home page: http://photoneffect.com/coldet/
|
||||
*/
|
||||
#include "sysdep.h"
|
||||
#include "coldetimpl.h"
|
||||
#include "mytritri.h"
|
||||
#include <assert.h>
|
||||
|
||||
__CD__BEGIN
|
||||
|
||||
class Check
|
||||
{
|
||||
public:
|
||||
Check() {}
|
||||
Check(BoxTreeNode* f, BoxTreeNode* s, int d)
|
||||
: m_first(f), m_second(s), depth(d) {}
|
||||
BoxTreeNode* m_first;
|
||||
BoxTreeNode* m_second;
|
||||
int depth;
|
||||
};
|
||||
|
||||
bool CollisionModel3DImpl::collision(CollisionModel3D* other,
|
||||
int AccuracyDepth,
|
||||
int MaxProcessingTime,
|
||||
float* other_transform)
|
||||
{
|
||||
m_ColType=Models;
|
||||
CollisionModel3DImpl* o=static_cast<CollisionModel3DImpl*>(other);
|
||||
if (!m_Final) throw Inconsistency();
|
||||
if (!o->m_Final) throw Inconsistency();
|
||||
Matrix3D t=( other_transform==NULL ? o->m_Transform : *((Matrix3D*)other_transform) );
|
||||
if (m_Static) t *= m_InvTransform;
|
||||
else t *= m_Transform.Inverse();
|
||||
RotationState rs(t);
|
||||
|
||||
if (AccuracyDepth<0) AccuracyDepth=0xFFFFFF;
|
||||
if (MaxProcessingTime==0) MaxProcessingTime=0xFFFFFF;
|
||||
|
||||
DWORD EndTime,BeginTime = GetTickCount();
|
||||
int num=Max(m_Triangles.size(),o->m_Triangles.size());
|
||||
int Allocated=Max(64,(num>>4));
|
||||
std::vector<Check> checks(Allocated);
|
||||
|
||||
int queue_idx=1;
|
||||
Check& c=checks[0];
|
||||
c.m_first=&m_Root;
|
||||
c.depth=0;
|
||||
c.m_second=&o->m_Root;
|
||||
while (queue_idx>0)
|
||||
{
|
||||
if (queue_idx>(Allocated/2)) // enlarge the queue.
|
||||
{
|
||||
Check c;
|
||||
checks.insert(checks.end(),Allocated,c);
|
||||
Allocated*=2;
|
||||
}
|
||||
EndTime=GetTickCount();
|
||||
if (EndTime >= (BeginTime+MaxProcessingTime)) throw TimeoutExpired();
|
||||
|
||||
// @@@ add depth check
|
||||
//Check c=checks.back();
|
||||
Check& c=checks[--queue_idx];
|
||||
BoxTreeNode* first=c.m_first;
|
||||
BoxTreeNode* second=c.m_second;
|
||||
assert(first!=NULL);
|
||||
assert(second!=NULL);
|
||||
if (first->intersect(*second,rs))
|
||||
{
|
||||
int tnum1=first->getTrianglesNumber();
|
||||
int tnum2=second->getTrianglesNumber();
|
||||
if (tnum1>0 && tnum2>0)
|
||||
{
|
||||
{
|
||||
for(int i=0;i<tnum2;i++)
|
||||
{
|
||||
BoxedTriangle* bt2=second->getTriangle(i);
|
||||
Triangle tt(Transform(bt2->v1,rs.t),Transform(bt2->v2,rs.t),Transform(bt2->v3,rs.t));
|
||||
for(int j=0;j<tnum1;j++)
|
||||
{
|
||||
BoxedTriangle* bt1=first->getTriangle(j);
|
||||
if (tt.intersect(*bt1))
|
||||
{
|
||||
m_ColTri1=*bt1;
|
||||
m_iColTri1=getTriangleIndex(bt1);
|
||||
m_ColTri2=tt;
|
||||
m_iColTri2=o->getTriangleIndex(bt2);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
if (first->getSonsNumber()==0)
|
||||
{
|
||||
BoxTreeNode* s1=second->getSon(0);
|
||||
BoxTreeNode* s2=second->getSon(1);
|
||||
assert(s1!=NULL);
|
||||
assert(s2!=NULL);
|
||||
|
||||
Check& c1=checks[queue_idx++];
|
||||
c1.m_first=first;
|
||||
c1.m_second=s1;
|
||||
|
||||
Check& c2=checks[queue_idx++];
|
||||
c2.m_first=first;
|
||||
c2.m_second=s2;
|
||||
}
|
||||
else
|
||||
if (second->getSonsNumber()==0)
|
||||
{
|
||||
BoxTreeNode* f1=first->getSon(0);
|
||||
BoxTreeNode* f2=first->getSon(1);
|
||||
assert(f1!=NULL);
|
||||
assert(f2!=NULL);
|
||||
|
||||
Check& c1=checks[queue_idx++];
|
||||
c1.m_first=f1;
|
||||
c1.m_second=second;
|
||||
|
||||
Check& c2=checks[queue_idx++];
|
||||
c2.m_first=f2;
|
||||
c2.m_second=second;
|
||||
}
|
||||
else
|
||||
{
|
||||
float v1=first->getVolume();
|
||||
float v2=second->getVolume();
|
||||
if (v1>v2)
|
||||
{
|
||||
BoxTreeNode* f1=first->getSon(0);
|
||||
BoxTreeNode* f2=first->getSon(1);
|
||||
assert(f1!=NULL);
|
||||
assert(f2!=NULL);
|
||||
|
||||
Check& c1=checks[queue_idx++];
|
||||
c1.m_first=f1;
|
||||
c1.m_second=second;
|
||||
|
||||
Check& c2=checks[queue_idx++];
|
||||
c2.m_first=f2;
|
||||
c2.m_second=second;
|
||||
}
|
||||
else
|
||||
{
|
||||
BoxTreeNode* s1=second->getSon(0);
|
||||
BoxTreeNode* s2=second->getSon(1);
|
||||
assert(s1!=NULL);
|
||||
assert(s2!=NULL);
|
||||
|
||||
Check& c1=checks[queue_idx++];
|
||||
c1.m_first=first;
|
||||
c1.m_second=s1;
|
||||
|
||||
Check& c2=checks[queue_idx++];
|
||||
c2.m_first=first;
|
||||
c2.m_second=s2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CollisionModel3DImpl::rayCollision(float origin[3],
|
||||
float direction[3],
|
||||
bool closest,
|
||||
float segmin,
|
||||
float segmax)
|
||||
{
|
||||
float mintparm=9e9f,tparm;
|
||||
Vector3D col_point;
|
||||
m_ColType=Ray;
|
||||
Vector3D O;
|
||||
Vector3D D;
|
||||
if (m_Static)
|
||||
{
|
||||
O=Transform(*(Vector3D*)origin,m_InvTransform);
|
||||
D=rotateVector(*(Vector3D*)direction,m_InvTransform);
|
||||
}
|
||||
else
|
||||
{
|
||||
Matrix3D inv=m_Transform.Inverse();
|
||||
O=Transform(*(Vector3D*)origin,inv);
|
||||
D=rotateVector(*(Vector3D*)direction,inv);
|
||||
}
|
||||
if (segmin!=0.0f) // normalize ray
|
||||
{
|
||||
O+=segmin*D;
|
||||
segmax-=segmin;
|
||||
segmin=0.0f;
|
||||
}
|
||||
if (segmax<segmin)
|
||||
{
|
||||
D=-D;
|
||||
segmax=-segmax;
|
||||
}
|
||||
std::vector<BoxTreeNode*> checks;
|
||||
checks.push_back(&m_Root);
|
||||
while (!checks.empty())
|
||||
{
|
||||
BoxTreeNode* b=checks.back();
|
||||
checks.pop_back();
|
||||
if (b->intersect(O,D,segmax))
|
||||
{
|
||||
int sons=b->getSonsNumber();
|
||||
if (sons)
|
||||
while (sons--) checks.push_back(b->getSon(sons));
|
||||
else
|
||||
{
|
||||
int tri=b->getTrianglesNumber();
|
||||
while (tri--)
|
||||
{
|
||||
BoxedTriangle* bt=b->getTriangle(tri);
|
||||
Triangle* t=static_cast<Triangle*>(bt);
|
||||
if (t->intersect(O,D,col_point,tparm,segmax))
|
||||
{
|
||||
if (closest)
|
||||
{
|
||||
if (tparm<mintparm)
|
||||
{
|
||||
mintparm=tparm;
|
||||
m_ColTri1=*bt;
|
||||
m_iColTri1=getTriangleIndex(bt);
|
||||
m_ColPoint=col_point;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ColTri1=*bt;
|
||||
m_iColTri1=getTriangleIndex(bt);
|
||||
m_ColPoint=col_point;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (closest && mintparm<9e9f) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CollisionModel3DImpl::sphereCollision(float origin[3], float radius)
|
||||
{
|
||||
m_ColType=Sphere;
|
||||
Vector3D O;
|
||||
if (m_Static)
|
||||
O=Transform(*(Vector3D*)origin,m_InvTransform);
|
||||
else
|
||||
{
|
||||
Matrix3D inv=m_Transform.Inverse();
|
||||
O=Transform(*(Vector3D*)origin,inv);
|
||||
}
|
||||
std::vector<BoxTreeNode*> checks;
|
||||
checks.push_back(&m_Root);
|
||||
while (!checks.empty())
|
||||
{
|
||||
BoxTreeNode* b=checks.back();
|
||||
checks.pop_back();
|
||||
if (b->intersect(O,radius))
|
||||
{
|
||||
int sons=b->getSonsNumber();
|
||||
if (sons)
|
||||
while (sons--) checks.push_back(b->getSon(sons));
|
||||
else
|
||||
{
|
||||
int tri=b->getTrianglesNumber();
|
||||
while (tri--)
|
||||
{
|
||||
BoxedTriangle* bt=b->getTriangle(tri);
|
||||
Triangle* t=static_cast<Triangle*>(bt);
|
||||
if (t->intersect(O,radius,m_ColPoint))
|
||||
{
|
||||
m_ColTri1=*bt;
|
||||
m_iColTri1=getTriangleIndex(bt);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool CollisionModel3DImpl::getCollidingTriangles(float t1[9], float t2[9], bool ModelSpace)
|
||||
{
|
||||
if (ModelSpace)
|
||||
{
|
||||
if (t1!=NULL)
|
||||
{
|
||||
*((Vector3D*)&t1[0]) = m_ColTri1.v1;
|
||||
*((Vector3D*)&t1[3]) = m_ColTri1.v2;
|
||||
*((Vector3D*)&t1[6]) = m_ColTri1.v3;
|
||||
}
|
||||
if (t2!=NULL)
|
||||
{
|
||||
*((Vector3D*)&t2[0]) = m_ColTri2.v1;
|
||||
*((Vector3D*)&t2[3]) = m_ColTri2.v2;
|
||||
*((Vector3D*)&t2[6]) = m_ColTri2.v3;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (t1!=NULL)
|
||||
{
|
||||
*((Vector3D*)&t1[0]) = Transform(m_ColTri1.v1,m_Transform);
|
||||
*((Vector3D*)&t1[3]) = Transform(m_ColTri1.v2,m_Transform);
|
||||
*((Vector3D*)&t1[6]) = Transform(m_ColTri1.v3,m_Transform);
|
||||
}
|
||||
if (t2!=NULL)
|
||||
{
|
||||
*((Vector3D*)&t2[0]) = Transform(m_ColTri2.v1,m_Transform);
|
||||
*((Vector3D*)&t2[3]) = Transform(m_ColTri2.v2,m_Transform);
|
||||
*((Vector3D*)&t2[6]) = Transform(m_ColTri2.v3,m_Transform);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CollisionModel3DImpl::getCollidingTriangles(int& t1, int& t2)
|
||||
{
|
||||
t1=m_iColTri1;
|
||||
t2=m_iColTri2;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CollisionModel3DImpl::getCollisionPoint(float p[3], bool ModelSpace)
|
||||
{
|
||||
Vector3D& v=*((Vector3D*)p);
|
||||
switch (m_ColType)
|
||||
{
|
||||
case Models: v=my_tri_tri_intersect(m_ColTri1,m_ColTri2); break;
|
||||
case Sphere:
|
||||
case Ray: v=m_ColPoint; break;
|
||||
default: v=Vector3D::Zero;
|
||||
}
|
||||
if (!ModelSpace) v=Transform(v,m_Transform);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SphereRayCollision(float center[3], float radius,
|
||||
float origin[3], float direction[3],
|
||||
float point[3])
|
||||
{
|
||||
Vector3D& C=*((Vector3D*)center);
|
||||
Vector3D& O=*((Vector3D*)origin);
|
||||
Vector3D D=((Vector3D*)direction)->Normalized();
|
||||
Vector3D& P=*((Vector3D*)point);
|
||||
Vector3D EO=C-O;
|
||||
float v=EO*D;
|
||||
float disc=radius*radius - (EO*EO - v*v);
|
||||
if (disc<0.0f) return false;
|
||||
float d=sqrt(disc);
|
||||
P=O+(v-d)*D;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SphereSphereCollision(float c1[3], float r1,
|
||||
float c2[3], float r2)
|
||||
{
|
||||
Vector3D& C1=*((Vector3D*)c1);
|
||||
Vector3D& C2=*((Vector3D*)c2);
|
||||
float dist=(C2-C1).SquareMagnitude();
|
||||
float sum=r1+r2;
|
||||
return (dist < sum*sum);
|
||||
}
|
||||
|
||||
__CD__END
|
157
coldet/coldet.dsp
Normal file
157
coldet/coldet.dsp
Normal file
@ -0,0 +1,157 @@
|
||||
# Microsoft Developer Studio Project File - Name="coldet" - Package Owner=<4>
|
||||
# Microsoft Developer Studio Generated Build File, Format Version 6.00
|
||||
# ** DO NOT EDIT **
|
||||
|
||||
# TARGTYPE "Win32 (x86) Dynamic-Link Library" 0x0102
|
||||
|
||||
CFG=coldet - Win32 Debug
|
||||
!MESSAGE This is not a valid makefile. To build this project using NMAKE,
|
||||
!MESSAGE use the Export Makefile command and run
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "coldet.mak".
|
||||
!MESSAGE
|
||||
!MESSAGE You can specify a configuration when running NMAKE
|
||||
!MESSAGE by defining the macro CFG on the command line. For example:
|
||||
!MESSAGE
|
||||
!MESSAGE NMAKE /f "coldet.mak" CFG="coldet - Win32 Debug"
|
||||
!MESSAGE
|
||||
!MESSAGE Possible choices for configuration are:
|
||||
!MESSAGE
|
||||
!MESSAGE "coldet - Win32 Release" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE "coldet - Win32 Debug" (based on "Win32 (x86) Dynamic-Link Library")
|
||||
!MESSAGE
|
||||
|
||||
# Begin Project
|
||||
# PROP AllowPerConfigDependencies 0
|
||||
# PROP Scc_ProjName ""
|
||||
# PROP Scc_LocalPath ""
|
||||
CPP=cl.exe
|
||||
MTL=midl.exe
|
||||
RSC=rc.exe
|
||||
|
||||
!IF "$(CFG)" == "coldet - Win32 Release"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 0
|
||||
# PROP BASE Output_Dir "Release"
|
||||
# PROP BASE Intermediate_Dir "Release"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 0
|
||||
# PROP Output_Dir "Release"
|
||||
# PROP Intermediate_Dir "Release"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COLDET_EXPORTS" /YX /FD /c
|
||||
# ADD CPP /nologo /MT /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COLDET_EXPORTS" /YX /FD /c
|
||||
# ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x409 /d "NDEBUG"
|
||||
# ADD RSC /l 0x409 /d "NDEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /machine:I386
|
||||
|
||||
!ELSEIF "$(CFG)" == "coldet - Win32 Debug"
|
||||
|
||||
# PROP BASE Use_MFC 0
|
||||
# PROP BASE Use_Debug_Libraries 1
|
||||
# PROP BASE Output_Dir "Debug"
|
||||
# PROP BASE Intermediate_Dir "Debug"
|
||||
# PROP BASE Target_Dir ""
|
||||
# PROP Use_MFC 0
|
||||
# PROP Use_Debug_Libraries 1
|
||||
# PROP Output_Dir "Debug"
|
||||
# PROP Intermediate_Dir "Debug"
|
||||
# PROP Target_Dir ""
|
||||
# ADD BASE CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COLDET_EXPORTS" /YX /FD /GZ /c
|
||||
# ADD CPP /nologo /MTd /W3 /Gm /GX /ZI /Od /D "WIN32" /D "_DEBUG" /D "_WINDOWS" /D "_MBCS" /D "_USRDLL" /D "COLDET_EXPORTS" /FR /YX /FD /GZ /c
|
||||
# ADD BASE MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD MTL /nologo /D "_DEBUG" /mktyplib203 /win32
|
||||
# ADD BASE RSC /l 0x409 /d "_DEBUG"
|
||||
# ADD RSC /l 0x409 /d "_DEBUG"
|
||||
BSC32=bscmake.exe
|
||||
# ADD BASE BSC32 /nologo
|
||||
# ADD BSC32 /nologo
|
||||
LINK32=link.exe
|
||||
# ADD BASE LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||
# ADD LINK32 kernel32.lib user32.lib gdi32.lib winspool.lib comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib odbc32.lib odbccp32.lib /nologo /dll /debug /machine:I386 /pdbtype:sept
|
||||
|
||||
!ENDIF
|
||||
|
||||
# Begin Target
|
||||
|
||||
# Name "coldet - Win32 Release"
|
||||
# Name "coldet - Win32 Debug"
|
||||
# Begin Group "Source Files"
|
||||
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\box.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\box_bld.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\coldet.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\coldet_bld.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\math3d.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\mytritri.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\sysdep.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\tritri.c
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Header Files"
|
||||
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\box.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\coldet.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\coldetimpl.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\math3d.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\mytritri.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\sysdep.h
|
||||
# End Source File
|
||||
# End Group
|
||||
# Begin Group "Resource Files"
|
||||
|
||||
# PROP Default_Filter "ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe"
|
||||
# End Group
|
||||
# End Target
|
||||
# End Project
|
180
coldet/coldet.h
Normal file
180
coldet/coldet.h
Normal file
@ -0,0 +1,180 @@
|
||||
/* ColDet - C++ 3D Collision Detection Library
|
||||
* Copyright (C) 2000 Amir Geva
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Any comments, questions and bug reports send to:
|
||||
* photon@photoneffect.com
|
||||
*
|
||||
* Or visit the home page: http://photoneffect.com/coldet/
|
||||
*/
|
||||
/** \file coldet.h
|
||||
3D Collision Detection
|
||||
|
||||
Interface for the library.
|
||||
Isolated from any implementation details.
|
||||
*/
|
||||
#ifndef H_COLDET
|
||||
#define H_COLDET
|
||||
|
||||
#ifndef EXPORT
|
||||
#define EXPORT
|
||||
#endif
|
||||
|
||||
/** Collision Model. Will represent the mesh to be tested for
|
||||
collisions. It has to be notified of all triangles, via
|
||||
addTriangle()
|
||||
After all triangles are added, a call to finalize() will
|
||||
process the information and prepare for collision tests.
|
||||
Call collision() to check for a collision
|
||||
|
||||
Note: Transformations must not contain scaling.
|
||||
*/
|
||||
class CollisionModel3D
|
||||
{
|
||||
public:
|
||||
virtual ~CollisionModel3D() {}
|
||||
|
||||
/** Optional: Optimization for construction speed.
|
||||
If you know the number of triangles. */
|
||||
virtual void setTriangleNumber(int num) = 0;
|
||||
|
||||
/** Use any of the forms of this functions to enter the coordinates
|
||||
of the model's triangles. */
|
||||
virtual void addTriangle(float x1, float y1, float z1,
|
||||
float x2, float y2, float z2,
|
||||
float x3, float y3, float z3) = 0;
|
||||
virtual void addTriangle(float v1[3], float v2[3], float v3[3]) = 0;
|
||||
|
||||
/** All triangles have been added, process model. */
|
||||
virtual void finalize() = 0;
|
||||
|
||||
/** The the current affine matrix for the model.
|
||||
See transform.txt for format information */
|
||||
virtual void setTransform(float m[16]) = 0;
|
||||
|
||||
/** Check for collision with another model.
|
||||
Do not mix model types here.
|
||||
|
||||
MaxProcessingTime determines the maximum time in milliseconds
|
||||
to check for collision. If a rejection is not found by that
|
||||
time, the function will return true.
|
||||
|
||||
AccuracyDepth is not yet supported.
|
||||
|
||||
other_transform allows overriding the other model's
|
||||
transform, by supplying an alternative one.
|
||||
This can be useful when testing a model against itself
|
||||
with different orientations.
|
||||
*/
|
||||
virtual bool collision(CollisionModel3D* other,
|
||||
int AccuracyDepth=-1,
|
||||
int MaxProcessingTime=0,
|
||||
float* other_transform=0) = 0;
|
||||
|
||||
/** Returns true if the ray given in world space coordinates
|
||||
intersects with the object.
|
||||
getCollidingTriangles() and getCollisionPoint() can be
|
||||
used to retrieve information about a collision.
|
||||
If closest if false, the first triangle that collides with
|
||||
the ray is used. Otherwise the closest one will be used.
|
||||
Closest triangle searching will slow the test considerably.
|
||||
The default ray is a standard infinite ray. However, using
|
||||
segmin and segmax you can define a line segment along the
|
||||
ray.
|
||||
*/
|
||||
virtual bool rayCollision(float origin[3],
|
||||
float direction[3],
|
||||
bool closest=false,
|
||||
float segmin=0.0f,
|
||||
float segmax=3.4e+38F) = 0;
|
||||
|
||||
/** Returns true if the given sphere collides with the model.
|
||||
getCollidingTriangles() and getCollisionPoint() can be
|
||||
used to retrieve information about a collision.
|
||||
*/
|
||||
virtual bool sphereCollision(float origin[3],
|
||||
float radius) = 0;
|
||||
|
||||
/** Retrieve the pair of triangles that collided.
|
||||
Only valid after a call to collision() that returned true.
|
||||
t1 is this model's triangle and t2 is the other one.
|
||||
In case of ray or sphere collision, only t1 will be valid.
|
||||
The coordinates will be in _this_ model's coordinate space,
|
||||
unless ModelSpace is false, in which case, coordinates will
|
||||
be transformed by the model's current transform to world space.
|
||||
*/
|
||||
virtual bool getCollidingTriangles(float t1[9], float t2[9], bool ModelSpace=true) = 0;
|
||||
|
||||
/** Retrieve the pair of triangles indices that collided.
|
||||
Only valid after a call to collision() that returned true.
|
||||
t1 belongs to _this_ model, while t2 is in the other one.
|
||||
*/
|
||||
virtual bool getCollidingTriangles(int& t1, int& t2) = 0;
|
||||
|
||||
/** Retrieve the detected collision point.
|
||||
Only valid after a call to collision()
|
||||
that returned true.
|
||||
The coordinates will be in _this_ model's coordinate space,
|
||||
unless ModelSpace is false, in which case, coordinates will
|
||||
be transformed by the model's current transform to world space.
|
||||
*/
|
||||
virtual bool getCollisionPoint(float p[3], bool ModelSpace=true) = 0;
|
||||
};
|
||||
|
||||
/** Timeout exception class. Exception will be thrown if
|
||||
the detection algorithm could not complete within
|
||||
the given time limit. */
|
||||
class TimeoutExpired {};
|
||||
|
||||
/** Inconsistency exception. Exception will be thrown if
|
||||
the model is inconsistent.
|
||||
Examples:
|
||||
Checking for collisions before calling finalize()
|
||||
Trying to add triangles after calling finalize() */
|
||||
class Inconsistency {};
|
||||
|
||||
/** Create a new collision model object.
|
||||
Use delete when finished with it.
|
||||
|
||||
Setting Static to true indicates that the model does not
|
||||
move a lot, and certain calculations can be done every time
|
||||
its transform changes instead of every collision test.
|
||||
*/
|
||||
EXPORT CollisionModel3D* newCollisionModel3D(bool Static=false);
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////
|
||||
// Utility Functions
|
||||
//////////////////////////////////////////////
|
||||
|
||||
/** Checks for intersection between a ray and a sphere.
|
||||
center, radius define the sphere
|
||||
origin, direction define the ray
|
||||
point will contain point of intersection, if one is found.
|
||||
*/
|
||||
bool SphereRayCollision(float center[3], float radius,
|
||||
float origin[3], float direction[3],
|
||||
float point[3]);
|
||||
|
||||
/** Checks for intersection between 2 spheres. */
|
||||
bool SphereSphereCollision(float c1[3], float r1,
|
||||
float c2[3], float r2);
|
||||
|
||||
|
||||
|
||||
#endif // H_COLDET
|
74
coldet/coldet_bld.cpp
Normal file
74
coldet/coldet_bld.cpp
Normal file
@ -0,0 +1,74 @@
|
||||
/* ColDet - C++ 3D Collision Detection Library
|
||||
* Copyright (C) 2000 Amir Geva
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Any comments, questions and bug reports send to:
|
||||
* photon@photoneffect.com
|
||||
*
|
||||
* Or visit the home page: http://photoneffect.com/coldet/
|
||||
*/
|
||||
#include "sysdep.h"
|
||||
#include "coldetimpl.h"
|
||||
|
||||
__CD__BEGIN
|
||||
|
||||
CollisionModel3D* newCollisionModel3D(bool Static)
|
||||
{
|
||||
return new CollisionModel3DImpl(Static);
|
||||
}
|
||||
|
||||
CollisionModel3DImpl::CollisionModel3DImpl(bool Static)
|
||||
: m_Root(Vector3D::Zero, Vector3D::Zero,0),
|
||||
m_Transform(Matrix3D::Identity),
|
||||
m_InvTransform(Matrix3D::Identity),
|
||||
m_ColTri1(Vector3D::Zero,Vector3D::Zero,Vector3D::Zero),
|
||||
m_ColTri2(Vector3D::Zero,Vector3D::Zero,Vector3D::Zero),
|
||||
m_iColTri1(0),
|
||||
m_iColTri2(0),
|
||||
m_Final(false),
|
||||
m_Static(Static)
|
||||
{}
|
||||
|
||||
void CollisionModel3DImpl::addTriangle(const Vector3D& v1, const Vector3D& v2, const Vector3D& v3)
|
||||
{
|
||||
if (m_Final) throw Inconsistency();
|
||||
m_Triangles.push_back(BoxedTriangle(v1,v2,v3));
|
||||
}
|
||||
|
||||
void CollisionModel3DImpl::setTransform(const Matrix3D& m)
|
||||
{
|
||||
m_Transform=m;
|
||||
if (m_Static) m_InvTransform=m_Transform.Inverse();
|
||||
}
|
||||
|
||||
void CollisionModel3DImpl::finalize()
|
||||
{
|
||||
if (m_Final) throw Inconsistency();
|
||||
// Prepare initial triangle list
|
||||
m_Final=true;
|
||||
for(unsigned i=0;i<m_Triangles.size();i++)
|
||||
{
|
||||
BoxedTriangle& bt=m_Triangles[i];
|
||||
m_Root.m_Boxes.push_back(&bt);
|
||||
}
|
||||
int logdepth=0;
|
||||
for(int num=m_Triangles.size();num>0;num>>=1,logdepth++);
|
||||
m_Root.m_logdepth=int(logdepth*1.5f);
|
||||
m_Root.divide(0);
|
||||
}
|
||||
|
||||
__CD__END
|
108
coldet/coldetimpl.h
Normal file
108
coldet/coldetimpl.h
Normal file
@ -0,0 +1,108 @@
|
||||
/* ColDet - C++ 3D Collision Detection Library
|
||||
* Copyright (C) 2000 Amir Geva
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Any comments, questions and bug reports send to:
|
||||
* photon@photoneffect.com
|
||||
*
|
||||
* Or visit the home page: http://photoneffect.com/coldet/
|
||||
*/
|
||||
#ifndef H_COLDET_IMPL
|
||||
#define H_COLDET_IMPL
|
||||
|
||||
#include "coldet.h"
|
||||
#include "box.h"
|
||||
#include "math3d.h"
|
||||
#include <vector>
|
||||
|
||||
__CD__BEGIN
|
||||
|
||||
class CollisionModel3DImpl : public CollisionModel3D
|
||||
{
|
||||
public:
|
||||
CollisionModel3DImpl(bool Static);
|
||||
void setTriangleNumber(int num) { if (!m_Final) m_Triangles.reserve(num); }
|
||||
|
||||
void addTriangle(float x1, float y1, float z1,
|
||||
float x2, float y2, float z2,
|
||||
float x3, float y3, float z3)
|
||||
{
|
||||
addTriangle(Vector3D(x1,y1,z1),
|
||||
Vector3D(x2,y2,z2),
|
||||
Vector3D(x3,y3,z3));
|
||||
}
|
||||
void addTriangle(float v1[3], float v2[3], float v3[3])
|
||||
{
|
||||
addTriangle(Vector3D(v1[0],v1[1],v1[2]),
|
||||
Vector3D(v2[0],v2[1],v2[2]),
|
||||
Vector3D(v3[0],v3[1],v3[2]));
|
||||
}
|
||||
void addTriangle(const Vector3D& v1, const Vector3D& v2, const Vector3D& v3);
|
||||
void finalize();
|
||||
|
||||
void setTransform(float m[16]) { setTransform(*(Matrix3D*)m); }
|
||||
void setTransform(const Matrix3D& m);
|
||||
|
||||
bool collision(CollisionModel3D* other,
|
||||
int AccuracyDepth,
|
||||
int MaxProcessingTime,
|
||||
float* other_transform);
|
||||
|
||||
bool rayCollision(float origin[3], float direction[3], bool closest,
|
||||
float segmin, float segmax);
|
||||
bool sphereCollision(float origin[3], float radius);
|
||||
|
||||
bool getCollidingTriangles(float t1[9], float t2[9], bool ModelSpace);
|
||||
bool getCollidingTriangles(int& t1, int& t2);
|
||||
bool getCollisionPoint(float p[3], bool ModelSpace);
|
||||
|
||||
|
||||
int getTriangleIndex(BoxedTriangle* bt)
|
||||
{
|
||||
//return int(bt-m_Triangles.begin());
|
||||
return int(bt-&(*m_Triangles.begin()));
|
||||
}
|
||||
|
||||
/** Stores all the actual triangles. Other objects will use
|
||||
pointers into this array.
|
||||
*/
|
||||
std::vector<BoxedTriangle> m_Triangles;
|
||||
/** Root of the hierarchy tree */
|
||||
BoxTreeInnerNode m_Root;
|
||||
/** The current transform and its inverse */
|
||||
Matrix3D m_Transform,m_InvTransform;
|
||||
/** The triangles that last collided */
|
||||
Triangle m_ColTri1,m_ColTri2;
|
||||
/** The indices of the triangles that last collided */
|
||||
int m_iColTri1,m_iColTri2;
|
||||
/** The collision point of the last test */
|
||||
Vector3D m_ColPoint;
|
||||
|
||||
/** Type of the last collision test */
|
||||
enum { Models, Ray, Sphere }
|
||||
m_ColType;
|
||||
/** Flag for indicating the model is finalized. */
|
||||
bool m_Final;
|
||||
/** Static models will maintain the same transform for a while
|
||||
so the inverse transform is calculated each set instead
|
||||
of in the collision test. */
|
||||
bool m_Static;
|
||||
};
|
||||
|
||||
__CD__BEGIN
|
||||
|
||||
#endif // H_COLDET_IMPL
|
50
coldet/makefile.g++
Normal file
50
coldet/makefile.g++
Normal file
@ -0,0 +1,50 @@
|
||||
PROJECT=coldet
|
||||
LIB=libcoldet.a
|
||||
CC=g++
|
||||
OPT=-O2
|
||||
CFLAGS=-c $(OPT) -DGCC
|
||||
OBJS= \
|
||||
coldet.o \
|
||||
coldet_bld.o \
|
||||
box.o \
|
||||
box_bld.o \
|
||||
tritri.o \
|
||||
math3d.o \
|
||||
sysdep.o \
|
||||
mytritri.o
|
||||
|
||||
all: $(LIB)
|
||||
|
||||
$(LIB): $(OBJS)
|
||||
rm -f $(LIB)
|
||||
ar cr $(LIB) $(OBJS)
|
||||
ranlib $(LIB)
|
||||
|
||||
coldet.o: coldet.cpp
|
||||
$(CC) $(CFLAGS) coldet.cpp
|
||||
|
||||
coldet_bld.o: coldet_bld.cpp
|
||||
$(CC) $(CFLAGS) coldet_bld.cpp
|
||||
|
||||
box.o: box.cpp
|
||||
$(CC) $(CFLAGS) box.cpp
|
||||
|
||||
box_bld.o: box_bld.cpp
|
||||
$(CC) $(CFLAGS) box_bld.cpp
|
||||
|
||||
tritri.o: tritri.c
|
||||
gcc $(CFLAGS) tritri.c
|
||||
|
||||
mytritri.o: mytritri.cpp
|
||||
$(CC) $(CFLAGS) mytritri.cpp
|
||||
|
||||
math3d.o: math3d.cpp
|
||||
$(CC) $(CFLAGS) math3d.cpp
|
||||
|
||||
sysdep.o: sysdep.cpp
|
||||
$(CC) $(CFLAGS) sysdep.cpp
|
||||
|
||||
|
||||
clean:
|
||||
rm -f *.o $(LIB)
|
||||
|
93
coldet/math3d.cpp
Normal file
93
coldet/math3d.cpp
Normal file
@ -0,0 +1,93 @@
|
||||
/* ColDet - C++ 3D Collision Detection Library
|
||||
* Copyright (C) 2000 Amir Geva
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Any comments, questions and bug reports send to:
|
||||
* photon@photoneffect.com
|
||||
*
|
||||
* Or visit the home page: http://photoneffect.com/coldet/
|
||||
*/
|
||||
#include "sysdep.h"
|
||||
#include "math3d.h"
|
||||
|
||||
const Vector3D Vector3D::Zero(0.0f,0.0f,0.0f);
|
||||
const Matrix3D Matrix3D::Identity(1.0f,0.0f,0.0f,0.0f,
|
||||
0.0f,1.0f,0.0f,0.0f,
|
||||
0.0f,0.0f,1.0f,0.0f,
|
||||
0.0f,0.0f,0.0f,1.0f);
|
||||
|
||||
|
||||
inline float
|
||||
MINOR(const Matrix3D& m, const int r0, const int r1, const int r2, const int c0, const int c1, const int c2)
|
||||
{
|
||||
return m(r0,c0) * (m(r1,c1) * m(r2,c2) - m(r2,c1) * m(r1,c2)) -
|
||||
m(r0,c1) * (m(r1,c0) * m(r2,c2) - m(r2,c0) * m(r1,c2)) +
|
||||
m(r0,c2) * (m(r1,c0) * m(r2,c1) - m(r2,c0) * m(r1,c1));
|
||||
}
|
||||
|
||||
|
||||
Matrix3D
|
||||
Matrix3D::Adjoint() const
|
||||
{
|
||||
return Matrix3D( MINOR(*this, 1, 2, 3, 1, 2, 3),
|
||||
-MINOR(*this, 0, 2, 3, 1, 2, 3),
|
||||
MINOR(*this, 0, 1, 3, 1, 2, 3),
|
||||
-MINOR(*this, 0, 1, 2, 1, 2, 3),
|
||||
|
||||
-MINOR(*this, 1, 2, 3, 0, 2, 3),
|
||||
MINOR(*this, 0, 2, 3, 0, 2, 3),
|
||||
-MINOR(*this, 0, 1, 3, 0, 2, 3),
|
||||
MINOR(*this, 0, 1, 2, 0, 2, 3),
|
||||
|
||||
MINOR(*this, 1, 2, 3, 0, 1, 3),
|
||||
-MINOR(*this, 0, 2, 3, 0, 1, 3),
|
||||
MINOR(*this, 0, 1, 3, 0, 1, 3),
|
||||
-MINOR(*this, 0, 1, 2, 0, 1, 3),
|
||||
|
||||
-MINOR(*this, 1, 2, 3, 0, 1, 2),
|
||||
MINOR(*this, 0, 2, 3, 0, 1, 2),
|
||||
-MINOR(*this, 0, 1, 3, 0, 1, 2),
|
||||
MINOR(*this, 0, 1, 2, 0, 1, 2));
|
||||
}
|
||||
|
||||
|
||||
float
|
||||
Matrix3D::Determinant() const
|
||||
{
|
||||
return m[0][0] * MINOR(*this, 1, 2, 3, 1, 2, 3) -
|
||||
m[0][1] * MINOR(*this, 1, 2, 3, 0, 2, 3) +
|
||||
m[0][2] * MINOR(*this, 1, 2, 3, 0, 1, 3) -
|
||||
m[0][3] * MINOR(*this, 1, 2, 3, 0, 1, 2);
|
||||
}
|
||||
|
||||
Matrix3D
|
||||
Matrix3D::Inverse() const
|
||||
{
|
||||
return (1.0f / Determinant()) * Adjoint();
|
||||
}
|
||||
|
||||
Vector3D Matrix3D::GetTranslate() const
|
||||
{
|
||||
return Vector3D(m[3][0], m[3][1], m[3][2]);
|
||||
}
|
||||
|
||||
void Matrix3D::Translate(const Vector3D & v)
|
||||
{
|
||||
m[3][0] += v.x * m[0][0] + v.y * m[1][0] + v.z * m[2][0];
|
||||
m[3][1] += v.x * m[0][1] + v.y * m[1][1] + v.z * m[2][1];
|
||||
m[3][2] += v.x * m[0][2] + v.y * m[1][2] + v.z * m[2][2];
|
||||
}
|
335
coldet/math3d.h
Normal file
335
coldet/math3d.h
Normal file
@ -0,0 +1,335 @@
|
||||
/* ColDet - C++ 3D Collision Detection Library
|
||||
* Copyright (C) 2000 Amir Geva
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Any comments, questions and bug reports send to:
|
||||
* photon@photoneffect.com
|
||||
*
|
||||
* Or visit the home page: http://photoneffect.com/coldet/
|
||||
*/
|
||||
#ifndef H_MATH3D
|
||||
#define H_MATH3D
|
||||
|
||||
#include <math.h>
|
||||
|
||||
struct Vector3D;
|
||||
struct Matrix3;
|
||||
struct Matrix3D;
|
||||
struct Plane;
|
||||
|
||||
inline float flabs(float f) { return (f>=0.0f?f:-f); }
|
||||
const float epsilon=1e-8f;
|
||||
inline bool IsZero(float f) { return flabs(f)<epsilon; }
|
||||
|
||||
Vector3D operator*(float scalar, const Vector3D& v);
|
||||
Vector3D operator*(const Vector3D & v, float scalar);
|
||||
float operator*(const Vector3D& v1, const Vector3D& v2);
|
||||
Vector3D operator+(const Vector3D& v1, const Vector3D& v2);
|
||||
Vector3D operator-(const Vector3D& v1, const Vector3D& v2);
|
||||
Vector3D CrossProduct(const Vector3D& v1, const Vector3D& v2);
|
||||
Matrix3D operator*(const Matrix3D& m1, const Matrix3D& m2);
|
||||
Matrix3D operator*(float scalar, const Matrix3D& m);
|
||||
|
||||
struct Vector3D
|
||||
{
|
||||
float x,y,z;
|
||||
static const Vector3D Zero;
|
||||
|
||||
Vector3D() {}
|
||||
Vector3D(float X, float Y, float Z) : x(X), y(Y), z(Z) {}
|
||||
Vector3D(const Vector3D& v) : x(v.x), y(v.y), z(v.z) {}
|
||||
|
||||
Vector3D& operator+=(const Vector3D& v) { x+=v.x; y+=v.y; z+=v.z; return *this; }
|
||||
Vector3D& operator*=(float s) { x*=s; y*=s; z*=s; return *this; }
|
||||
Vector3D& operator/=(float s) { return *this *= (1.0f/s); }
|
||||
bool operator==(const Vector3D& v) { return x==v.x && y==v.y && z==v.z; }
|
||||
|
||||
Vector3D operator- () const { return Vector3D(-x,-y,-z); }
|
||||
float SquareMagnitude () const { return x*x+y*y+z*z; }
|
||||
float Magnitude () const { return (float)sqrt(SquareMagnitude()); }
|
||||
Vector3D Normalized () const { return (1.0f/Magnitude())*(*this); }
|
||||
float operator[] (int i) const { return ((float*)&x)[i]; }
|
||||
float& operator[] (int i) { return ((float*)&x)[i]; }
|
||||
};
|
||||
|
||||
#define _11 sclr.s11
|
||||
#define _12 sclr.s12
|
||||
#define _13 sclr.s13
|
||||
#define _14 sclr.s14
|
||||
#define _21 sclr.s21
|
||||
#define _22 sclr.s22
|
||||
#define _23 sclr.s23
|
||||
#define _24 sclr.s24
|
||||
#define _31 sclr.s31
|
||||
#define _32 sclr.s32
|
||||
#define _33 sclr.s33
|
||||
#define _34 sclr.s34
|
||||
#define _41 sclr.s41
|
||||
#define _42 sclr.s42
|
||||
#define _43 sclr.s43
|
||||
#define _44 sclr.s44
|
||||
|
||||
struct Matrix3
|
||||
{
|
||||
union {
|
||||
struct { float s11,s12,s13,
|
||||
s21,s22,s23,
|
||||
s31,s32,s33; } sclr;
|
||||
float m[3][3];
|
||||
};
|
||||
static const Matrix3 Identity;
|
||||
|
||||
Vector3D& baseRow(int i) { return *((Vector3D*)m[i]); }
|
||||
float operator() (int i, int j) const { return m[i][j]; }
|
||||
float& operator() (int i, int j) { return m[i][j]; }
|
||||
};
|
||||
|
||||
struct Matrix3D
|
||||
{
|
||||
union {
|
||||
struct { float s11,s12,s13,s14,
|
||||
s21,s22,s23,s24,
|
||||
s31,s32,s33,s34,
|
||||
s41,s42,s43,s44; } sclr;
|
||||
float m[4][4];
|
||||
};
|
||||
static const Matrix3D Identity;
|
||||
|
||||
Matrix3D() {}
|
||||
|
||||
Matrix3D(float f11, float f12, float f13, float f14,
|
||||
float f21, float f22, float f23, float f24,
|
||||
float f31, float f32, float f33, float f34,
|
||||
float f41, float f42, float f43, float f44)
|
||||
{
|
||||
_11=f11; _12=f12; _13=f13; _14=f14;
|
||||
_21=f21; _22=f22; _23=f23; _24=f24;
|
||||
_31=f31; _32=f32; _33=f33; _34=f34;
|
||||
_41=f41; _42=f42; _43=f43; _44=f44;
|
||||
}
|
||||
|
||||
Matrix3D& operator*= (const Matrix3D& m)
|
||||
{
|
||||
return *this = *this * m;
|
||||
}
|
||||
|
||||
friend Matrix3D PitchMatrix3D(const float theta);
|
||||
friend Matrix3D YawMatrix3D(const float theta);
|
||||
friend Matrix3D RollMatrix3D(const float theta);
|
||||
void rotate(const Vector3D& v);
|
||||
|
||||
Matrix3D Inverse() const;
|
||||
Matrix3D Adjoint() const;
|
||||
float Determinant() const;
|
||||
Vector3D GetTranslate() const;
|
||||
void Translate(const Vector3D & v);
|
||||
|
||||
float operator() (int i, int j) const { return m[i][j]; }
|
||||
float& operator() (int i, int j) { return m[i][j]; }
|
||||
};
|
||||
|
||||
struct Plane
|
||||
{
|
||||
Vector3D normal;
|
||||
float d;
|
||||
|
||||
Plane(const Vector3D& a, const Vector3D& b, const Vector3D& c)
|
||||
{
|
||||
normal = CrossProduct(b - a, c - a).Normalized();
|
||||
d = -normal * a;
|
||||
}
|
||||
|
||||
float Classify(const Vector3D& v)
|
||||
{
|
||||
return v * normal + d;
|
||||
}
|
||||
};
|
||||
|
||||
inline Vector3D operator* (float scalar, const Vector3D& v)
|
||||
{
|
||||
return Vector3D(scalar*v.x,scalar*v.y,scalar*v.z);
|
||||
}
|
||||
|
||||
inline Vector3D operator* (const Vector3D& v, float scalar)
|
||||
{
|
||||
return Vector3D(scalar*v.x,scalar*v.y,scalar*v.z);
|
||||
}
|
||||
|
||||
inline Vector3D operator+ (const Vector3D& v1, const Vector3D& v2)
|
||||
{
|
||||
return Vector3D(v1.x+v2.x,v1.y+v2.y,v1.z+v2.z);
|
||||
}
|
||||
|
||||
inline Vector3D operator- (const Vector3D& v1, const Vector3D& v2)
|
||||
{
|
||||
return Vector3D(v1.x-v2.x,v1.y-v2.y,v1.z-v2.z);
|
||||
}
|
||||
|
||||
inline float operator* (const Vector3D& v1, const Vector3D& v2)
|
||||
{
|
||||
return v1.x*v2.x + v1.y*v2.y + v1.z*v2.z;
|
||||
}
|
||||
|
||||
inline Vector3D CrossProduct(const Vector3D& v1, const Vector3D& v2)
|
||||
{
|
||||
return Vector3D(v1.y*v2.z-v2.y*v1.z,
|
||||
v1.z*v2.x-v2.z*v1.x,
|
||||
v1.x*v2.y-v2.x*v1.y);
|
||||
}
|
||||
|
||||
inline Vector3D Transform(const Vector3D& v, const Matrix3D& m)
|
||||
{
|
||||
return Vector3D(v.x*m._11 + v.y*m._21 + v.z*m._31 + m._41,
|
||||
v.x*m._12 + v.y*m._22 + v.z*m._32 + m._42,
|
||||
v.x*m._13 + v.y*m._23 + v.z*m._33 + m._43);
|
||||
}
|
||||
|
||||
inline Vector3D rotateVector(const Vector3D& v, const Matrix3D& m)
|
||||
{
|
||||
return Vector3D(v.x*m._11 + v.y*m._21 + v.z*m._31,
|
||||
v.x*m._12 + v.y*m._22 + v.z*m._32,
|
||||
v.x*m._13 + v.y*m._23 + v.z*m._33);
|
||||
}
|
||||
|
||||
inline Matrix3D operator*(float scalar, const Matrix3D& m)
|
||||
{
|
||||
return Matrix3D(scalar*m(0,0),scalar*m(0,1),scalar*m(0,2),scalar*m(0,3),
|
||||
scalar*m(1,0),scalar*m(1,1),scalar*m(1,2),scalar*m(1,3),
|
||||
scalar*m(2,0),scalar*m(2,1),scalar*m(2,2),scalar*m(2,3),
|
||||
scalar*m(3,0),scalar*m(3,1),scalar*m(3,2),scalar*m(3,3));
|
||||
}
|
||||
|
||||
inline Matrix3D operator*(const Matrix3D& m1, const Matrix3D& m2)
|
||||
{
|
||||
return Matrix3D(
|
||||
m1._11*m2._11 + m1._12*m2._21 + m1._13*m2._31 + m1._14*m2._41,
|
||||
m1._11*m2._12 + m1._12*m2._22 + m1._13*m2._32 + m1._14*m2._42,
|
||||
m1._11*m2._13 + m1._12*m2._23 + m1._13*m2._33 + m1._14*m2._43,
|
||||
m1._11*m2._14 + m1._12*m2._24 + m1._13*m2._34 + m1._14*m2._44,
|
||||
m1._21*m2._11 + m1._22*m2._21 + m1._23*m2._31 + m1._24*m2._41,
|
||||
m1._21*m2._12 + m1._22*m2._22 + m1._23*m2._32 + m1._24*m2._42,
|
||||
m1._21*m2._13 + m1._22*m2._23 + m1._23*m2._33 + m1._24*m2._43,
|
||||
m1._21*m2._14 + m1._22*m2._24 + m1._23*m2._34 + m1._24*m2._44,
|
||||
m1._31*m2._11 + m1._32*m2._21 + m1._33*m2._31 + m1._34*m2._41,
|
||||
m1._31*m2._12 + m1._32*m2._22 + m1._33*m2._32 + m1._34*m2._42,
|
||||
m1._31*m2._13 + m1._32*m2._23 + m1._33*m2._33 + m1._34*m2._43,
|
||||
m1._31*m2._14 + m1._32*m2._24 + m1._33*m2._34 + m1._34*m2._44,
|
||||
m1._41*m2._11 + m1._42*m2._21 + m1._43*m2._31 + m1._44*m2._41,
|
||||
m1._41*m2._12 + m1._42*m2._22 + m1._43*m2._32 + m1._44*m2._42,
|
||||
m1._41*m2._13 + m1._42*m2._23 + m1._43*m2._33 + m1._44*m2._43,
|
||||
m1._41*m2._14 + m1._42*m2._24 + m1._43*m2._34 + m1._44*m2._44);
|
||||
}
|
||||
|
||||
inline void
|
||||
Matrix3D::rotate(const Vector3D& v)
|
||||
{
|
||||
if (v.x!=0.0f) *this = PitchMatrix3D(v.x) * (*this);
|
||||
if (v.y!=0.0f) *this = YawMatrix3D (v.y) * (*this);
|
||||
if (v.z!=0.0f) *this = RollMatrix3D (v.z) * (*this);
|
||||
}
|
||||
|
||||
inline Matrix3D
|
||||
TranslateMatrix3D(const Vector3D& v)
|
||||
{
|
||||
return Matrix3D(1.0f,0.0f,0.0f,0.0f,
|
||||
0.0f,1.0f,0.0f,0.0f,
|
||||
0.0f,0.0f,1.0f,0.0f,
|
||||
v.x, v.y, v.z,1.0f);
|
||||
}
|
||||
|
||||
|
||||
inline Matrix3D
|
||||
ScaleMatrix3D(const Vector3D& v)
|
||||
{
|
||||
return Matrix3D( v.x,0.0f,0.0f,0.0f,
|
||||
0.0f, v.y,0.0f,0.0f,
|
||||
0.0f,0.0f, v.z,0.0f,
|
||||
0.0f,0.0f,0.0f,1.0f);
|
||||
}
|
||||
|
||||
|
||||
inline Matrix3D
|
||||
ScaleMatrix3D(const float s)
|
||||
{
|
||||
return ScaleMatrix3D(Vector3D(s,s,s));
|
||||
}
|
||||
|
||||
|
||||
inline Matrix3D
|
||||
PitchMatrix3D(const float c, const float s)
|
||||
{
|
||||
return Matrix3D(1.0f, 0.0f, 0.0f, 0.0f,
|
||||
0.0f, c, -s, 0.0f,
|
||||
0.0f, s, c, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
|
||||
inline Matrix3D
|
||||
PitchMatrix3D(const float theta)
|
||||
{
|
||||
return PitchMatrix3D((float) cos(theta), (float) sin(theta));
|
||||
}
|
||||
|
||||
|
||||
inline Matrix3D
|
||||
YawMatrix3D(const float c, const float s)
|
||||
{
|
||||
return Matrix3D( c, 0.0f, s, 0.0f,
|
||||
0.0f, 1.0f, 0.0f, 0.0f,
|
||||
-s, 0.0f, c, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
|
||||
inline Matrix3D
|
||||
YawMatrix3D(const float theta)
|
||||
{
|
||||
return YawMatrix3D((float) cos(theta), (float) sin(theta));
|
||||
}
|
||||
|
||||
|
||||
inline Matrix3D
|
||||
RollMatrix3D(const float c, const float s)
|
||||
{
|
||||
return Matrix3D(c, -s, 0.0f, 0.0f,
|
||||
s, c, 0.0f, 0.0f,
|
||||
0.0f, 0.0f, 1.0f, 0.0f,
|
||||
0.0f, 0.0f, 0.0f, 1.0f);
|
||||
}
|
||||
|
||||
|
||||
inline Matrix3D
|
||||
RollMatrix3D(const float theta)
|
||||
{
|
||||
return RollMatrix3D((float) cos(theta), (float) sin(theta));
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
inline T Max(T a, T b)
|
||||
{
|
||||
return (a>b ? a : b);
|
||||
}
|
||||
|
||||
template<class T>
|
||||
inline T Min(T a, T b)
|
||||
{
|
||||
return (a<b ? a : b);
|
||||
}
|
||||
|
||||
#endif // H_MATH3D
|
73
coldet/mytritri.cpp
Normal file
73
coldet/mytritri.cpp
Normal file
@ -0,0 +1,73 @@
|
||||
/* ColDet - C++ 3D Collision Detection Library
|
||||
* Copyright (C) 2000 Amir Geva
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Any comments, questions and bug reports send to:
|
||||
* photon@photoneffect.com
|
||||
*
|
||||
* Or visit the home page: http://photoneffect.com/coldet/
|
||||
*/
|
||||
#include "sysdep.h"
|
||||
#include "mytritri.h"
|
||||
|
||||
Vector3D my_tri_tri_intersect(const Triangle& t1, const Triangle& t2)
|
||||
{
|
||||
Plane p1(t1.v1,t1.v2,t1.v3);
|
||||
int other_side=0;
|
||||
{
|
||||
float f1=p1.Classify(t2.v1);
|
||||
float f2=p1.Classify(t2.v2);
|
||||
float f3=p1.Classify(t2.v3);
|
||||
float f12=f1*f2;
|
||||
float f23=f2*f3;
|
||||
if (f12>0.0f && f23>0.0f) return Vector3D::Zero;
|
||||
other_side=(f12<0.0f?(f23<0.0f?1:0):2);
|
||||
}
|
||||
Plane p2(t2.v1,t2.v2,t2.v3);
|
||||
Vector3D n12(p1.normal+p2.normal);
|
||||
TriangleDesc td2(t2,p2);
|
||||
const Vector3D& a2=td2[other_side+1];
|
||||
const Vector3D& b2=td2[other_side];
|
||||
const Vector3D& c2=td2[other_side+2];
|
||||
float t21=-(p1.d+p2.d+a2*n12)/((b2-a2)*n12);
|
||||
TriangleDesc td1(t1,p1);
|
||||
Vector3D P21(a2+t21*(b2-a2));
|
||||
if (td1.pointInTri(P21)) return P21;
|
||||
float t22=-(p1.d+p2.d+c2*n12)/((b2-c2)*n12);
|
||||
Vector3D P22(c2+t22*(b2-c2));
|
||||
if (td1.pointInTri(P22)) return P22;
|
||||
|
||||
{
|
||||
float f1=p2.Classify(t1.v1);
|
||||
float f2=p2.Classify(t1.v2);
|
||||
float f3=p2.Classify(t1.v3);
|
||||
float f12=f1*f2;
|
||||
float f23=f2*f3;
|
||||
if (f12>0.0f && f23>0.0f) return Vector3D::Zero;
|
||||
other_side=(f12<0.0f?(f23<0.0f?1:0):2);
|
||||
}
|
||||
const Vector3D& a1=td1[other_side+1];
|
||||
const Vector3D& b1=td1[other_side];
|
||||
const Vector3D& c1=td1[other_side+2];
|
||||
float t11=-(p1.d+p2.d+a1*n12)/((b1-a1)*n12);
|
||||
Vector3D P11(a1+t11*(b1-a1));
|
||||
if (td2.pointInTri(P11)) return P11;
|
||||
float t12=-(p1.d+p2.d+c1*n12)/((b1-c1)*n12);
|
||||
Vector3D P12(c1+t12*(b1-c1));
|
||||
if (td2.pointInTri(P12)) return P12;
|
||||
return Vector3D::Zero;
|
||||
}
|
96
coldet/mytritri.h
Normal file
96
coldet/mytritri.h
Normal file
@ -0,0 +1,96 @@
|
||||
/* ColDet - C++ 3D Collision Detection Library
|
||||
* Copyright (C) 2000 Amir Geva
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Any comments, questions and bug reports send to:
|
||||
* photon@photoneffect.com
|
||||
*
|
||||
* Or visit the home page: http://photoneffect.com/coldet/
|
||||
*/
|
||||
#ifndef H_MYTRITRI
|
||||
#define H_MYTRITRI
|
||||
|
||||
#include "box.h"
|
||||
|
||||
/** A slower triangle-triangle intersection test, that returns the
|
||||
point of intersection. */
|
||||
Vector3D my_tri_tri_intersect(const Triangle& t1, const Triangle& t2);
|
||||
|
||||
/** Triangle description class. It is used to determine if a point
|
||||
on the triangle's plane is inside the triangle. */
|
||||
class TriangleDesc : public Triangle
|
||||
{
|
||||
public:
|
||||
TriangleDesc(const Triangle& t, const Plane& p)
|
||||
: Triangle(t)
|
||||
{
|
||||
const Vector3D& n=p.normal;
|
||||
Vector3D a(flabs(n.x),flabs(n.y),flabs(n.z));
|
||||
if (a.x>a.y)
|
||||
{
|
||||
if (a.x>a.z) { i1=1; i2=2; }
|
||||
else { i1=0; i2=1; }
|
||||
}
|
||||
else
|
||||
{
|
||||
if (a.y>a.z) { i1=0; i2=2; }
|
||||
else { i1=0; i2=1; }
|
||||
}
|
||||
}
|
||||
|
||||
bool pointInTri(const Vector3D& P)
|
||||
{
|
||||
Vector3D u(P[i1]-v1[i1],
|
||||
v2[i1]-v1[i1],
|
||||
v3[i1]-v1[i1]);
|
||||
Vector3D v(P[i2]-v1[i2],
|
||||
v2[i2]-v1[i2],
|
||||
v3[i2]-v1[i2]);
|
||||
float a,b;
|
||||
if (u.y==0.0f)
|
||||
{
|
||||
b=u.x/u.z;
|
||||
if (b>=0.0f && b<=1.0f) a=(v.x-b*v.z)/v.y;
|
||||
else return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
b=(v.x*u.y-u.x*v.y)/(v.z*u.y-u.z*v.y);
|
||||
if (b>=0.0f && b<=1.0f) a=(u.x-b*u.z)/u.y;
|
||||
else return false;
|
||||
}
|
||||
return (a>=0 && (a+b)<=1);
|
||||
}
|
||||
|
||||
const Vector3D& operator[] (int index)
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0: return v1;
|
||||
case 1: return v2;
|
||||
case 2: return v3;
|
||||
case 3: return v1;
|
||||
}
|
||||
return v2;
|
||||
}
|
||||
|
||||
int i1,i2;
|
||||
};
|
||||
|
||||
|
||||
|
||||
#endif // H_MYTRITRI
|
52
coldet/quickstart.html
Normal file
52
coldet/quickstart.html
Normal file
@ -0,0 +1,52 @@
|
||||
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
|
||||
<html>
|
||||
<head>
|
||||
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
|
||||
<title>ColDet - Quick Start</title>
|
||||
</head>
|
||||
<body>
|
||||
|
||||
<center>
|
||||
<h1>
|
||||
Quickstart:</h1></center>
|
||||
|
||||
<h3>
|
||||
Model Setup:</h3>
|
||||
For each mesh, create a collision model by using:
|
||||
<pre>CollisionModel3D* model = newCollisionModel3D();</pre>
|
||||
(Shared meshes can use one model)
|
||||
<br>Add all the triangles the mesh has to the model by using:
|
||||
<pre>model->addTriangle(vertex1,vertex2,vertex3);</pre>
|
||||
Call:
|
||||
<pre>model->finalize();</pre>
|
||||
|
||||
<h3>
|
||||
Collision Test:</h3>
|
||||
Assuming you have two models (m1,m2), either set both of their’s transformation
|
||||
<br>matrices (world matrix) by calling:
|
||||
<pre>m1->setTransform(model1_transformation_matrix);</pre>
|
||||
|
||||
<pre>m2->setTransform(model2_transformation_matrix);</pre>
|
||||
or set only one of them (in case you’re testing the model against itself,
|
||||
with different
|
||||
<br>transform) Then call:
|
||||
<pre>m1->collision(m2);</pre>
|
||||
The function returns a bool indicating if a collision has occurred.
|
||||
Note that if you test a
|
||||
<br>model against itself with a different transform, you need to supply
|
||||
that transform as an
|
||||
<br>optional parameter.
|
||||
<br>
|
||||
<h3>
|
||||
Collision Test Results:</h3>
|
||||
Use the getCollidingTriangles function to get which triangles have collided.
|
||||
Use the
|
||||
<br>getCollisionPoint function to find the exact collision point.
|
||||
<br>
|
||||
<h3>
|
||||
Other Collision Tests:</h3>
|
||||
You can use the rayCollision and sphereCollision functions to test the
|
||||
model against
|
||||
<br>these primitives.
|
||||
</body>
|
||||
</html>
|
29
coldet/readme.txt
Normal file
29
coldet/readme.txt
Normal file
@ -0,0 +1,29 @@
|
||||
ColDet - 3D Collision Detection Library
|
||||
Copyright (C) 2000 Amir Geva
|
||||
|
||||
|
||||
Description:
|
||||
ColDet is a 3D collision detection library, intended for games.
|
||||
It supports generic polyhedra, and even polygon soups.
|
||||
|
||||
Requirements:
|
||||
It is written in standard C++ and can be compiled on these systems:
|
||||
Windows: Visual C++ 6
|
||||
Windows: Borland C++ Builder 5
|
||||
Linux: g++ 2.8
|
||||
Other systems that have g++ will probably compile with no modification.
|
||||
The code is portable to any system with a standard C++ compliant compiler
|
||||
(as compliant as they get)
|
||||
|
||||
Installation:
|
||||
Use the supplied Visual C++ project file (coldet.dsp)
|
||||
or the makefile (for systems with g++)
|
||||
In other cases, just create a project/makefile and include all of the source files.
|
||||
|
||||
Distribution:
|
||||
It is distributed under the Library GNU Public License (See the file: COPYING)
|
||||
Any redistribution of the files in this package must include the entire package.
|
||||
|
||||
Contact Information:
|
||||
Web Site: http://photoneffect.com/coldet/
|
||||
email: photon@photoneffect.com
|
41
coldet/sysdep.cpp
Normal file
41
coldet/sysdep.cpp
Normal file
@ -0,0 +1,41 @@
|
||||
/* ColDet - C++ 3D Collision Detection Library
|
||||
* Copyright (C) 2000 Amir Geva
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Any comments, questions and bug reports send to:
|
||||
* photon@photoneffect.com
|
||||
*
|
||||
* Or visit the home page: http://photoneffect.com/coldet/
|
||||
*/
|
||||
#include "sysdep.h"
|
||||
|
||||
#ifdef GCC
|
||||
|
||||
#include <sys/time.h>
|
||||
|
||||
// Returns a time index in milliseconds
|
||||
DWORD GetTickCount()
|
||||
{
|
||||
static struct timezone tz={0,0};
|
||||
static const double t1=1000.0;
|
||||
static const double t2=0.001;
|
||||
timeval t;
|
||||
gettimeofday(&t,&tz);
|
||||
return long((t.tv_sec&0x000FFFFF)*t1 + t.tv_usec*t2);
|
||||
}
|
||||
|
||||
#endif
|
55
coldet/sysdep.h
Normal file
55
coldet/sysdep.h
Normal file
@ -0,0 +1,55 @@
|
||||
/* ColDet - C++ 3D Collision Detection Library
|
||||
* Copyright (C) 2000 Amir Geva
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Library General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library 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
|
||||
* Library General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Library General Public
|
||||
* License along with this library; if not, write to the
|
||||
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
||||
* Boston, MA 02111-1307, USA.
|
||||
*
|
||||
* Any comments, questions and bug reports send to:
|
||||
* photon@photoneffect.com
|
||||
*
|
||||
* Or visit the home page: http://photoneffect.com/coldet/
|
||||
*/
|
||||
#ifndef H_SYSDEP
|
||||
#define H_SYSDEP
|
||||
|
||||
#ifdef GCC
|
||||
|
||||
typedef unsigned long DWORD;
|
||||
DWORD GetTickCount();
|
||||
#define __CD__BEGIN
|
||||
#define __CD__END
|
||||
|
||||
#elif defined(WIN32)
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <windows.h>
|
||||
#define __CD__BEGIN
|
||||
#define __CD__END
|
||||
#ifdef COLDET_EXPORTS
|
||||
#define EXPORT __declspec(dllexport)
|
||||
#else
|
||||
#define EXPORT __declspec(dllimport)
|
||||
#endif
|
||||
#else
|
||||
|
||||
#error No system specified (WIN32 GCC)
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef EXPORT
|
||||
#define EXPORT
|
||||
#endif
|
||||
|
||||
#endif // H_SYSDEP
|
21
coldet/transform.txt
Normal file
21
coldet/transform.txt
Normal file
@ -0,0 +1,21 @@
|
||||
The matrices used to describe model transformations are affine 4x4 matrices
|
||||
which are D3D style, row major with translations in the 4th row.
|
||||
|
||||
1 2 3 4
|
||||
5 6 7 8
|
||||
9 10 11 12
|
||||
13 14 15 16
|
||||
|
||||
The translation vector Tx,Ty,Tz is in elements 13,14,15
|
||||
|
||||
If you use the transposed scheme, which is:
|
||||
1 5 9 13
|
||||
2 6 10 14
|
||||
3 7 11 15
|
||||
4 8 12 16
|
||||
|
||||
With the translation vector in elements 13,14,15 you can use
|
||||
this matrix without any conversion.
|
||||
|
||||
It is also important to note that the transformations should include
|
||||
no scaling, as it disrupts the consistency of the collision model.
|
292
coldet/tritri.c
Normal file
292
coldet/tritri.c
Normal file
@ -0,0 +1,292 @@
|
||||
/* Triangle/triangle intersection test routine,
|
||||
* by Tomas Moller, 1997.
|
||||
* See article "A Fast Triangle-Triangle Intersection Test",
|
||||
* Journal of Graphics Tools, 2(2), 1997
|
||||
*
|
||||
* int tri_tri_intersect(float V0[3],float V1[3],float V2[3],
|
||||
* float U0[3],float U1[3],float U2[3])
|
||||
*
|
||||
* parameters: vertices of triangle 1: V0,V1,V2
|
||||
* vertices of triangle 2: U0,U1,U2
|
||||
* result : returns 1 if the triangles intersect, otherwise 0
|
||||
*
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
|
||||
|
||||
/* if USE_EPSILON_TEST is true then we do a check:
|
||||
if |dv|<EPSILON then dv=0.0;
|
||||
else no check is done (which is less robust)
|
||||
*/
|
||||
#define USE_EPSILON_TEST TRUE
|
||||
#define EPSILON 0.000001
|
||||
|
||||
|
||||
/* some macros */
|
||||
#define CROSS(dest,v1,v2) \
|
||||
dest[0]=v1[1]*v2[2]-v1[2]*v2[1]; \
|
||||
dest[1]=v1[2]*v2[0]-v1[0]*v2[2]; \
|
||||
dest[2]=v1[0]*v2[1]-v1[1]*v2[0];
|
||||
|
||||
#define DOT(v1,v2) (v1[0]*v2[0]+v1[1]*v2[1]+v1[2]*v2[2])
|
||||
|
||||
#define SUB(dest,v1,v2) \
|
||||
dest[0]=v1[0]-v2[0]; \
|
||||
dest[1]=v1[1]-v2[1]; \
|
||||
dest[2]=v1[2]-v2[2];
|
||||
|
||||
/* sort so that a<=b */
|
||||
#define SORT(a,b) \
|
||||
if(a>b) \
|
||||
{ \
|
||||
float c; \
|
||||
c=a; \
|
||||
a=b; \
|
||||
b=c; \
|
||||
}
|
||||
|
||||
#define ISECT(VV0,VV1,VV2,D0,D1,D2,isect0,isect1) \
|
||||
isect0=VV0+(VV1-VV0)*D0/(D0-D1); \
|
||||
isect1=VV0+(VV2-VV0)*D0/(D0-D2);
|
||||
|
||||
|
||||
#define COMPUTE_INTERVALS(VV0,VV1,VV2,D0,D1,D2,D0D1,D0D2,isect0,isect1) \
|
||||
if(D0D1>0.0f) \
|
||||
{ \
|
||||
/* here we know that D0D2<=0.0 */ \
|
||||
/* that is D0, D1 are on the same side, D2 on the other or on the plane */ \
|
||||
ISECT(VV2,VV0,VV1,D2,D0,D1,isect0,isect1); \
|
||||
} \
|
||||
else if(D0D2>0.0f) \
|
||||
{ \
|
||||
/* here we know that d0d1<=0.0 */ \
|
||||
ISECT(VV1,VV0,VV2,D1,D0,D2,isect0,isect1); \
|
||||
} \
|
||||
else if(D1*D2>0.0f || D0!=0.0f) \
|
||||
{ \
|
||||
/* here we know that d0d1<=0.0 or that D0!=0.0 */ \
|
||||
ISECT(VV0,VV1,VV2,D0,D1,D2,isect0,isect1); \
|
||||
} \
|
||||
else if(D1!=0.0f) \
|
||||
{ \
|
||||
ISECT(VV1,VV0,VV2,D1,D0,D2,isect0,isect1); \
|
||||
} \
|
||||
else if(D2!=0.0f) \
|
||||
{ \
|
||||
ISECT(VV2,VV0,VV1,D2,D0,D1,isect0,isect1); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
/* triangles are coplanar */ \
|
||||
return coplanar_tri_tri(N1,V0,V1,V2,U0,U1,U2); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* this edge to edge test is based on Franlin Antonio's gem:
|
||||
"Faster Line Segment Intersection", in Graphics Gems III,
|
||||
pp. 199-202 */
|
||||
#define EDGE_EDGE_TEST(V0,U0,U1) \
|
||||
Bx=U0[i0]-U1[i0]; \
|
||||
By=U0[i1]-U1[i1]; \
|
||||
Cx=V0[i0]-U0[i0]; \
|
||||
Cy=V0[i1]-U0[i1]; \
|
||||
f=Ay*Bx-Ax*By; \
|
||||
d=By*Cx-Bx*Cy; \
|
||||
if((f>0 && d>=0 && d<=f) || (f<0 && d<=0 && d>=f)) \
|
||||
{ \
|
||||
e=Ax*Cy-Ay*Cx; \
|
||||
if(f>0) \
|
||||
{ \
|
||||
if(e>=0 && e<=f) return 1; \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
if(e<=0 && e>=f) return 1; \
|
||||
} \
|
||||
}
|
||||
|
||||
#define EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2) \
|
||||
{ \
|
||||
float Ax,Ay,Bx,By,Cx,Cy,e,d,f; \
|
||||
Ax=V1[i0]-V0[i0]; \
|
||||
Ay=V1[i1]-V0[i1]; \
|
||||
/* test edge U0,U1 against V0,V1 */ \
|
||||
EDGE_EDGE_TEST(V0,U0,U1); \
|
||||
/* test edge U1,U2 against V0,V1 */ \
|
||||
EDGE_EDGE_TEST(V0,U1,U2); \
|
||||
/* test edge U2,U1 against V0,V1 */ \
|
||||
EDGE_EDGE_TEST(V0,U2,U0); \
|
||||
}
|
||||
|
||||
#define POINT_IN_TRI(V0,U0,U1,U2) \
|
||||
{ \
|
||||
float a,b,c,d0,d1,d2; \
|
||||
/* is T1 completly inside T2? */ \
|
||||
/* check if V0 is inside tri(U0,U1,U2) */ \
|
||||
a=U1[i1]-U0[i1]; \
|
||||
b=-(U1[i0]-U0[i0]); \
|
||||
c=-a*U0[i0]-b*U0[i1]; \
|
||||
d0=a*V0[i0]+b*V0[i1]+c; \
|
||||
\
|
||||
a=U2[i1]-U1[i1]; \
|
||||
b=-(U2[i0]-U1[i0]); \
|
||||
c=-a*U1[i0]-b*U1[i1]; \
|
||||
d1=a*V0[i0]+b*V0[i1]+c; \
|
||||
\
|
||||
a=U0[i1]-U2[i1]; \
|
||||
b=-(U0[i0]-U2[i0]); \
|
||||
c=-a*U2[i0]-b*U2[i1]; \
|
||||
d2=a*V0[i0]+b*V0[i1]+c; \
|
||||
if(d0*d1>0.0) \
|
||||
{ \
|
||||
if(d0*d2>0.0) return 1; \
|
||||
} \
|
||||
}
|
||||
|
||||
int coplanar_tri_tri(float N[3],float V0[3],float V1[3],float V2[3],
|
||||
float U0[3],float U1[3],float U2[3])
|
||||
{
|
||||
float A[3];
|
||||
short i0,i1;
|
||||
/* first project onto an axis-aligned plane, that maximizes the area */
|
||||
/* of the triangles, compute indices: i0,i1. */
|
||||
A[0]=fabs(N[0]);
|
||||
A[1]=fabs(N[1]);
|
||||
A[2]=fabs(N[2]);
|
||||
if(A[0]>A[1])
|
||||
{
|
||||
if(A[0]>A[2])
|
||||
{
|
||||
i0=1; /* A[0] is greatest */
|
||||
i1=2;
|
||||
}
|
||||
else
|
||||
{
|
||||
i0=0; /* A[2] is greatest */
|
||||
i1=1;
|
||||
}
|
||||
}
|
||||
else /* A[0]<=A[1] */
|
||||
{
|
||||
if(A[2]>A[1])
|
||||
{
|
||||
i0=0; /* A[2] is greatest */
|
||||
i1=1;
|
||||
}
|
||||
else
|
||||
{
|
||||
i0=0; /* A[1] is greatest */
|
||||
i1=2;
|
||||
}
|
||||
}
|
||||
|
||||
/* test all edges of triangle 1 against the edges of triangle 2 */
|
||||
EDGE_AGAINST_TRI_EDGES(V0,V1,U0,U1,U2);
|
||||
EDGE_AGAINST_TRI_EDGES(V1,V2,U0,U1,U2);
|
||||
EDGE_AGAINST_TRI_EDGES(V2,V0,U0,U1,U2);
|
||||
|
||||
/* finally, test if tri1 is totally contained in tri2 or vice versa */
|
||||
POINT_IN_TRI(V0,U0,U1,U2);
|
||||
POINT_IN_TRI(U0,V0,V1,V2);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int tri_tri_intersect(float V0[3],float V1[3],float V2[3],
|
||||
float U0[3],float U1[3],float U2[3])
|
||||
{
|
||||
float E1[3],E2[3];
|
||||
float N1[3],N2[3],d1,d2;
|
||||
float du0,du1,du2,dv0,dv1,dv2;
|
||||
float D[3];
|
||||
float isect1[2], isect2[2];
|
||||
float du0du1,du0du2,dv0dv1,dv0dv2;
|
||||
short index;
|
||||
float vp0,vp1,vp2;
|
||||
float up0,up1,up2;
|
||||
float b,c,max;
|
||||
|
||||
/* compute plane equation of triangle(V0,V1,V2) */
|
||||
SUB(E1,V1,V0);
|
||||
SUB(E2,V2,V0);
|
||||
CROSS(N1,E1,E2);
|
||||
d1=-DOT(N1,V0);
|
||||
/* plane equation 1: N1.X+d1=0 */
|
||||
|
||||
/* put U0,U1,U2 into plane equation 1 to compute signed distances to the plane*/
|
||||
du0=DOT(N1,U0)+d1;
|
||||
du1=DOT(N1,U1)+d1;
|
||||
du2=DOT(N1,U2)+d1;
|
||||
|
||||
/* coplanarity robustness check */
|
||||
#if USE_EPSILON_TEST==TRUE
|
||||
if(fabs(du0)<EPSILON) du0=0.0;
|
||||
if(fabs(du1)<EPSILON) du1=0.0;
|
||||
if(fabs(du2)<EPSILON) du2=0.0;
|
||||
#endif
|
||||
du0du1=du0*du1;
|
||||
du0du2=du0*du2;
|
||||
|
||||
if(du0du1>0.0f && du0du2>0.0f) /* same sign on all of them + not equal 0 ? */
|
||||
return 0; /* no intersection occurs */
|
||||
|
||||
/* compute plane of triangle (U0,U1,U2) */
|
||||
SUB(E1,U1,U0);
|
||||
SUB(E2,U2,U0);
|
||||
CROSS(N2,E1,E2);
|
||||
d2=-DOT(N2,U0);
|
||||
/* plane equation 2: N2.X+d2=0 */
|
||||
|
||||
/* put V0,V1,V2 into plane equation 2 */
|
||||
dv0=DOT(N2,V0)+d2;
|
||||
dv1=DOT(N2,V1)+d2;
|
||||
dv2=DOT(N2,V2)+d2;
|
||||
|
||||
#if USE_EPSILON_TEST==TRUE
|
||||
if(fabs(dv0)<EPSILON) dv0=0.0;
|
||||
if(fabs(dv1)<EPSILON) dv1=0.0;
|
||||
if(fabs(dv2)<EPSILON) dv2=0.0;
|
||||
#endif
|
||||
|
||||
dv0dv1=dv0*dv1;
|
||||
dv0dv2=dv0*dv2;
|
||||
|
||||
if(dv0dv1>0.0f && dv0dv2>0.0f) /* same sign on all of them + not equal 0 ? */
|
||||
return 0; /* no intersection occurs */
|
||||
|
||||
/* compute direction of intersection line */
|
||||
CROSS(D,N1,N2);
|
||||
|
||||
/* compute and index to the largest component of D */
|
||||
max=fabs(D[0]);
|
||||
index=0;
|
||||
b=fabs(D[1]);
|
||||
c=fabs(D[2]);
|
||||
if(b>max) max=b,index=1;
|
||||
if(c>max) max=c,index=2;
|
||||
|
||||
/* this is the simplified projection onto L*/
|
||||
vp0=V0[index];
|
||||
vp1=V1[index];
|
||||
vp2=V2[index];
|
||||
|
||||
up0=U0[index];
|
||||
up1=U1[index];
|
||||
up2=U2[index];
|
||||
|
||||
/* compute interval for triangle 1 */
|
||||
COMPUTE_INTERVALS(vp0,vp1,vp2,dv0,dv1,dv2,dv0dv1,dv0dv2,isect1[0],isect1[1]);
|
||||
|
||||
/* compute interval for triangle 2 */
|
||||
COMPUTE_INTERVALS(up0,up1,up2,du0,du1,du2,du0du1,du0du2,isect2[0],isect2[1]);
|
||||
|
||||
SORT(isect1[0],isect1[1]);
|
||||
SORT(isect2[0],isect2[1]);
|
||||
|
||||
if(isect1[1]<isect2[0] || isect2[1]<isect1[0]) return 0;
|
||||
return 1;
|
||||
}
|
||||
|
153
common_sdl_gl.cpp
Normal file
153
common_sdl_gl.cpp
Normal file
@ -0,0 +1,153 @@
|
||||
#include <iostream>
|
||||
#include <SDL.h>
|
||||
#include <SDL_opengl.h>
|
||||
|
||||
extern int global_EC;
|
||||
|
||||
#ifndef VIEWGL_FOVY
|
||||
#define VIEWGL_FOVY 60.0f
|
||||
#endif
|
||||
#ifndef VIEWGL_ZNEAR
|
||||
#define VIEWGL_ZNEAR 0.1f
|
||||
#endif
|
||||
#ifndef VIEWGL_ZFAR
|
||||
#define VIEWGL_ZFAR 250.0f
|
||||
#endif
|
||||
|
||||
extern SDL_Surface* screen;
|
||||
int videoFlags = 0;
|
||||
|
||||
/*
|
||||
void ERROR(const char* s) {
|
||||
std::cerr << "Error" << s << std::endl;
|
||||
std::cerr << "* last SDL error was: " << SDL_GetError() << std::endl;
|
||||
global_EC = 1;
|
||||
exit(1);
|
||||
}*/
|
||||
|
||||
int resize(int w, int h) {
|
||||
GLfloat ratio;
|
||||
if ( h == 0 )
|
||||
h = 1;
|
||||
ratio = ( GLfloat )w / ( GLfloat )h;
|
||||
glViewport( 0, 0, ( GLint )w, ( GLint )h );
|
||||
glMatrixMode( GL_PROJECTION );
|
||||
glLoadIdentity( );
|
||||
//glRotatef(180, 0, 0, 1);
|
||||
gluPerspective( VIEWGL_FOVY, ratio, VIEWGL_ZNEAR, VIEWGL_ZFAR);
|
||||
|
||||
//glOrtho(-1.0f, 1.0f, -1.0f, 1.0f, 0.1f, 300.0f);
|
||||
glMatrixMode( GL_MODELVIEW );
|
||||
glLoadIdentity( );
|
||||
return(1);
|
||||
}
|
||||
|
||||
void initVideo(int w, int h, int bpp) {
|
||||
const SDL_VideoInfo *videoInfo;
|
||||
/*
|
||||
SDL_Rect **modes;
|
||||
int i;
|
||||
|
||||
videoInfo = SDL_GetVideoInfo( );
|
||||
modes=SDL_ListModes(videoInfo->vfmt, SDL_FULLSCREEN|SDL_HWSURFACE);
|
||||
if(modes == (SDL_Rect **)0){
|
||||
printf("No modes available!\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if(modes == (SDL_Rect **)-1){
|
||||
printf("All resolutions available.\n");
|
||||
}
|
||||
else{
|
||||
printf("Available Modes\n");
|
||||
for(i=0;modes[i];++i)
|
||||
printf(" %d x %d\n", modes[i]->w, modes[i]->h);
|
||||
}
|
||||
*/
|
||||
|
||||
if (!videoInfo)
|
||||
ERROR("VideoInfo query failed");
|
||||
videoFlags = SDL_OPENGL;
|
||||
videoFlags |= SDL_GL_DOUBLEBUFFER;
|
||||
videoFlags |= SDL_HWPALETTE;
|
||||
//videoFlags |= SDL_RESIZABLE;
|
||||
//videoFlags |= SDL_FULLSCREEN;
|
||||
|
||||
if ( videoInfo->hw_available ) {
|
||||
std::cerr << "Info: Using HWSURFACE" << std::endl;
|
||||
videoFlags |= SDL_HWSURFACE;
|
||||
}
|
||||
else {
|
||||
std::cerr << "Info: Using SWSURFACE" << std::endl;
|
||||
videoFlags |= SDL_SWSURFACE;
|
||||
}
|
||||
if ( videoInfo->blit_hw ) {
|
||||
std::cerr << "Info: Using HWACCEL" << std::endl;
|
||||
videoFlags |= SDL_HWACCEL;
|
||||
}
|
||||
SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 );
|
||||
|
||||
screen = SDL_SetVideoMode( w, h, bpp, videoFlags );
|
||||
if (!screen)
|
||||
ERROR("SDL failed to generate requested VideoSurface!");
|
||||
|
||||
resize(w, h);
|
||||
}
|
||||
|
||||
void initGL() {
|
||||
GLfloat LightAmbient[] = { 0.5f, 0.5f, 0.5f, 1.0f };
|
||||
GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
GLfloat LightPosition[] = { 500.0f, 200.0f, 300.0f, 1.0f };
|
||||
|
||||
//glEnable( GL_TEXTURE_2D );
|
||||
glShadeModel( GL_SMOOTH );
|
||||
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
|
||||
//glClearDepth( 1.0f );
|
||||
glEnable( GL_DEPTH_TEST );
|
||||
glEnable( GL_LIGHTING );
|
||||
//glDepthFunc( GL_LEQUAL );
|
||||
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
|
||||
glLightfv( GL_LIGHT0, GL_AMBIENT, LightAmbient );
|
||||
glLightfv( GL_LIGHT0, GL_DIFFUSE, LightDiffuse );
|
||||
glLightfv( GL_LIGHT0, GL_POSITION, LightPosition );
|
||||
glEnable( GL_LIGHT0 );
|
||||
glEnable( GL_COLOR_MATERIAL);
|
||||
glCullFace(GL_BACK);
|
||||
glPolygonMode(GL_FRONT, GL_FILL);
|
||||
glPolygonMode(GL_BACK, GL_LINE);
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
SDL_Surface* createRGBASurface(int w, int h) {
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
#define rmask 0xff000000
|
||||
#define gmask 0x00ff0000
|
||||
#define bmask 0x0000ff00
|
||||
#define amask 0x000000ff
|
||||
#else
|
||||
#define rmask 0x000000ff
|
||||
#define gmask 0x0000ff00
|
||||
#define bmask 0x00ff0000
|
||||
#define amask 0xff000000
|
||||
#endif
|
||||
return SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA,
|
||||
64, 64, 32, rmask, gmask, bmask, amask);
|
||||
}
|
||||
|
||||
SDL_Surface* createRGBSurface(int w, int h) {
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
#define rmask 0xff000000
|
||||
#define gmask 0x00ff0000
|
||||
#define bmask 0x0000ff00
|
||||
#define amask 0x000000ff
|
||||
#else
|
||||
#define rmask 0x000000ff
|
||||
#define gmask 0x0000ff00
|
||||
#define bmask 0x00ff0000
|
||||
#define amask 0xff000000
|
||||
#endif
|
||||
return SDL_CreateRGBSurface(SDL_SWSURFACE,
|
||||
w, h, 24, rmask, gmask, bmask, amask);
|
||||
}
|
||||
*/
|
17
common_sdl_gl.h
Normal file
17
common_sdl_gl.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef SDL_GL_COMMON_FUNCS_H
|
||||
#define SDL_GL_COMMON_FUNCS_H
|
||||
#include <SDL.h>
|
||||
|
||||
int resize(int w, int h);
|
||||
void initVideo(int w, int h, int bpp);
|
||||
void initGL();
|
||||
//void ERROR(const char* s);
|
||||
|
||||
//SDL_Surface* createRGBSurface(int w, int h);
|
||||
//SDL_Surface* createRGBASurface(int w, int h);
|
||||
|
||||
extern int videoFlags;
|
||||
extern int global_Done;
|
||||
extern int global_EC;
|
||||
|
||||
#endif
|
100
dataholder.cpp
Normal file
100
dataholder.cpp
Normal file
@ -0,0 +1,100 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This software is provided as-is, without any express or implied *
|
||||
* warranty. In no event will the authors be held liable for any *
|
||||
* damages arising from the use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute *
|
||||
* it freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must *
|
||||
* not claim that you wrote the original software. If you use this *
|
||||
* software in a product, an acknowledgment in the product documentation *
|
||||
* would be appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must *
|
||||
* not be misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source *
|
||||
* distribution. *
|
||||
************************************************************************/
|
||||
#include "dataholder.h"
|
||||
#include "log.h"
|
||||
#include "cistring.h"
|
||||
|
||||
namespace OpenGTA {
|
||||
template<> ActiveStyle::ActiveData() {
|
||||
m_data = 0;
|
||||
}
|
||||
|
||||
template<> ActiveStyle::~ActiveData() {
|
||||
unload();
|
||||
}
|
||||
|
||||
template<> GraphicsBase & ActiveStyle::get() {
|
||||
assert(m_data);
|
||||
return *m_data;
|
||||
}
|
||||
|
||||
template<class T> void ActiveData<T>::unload() {
|
||||
if (m_data)
|
||||
delete m_data;
|
||||
m_data = 0;
|
||||
}
|
||||
|
||||
template<> void ActiveStyle::load(const std::string & file) {
|
||||
unload();
|
||||
Util::ci_string tmpname(file.c_str());
|
||||
if (tmpname.find(".g24") != std::string::npos) {
|
||||
m_data = new Graphics24Bit(file);
|
||||
}
|
||||
else if (tmpname.find(".gry") != std::string::npos) {
|
||||
m_data = new Graphics8Bit(file);
|
||||
}
|
||||
else {
|
||||
try {
|
||||
m_data = new Graphics8Bit(file);
|
||||
}
|
||||
catch (const Exception & e) {
|
||||
INFO << "loading 8 bit failed: " << e.what() << std::endl;
|
||||
m_data = 0;
|
||||
try {
|
||||
m_data = new Graphics24Bit(file);
|
||||
}
|
||||
catch (const Exception & e) {
|
||||
ERROR << "loading 24 bit failed " << e.what() << std::endl;
|
||||
m_data = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
assert(m_data);
|
||||
}
|
||||
|
||||
template<> ActiveMap::ActiveData() {
|
||||
m_data = 0;
|
||||
}
|
||||
|
||||
template<> ActiveMap::~ActiveData() {
|
||||
unload();
|
||||
}
|
||||
|
||||
template<> Map & ActiveMap::get() {
|
||||
assert(m_data);
|
||||
return *m_data;
|
||||
}
|
||||
|
||||
template<> void ActiveMap::load(const std::string & file) {
|
||||
unload();
|
||||
try {
|
||||
m_data = new Map(file);
|
||||
}
|
||||
catch (const Exception & e) {
|
||||
ERROR << "loading map failed: " << e.what();
|
||||
m_data = 0;
|
||||
}
|
||||
assert(m_data);
|
||||
}
|
||||
|
||||
}
|
64
dataholder.h
Normal file
64
dataholder.h
Normal file
@ -0,0 +1,64 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This software is provided as-is, without any express or implied *
|
||||
* warranty. In no event will the authors be held liable for any *
|
||||
* damages arising from the use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute *
|
||||
* it freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must *
|
||||
* not claim that you wrote the original software. If you use this *
|
||||
* software in a product, an acknowledgment in the product documentation *
|
||||
* would be appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must *
|
||||
* not be misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source *
|
||||
* distribution. *
|
||||
************************************************************************/
|
||||
#ifndef STYLE_HOLDER_H
|
||||
#define STYLE_HOLDER_H
|
||||
#include <string>
|
||||
#include "opengta.h"
|
||||
#include "m_exceptions.h"
|
||||
#include "Singleton.h"
|
||||
|
||||
namespace OpenGTA {
|
||||
/*
|
||||
class ActiveStyle {
|
||||
public:
|
||||
ActiveStyle();
|
||||
~ActiveStyle();
|
||||
GraphicsBase & getStyle();
|
||||
void load(const std::string & file);
|
||||
private:
|
||||
void unload();
|
||||
GraphicsBase* m_style;
|
||||
};
|
||||
*/
|
||||
template <class T>
|
||||
class ActiveData {
|
||||
public:
|
||||
ActiveData();
|
||||
~ActiveData();
|
||||
T & get();
|
||||
void load(const std::string & file);
|
||||
private:
|
||||
void unload();
|
||||
T* m_data;
|
||||
};
|
||||
|
||||
typedef ActiveData< GraphicsBase > ActiveStyle;
|
||||
typedef ActiveData< Map > ActiveMap;
|
||||
|
||||
typedef Loki::SingletonHolder< ActiveStyle, Loki::CreateUsingNew, Loki::DefaultLifetime,
|
||||
Loki::SingleThreaded> StyleHolder;
|
||||
typedef Loki::SingletonHolder< ActiveMap, Loki::CreateUsingNew, Loki::DefaultLifetime,
|
||||
Loki::SingleThreaded> MapHolder;
|
||||
}
|
||||
|
||||
#endif
|
27
doc/doc_links.txt
Normal file
27
doc/doc_links.txt
Normal file
@ -0,0 +1,27 @@
|
||||
Cityscape Data Structure
|
||||
http://azz.gouranga.com/files/cds.zip
|
||||
|
||||
Do not miss the rest of these gems:
|
||||
http://azz.gouranga.com/index.php?page=8
|
||||
|
||||
GTA Mission Template Description (can be found elsewhere)
|
||||
http://www.fileplanet.com/19571/10000/fileinfo/2/0/section/General
|
||||
|
||||
GTA2 Format Docs (somewhat related ;-)
|
||||
http://files.filefront.com/GTA2+Format+Docs/;10536;;/fileinfo.html
|
||||
|
||||
The unofficial Grand Theft Auto Reference Handbook
|
||||
http://gta.mendelsohn.de/Reference/
|
||||
|
||||
Corrections and Notes regarding DMA GTA technical doument [cds.doc v12.10]
|
||||
http://www.fifengr.com/gtacars/topic.html
|
||||
|
||||
--- other links ---
|
||||
A Stream-based Time Synchronization Technique For Networked Computer Games
|
||||
http://www.mine-control.com/zack/timesync/timesync.html
|
||||
|
||||
Fix Your Timestep!
|
||||
http://www.gaffer.org/game-physics/fix-your-timestep/
|
||||
|
||||
Car Physics for Games - by Marco Monster
|
||||
http://web.archive.org/web/20051218060818/http://home.planet.nl/~monstrous/tutcar.html
|
133
doc/gouranga.txt
Normal file
133
doc/gouranga.txt
Normal file
@ -0,0 +1,133 @@
|
||||
i emailed you all this but am posting it here just-in-case:
|
||||
|
||||
hi, i declare myself an expert on gta1 and gta2 map format, i can help you with anything you ask, email me at jernejcoder@gmail.com, let's get straight to answers:
|
||||
|
||||
* Can anyone tell me more about the height/size of blocks as drawn in-game? Currently I texture a unit-cube, but that doesn't look right (may have other causes).
|
||||
|
||||
one gta cube is 1*1*1 unit big
|
||||
|
||||
* When looking at the "slope type" bits in "type_map" (CDS.DOC) I am not sure howto interpret something like "1- 2 = up 26 low, high"; is it 26 degrees, pixel or another unit?
|
||||
|
||||
use it like this:
|
||||
|
||||
* 1- 2 = up 26 low, high
|
||||
* 3 - 4 = down 26 low, high
|
||||
* 5 - 6 = left 26 low, high
|
||||
* 7 - 8 = right 26 low, high
|
||||
|
||||
* 9 - 16 = up 7 low - high
|
||||
* 17 - 24 = down 7 low - high
|
||||
* 25 - 32 = left 7 low - high
|
||||
* 33 - 40 = right 7 low - high
|
||||
|
||||
* 41 - 44 = 45 up,down,left,right
|
||||
|
||||
there are 3 types of slopes in gta1, (90°, 45° and 7°) all change level for just one cube.
|
||||
take parts 1 and 2, these when used together make a pass from lower to upper level over 2 cubes, cube 1 is lower and cube 2 is upper part for this.
|
||||
|
||||
* Concerning the FON files; the GTA hacking handbook (http://gta.mendelsohn.de/Reference/Fil_index.html) seems to define them, but the link is broken; the older (zip) version doesn't contain that file. Is that fileformat documented somewhere?
|
||||
|
||||
this is very easy format:
|
||||
|
||||
Quote:
|
||||
|
||||
|
||||
type
|
||||
TFon_file_header = packed record
|
||||
NumPics:byte;
|
||||
height:Byte;
|
||||
end;
|
||||
|
||||
type
|
||||
TFon_image_header = packed record
|
||||
width:byte;
|
||||
end;
|
||||
|
||||
the file starts with TFon_file_header which tells you num pics and all pictures height
|
||||
|
||||
then for NumPics there are repeatitous data for characters starting with TFon_image_header that tells you character width, following that you get charwidth * fontheight of 8 bit bitmap data.
|
||||
|
||||
last 768 bytes in a file is palette (RGB format)
|
||||
|
||||
|
||||
|
||||
|
||||
i have sound format as well:
|
||||
|
||||
Quote:
|
||||
|
||||
|
||||
grand theft auto .sdt format
|
||||
this file is copyright 2002 Delfi delfi@volja.net
|
||||
data types are named as used in borland delphi's object pascal language
|
||||
|
||||
warning!
|
||||
this is for GTA1 and GTA:L only
|
||||
gta2 and gta3 use different format...
|
||||
|
||||
sdt files contains info for raw sound data files with same name but raw extension
|
||||
|
||||
divide size of sdt file by 12 to get number of sound records
|
||||
each record contains information on how to use raw file
|
||||
|
||||
here is delphi packed record:
|
||||
|
||||
Tsoundentry = packed record
|
||||
rawstart: longword;
|
||||
rawsize: longword;
|
||||
samplerate: longword;
|
||||
end;
|
||||
|
||||
you can export sound like this:
|
||||
|
||||
make new empty file and write wav file header:
|
||||
|
||||
TWave_data = packed record
|
||||
ChunkID: array[0..3] of char; // 'RIFF' text
|
||||
ChunkSize: Longword;
|
||||
Format: array[0..3] of char; // 'WAVE' text
|
||||
Subchunk1ID: array[0..3] of char; // 'fmt ' text
|
||||
Subchunk1Size: Longword;
|
||||
AudioFormat: Word;
|
||||
NumChannels: Word;
|
||||
SampleRate: Longword;
|
||||
ByteRate: Longword;
|
||||
BlockAlign: Word;
|
||||
BitsPerSample: Word;
|
||||
Subchunk2ID: array[0..3] of char; // 'data' text
|
||||
Subchunk2Size: Longword;
|
||||
end;
|
||||
|
||||
set info in header
|
||||
|
||||
Wave_data.ChunkID := 'RIFF';
|
||||
Wave_data.ChunkSize:= 49188;
|
||||
Wave_data.Format:= 'WAVE';
|
||||
Wave_data.Subchunk1ID:= 'fmt ';
|
||||
Wave_data.Subchunk1Size:= 16;
|
||||
Wave_data.AudioFormat:= 1;
|
||||
Wave_data.NumChannels:= 1;
|
||||
Wave_data.SampleRate:= sample rate of entry
|
||||
Wave_data.BitsPerSample:=8;
|
||||
Wave_data.ByteRate:= sample rate of entry
|
||||
Wave_data.BlockAlign:=1;
|
||||
Wave_data.Subchunk2ID:= 'data';
|
||||
Wave_data.Subchunk2Size:= raw data size
|
||||
|
||||
now copy raw data and write it after this header
|
||||
if you did everything correct you will be able to play wav file with any program...
|
||||
|
||||
something interesting from GTA Wave gta sound editor readme file:
|
||||
In GTA, all the sounds are in 8-bit mono format, except for those in
|
||||
LEVEL000. The sounds in this file are 16-bit, the first three being
|
||||
stereo.
|
||||
|
||||
|
||||
|
||||
should this be all for now, i have slope cubes in a 3d format representation if you want, email me at jernejcoder@gmail.com or MSN - stdcall@gmail.com (messenger only)
|
||||
|
||||
i'm onto a similar project, a gta1 / gta2 clone project, but gta formats are too limiting for me, and i went onto coding my own gta game clone, you can get screenshoots & demo http://gtatools.com/tdc/, it is written with opengl and delphi 4, i've gotten rendering pretty much perfect, and made my own map and sprite editor, but won't be compatible with gta file formats, but converters can be easily done, here is a picture:
|
||||
|
||||
gtatools.com/tdc/tdcware.jpg
|
||||
|
||||
best regards, Jernej L.
|
20
doc/gta1_winex.txt
Normal file
20
doc/gta1_winex.txt
Normal file
@ -0,0 +1,20 @@
|
||||
GTA Settings runs fine here. Winex 2.2.1.
|
||||
---
|
||||
In order to run "GTA Settings.exe" you need a legit Windows install (so you have MFC42.DLL to be specific). The DLL needs to be in your WineX "windows\system32" directory.
|
||||
---
|
||||
no need to use the setup tool, drop this into your system.reg:
|
||||
|
||||
[Software\\DMA Design\\Grand Theft Auto]
|
||||
"Language"=dword:00000000
|
||||
|
||||
[Software\\DMA Design\\Grand Theft Auto\\Controls]
|
||||
"Control 0"=dword:000000cb
|
||||
"Control 1"=dword:000000cd
|
||||
"Control 2"=dword:000000c8
|
||||
"Control 3"=dword:000000d0
|
||||
"Control 4"=dword:00000039
|
||||
"Control 5"=dword:0000001c
|
||||
"Control 6"=dword:0000001d
|
||||
"Control 7"=dword:0000002d
|
||||
"Control 8"=dword:0000002c
|
||||
"Control 9"=dword:0000000f
|
79
doc/hacking.txt
Normal file
79
doc/hacking.txt
Normal file
@ -0,0 +1,79 @@
|
||||
== OpenGTA project overview ==
|
||||
|
||||
- \subpage Fileformats
|
||||
- \subpage Rendering
|
||||
|
||||
|
||||
\namespace Audio
|
||||
\brief Making noise.
|
||||
|
||||
Very incomplete wrapper around \e SDL_sound and \e SDL_mixer.
|
||||
|
||||
\namespace Loki
|
||||
\brief From: http://loki-lib.sourceforge.net/
|
||||
|
||||
Loki is a C++ library of designs, containing flexible implementations
|
||||
of common design patterns and idioms.
|
||||
|
||||
I only use the \e Singleton a lot, but there is some nice code there.
|
||||
|
||||
\namespace OpenGL
|
||||
\brief Drawing stuff
|
||||
|
||||
A bunch of quite experimental code; the highlights:
|
||||
|
||||
- #OpenGL::TextureCache
|
||||
|
||||
The following are used as \e Singletons:
|
||||
- #OpenGL::Camera --- #OpenGL::CameraHolder
|
||||
- #OpenGL::Screen --- #OpenGL::ScreenHolder
|
||||
- #OpenGL::SpriteCache --- #OpenGL::SpriteCacheHolder
|
||||
|
||||
\namespace Util
|
||||
\brief This and that
|
||||
|
||||
- #Util::ci_string
|
||||
- #Util::Log
|
||||
- A bunch of exceptions derived from std::exception
|
||||
|
||||
And a \e Singleton object:
|
||||
- #Util::BufferCache --- #Util::BufferCacheHolder
|
||||
|
||||
|
||||
= Fileformats of the GTA1 data files =
|
||||
|
||||
Fortunately some documentation exists, specifically about
|
||||
the most important formats.
|
||||
|
||||
Reading _(cds.doc) is probably vital; you may want them all.
|
||||
So in no particular order:
|
||||
|
||||
include(`doc/doc_links.txt')dnl ~oh m4, your glorious thing~
|
||||
|
||||
Support for the following formats is implemented:
|
||||
- CMP (compressed map) #OpenGTA::Map
|
||||
- FNT (font bitmaps) #OpenGTA::Font
|
||||
- FXT (text strings) #OpenGTA::MessageDB
|
||||
- GRY (8bit graphics) #OpenGTA::Graphics8Bit
|
||||
- G24 (24 bit graphics) #OpenGTA::Graphics24Bit
|
||||
- SDT (RAW sound offsets) #OpenGTA::SoundsDB
|
||||
|
||||
|
||||
= Rendering the scene =
|
||||
|
||||
The central part is #OpenGTA::CityView, which renders the #OpenGTA::Map
|
||||
using the graphics loaded inside a derived instance of
|
||||
#OpenGTA::GraphicsBase.
|
||||
|
||||
CityView maintains a couple of #OpenGL::TextureCache (s) to store the
|
||||
texture-ids (for the static city blocks).
|
||||
|
||||
#OpenGTA::BlockData contains the vertex data and texture coords for
|
||||
each of the of the possible blocks; this corresponds to
|
||||
#OpenGTA::Map::BlockInfo::slopeType.
|
||||
|
||||
Drawing of objects (sprites) is being moved into #OpenGTA::SpriteManager,
|
||||
though this is not yet complete.
|
||||
|
||||
#OpenGL::DrawableFont can display strings using the bitmaps from
|
||||
a #OpenGTA::Font.
|
80
doc/more_hints_delfi.txt
Normal file
80
doc/more_hints_delfi.txt
Normal file
@ -0,0 +1,80 @@
|
||||
2006/8/21, tok@openlinux.org.uk <tok@openlinux.org.uk>:
|
||||
> I have got it; quite a lot in there.
|
||||
>
|
||||
> Guess I have to try my luck with dosbox, wine and such; last time I
|
||||
> tried neither m1win nor junction25 were working very well (if I remember
|
||||
> correctly).
|
||||
|
||||
thats weird, since i can run both topdown j25 and 3D beta j25 just
|
||||
fine, only M1win doesn't work (on xp) for some reason. i sent you old
|
||||
M1 for DOS in the pack i sent you the url to.
|
||||
|
||||
> Thanks for the other tips; now the main problem are the incorrect
|
||||
> tex-coords. I think I have a pretty good idea why it breaks and a few
|
||||
> on how to fix it.
|
||||
> I found the off-by-one in the tile-indices on my own on the same afternoon.
|
||||
|
||||
some of your side tiles are rotated, there is no side rotation, sides
|
||||
only have a bit flag which means "mirror" - no rotations.
|
||||
|
||||
cds says about side tiles that bit 5 and 6 in type_map_ext contain the
|
||||
mirroring:
|
||||
bit 5 means that textures on north and south sides should be mirrored,
|
||||
bit 6 indicates same for east and west side of that cube.
|
||||
|
||||
> I have started with the g24 files and hit a small snag; I don't
|
||||
> understand 'palette_index' (so far) and the actual way tiles
|
||||
> (lid+side textures; not working with sprites so far) index the clut
|
||||
> isn't working either. [but don't tell me yet]
|
||||
|
||||
the pal_index reindexes virtual palette numbers into actual - physical
|
||||
palette numbers.
|
||||
|
||||
it works like this:
|
||||
|
||||
you take tile palette index, you add palette_index
|
||||
|
||||
for sprites for example you need to skip clut dedicated to tiles:
|
||||
pal_index = (g24_header.tileclut_size div 1024)+ activesprite.clut;
|
||||
|
||||
for tiles it is just simple, but remember - if it is lid you need to
|
||||
add side tiles to the number (and side tiles + lid tiles for animation
|
||||
/ aux tiles):
|
||||
pal_index[tile number]
|
||||
|
||||
please_see_attached_illustration which also shows the palclut visualized :)
|
||||
|
||||
> I have put a few new screenshots (after your fixes) up and removed the
|
||||
> code until I have worked out the license.
|
||||
> I am soon going on vacation for some time, so there won't be any updates
|
||||
> for a few weeks. You'll hear from me when I am back.
|
||||
>
|
||||
> these already look a lot better
|
||||
> http://skybound.portland.co.uk/gta/nyc_3d__two_bugs_down_2006-08-21.jpg
|
||||
|
||||
In the nyc i can clearly see you are rotating side tiles, where they
|
||||
shouldn't be, side tiles are never rotated in gta1 (they are in gta2)
|
||||
in gta1 they just have mirroring flag in type_map_ext.
|
||||
|
||||
> http://skybound.portland.co.uk/gta/far_out_2006-08-21.jpg
|
||||
|
||||
and i am seeing this right? - the san andreas map on screenshoot -
|
||||
unless you rotated the camera itself, should be rotated 180° left (i
|
||||
know how it shouls look, since i drawn entire san andreas map layout
|
||||
in mspaint with alt + tabbing 7 years ago ;) ).
|
||||
|
||||
> http://skybound.portland.co.uk/gta/texture_coords_are_next_2006-08-21.jpg
|
||||
|
||||
this looks quite right, but it appears lid rotation is wrong in blocks
|
||||
where the type_map_ext mirror flags are used.
|
||||
|
||||
i have a delphi project written in pascal, which can render all tiles
|
||||
from g24 files, i can send you whole source code for it, it may help
|
||||
you understand how g24 files work :)
|
||||
|
||||
thats all for now, and enjoy your vacations! :)
|
||||
|
||||
|
||||
> Best regards,
|
||||
> tok
|
||||
>
|
115
doc/more_info.txt
Normal file
115
doc/more_info.txt
Normal file
@ -0,0 +1,115 @@
|
||||
you should only work with g24 files, since most, if not all mods for gta
|
||||
only use g24 files, they are much better quality and are not any harder than
|
||||
gry files (actually there are also GRX files described in cds.doc for use by
|
||||
editor but nobody has these).
|
||||
|
||||
you should take a look at how the slope models work, it is all in very
|
||||
simple order, you could simplify things a lot, since gta1 maps don't use
|
||||
more complex things.
|
||||
|
||||
my friend steve made some nice code for rendering map slopes some time back,
|
||||
here is how it works in pascal, basicly it modifies edge heights for the
|
||||
cube depending on slope number, slope 0 is normal cube and other slope
|
||||
levels modify the height, the bottom vertices stay where they are, so you
|
||||
can easily draw quads using this:
|
||||
|
||||
// 1---2
|
||||
// | z |
|
||||
// 3---4
|
||||
|
||||
// calculate slope (lid vertex z values)
|
||||
case s of
|
||||
1..8: // 2 blocks
|
||||
begin
|
||||
z1:=(((s-1) mod 2)+ord(s in [1,2, 5,6]))/2;
|
||||
z2:=(((s-1) mod 2)+ord(s in [1,2, 7,8]))/2;
|
||||
z3:=(((s-1) mod 2)+ord(s in [3,4, 5,6]))/2;
|
||||
z4:=(((s-1) mod 2)+ord(s in [3,4, 7,8]))/2;
|
||||
end;
|
||||
9..40: // 8 blocks
|
||||
begin
|
||||
z1:=(((s-9) mod 8)+ord(s in [9..16, 25..32]))/8;
|
||||
z2:=(((s-9) mod 8)+ord(s in [9..16, 33..40]))/8;
|
||||
z3:=(((s-9) mod 8)+ord(s in [17..24, 25..32]))/8;
|
||||
z4:=(((s-9) mod 8)+ord(s in [17..24, 33..40]))/8;
|
||||
end;
|
||||
41..44: // 1 block
|
||||
begin
|
||||
z1:=ord(s in [41, 43]);
|
||||
z2:=ord(s in [41, 44]);
|
||||
z3:=ord(s in [42, 43]);
|
||||
z4:=ord(s in [42, 44]);
|
||||
end;
|
||||
else // no slope
|
||||
z1:=1; z2:=1; z3:=1; z4:=1;
|
||||
//z1:=0; z2:=0; z3:=0; z4:=0;
|
||||
end;
|
||||
|
||||
i don't recomment display lists for this, i tried it in my game and got huge
|
||||
slowdowns, maybe if you compiled bigger parts of maps into it, but you will
|
||||
need to take into account that the game uses sprites, and sprites + slopes
|
||||
don't mix too good, in my game i solved this by rendering without any depth
|
||||
buffer at all, but i have to do some painful sorting of rendering order, if
|
||||
you want to render map with zbuffer you could use projected textures for
|
||||
cars or render map in layers bottom to up, switching off zbuffer when
|
||||
rendering sprites.
|
||||
|
||||
if a cube is set to flat, all faces on it use transparency, and if left +
|
||||
right faces use same texture the right face is folded into left double-sided
|
||||
tile one to form fences (same applies to up and bottom tiles, they create a
|
||||
double-sided fence on north tile only)
|
||||
|
||||
transparency rule in gta this:
|
||||
|
||||
every palette index 0 is transparent if the map tile is set to use it. i
|
||||
recommend you to convert graphical data, take the 8 bit graphic and palette
|
||||
and create 32 bit image and upload it to opengl, create alpha transparency
|
||||
channel using palette index 0.
|
||||
|
||||
every tile can have 4 shading levels, in g24 they are stored in palette
|
||||
clut, i recommend you to ignore the shading data as whole, and use glcolor
|
||||
commands to apply shading levels, also gtacars g24 editor has a terrible
|
||||
habbit of generating these shades wrong and they look ugly in some mode.
|
||||
|
||||
for sprites, they use one palette, except peds (pedesterian and cop) and
|
||||
cars,
|
||||
i suggest your game should render all ped sprites into one bigger texture,
|
||||
using vertex coordinates to address each of these, you will need to create
|
||||
around 30 or more different recoloured remaps while loading g24 file (all
|
||||
tiles would fit into 256*512 texture if you use block sorting algorythm to
|
||||
optimize room usage), every ped remap would cost 524.288 bytes, 30 remaps
|
||||
would so end up at 15728640b - 15 mb, too bad that all new hardware comes
|
||||
without support for palettized textures, they would help a lot here, gta1
|
||||
for windows for example uses driectdraw and the renderer is custom built.
|
||||
|
||||
cars are even more difficult, they come in 16 different color variant, and
|
||||
each of cars can have delta damage or doors or special police light
|
||||
animations on them, i talked to dma employee working on gta2 and he said
|
||||
that each car simply uses its own texture, which is created, modified and
|
||||
destroyed as needed, don't worrs about speed, i done tests for my own game
|
||||
and i can say that this is not a problem, the deltas don't change too often,
|
||||
and when they are they are cached as long as the car is onscreen.
|
||||
|
||||
some fonts in gta1 have limited use, such as pager messages or score counter
|
||||
so they are missing characters or use modified order, a lot of font stuff is
|
||||
hard-coded, but i found out that some onscreen fonts such as score
|
||||
multiplier and lifes counter fonts are actually remapped using a palette in
|
||||
G24 file (!!), i suggest you to just use the font as-is and ignore the
|
||||
recoloring variants, probably very few people would notice this, but then
|
||||
you can recolour them with glcolor commands aniway.
|
||||
|
||||
the idea of a project website sounds good, don't worry about legal troubles,
|
||||
take2 won't bother about this little project for a older game that they
|
||||
released as free few years ago on rockstar classics website (
|
||||
http://www.rockstargames.com/classics/), they did discreetly interfere when
|
||||
a member on gtaforums ran a project to bring gta vice city map to unreal
|
||||
tournament engine, and for hot cofee fiasco they knew it was their fault all
|
||||
the time, and they even supported us with emails that aren't for the public,
|
||||
as for the CDS and MTD docs, they were officaly released to public with no
|
||||
licenses (same for gta2 too) so using them is not legal trouble.
|
||||
|
||||
also when you have time check out http://www.dmadesign.org/ it is DMA Design
|
||||
history website ran by Mike Daily who worked on gta1 graphical engine for
|
||||
gta1, gta1 prototypes and created lemmings game, it has some history pages
|
||||
and a forum, altrough it looks inactive it is not, if you want you can ask
|
||||
him questions in the forum :)
|
1413
doc/slopes1.txt
Normal file
1413
doc/slopes1.txt
Normal file
File diff suppressed because it is too large
Load Diff
33
font_cache.cpp
Normal file
33
font_cache.cpp
Normal file
@ -0,0 +1,33 @@
|
||||
#include "font_cache.h"
|
||||
|
||||
namespace OpenGTA {
|
||||
FontCache::FontCache() {
|
||||
}
|
||||
|
||||
FontCache::~FontCache() {
|
||||
}
|
||||
|
||||
OpenGL::DrawableFont & FontCache::getFont(const std::string & file,
|
||||
const uint32_t scale) {
|
||||
FontMap::iterator i = findFont(file, scale);
|
||||
if (i == loadedFonts.end()) {
|
||||
OpenGL::DrawableFont* fnt = createFont(file, scale);
|
||||
assert(fnt);
|
||||
loadedFonts.insert(std::make_pair<FontIdentifier, OpenGL::DrawableFont*>(
|
||||
FontIdentifier(file, scale), fnt));
|
||||
return *fnt;
|
||||
}
|
||||
return *i->second;
|
||||
}
|
||||
|
||||
FontCache::FontMap::iterator FontCache::findFont(const std::string & file, const uint32_t & scale) {
|
||||
return loadedFonts.find(FontIdentifier(file, scale));
|
||||
}
|
||||
|
||||
OpenGL::DrawableFont* FontCache::createFont(const std::string & file, const uint32_t & scale) {
|
||||
OpenGL::DrawableFont * fnt = new OpenGL::DrawableFont();
|
||||
fnt->setScale(scale);
|
||||
fnt->loadFont(file);
|
||||
return fnt;
|
||||
}
|
||||
}
|
44
font_cache.h
Normal file
44
font_cache.h
Normal file
@ -0,0 +1,44 @@
|
||||
#ifndef FONT_CACHE_H
|
||||
#define FONT_CACHE_H
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "gl_font.h"
|
||||
#include "Singleton.h"
|
||||
|
||||
namespace OpenGTA {
|
||||
|
||||
class FontCache {
|
||||
public:
|
||||
FontCache();
|
||||
~FontCache();
|
||||
OpenGL::DrawableFont & getFont(const std::string & file, const uint32_t scale);
|
||||
|
||||
private:
|
||||
struct FontIdentifier {
|
||||
FontIdentifier(const std::string & f, const uint32_t s) : filename(f), scale(s) {}
|
||||
const std::string filename;
|
||||
const uint32_t scale;
|
||||
bool operator == (const FontIdentifier & o) const {
|
||||
if (scale == o.scale && filename == o.filename)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool operator < (const FontIdentifier & o) const {
|
||||
if (scale < o.scale)
|
||||
return true;
|
||||
if (scale > o.scale)
|
||||
return false;
|
||||
return filename < o.filename;
|
||||
}
|
||||
};
|
||||
typedef std::map<FontIdentifier, OpenGL::DrawableFont*> FontMap;
|
||||
FontMap loadedFonts;
|
||||
FontMap::iterator findFont(const std::string & file, const uint32_t & scale);
|
||||
OpenGL::DrawableFont* createFont(const std::string & file, const uint32_t & scale);
|
||||
};
|
||||
|
||||
typedef Loki::SingletonHolder<FontCache, Loki::CreateUsingNew,
|
||||
Loki::DefaultLifetime, Loki::SingleThreaded> FontCacheHolder;
|
||||
}
|
||||
|
||||
#endif
|
60
fx_sdt.h
Normal file
60
fx_sdt.h
Normal file
@ -0,0 +1,60 @@
|
||||
/* derived from:
|
||||
*
|
||||
* grand theft auto .sdt format
|
||||
* copyright 2002 Delfi delfi@volja.net
|
||||
*/
|
||||
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This software is provided as-is, without any express or implied *
|
||||
* warranty. In no event will the authors be held liable for any *
|
||||
* damages arising from the use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute *
|
||||
* it freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must *
|
||||
* not claim that you wrote the original software. If you use this *
|
||||
* software in a product, an acknowledgment in the product documentation *
|
||||
* would be appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must *
|
||||
* not be misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source *
|
||||
* distribution. *
|
||||
************************************************************************/
|
||||
#ifndef OGTA_FX_SDT_H
|
||||
#define OGTA_FX_SDT_H
|
||||
#include <physfs.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
|
||||
namespace OpenGTA {
|
||||
class SoundsDB {
|
||||
public:
|
||||
SoundsDB();
|
||||
SoundsDB(const std::string & sdt_file);
|
||||
~SoundsDB();
|
||||
void load(const std::string & sdt_file);
|
||||
struct Entry {
|
||||
Entry(PHYSFS_uint32, PHYSFS_uint32, PHYSFS_uint32);
|
||||
PHYSFS_uint32 rawStart;
|
||||
PHYSFS_uint32 rawSize;
|
||||
PHYSFS_uint32 sampleRate;
|
||||
};
|
||||
typedef PHYSFS_uint16 KeyType;
|
||||
Entry & getEntry(KeyType key);
|
||||
unsigned char* getBuffered(KeyType key);
|
||||
|
||||
private:
|
||||
void clear();
|
||||
typedef std::map<KeyType, Entry> MapType;
|
||||
MapType knownEntries;
|
||||
PHYSFS_file *dataFile;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
247
gfx_extract.cpp
Normal file
247
gfx_extract.cpp
Normal file
@ -0,0 +1,247 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This software is provided as-is, without any express or implied *
|
||||
* warranty. In no event will the authors be held liable for any *
|
||||
* damages arising from the use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute *
|
||||
* it freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must *
|
||||
* not claim that you wrote the original software. If you use this *
|
||||
* software in a product, an acknowledgment in the product documentation *
|
||||
* would be appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must *
|
||||
* not be misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source *
|
||||
* distribution. *
|
||||
************************************************************************/
|
||||
#include <iostream>
|
||||
#include <getopt.h>
|
||||
#include <stdlib.h>
|
||||
#include <SDL.h>
|
||||
|
||||
#ifdef DUMP_DELTA_DEBUG
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#endif
|
||||
|
||||
#include "opengta.h"
|
||||
#include "dataholder.h"
|
||||
#include "m_exceptions.h"
|
||||
#include "set.h"
|
||||
|
||||
SDL_Surface* image = NULL;
|
||||
|
||||
void at_exit() {
|
||||
if (image)
|
||||
SDL_FreeSurface(image);
|
||||
PHYSFS_deinit();
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
void display_image(SDL_Surface* s) {
|
||||
SDL_Surface *screen = SDL_SetVideoMode(640, 480, 32, SDL_DOUBLEBUF);
|
||||
SDL_Event event;
|
||||
SDL_BlitSurface(s, NULL, screen, NULL);
|
||||
SDL_Flip(screen);
|
||||
while (1) {
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch(event.type) {
|
||||
case SDL_QUIT:
|
||||
return;
|
||||
case SDL_KEYDOWN:
|
||||
if (event.key.keysym.sym == SDLK_ESCAPE)
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
SDL_Delay(100);
|
||||
}
|
||||
}
|
||||
|
||||
SDL_Surface* get_image(unsigned char* rp, unsigned int w, unsigned int h) {
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
#define rmask 0xff000000
|
||||
#define gmask 0x00ff0000
|
||||
#define bmask 0x0000ff00
|
||||
#define amask 0x000000ff
|
||||
#else
|
||||
#define rmask 0x000000ff
|
||||
#define gmask 0x0000ff00
|
||||
#define bmask 0x00ff0000
|
||||
#define amask 0xff000000
|
||||
#endif
|
||||
SDL_Surface* s = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA,
|
||||
w, h, 32, rmask, gmask, bmask, amask);
|
||||
SDL_LockSurface(s);
|
||||
unsigned char* dst = static_cast<unsigned char*>(s->pixels);
|
||||
for (unsigned int i=0; i<w*h; i++) {
|
||||
*dst = *rp; ++dst;++rp;
|
||||
*dst = *rp; ++dst;++rp;
|
||||
*dst = *rp; ++dst;++rp;
|
||||
*dst = *rp; ++dst;++rp;
|
||||
//*dst = 0xff; ++dst;
|
||||
}
|
||||
SDL_UnlockSurface(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
void usage(const char* a0) {
|
||||
std::cout << "USAGE: " << a0 << " --file $STYLE --extract|--display [--section N] --index N" <<
|
||||
std::endl;
|
||||
std::cout << "Where section 0 are 'side blocks', 1 'lid blocks', 2 'aux blocks' and 3 are 'sprites'" << std::endl;
|
||||
std::cout << "You can apply remaps (--remap N) and deltas (--delta N) but the relative indices are" << std::endl;
|
||||
std::cout << "not always correct (== experimental)." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
atexit(at_exit);
|
||||
PHYSFS_init(argv[0]);
|
||||
// add pwd to search path
|
||||
PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1);
|
||||
PHYSFS_addToSearchPath("gtadata.zip", 1);
|
||||
char* file = NULL;
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
|
||||
int c = 0;
|
||||
int mode = 0;
|
||||
int remap = -1;
|
||||
int delta = 0;
|
||||
Util::Set delta_as_set(32, (unsigned char*)&delta);
|
||||
bool delta_set = false;
|
||||
bool rgba = true;
|
||||
|
||||
unsigned int idx = 0;
|
||||
unsigned int section = 0;
|
||||
while (1) {
|
||||
int option_index = 0;
|
||||
static struct option long_options[] = {
|
||||
{"info", 0, 0, 'i'},
|
||||
{"display", 0, 0, 'd'},
|
||||
{"extract", 0, 0, 'e'},
|
||||
{"section", 1, 0, 's'},
|
||||
{"index", 1, 0, 'x'},
|
||||
{"file", 1, 0, 'f'},
|
||||
{"remap", 1, 0, 'r'},
|
||||
{"delta", 1, 0, 'a'},
|
||||
{"delta-set", 1, 0, 'A'},
|
||||
{0, 0, 0, 0}
|
||||
};
|
||||
|
||||
c = getopt_long (argc, argv, "h",
|
||||
long_options, &option_index);
|
||||
if (c == -1)
|
||||
break;
|
||||
switch (c) {
|
||||
case 'i':
|
||||
mode = 0;
|
||||
break;
|
||||
case 'd':
|
||||
mode |= 1;
|
||||
break;
|
||||
case 'e':
|
||||
mode |= 2;
|
||||
break;
|
||||
case 'f':
|
||||
file = optarg;
|
||||
break;
|
||||
case 'x':
|
||||
idx = atoi(optarg);
|
||||
break;
|
||||
case 's':
|
||||
section = atoi(optarg);
|
||||
break;
|
||||
case 'r':
|
||||
remap = atoi(optarg);
|
||||
break;
|
||||
case 'a':
|
||||
delta = atoi(optarg);
|
||||
break;
|
||||
case 'A':
|
||||
delta_set = true;
|
||||
delta_as_set.set_item(atoi(optarg), true);
|
||||
break;
|
||||
case 'h':
|
||||
default:
|
||||
usage(argv[0]);
|
||||
return(0);
|
||||
}
|
||||
}
|
||||
|
||||
if (!file) {
|
||||
std::cerr << "Error: no data file selected" << std::endl;
|
||||
usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
if (!PHYSFS_exists(file)) {
|
||||
std::cerr << "File does not exist in searchpath: " << file << std::endl;
|
||||
return 1;
|
||||
}
|
||||
try {
|
||||
// exception handling of the constructor doesn't work here; urgh...
|
||||
OpenGTA::StyleHolder::Instance().load(file);
|
||||
OpenGTA::GraphicsBase & graphics = OpenGTA::StyleHolder::Instance().get();
|
||||
if (delta_set)
|
||||
graphics.setDeltaHandling(true);
|
||||
|
||||
if (!mode)
|
||||
return 0;
|
||||
|
||||
switch(section) {
|
||||
case 0:
|
||||
graphics.getSide(idx, remap, rgba);
|
||||
image = get_image(graphics.getTmpBuffer(rgba), 64,64);
|
||||
break;
|
||||
case 1:
|
||||
graphics.getLid(idx, remap, rgba);
|
||||
image = get_image(graphics.getTmpBuffer(rgba), 64, 64);
|
||||
break;
|
||||
case 2:
|
||||
graphics.getAux(idx, remap, rgba);
|
||||
image = get_image(graphics.getTmpBuffer(rgba), 64, 64);
|
||||
break;
|
||||
case 3:
|
||||
OpenGTA::GraphicsBase::SpriteInfo *sprite = graphics.getSprite(idx);
|
||||
std::cout << "Sprite is " << int(sprite->w) << "x" << int(sprite->h) <<
|
||||
" with " << int(sprite->deltaCount) << " deltas" << std::endl;
|
||||
image = get_image(graphics.getSpriteBitmap(idx, remap, delta), sprite->w, sprite->h);
|
||||
#ifdef DUMP_DELTA_DEBUG
|
||||
if (delta && !delta_set) {
|
||||
std::cout << "dumping delta" << std::endl;
|
||||
OpenGTA::GraphicsBase::DeltaInfo & dinfo = sprite->delta[delta-1];
|
||||
int dump_fd = open("delta.raw", O_WRONLY | O_CREAT | O_TRUNC,
|
||||
S_IRUSR | S_IWUSR);
|
||||
write(dump_fd, dinfo.ptr, dinfo.size);
|
||||
close(dump_fd);
|
||||
}
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
if (!image) {
|
||||
std::cerr << "Error: image pointer is NULL; aborting" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
if (mode & 1) {
|
||||
display_image(image);
|
||||
}
|
||||
if (mode & 2) {
|
||||
SDL_SaveBMP(image, "out.bmp");
|
||||
}
|
||||
}
|
||||
catch (Exception & e) {
|
||||
std::cerr << "Exception occured: " << e.what() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
85
gl_base.cpp
Normal file
85
gl_base.cpp
Normal file
@ -0,0 +1,85 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This software is provided as-is, without any express or implied *
|
||||
* warranty. In no event will the authors be held liable for any *
|
||||
* damages arising from the use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute *
|
||||
* it freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must *
|
||||
* not claim that you wrote the original software. If you use this *
|
||||
* software in a product, an acknowledgment in the product documentation *
|
||||
* would be appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must *
|
||||
* not be misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source *
|
||||
* distribution. *
|
||||
************************************************************************/
|
||||
#include "gl_base.h"
|
||||
#include <SDL_opengl.h>
|
||||
#include "common_sdl_gl.h"
|
||||
#include "log.h"
|
||||
|
||||
using namespace Util;
|
||||
|
||||
namespace OpenGL {
|
||||
template<class T> void ImmediateRenderer<T>::assertCorrectPrimitive(GLenum newType) {
|
||||
if (!insideBegin) {
|
||||
WARN << "Missing glBegin() call" << std::endl;
|
||||
}
|
||||
else {
|
||||
if (currentPrimitiveType == newType)
|
||||
return;
|
||||
WARN << "Forcing switch of primitive type" << std::endl;
|
||||
glEnd();
|
||||
}
|
||||
glBegin(newType);
|
||||
currentPrimitiveType = newType;
|
||||
insideBegin = true;
|
||||
}
|
||||
|
||||
template<class T> void ImmediateRenderer<T>::begin(GLenum type) {
|
||||
// FIXME: check !insideBegin
|
||||
currentPrimitiveType = type;
|
||||
insideBegin = true;
|
||||
}
|
||||
template<class T> void ImmediateRenderer<T>::end() {
|
||||
insideBegin = false;
|
||||
}
|
||||
|
||||
template<class T> GLenum ImmediateRenderer<T>::currentPrimitiveType = GL_POINTS;
|
||||
|
||||
template<> void ImmediateRenderer<Quad2Int>::draw(const Quad2Int & quad) {
|
||||
//assertCorrectPrimitive(quad.primitiveType);
|
||||
for (int i = 0; i < 4; i++)
|
||||
glVertex2i(quad.vertices[i][0], quad.vertices[i][1]);
|
||||
}
|
||||
template<> void ImmediateRenderer<ColoredQuad2Int>::draw(const ColoredQuad2Int & quad) {
|
||||
//assertCorrectPrimitive(quad.primitiveType);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
glColor3f(quad.colors[i][0], quad.colors[i][1], quad.colors[i][2]);
|
||||
glVertex2i(quad.vertices[i][0], quad.vertices[i][1]);
|
||||
}
|
||||
}
|
||||
template<> void ImmediateRenderer<FontQuad>::draw(const FontQuad & quad) {
|
||||
glBindTexture(GL_TEXTURE_2D, quad.texId);
|
||||
glBegin(quad.primitiveType);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
glTexCoord2f(quad.texCoords[i][0], quad.texCoords[i][1]);
|
||||
glVertex2i(quad.vertices[i][0], quad.vertices[i][1]);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
/*
|
||||
template<> void ImmediateRenderer<OpenGTA::Map::BlockInfo>::draw(const OpenGTA::Map::BlockInfo & info) {
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
}
|
||||
}
|
||||
*/
|
||||
}
|
94
gl_base.h
Normal file
94
gl_base.h
Normal file
@ -0,0 +1,94 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This software is provided as-is, without any express or implied *
|
||||
* warranty. In no event will the authors be held liable for any *
|
||||
* damages arising from the use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute *
|
||||
* it freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must *
|
||||
* not claim that you wrote the original software. If you use this *
|
||||
* software in a product, an acknowledgment in the product documentation *
|
||||
* would be appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must *
|
||||
* not be misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source *
|
||||
* distribution. *
|
||||
************************************************************************/
|
||||
#ifndef GL_BASE_H
|
||||
#define GL_BASE_H
|
||||
#include <SDL_opengl.h>
|
||||
|
||||
namespace OpenGL {
|
||||
/*
|
||||
template<GLenum target>
|
||||
struct TexOps
|
||||
{
|
||||
static GLuint create();
|
||||
static void bind(GLuint id);
|
||||
static void destropy(GLuint id);
|
||||
};
|
||||
*/
|
||||
|
||||
template<typename vertex_type, int entries_per_vertex>
|
||||
struct Quad
|
||||
{
|
||||
vertex_type vertices[4][entries_per_vertex];
|
||||
static const GLenum primitiveType = GL_QUADS;
|
||||
};
|
||||
template<typename normal_type, int entries_per_vertex>
|
||||
struct QuadNormals
|
||||
{
|
||||
normal_type normals[4][entries_per_vertex];
|
||||
};
|
||||
template<typename color_type, int num_colors>
|
||||
struct QuadColors
|
||||
{
|
||||
color_type colors[4][num_colors];
|
||||
};
|
||||
template<typename texcoord_type, int num_coords>
|
||||
struct QuadTexCoords
|
||||
{
|
||||
texcoord_type texCoords[4][num_coords];
|
||||
GLuint texId;
|
||||
};
|
||||
|
||||
template<typename vertex_type, int entries_per_vertex, typename color_type, int num_colors>
|
||||
struct ColoredQuad : public Quad<vertex_type, entries_per_vertex>,
|
||||
public QuadColors<color_type, num_colors>
|
||||
{
|
||||
};
|
||||
|
||||
template<typename vertex_type, int entries_per_vertex, typename texcoord_type, int num_coords>
|
||||
struct TexturedQuad : public Quad<vertex_type, entries_per_vertex>,
|
||||
public QuadTexCoords<texcoord_type, num_coords>
|
||||
{
|
||||
};
|
||||
|
||||
typedef Quad<GLint, 2> Quad2Int;
|
||||
typedef ColoredQuad<GLint, 2, GLfloat, 3> ColoredQuad2Int;
|
||||
typedef TexturedQuad<GLint, 2, GLfloat, 2> FontQuad;
|
||||
|
||||
|
||||
template<class T> class ImmediateRenderer
|
||||
{
|
||||
public:
|
||||
static void draw(const T & t);
|
||||
static void begin(GLenum type);
|
||||
static void end();
|
||||
protected:
|
||||
static GLenum currentPrimitiveType;
|
||||
static bool insideBegin;
|
||||
static void assertCorrectPrimitive(GLenum newType);
|
||||
};
|
||||
|
||||
// ugly as hell, but seems to work
|
||||
#define Renderer ImmediateRenderer
|
||||
|
||||
}
|
||||
#endif
|
255
gl_camera.cpp
Normal file
255
gl_camera.cpp
Normal file
@ -0,0 +1,255 @@
|
||||
#include "gl_camera.h"
|
||||
#include "gl_screen.h"
|
||||
#include "opengta.h"
|
||||
#include "dataholder.h"
|
||||
#include <iostream>
|
||||
#include "log.h"
|
||||
#include "blockdata.h"
|
||||
|
||||
using namespace OpenGTA;
|
||||
float slope_height_offset(unsigned char slope_type, float dx, float dz);
|
||||
namespace OpenGL {
|
||||
|
||||
/* implementation mainly taken from:
|
||||
*
|
||||
* "Talk to me like I'm a 3 year old!" Programming Lessons
|
||||
* by DigiBen (digiben@gametutorials.com)
|
||||
*
|
||||
*/
|
||||
|
||||
Camera::Camera() : eye(), center(), up(), doRotate(false),
|
||||
camGravity(false), gameCamMode(false), followTarget(¢er) {
|
||||
interpolateStart = 0;
|
||||
interpolateEnd = 0;
|
||||
}
|
||||
|
||||
void Camera::update_game(Uint32 ticks) {
|
||||
Vector3D delta(center - *followTarget);
|
||||
//INFO << delta.x << ", " << delta.y << ", " << delta.z << std::endl;
|
||||
delta.y = 0;
|
||||
center += -delta;
|
||||
eye += -delta;
|
||||
gluLookAt(eye.x, eye.y, eye.z, center.x, center.y, center.z,
|
||||
up.x, up.y, up.z);
|
||||
}
|
||||
|
||||
void Camera::setFollowMode(const Vector3D & target) {
|
||||
followTarget = ⌖
|
||||
//INFO << "following " << target.x << ", " << target.y << ", " << target.z << std::endl;
|
||||
gameCamMode = 1;
|
||||
}
|
||||
|
||||
void Camera::releaseFollowMode() {
|
||||
followTarget = ¢er;
|
||||
gameCamMode = 0;
|
||||
}
|
||||
|
||||
void Camera::update(Uint32 ticks) {
|
||||
if (gameCamMode) {
|
||||
update_game(ticks);
|
||||
return;
|
||||
}
|
||||
moveByMouse();
|
||||
|
||||
float x,y,z;
|
||||
x = floor(eye.x);
|
||||
y = floor(eye.y);
|
||||
z = floor(eye.z);
|
||||
int do_grav = 1;
|
||||
float delta_y = 0;
|
||||
if (camGravity && do_grav) {
|
||||
center.y -= 0.1f * ticks/40.0f;
|
||||
eye.y -= 0.1f * ticks/40.0f;
|
||||
}
|
||||
|
||||
OpenGTA::Map & map = OpenGTA::MapHolder::Instance().get();
|
||||
if (y < map.getNumBlocksAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z)) && y > 0.0f) {
|
||||
OpenGTA::Map::BlockInfo * block = map.getBlockAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z), PHYSFS_uint8(y));
|
||||
if (block->blockType() > 0 && block->blockType() <= 5) {
|
||||
float bz = slope_height_offset(block->slopeType(), eye.x - x, eye.z - z);
|
||||
if (block->slopeType() == 0 && block->blockType() != 5)
|
||||
bz -= 1;
|
||||
//INFO << int(block->blockType()) << ", " << eye.y << ", " <<
|
||||
// eye.y - y << ", " << eye.y - y - bz << ", " << bz << std::endl;
|
||||
float react_delta = 0.3f;
|
||||
if (block->blockType() == 5)
|
||||
react_delta = 0.0f;
|
||||
if (eye.y - y - bz < react_delta) {
|
||||
//do_grav = 0;
|
||||
Vector3D new_eye(eye);
|
||||
new_eye.y = y + bz + react_delta;
|
||||
delta_y = new_eye.y - eye.y;
|
||||
center.y = center.y - eye.y + new_eye.y;
|
||||
eye.y = new_eye.y;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (y >= 1.0f) {
|
||||
block = map.getBlockAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z), PHYSFS_uint8(y-1));
|
||||
if (block->blockType() > 0) {
|
||||
INFO << "below is " << int(block->blockType()) << std::endl;
|
||||
center.y = center.y - eye.y + y + 0.3f;
|
||||
eye.y = y + 0.3f;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
y -= 1;
|
||||
if (y < map.getNumBlocksAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z)) && y > 0.0f) {
|
||||
OpenGTA::Map::BlockInfo * block = map.getBlockAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z), PHYSFS_uint8(y));
|
||||
if (block->blockType() == 5) {
|
||||
float bz = slope_height_offset(block->slopeType(), eye.x - x, eye.z - z);
|
||||
//INFO << eye.y << ", " << y << " bz " << bz << std::endl;
|
||||
if (eye.y - y - bz < 0.4f) {
|
||||
Vector3D new_eye(eye);
|
||||
new_eye.y = y + bz + 0.4;
|
||||
delta_y = new_eye.y - eye.y;
|
||||
//INFO << "setting " << new_eye.y << std::endl;
|
||||
center.y = center.y - eye.y + new_eye.y;
|
||||
eye.y = new_eye.y;
|
||||
do_grav = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
if (camGravity && do_grav) {
|
||||
Vector dn(0, -0.1f*do_grav, 0);
|
||||
eye += dn;
|
||||
center += dn;
|
||||
}*/
|
||||
/*
|
||||
if (camGravity && do_grav) {
|
||||
center.y -= 0.1f * ticks/40.0f;
|
||||
eye.y -= 0.1f * ticks/40.0f;
|
||||
}*/
|
||||
|
||||
if (interpolateStart) {
|
||||
float as_one = float(interpolateStart - 1) / interpolateEnd;
|
||||
Vector3D now = (1 - as_one) * interpolateFrom + as_one * interpolateTo;
|
||||
center = center - eye + now;
|
||||
eye = now;
|
||||
|
||||
interpolateStart += ticks;
|
||||
if (interpolateStart > interpolateEnd)
|
||||
interpolateStart = 0;
|
||||
}
|
||||
else {
|
||||
|
||||
if (speed > 0.01f || speed < -0.01f) {
|
||||
|
||||
Vector3D v = center - eye;
|
||||
if (camGravity)
|
||||
v.y = delta_y;
|
||||
v = v.Normalized();
|
||||
center += speed * ticks/40.0f * v;
|
||||
eye += speed * ticks/40.0f * v;
|
||||
//INFO << v.y << std::endl;
|
||||
}
|
||||
|
||||
if (doRotate)
|
||||
rotateAround(Vector3D(center.x, 0, center.z), 0, 0.01f, 0);
|
||||
}
|
||||
gluLookAt(eye.x, eye.y, eye.z, center.x, center.y, center.z,
|
||||
up.x, up.y, up.z);
|
||||
}
|
||||
|
||||
void Camera::setRotating(bool demo) {
|
||||
doRotate = demo;
|
||||
}
|
||||
|
||||
void Camera::setCamGravity(bool demo) {
|
||||
camGravity = demo;
|
||||
}
|
||||
|
||||
void Camera::setVectors(const Vector3D & e, const Vector3D & c, const Vector3D & u) {
|
||||
eye = e;
|
||||
center = c;
|
||||
up = u;
|
||||
}
|
||||
|
||||
void Camera::setSpeed(float new_speed) {
|
||||
speed = new_speed;
|
||||
}
|
||||
|
||||
void Camera::translateBy(const Vector3D & t) {
|
||||
eye += t;
|
||||
center += t;
|
||||
}
|
||||
|
||||
void Camera::translateTo(const Vector3D & e) {
|
||||
Vector3D rel = eye - e;
|
||||
translateBy(rel);
|
||||
}
|
||||
|
||||
void Camera::rotateView(float x, float y, float z) {
|
||||
Vector3D v = center - eye;
|
||||
if (x) {
|
||||
center.z = eye.z + sin(x) * v.y + cos(x) * v.z;
|
||||
center.y = eye.y + cos(x) * v.y - sin(x) * v.z;
|
||||
}
|
||||
if (y) {
|
||||
center.z = eye.z + sin(y) * v.x + cos(y) * v.z;
|
||||
center.x = eye.x + cos(y) * v.x - sin(y) * v.z;
|
||||
}
|
||||
if (z) {
|
||||
center.x = eye.x + sin(z) * v.y + cos(z) * v.x;
|
||||
center.y = eye.y + cos(z) * v.y - sin(z) * v.x;
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::rotateAround(const Vector3D & lookAt, float x, float y, float z) {
|
||||
Vector3D v = eye - lookAt;
|
||||
if (x) {
|
||||
eye.z = lookAt.z + sin(x) * v.y + cos(x) * v.z;
|
||||
eye.y = lookAt.y + cos(x) * v.y - sin(x) * v.z;
|
||||
}
|
||||
if (y) {
|
||||
eye.z = lookAt.z + sin(y) * v.x + cos(y) * v.z;
|
||||
eye.x = lookAt.x + cos(y) * v.x - sin(y) * v.z;
|
||||
}
|
||||
if (z) {
|
||||
eye.x = lookAt.x + sin(z) * v.y + cos(z) * v.x;
|
||||
eye.y = lookAt.y + cos(z) * v.y - sin(z) * v.x;
|
||||
}
|
||||
}
|
||||
|
||||
void Camera::moveByMouse() {
|
||||
Screen & screen = ScreenHolder::Instance();
|
||||
int w, h;
|
||||
w = screen.getWidth() / 2;
|
||||
h = screen.getHeight() / 2;
|
||||
int mx, my;
|
||||
SDL_GetMouseState(&mx, &my);
|
||||
SDL_WarpMouse(w, h);
|
||||
if ((mx == w) && (my == h))
|
||||
return;
|
||||
float rot_x = (float(w) - mx) / 100;
|
||||
float rot_y = (float(h) - my) / 100;
|
||||
center.y += rot_y * 8;
|
||||
if (center.y - eye.y > 15)
|
||||
center.y = eye.y + 15;
|
||||
else if (center.y - eye.y < -15)
|
||||
center.y = eye.y - 15;
|
||||
rotateView(0, -rot_x, 0);
|
||||
}
|
||||
|
||||
void Camera::interpolate(const Vector3D & to, const Uint32 & start, const Uint32 & end) {
|
||||
interpolateFrom = eye;
|
||||
interpolateTo = to;
|
||||
interpolateStart = start;
|
||||
interpolateEnd = end;
|
||||
}
|
||||
|
||||
#if 0
|
||||
void QuaternionCamera::update(Uint32 ticks) {
|
||||
float cur_ratio = 0;
|
||||
quat step = exp(sampleLinear(ln_start, ln_end, cur_ratio));
|
||||
mtx44 m = quatToRotationMatrix(step);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
glMultMatrixf((float*)m.x);
|
||||
}
|
||||
#endif
|
||||
}
|
51
gl_camera.h
Normal file
51
gl_camera.h
Normal file
@ -0,0 +1,51 @@
|
||||
#ifndef GL_CAMERA_H
|
||||
#define GL_CAMERA_H
|
||||
#include <SDL.h>
|
||||
#include <SDL_opengl.h>
|
||||
#include "math3d.h"
|
||||
#include "Singleton.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
class Camera {
|
||||
public:
|
||||
Camera();
|
||||
void setSpeed(float forward_is_positive);
|
||||
void setRotating(bool demo);
|
||||
void setCamGravity(bool demo);
|
||||
void rotateView(float x, float y, float z);
|
||||
void rotateAround(const Vector3D & c, float x, float y, float z);
|
||||
void translateBy(const Vector3D & t);
|
||||
void translateTo(const Vector3D & e);
|
||||
void setVectors(const Vector3D & e, const Vector3D & c, const Vector3D & u);
|
||||
void moveByMouse();
|
||||
void interpolate(const Vector3D & to, const Uint32 & start, const Uint32 & end);
|
||||
void setFollowMode(const Vector3D & target);
|
||||
void releaseFollowMode();
|
||||
|
||||
void update(Uint32 dt);
|
||||
Vector3D & getEye() { return eye; }
|
||||
Vector3D & getCenter() { return center; }
|
||||
Vector3D & getUp() { return up; }
|
||||
private:
|
||||
void update_game(Uint32 dt);
|
||||
Vector3D eye;
|
||||
Vector3D center;
|
||||
Vector3D up;
|
||||
float speed;
|
||||
bool doRotate;
|
||||
bool camGravity;
|
||||
bool gameCamMode;
|
||||
Vector3D const * followTarget;
|
||||
|
||||
Vector3D interpolateFrom;
|
||||
Vector3D interpolateTo;
|
||||
Uint32 interpolateStart;
|
||||
Uint32 interpolateEnd;
|
||||
};
|
||||
|
||||
using namespace Loki;
|
||||
typedef SingletonHolder<Camera, CreateUsingNew, DefaultLifetime,
|
||||
SingleThreaded> CameraHolder;
|
||||
}
|
||||
#endif
|
1113
gl_cityview.cpp
Normal file
1113
gl_cityview.cpp
Normal file
File diff suppressed because it is too large
Load Diff
96
gl_cityview.h
Normal file
96
gl_cityview.h
Normal file
@ -0,0 +1,96 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This software is provided as-is, without any express or implied *
|
||||
* warranty. In no event will the authors be held liable for any *
|
||||
* damages arising from the use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute *
|
||||
* it freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must *
|
||||
* not claim that you wrote the original software. If you use this *
|
||||
* software in a product, an acknowledgment in the product documentation *
|
||||
* would be appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must *
|
||||
* not be misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source *
|
||||
* distribution. *
|
||||
************************************************************************/
|
||||
#ifndef GL_CITYVIEW_H
|
||||
#define GL_CITYVIEW_H
|
||||
|
||||
#include "opengta.h"
|
||||
#include "navdata.h"
|
||||
#include "gl_texturecache.h"
|
||||
#include "gl_frustum.h"
|
||||
#include "gl_pagedtexture.h"
|
||||
|
||||
namespace OpenGTA {
|
||||
|
||||
class CityView {
|
||||
public:
|
||||
CityView();
|
||||
~CityView();
|
||||
void loadMap(const std::string &map, const std::string &style);
|
||||
void createLevelObject(OpenGTA::Map::ObjectPosition *obj);
|
||||
void setPosition(const GLfloat & x, const GLfloat & y, const GLfloat & z);
|
||||
void setTopDownView(const GLfloat & height);
|
||||
//void setCamVector(const GLfloat & x, const GLfloat & y, const GLfloat & z);
|
||||
void setZoom(const GLfloat zoom);
|
||||
void setViewMode(bool topDown);
|
||||
bool getViewMode() { return topDownView; }
|
||||
void setDrawHeadingArrows(bool yes) { drawHeadingMarkers = yes; }
|
||||
void setTexFlipTest(int v) { texFlipTest = v; }
|
||||
GLfloat* getCamPos() { return (GLfloat*)&camPos; }
|
||||
void setVisibleRange(int);
|
||||
int getVisibleRange();
|
||||
void getTerrainHeight(GLfloat & x, GLfloat & y, GLfloat & z);
|
||||
void draw(Uint32 ticks);
|
||||
NavData::Sector* getCurrentSector();
|
||||
OpenGL::PagedTexture renderMap2Texture();
|
||||
|
||||
bool CityView::getDrawTextured();
|
||||
bool CityView::getDrawLines();
|
||||
void CityView::setDrawTextured(bool v);
|
||||
void CityView::setDrawLines(bool v);
|
||||
|
||||
void resetTextures();
|
||||
|
||||
protected:
|
||||
void setNull();
|
||||
void cleanup();
|
||||
void drawBlock(OpenGTA::Map::BlockInfo* bi);
|
||||
void drawObject(OpenGTA::Map::ObjectPosition*);
|
||||
//OpenGL::PagedTexture createSprite(size_t sprNum, GraphicsBase::SpriteInfo* info);
|
||||
Util::CFrustum frustum;
|
||||
OpenGL::TextureCache<uint8_t>* sideCache;
|
||||
OpenGL::TextureCache<uint8_t>* lidCache;
|
||||
Map* loadedMap;
|
||||
OpenGTA::GraphicsBase* style;
|
||||
GLfloat zoomLevel;
|
||||
GLfloat camPos[3];
|
||||
GLfloat camVec[3];
|
||||
int visibleRange;
|
||||
bool topDownView;
|
||||
bool drawTextured;
|
||||
bool drawLines;
|
||||
|
||||
int scene_rendered_vertices;
|
||||
int scene_rendered_blocks;
|
||||
|
||||
GLuint scene_display_list;
|
||||
bool scene_is_dirty;
|
||||
bool drawHeadingMarkers;
|
||||
int texFlipTest;
|
||||
|
||||
Uint32 lastCacheEmptyTicks;
|
||||
|
||||
NavData::Sector *current_sector;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
175
gl_font.cpp
Normal file
175
gl_font.cpp
Normal file
@ -0,0 +1,175 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This software is provided as-is, without any express or implied *
|
||||
* warranty. In no event will the authors be held liable for any *
|
||||
* damages arising from the use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute *
|
||||
* it freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must *
|
||||
* not claim that you wrote the original software. If you use this *
|
||||
* software in a product, an acknowledgment in the product documentation *
|
||||
* would be appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must *
|
||||
* not be misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source *
|
||||
* distribution. *
|
||||
************************************************************************/
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include "gl_font.h"
|
||||
#include "log.h"
|
||||
#include "buffercache.h"
|
||||
#include "m_exceptions.h"
|
||||
|
||||
namespace OpenGL {
|
||||
DrawableFont::DrawableFont() {
|
||||
fontSource = NULL;
|
||||
texCache = NULL;
|
||||
scale = 1;
|
||||
}
|
||||
DrawableFont::~DrawableFont() {
|
||||
cleanup();
|
||||
}
|
||||
void DrawableFont::setScale(unsigned int newScale) {
|
||||
scale = newScale;
|
||||
clearCached();
|
||||
}
|
||||
void DrawableFont::clearCached() {
|
||||
std::map<char, FontQuad*>::const_iterator j = drawables.begin();
|
||||
while (j != drawables.end()) {
|
||||
delete j->second;
|
||||
++j;
|
||||
}
|
||||
drawables.clear();
|
||||
}
|
||||
void DrawableFont::resetTextures() {
|
||||
clearCached();
|
||||
texCache->clearAll();
|
||||
}
|
||||
void DrawableFont::loadFont(const std::string & filename) {
|
||||
cleanup();
|
||||
fontSource = new OpenGTA::Font(filename);
|
||||
texCache = new TextureCache<char>(("FontTextures: " + filename).c_str());
|
||||
srcName.clear();
|
||||
srcName = filename;
|
||||
}
|
||||
void DrawableFont::cleanup() {
|
||||
clearCached();
|
||||
if (fontSource != NULL)
|
||||
delete fontSource;
|
||||
if (texCache != NULL)
|
||||
delete texCache;
|
||||
fontSource = NULL;
|
||||
texCache = NULL;
|
||||
}
|
||||
GLfloat DrawableFont::drawString(const std::string & text) {
|
||||
assert(texCache != NULL);
|
||||
assert(fontSource != NULL);
|
||||
std::string::const_iterator i = text.begin();
|
||||
std::string::const_iterator e = text.end();
|
||||
GLfloat move = 0.0f;
|
||||
while (i != e) {
|
||||
|
||||
if (*i != ' ') {
|
||||
FontQuad* character = NULL;
|
||||
std::map<char, FontQuad*>::const_iterator j = drawables.find(*i);
|
||||
if (j == drawables.end()) {
|
||||
character = createDrawableCharacter(*i);
|
||||
drawables[*i] = character;
|
||||
}
|
||||
else
|
||||
character = j->second;
|
||||
Renderer<FontQuad>::draw(*character);
|
||||
}
|
||||
GLfloat mm = float(fontSource->getMoveWidth(*i)) * 1.1f * scale;
|
||||
glTranslatef(mm, 0.0f, 0.0f);
|
||||
move += mm;
|
||||
i++;
|
||||
}
|
||||
return move;
|
||||
}
|
||||
|
||||
uint16_t DrawableFont::getHeight() {
|
||||
return scale * fontSource->getCharHeight();
|
||||
}
|
||||
|
||||
FontQuad* DrawableFont::createDrawableCharacter(const char & c) {
|
||||
GLuint texid;
|
||||
unsigned int w;
|
||||
unsigned int h;
|
||||
unsigned char * src = fontSource->getCharacterBitmap(
|
||||
fontSource->getIdByChar(c), &w, &h);
|
||||
if (src == NULL) {
|
||||
std::ostringstream o;
|
||||
o << "Failed to load bitmap for: " << c;
|
||||
throw E_UNKNOWNKEY(o.str());
|
||||
//throw std::string("Failed to load bitmap for character: " + c);
|
||||
}
|
||||
unsigned int glwidth = 1;
|
||||
unsigned int glheight = 1;
|
||||
|
||||
while(glwidth < w)
|
||||
glwidth <<= 1;
|
||||
|
||||
while(glheight < h)
|
||||
glheight <<= 1;
|
||||
|
||||
Util::BufferCache & bc = Util::BufferCacheHolder::Instance();
|
||||
|
||||
unsigned char* dst = bc.requestBuffer(glwidth * glheight * 4);
|
||||
assert(dst != NULL);
|
||||
unsigned char * t = dst;
|
||||
unsigned char * r = src;
|
||||
for (unsigned int i = 0; i < h; i++) {
|
||||
memcpy(t, r, w * 4);
|
||||
t += glwidth * 4;
|
||||
r += w * 4;
|
||||
}
|
||||
glGenTextures(1, &texid);
|
||||
glBindTexture(GL_TEXTURE_2D, texid);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glwidth, glheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, dst);
|
||||
texCache->addTexture(c, texid);
|
||||
|
||||
FontQuad* res = new FontQuad();
|
||||
res->vertices[0][0] = res->vertices[0][1] = 0;
|
||||
res->vertices[1][0] = w * scale;
|
||||
res->vertices[1][1] = 0;
|
||||
res->vertices[2][0] = w * scale;
|
||||
res->vertices[2][1] = h * scale;
|
||||
res->vertices[3][0] = 0;
|
||||
res->vertices[3][1] = h * scale;
|
||||
|
||||
float glw = float(w) / float(glwidth);
|
||||
float glh = float(h) / float(glheight);
|
||||
res->texCoords[0][0] = 0.0f;
|
||||
res->texCoords[0][1] = glh;
|
||||
res->texCoords[1][0] = glw;
|
||||
res->texCoords[1][1] = glh;
|
||||
res->texCoords[2][0] = glw;
|
||||
res->texCoords[2][1] = 0.0f;
|
||||
res->texCoords[3][0] = 0.0f;
|
||||
res->texCoords[3][1] = 0.0f;
|
||||
|
||||
res->texId = texid;
|
||||
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
int main() {
|
||||
OpenGL::DrawableFont *f = new OpenGL::DrawableFont();
|
||||
f->drawString("hello world");
|
||||
delete f;
|
||||
}
|
||||
#endif
|
54
gl_font.h
Normal file
54
gl_font.h
Normal file
@ -0,0 +1,54 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This software is provided as-is, without any express or implied *
|
||||
* warranty. In no event will the authors be held liable for any *
|
||||
* damages arising from the use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute *
|
||||
* it freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must *
|
||||
* not claim that you wrote the original software. If you use this *
|
||||
* software in a product, an acknowledgment in the product documentation *
|
||||
* would be appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must *
|
||||
* not be misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source *
|
||||
* distribution. *
|
||||
************************************************************************/
|
||||
#ifndef M_OPENGL_FONT_H
|
||||
#define M_OPENGL_FONT_H
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include "opengta.h"
|
||||
#include "gl_base.h"
|
||||
#include "gl_texturecache.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
class DrawableFont {
|
||||
public:
|
||||
DrawableFont();
|
||||
~DrawableFont();
|
||||
void loadFont(const std::string & filename);
|
||||
GLfloat drawString(const std::string & text) ;
|
||||
void setScale(unsigned int newScale);
|
||||
uint16_t getHeight();
|
||||
void resetTextures();
|
||||
private:
|
||||
void cleanup();
|
||||
void clearCached();
|
||||
FontQuad* createDrawableCharacter(const char & c);
|
||||
OpenGTA::Font *fontSource;
|
||||
std::string srcName;
|
||||
TextureCache<char> *texCache;
|
||||
std::map<char, FontQuad* > drawables;
|
||||
unsigned int scale;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
302
gl_frustum.cpp
Normal file
302
gl_frustum.cpp
Normal file
@ -0,0 +1,302 @@
|
||||
#include <cmath>
|
||||
#include <SDL_opengl.h>
|
||||
#include "gl_frustum.h"
|
||||
|
||||
namespace Util {
|
||||
// We create an enum of the sides so we don't have to call each side 0 or 1.
|
||||
// This way it makes it more understandable and readable when dealing with frustum sides.
|
||||
enum FrustumSide
|
||||
{
|
||||
RIGHT = 0, // The RIGHT side of the frustum
|
||||
LEFT = 1, // The LEFT side of the frustum
|
||||
BOTTOM = 2, // The BOTTOM side of the frustum
|
||||
TOP = 3, // The TOP side of the frustum
|
||||
BACK = 4, // The BACK side of the frustum
|
||||
FRONT = 5 // The FRONT side of the frustum
|
||||
};
|
||||
|
||||
// Like above, instead of saying a number for the ABC and D of the plane, we
|
||||
// want to be more descriptive.
|
||||
enum PlaneData
|
||||
{
|
||||
A = 0, // The X value of the plane's normal
|
||||
B = 1, // The Y value of the plane's normal
|
||||
C = 2, // The Z value of the plane's normal
|
||||
D = 3 // The distance the plane is from the origin
|
||||
};
|
||||
|
||||
///////////////////////////////// NORMALIZE PLANE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
|
||||
/////
|
||||
///// This normalizes a plane (A side) from a given frustum.
|
||||
/////
|
||||
///////////////////////////////// NORMALIZE PLANE \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
|
||||
void NormalizePlane(float frustum[6][4], int side)
|
||||
{
|
||||
// Here we calculate the magnitude of the normal to the plane (point A B C)
|
||||
// Remember that (A, B, C) is that same thing as the normal's (X, Y, Z).
|
||||
// To calculate magnitude you use the equation: magnitude = sqrt( x^2 + y^2 + z^2)
|
||||
float magnitude = (float)sqrt( frustum[side][A] * frustum[side][A] +
|
||||
frustum[side][B] * frustum[side][B] +
|
||||
frustum[side][C] * frustum[side][C] );
|
||||
|
||||
// Then we divide the plane's values by it's magnitude.
|
||||
// This makes it easier to work with.
|
||||
frustum[side][A] /= magnitude;
|
||||
frustum[side][B] /= magnitude;
|
||||
frustum[side][C] /= magnitude;
|
||||
frustum[side][D] /= magnitude;
|
||||
}
|
||||
|
||||
///////////////////////////////// CALCULATE FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
|
||||
/////
|
||||
///// This extracts our frustum from the projection and modelview matrix.
|
||||
/////
|
||||
///////////////////////////////// CALCULATE FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
|
||||
void CFrustum::CalculateFrustum()
|
||||
{
|
||||
float proj[16]; // This will hold our projection matrix
|
||||
float modl[16]; // This will hold our modelview matrix
|
||||
float clip[16]; // This will hold the clipping planes
|
||||
|
||||
// glGetFloatv() is used to extract information about our OpenGL world.
|
||||
// Below, we pass in GL_PROJECTION_MATRIX to abstract our projection matrix.
|
||||
// It then stores the matrix into an array of [16].
|
||||
glGetFloatv( GL_PROJECTION_MATRIX, proj );
|
||||
|
||||
// By passing in GL_MODELVIEW_MATRIX, we can abstract our model view matrix.
|
||||
// This also stores it in an array of [16].
|
||||
glGetFloatv( GL_MODELVIEW_MATRIX, modl );
|
||||
|
||||
// Now that we have our modelview and projection matrix, if we combine these 2 matrices,
|
||||
// it will give us our clipping planes. To combine 2 matrices, we multiply them.
|
||||
|
||||
clip[ 0] = modl[ 0] * proj[ 0] + modl[ 1] * proj[ 4] + modl[ 2] * proj[ 8] + modl[ 3] * proj[12];
|
||||
clip[ 1] = modl[ 0] * proj[ 1] + modl[ 1] * proj[ 5] + modl[ 2] * proj[ 9] + modl[ 3] * proj[13];
|
||||
clip[ 2] = modl[ 0] * proj[ 2] + modl[ 1] * proj[ 6] + modl[ 2] * proj[10] + modl[ 3] * proj[14];
|
||||
clip[ 3] = modl[ 0] * proj[ 3] + modl[ 1] * proj[ 7] + modl[ 2] * proj[11] + modl[ 3] * proj[15];
|
||||
|
||||
clip[ 4] = modl[ 4] * proj[ 0] + modl[ 5] * proj[ 4] + modl[ 6] * proj[ 8] + modl[ 7] * proj[12];
|
||||
clip[ 5] = modl[ 4] * proj[ 1] + modl[ 5] * proj[ 5] + modl[ 6] * proj[ 9] + modl[ 7] * proj[13];
|
||||
clip[ 6] = modl[ 4] * proj[ 2] + modl[ 5] * proj[ 6] + modl[ 6] * proj[10] + modl[ 7] * proj[14];
|
||||
clip[ 7] = modl[ 4] * proj[ 3] + modl[ 5] * proj[ 7] + modl[ 6] * proj[11] + modl[ 7] * proj[15];
|
||||
|
||||
clip[ 8] = modl[ 8] * proj[ 0] + modl[ 9] * proj[ 4] + modl[10] * proj[ 8] + modl[11] * proj[12];
|
||||
clip[ 9] = modl[ 8] * proj[ 1] + modl[ 9] * proj[ 5] + modl[10] * proj[ 9] + modl[11] * proj[13];
|
||||
clip[10] = modl[ 8] * proj[ 2] + modl[ 9] * proj[ 6] + modl[10] * proj[10] + modl[11] * proj[14];
|
||||
clip[11] = modl[ 8] * proj[ 3] + modl[ 9] * proj[ 7] + modl[10] * proj[11] + modl[11] * proj[15];
|
||||
|
||||
clip[12] = modl[12] * proj[ 0] + modl[13] * proj[ 4] + modl[14] * proj[ 8] + modl[15] * proj[12];
|
||||
clip[13] = modl[12] * proj[ 1] + modl[13] * proj[ 5] + modl[14] * proj[ 9] + modl[15] * proj[13];
|
||||
clip[14] = modl[12] * proj[ 2] + modl[13] * proj[ 6] + modl[14] * proj[10] + modl[15] * proj[14];
|
||||
clip[15] = modl[12] * proj[ 3] + modl[13] * proj[ 7] + modl[14] * proj[11] + modl[15] * proj[15];
|
||||
|
||||
// Now we actually want to get the sides of the frustum. To do this we take
|
||||
// the clipping planes we received above and extract the sides from them.
|
||||
|
||||
// This will extract the RIGHT side of the frustum
|
||||
m_Frustum[RIGHT][A] = clip[ 3] - clip[ 0];
|
||||
m_Frustum[RIGHT][B] = clip[ 7] - clip[ 4];
|
||||
m_Frustum[RIGHT][C] = clip[11] - clip[ 8];
|
||||
m_Frustum[RIGHT][D] = clip[15] - clip[12];
|
||||
|
||||
// Now that we have a normal (A,B,C) and a distance (D) to the plane,
|
||||
// we want to normalize that normal and distance.
|
||||
|
||||
// Normalize the RIGHT side
|
||||
NormalizePlane(m_Frustum, RIGHT);
|
||||
// This will extract the LEFT side of the frustum
|
||||
m_Frustum[LEFT][A] = clip[ 3] + clip[ 0];
|
||||
m_Frustum[LEFT][B] = clip[ 7] + clip[ 4];
|
||||
m_Frustum[LEFT][C] = clip[11] + clip[ 8];
|
||||
m_Frustum[LEFT][D] = clip[15] + clip[12];
|
||||
|
||||
// Normalize the LEFT side
|
||||
NormalizePlane(m_Frustum, LEFT);
|
||||
|
||||
// This will extract the BOTTOM side of the frustum
|
||||
m_Frustum[BOTTOM][A] = clip[ 3] + clip[ 1];
|
||||
m_Frustum[BOTTOM][B] = clip[ 7] + clip[ 5];
|
||||
m_Frustum[BOTTOM][C] = clip[11] + clip[ 9];
|
||||
m_Frustum[BOTTOM][D] = clip[15] + clip[13];
|
||||
|
||||
// Normalize the BOTTOM side
|
||||
NormalizePlane(m_Frustum, BOTTOM);
|
||||
|
||||
// This will extract the TOP side of the frustum
|
||||
m_Frustum[TOP][A] = clip[ 3] - clip[ 1];
|
||||
m_Frustum[TOP][B] = clip[ 7] - clip[ 5];
|
||||
m_Frustum[TOP][C] = clip[11] - clip[ 9];
|
||||
m_Frustum[TOP][D] = clip[15] - clip[13];
|
||||
|
||||
// Normalize the TOP side
|
||||
NormalizePlane(m_Frustum, TOP);
|
||||
|
||||
// This will extract the BACK side of the frustum
|
||||
m_Frustum[BACK][A] = clip[ 3] - clip[ 2];
|
||||
m_Frustum[BACK][B] = clip[ 7] - clip[ 6];
|
||||
m_Frustum[BACK][C] = clip[11] - clip[10];
|
||||
m_Frustum[BACK][D] = clip[15] - clip[14];
|
||||
|
||||
// Normalize the BACK side
|
||||
NormalizePlane(m_Frustum, BACK);
|
||||
|
||||
// This will extract the FRONT side of the frustum
|
||||
m_Frustum[FRONT][A] = clip[ 3] + clip[ 2];
|
||||
m_Frustum[FRONT][B] = clip[ 7] + clip[ 6];
|
||||
m_Frustum[FRONT][C] = clip[11] + clip[10];
|
||||
m_Frustum[FRONT][D] = clip[15] + clip[14];
|
||||
|
||||
// Normalize the FRONT side
|
||||
NormalizePlane(m_Frustum, FRONT);
|
||||
}
|
||||
|
||||
// The code below will allow us to make checks within the frustum. For example,
|
||||
// if we want to see if a point, a sphere, or a cube lies inside of the frustum.
|
||||
// Because all of our planes point INWARDS (The normals are all pointing inside the frustum)
|
||||
// we then can assume that if a point is in FRONT of all of the planes, it's inside.
|
||||
|
||||
///////////////////////////////// POINT IN FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
|
||||
/////
|
||||
///// This determines if a point is inside of the frustum
|
||||
/////
|
||||
///////////////////////////////// POINT IN FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
|
||||
bool CFrustum::PointInFrustum( float x, float y, float z )
|
||||
{
|
||||
// If you remember the plane equation (A*x + B*y + C*z + D = 0), then the rest
|
||||
// of this code should be quite obvious and easy to figure out yourself.
|
||||
// In case don't know the plane equation, it might be a good idea to look
|
||||
// at our Plane Collision tutorial at www.GameTutorials.com in OpenGL Tutorials.
|
||||
// I will briefly go over it here. (A,B,C) is the (X,Y,Z) of the normal to the plane.
|
||||
// They are the same thing... but just called ABC because you don't want to say:
|
||||
// (x*x + y*y + z*z + d = 0). That would be wrong, so they substitute them.
|
||||
// the (x, y, z) in the equation is the point that you are testing. The D is
|
||||
// The distance the plane is from the origin. The equation ends with "= 0" because
|
||||
// that is true when the point (x, y, z) is ON the plane. When the point is NOT on
|
||||
// the plane, it is either a negative number (the point is behind the plane) or a
|
||||
// positive number (the point is in front of the plane). We want to check if the point
|
||||
// is in front of the plane, so all we have to do is go through each point and make
|
||||
// sure the plane equation goes out to a positive number on each side of the frustum.
|
||||
// The result (be it positive or negative) is the distance the point is front the plane.
|
||||
|
||||
// Go through all the sides of the frustum
|
||||
for(int i = 0; i < 6; i++ )
|
||||
{
|
||||
// Calculate the plane equation and check if the point is behind a side of the frustum
|
||||
if(m_Frustum[i][A] * x + m_Frustum[i][B] * y + m_Frustum[i][C] * z + m_Frustum[i][D] <= 0)
|
||||
{
|
||||
// The point was behind a side, so it ISN'T in the frustum
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The point was inside of the frustum (In front of ALL the sides of the frustum)
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////// SPHERE IN FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
|
||||
/////
|
||||
///// This determines if a sphere is inside of our frustum by it's center and radius.
|
||||
/////
|
||||
///////////////////////////////// SPHERE IN FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
|
||||
bool CFrustum::SphereInFrustum( float x, float y, float z, float radius )
|
||||
{
|
||||
// Now this function is almost identical to the PointInFrustum(), except we
|
||||
// now have to deal with a radius around the point. The point is the center of
|
||||
// the radius. So, the point might be outside of the frustum, but it doesn't
|
||||
// mean that the rest of the sphere is. It could be half and half. So instead of
|
||||
// checking if it's less than 0, we need to add on the radius to that. Say the
|
||||
// equation produced -2, which means the center of the sphere is the distance of
|
||||
// 2 behind the plane. Well, what if the radius was 5? The sphere is still inside,
|
||||
// so we would say, if(-2 < -5) then we are outside. In that case it's false,
|
||||
// so we are inside of the frustum, but a distance of 3. This is reflected below.
|
||||
|
||||
// Go through all the sides of the frustum
|
||||
for(int i = 0; i < 6; i++ )
|
||||
{
|
||||
// If the center of the sphere is farther away from the plane than the radius
|
||||
if( m_Frustum[i][A] * x + m_Frustum[i][B] * y + m_Frustum[i][C] * z + m_Frustum[i][D] <= -radius )
|
||||
{
|
||||
// The distance was greater than the radius so the sphere is outside of the frustum
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// The sphere was inside of the frustum!
|
||||
return true;
|
||||
}
|
||||
|
||||
///////////////////////////////// CUBE IN FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
|
||||
/////
|
||||
///// This determines if a cube is in or around our frustum by it's center and 1/2 it's length
|
||||
/////
|
||||
///////////////////////////////// CUBE IN FRUSTUM \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
|
||||
bool CFrustum::CubeInFrustum( float x, float y, float z, float size )
|
||||
{
|
||||
// This test is a bit more work, but not too much more complicated.
|
||||
// Basically, what is going on is, that we are given the center of the cube,
|
||||
// and half the length. Think of it like a radius. Then we checking each point
|
||||
// in the cube and seeing if it is inside the frustum. If a point is found in front
|
||||
// of a side, then we skip to the next side. If we get to a plane that does NOT have
|
||||
// a point in front of it, then it will return false.
|
||||
|
||||
// *Note* - This will sometimes say that a cube is inside the frustum when it isn't.
|
||||
// This happens when all the corners of the bounding box are not behind any one plane.
|
||||
// This is rare and shouldn't effect the overall rendering speed.
|
||||
|
||||
for(int i = 0; i < 6; i++ )
|
||||
{
|
||||
if(m_Frustum[i][A] * (x - size) + m_Frustum[i][B] * (y - size) + m_Frustum[i][C] * (z - size) + m_Frustum[i][D] > 0)
|
||||
continue;
|
||||
if(m_Frustum[i][A] * (x + size) + m_Frustum[i][B] * (y - size) + m_Frustum[i][C] * (z - size) + m_Frustum[i][D] > 0)
|
||||
continue;
|
||||
if(m_Frustum[i][A] * (x - size) + m_Frustum[i][B] * (y + size) + m_Frustum[i][C] * (z - size) + m_Frustum[i][D] > 0)
|
||||
continue;
|
||||
if(m_Frustum[i][A] * (x + size) + m_Frustum[i][B] * (y + size) + m_Frustum[i][C] * (z - size) + m_Frustum[i][D] > 0)
|
||||
continue;
|
||||
if(m_Frustum[i][A] * (x - size) + m_Frustum[i][B] * (y - size) + m_Frustum[i][C] * (z + size) + m_Frustum[i][D] > 0)
|
||||
continue;
|
||||
if(m_Frustum[i][A] * (x + size) + m_Frustum[i][B] * (y - size) + m_Frustum[i][C] * (z + size) + m_Frustum[i][D] > 0)
|
||||
continue;
|
||||
if(m_Frustum[i][A] * (x - size) + m_Frustum[i][B] * (y + size) + m_Frustum[i][C] * (z + size) + m_Frustum[i][D] > 0)
|
||||
continue;
|
||||
if(m_Frustum[i][A] * (x + size) + m_Frustum[i][B] * (y + size) + m_Frustum[i][C] * (z + size) + m_Frustum[i][D] > 0)
|
||||
continue;
|
||||
|
||||
// If we get here, it isn't in the frustum
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CFrustum::BlockInFrustum(float x, float z, float size) {
|
||||
|
||||
const float b_height = 6.0f;
|
||||
for(int i = 0; i < 6; i++ )
|
||||
{
|
||||
if(m_Frustum[i][A] * (x - size) + m_Frustum[i][B] * 0.0f + m_Frustum[i][C] * (z - size) + m_Frustum[i][D] > 0)
|
||||
continue;
|
||||
if(m_Frustum[i][A] * (x + size) + m_Frustum[i][B] * 0.0f + m_Frustum[i][C] * (z - size) + m_Frustum[i][D] > 0)
|
||||
continue;
|
||||
if(m_Frustum[i][A] * (x - size) + m_Frustum[i][B] * b_height + m_Frustum[i][C] * (z - size) + m_Frustum[i][D] > 0)
|
||||
continue;
|
||||
if(m_Frustum[i][A] * (x + size) + m_Frustum[i][B] * b_height + m_Frustum[i][C] * (z - size) + m_Frustum[i][D] > 0)
|
||||
continue;
|
||||
if(m_Frustum[i][A] * (x - size) + m_Frustum[i][B] * 0.0f + m_Frustum[i][C] * (z + size) + m_Frustum[i][D] > 0)
|
||||
continue;
|
||||
if(m_Frustum[i][A] * (x + size) + m_Frustum[i][B] * 0.0f + m_Frustum[i][C] * (z + size) + m_Frustum[i][D] > 0)
|
||||
continue;
|
||||
if(m_Frustum[i][A] * (x - size) + m_Frustum[i][B] * b_height + m_Frustum[i][C] * (z + size) + m_Frustum[i][D] > 0)
|
||||
continue;
|
||||
if(m_Frustum[i][A] * (x + size) + m_Frustum[i][B] * b_height + m_Frustum[i][C] * (z + size) + m_Frustum[i][D] > 0)
|
||||
continue;
|
||||
|
||||
// If we get here, it isn't in the frustum
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
}
|
47
gl_frustum.h
Normal file
47
gl_frustum.h
Normal file
@ -0,0 +1,47 @@
|
||||
//***********************************************************************//
|
||||
// //
|
||||
// - "Talk to me like I'm a 3 year old!" Programming Lessons - //
|
||||
// //
|
||||
// $Author: DigiBen digiben@gametutorials.com //
|
||||
// //
|
||||
// $Program: Frustum Culling //
|
||||
// //
|
||||
// $Description: Demonstrates checking if shapes are in view //
|
||||
// //
|
||||
// $Date: 8/28/01 //
|
||||
// //
|
||||
//***********************************************************************//
|
||||
|
||||
#ifndef DIGIBEN_FRUSTUM
|
||||
#define DIGIBEN_FRUSTUM
|
||||
|
||||
namespace Util {
|
||||
|
||||
// This will allow us to create an object to keep track of our frustum
|
||||
class CFrustum {
|
||||
|
||||
public:
|
||||
|
||||
// Call this every time the camera moves to update the frustum
|
||||
void CalculateFrustum();
|
||||
|
||||
// This takes a 3D point and returns TRUE if it's inside of the frustum
|
||||
bool PointInFrustum(float x, float y, float z);
|
||||
|
||||
// This takes a 3D point and a radius and returns TRUE if the sphere is inside of the frustum
|
||||
bool SphereInFrustum(float x, float y, float z, float radius);
|
||||
|
||||
// This takes the center and half the length of the cube.
|
||||
bool CubeInFrustum( float x, float y, float z, float size );
|
||||
|
||||
bool BlockInFrustum(float x, float z, float size);
|
||||
|
||||
private:
|
||||
|
||||
// This holds the A B C and D values for each side of our frustum.
|
||||
float m_Frustum[6][4];
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
68
gl_pagedtexture.h
Normal file
68
gl_pagedtexture.h
Normal file
@ -0,0 +1,68 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This software is provided as-is, without any express or implied *
|
||||
* warranty. In no event will the authors be held liable for any *
|
||||
* damages arising from the use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute *
|
||||
* it freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must *
|
||||
* not claim that you wrote the original software. If you use this *
|
||||
* software in a product, an acknowledgment in the product documentation *
|
||||
* would be appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must *
|
||||
* not be misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source *
|
||||
* distribution. *
|
||||
************************************************************************/
|
||||
#ifndef PAGED_TEXTURE_H
|
||||
#define PAGED_TEXTURE_H
|
||||
|
||||
#include <SDL_opengl.h>
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
struct TexCoord {
|
||||
TexCoord(GLfloat a, GLfloat b) : u(a), v(b) {}
|
||||
TexCoord() : u(0.0f), v(0.0f) {}
|
||||
GLfloat u;
|
||||
GLfloat v;
|
||||
};
|
||||
|
||||
struct PagedTexture {
|
||||
private:
|
||||
void _copyCoords(const PagedTexture & other) {
|
||||
for (int i=0; i < 2; ++i) {
|
||||
coords[i].u = other.coords[i].u;
|
||||
coords[i].v = other.coords[i].v;
|
||||
}
|
||||
|
||||
}
|
||||
public:
|
||||
PagedTexture(GLuint p, GLfloat a, GLfloat b, GLfloat c, GLfloat d) :
|
||||
inPage(p) {
|
||||
coords[0].u = a;
|
||||
coords[0].v = b;
|
||||
coords[1].u = c;
|
||||
coords[1].v = d;
|
||||
}
|
||||
PagedTexture() : inPage(0) {}
|
||||
PagedTexture(const PagedTexture & other) : inPage(other.inPage) {
|
||||
_copyCoords(other);
|
||||
}
|
||||
PagedTexture & operator = (const PagedTexture & other) {
|
||||
inPage = other.inPage;
|
||||
_copyCoords(other);
|
||||
return *this;
|
||||
}
|
||||
GLuint inPage;
|
||||
TexCoord coords[2];
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
185
gl_screen.cpp
Normal file
185
gl_screen.cpp
Normal file
@ -0,0 +1,185 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This software is provided as-is, without any express or implied *
|
||||
* warranty. In no event will the authors be held liable for any *
|
||||
* damages arising from the use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute *
|
||||
* it freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must *
|
||||
* not claim that you wrote the original software. If you use this *
|
||||
* software in a product, an acknowledgment in the product documentation *
|
||||
* would be appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must *
|
||||
* not be misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source *
|
||||
* distribution. *
|
||||
************************************************************************/
|
||||
#include <string>
|
||||
#include "gl_screen.h"
|
||||
#include "log.h"
|
||||
#include "buffercache.h"
|
||||
#include "m_exceptions.h"
|
||||
|
||||
namespace OpenGL {
|
||||
#ifndef DEFAULT_SCREEN_WIDTH
|
||||
#define DEFAULT_SCREEN_WIDTH 640
|
||||
#endif
|
||||
#ifndef DEFAULT_SCREEN_HEIGHT
|
||||
#define DEFAULT_SCREEN_HEIGHT 480
|
||||
#endif
|
||||
|
||||
Screen::Screen() {
|
||||
surface = NULL;
|
||||
videoFlags = defaultVideoFlags;
|
||||
width = DEFAULT_SCREEN_WIDTH;
|
||||
height = DEFAULT_SCREEN_HEIGHT;
|
||||
bpp = 32;
|
||||
fieldOfView = 60.0f;
|
||||
nearPlane = 0.1f;
|
||||
farPlane = 250.0f;
|
||||
}
|
||||
|
||||
void Screen::activate(Uint32 w, Uint32 h) {
|
||||
if (w)
|
||||
width = w;
|
||||
if (h)
|
||||
height = h;
|
||||
initSDL();
|
||||
resize(width, height);
|
||||
initGL();
|
||||
setSystemMouseCursor(false);
|
||||
}
|
||||
|
||||
void Screen::setSystemMouseCursor(bool visible) {
|
||||
SDL_ShowCursor((visible ? SDL_ENABLE : SDL_DISABLE));
|
||||
}
|
||||
|
||||
Uint32 Screen::getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
Uint32 Screen::getHeight() {
|
||||
return height;
|
||||
}
|
||||
|
||||
bool Screen::getFullscreen() {
|
||||
return (videoFlags & SDL_FULLSCREEN);
|
||||
}
|
||||
|
||||
void Screen::setFullScreenFlag(bool v) {
|
||||
if (v && getFullscreen())
|
||||
return;
|
||||
else if (!v && !getFullscreen())
|
||||
return;
|
||||
if (v)
|
||||
videoFlags |= SDL_FULLSCREEN;
|
||||
else
|
||||
videoFlags ^= SDL_FULLSCREEN;
|
||||
}
|
||||
|
||||
Screen::~Screen() {
|
||||
setSystemMouseCursor(true);
|
||||
if (SDL_WasInit(SDL_INIT_VIDEO))
|
||||
SDL_Quit();
|
||||
surface = NULL;
|
||||
}
|
||||
|
||||
void Screen::toggleFullscreen() {
|
||||
if (videoFlags & SDL_FULLSCREEN)
|
||||
videoFlags ^= SDL_FULLSCREEN;
|
||||
else
|
||||
videoFlags |= SDL_FULLSCREEN;
|
||||
resize(width, height);
|
||||
}
|
||||
|
||||
void Screen::initSDL() {
|
||||
int err = SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER);
|
||||
if (err)
|
||||
//throw "SDL_Init failed: " + std::string(SDL_GetError());
|
||||
throw E_INVALIDFORMAT("SDL_Init failed: " + std::string(SDL_GetError()));
|
||||
SDL_GL_SetAttribute( SDL_GL_RED_SIZE, 8);
|
||||
SDL_GL_SetAttribute( SDL_GL_GREEN_SIZE, 8);
|
||||
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8);
|
||||
SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, 16);
|
||||
SDL_GL_SetAttribute( SDL_GL_SWAP_CONTROL, 1);
|
||||
}
|
||||
|
||||
void Screen::initGL() {
|
||||
//GLfloat LightAmbient[] = { 0.8f, 0.8f, 0.8f, 1.0f };
|
||||
//GLfloat LightDiffuse[] = { 1.0f, 1.0f, 1.0f, 1.0f };
|
||||
//GLfloat LightPosition[] = { 128.0f, 200.0f, 128.0f, 1.0f };
|
||||
|
||||
//glShadeModel( GL_SMOOTH );
|
||||
glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
|
||||
glEnable( GL_DEPTH_TEST );
|
||||
//glEnable( GL_LIGHTING );
|
||||
glHint( GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST );
|
||||
//glLightfv( GL_LIGHT0, GL_AMBIENT, LightAmbient );
|
||||
//glLightfv( GL_LIGHT0, GL_DIFFUSE, LightDiffuse );
|
||||
//glLightfv( GL_LIGHT0, GL_POSITION, LightPosition );
|
||||
//glEnable( GL_LIGHT0 );
|
||||
glEnable( GL_COLOR_MATERIAL);
|
||||
glCullFace(GL_BACK);
|
||||
//glPolygonMode(GL_FRONT, GL_FILL);
|
||||
//glPolygonMode(GL_BACK, GL_LINE);
|
||||
}
|
||||
|
||||
void Screen::resize(Uint32 w, Uint32 h) {
|
||||
if (h == 0)
|
||||
h = 1;
|
||||
surface = SDL_SetVideoMode(w, h, bpp, videoFlags);
|
||||
glViewport(0, 0, w, h);
|
||||
width = w;
|
||||
height = h;
|
||||
}
|
||||
|
||||
void Screen::set3DProjection() {
|
||||
float ratio = float(width) / float(height);
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
gluPerspective( fieldOfView, ratio, nearPlane, farPlane);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
void Screen::setFlatProjection() {
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, width, 0, height, -1, 1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
}
|
||||
|
||||
void Screen::makeScreenshot(const char* filename) {
|
||||
INFO << "saving screen as: " << filename << std::endl;
|
||||
uint8_t *pixels = Util::BufferCacheHolder::Instance().requestBuffer(width * height * 3);
|
||||
|
||||
glReadBuffer(GL_FRONT);
|
||||
glReadPixels(0, 0, width, height, GL_RGB, GL_UNSIGNED_BYTE, reinterpret_cast<GLvoid*>(pixels));
|
||||
|
||||
SDL_Surface* image = SDL_CreateRGBSurface(SDL_SWSURFACE, width, height, 24,
|
||||
255U << (0),
|
||||
255U << (8),
|
||||
255U << (16),
|
||||
0);
|
||||
SDL_LockSurface(image);
|
||||
|
||||
uint8_t *imagepixels = reinterpret_cast<uint8_t*>(image->pixels);
|
||||
for (int y = (height - 1); y >= 0; --y) {
|
||||
uint8_t *row_begin = pixels + y * width * 3;
|
||||
uint8_t *row_end = row_begin + width * 3;
|
||||
|
||||
std::copy(row_begin, row_end, imagepixels);
|
||||
imagepixels += image->pitch;
|
||||
}
|
||||
SDL_UnlockSurface(image);
|
||||
SDL_SaveBMP(image, filename);
|
||||
SDL_FreeSurface( image );
|
||||
}
|
||||
}
|
66
gl_screen.h
Normal file
66
gl_screen.h
Normal file
@ -0,0 +1,66 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This software is provided as-is, without any express or implied *
|
||||
* warranty. In no event will the authors be held liable for any *
|
||||
* damages arising from the use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute *
|
||||
* it freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must *
|
||||
* not claim that you wrote the original software. If you use this *
|
||||
* software in a product, an acknowledgment in the product documentation *
|
||||
* would be appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must *
|
||||
* not be misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source *
|
||||
* distribution. *
|
||||
************************************************************************/
|
||||
#ifndef GL_SCREEN_H
|
||||
#define GL_SCREEN_H
|
||||
|
||||
#include <SDL.h>
|
||||
#include <SDL_opengl.h>
|
||||
|
||||
#include "Singleton.h"
|
||||
|
||||
namespace OpenGL {
|
||||
class Screen {
|
||||
public:
|
||||
Screen();
|
||||
~Screen();
|
||||
void set3DProjection();
|
||||
void setFlatProjection();
|
||||
void setFullScreenFlag(bool v);
|
||||
void toggleFullscreen();
|
||||
void activate(Uint32 w = 0, Uint32 h = 0);
|
||||
void resize(Uint32 w, Uint32 h);
|
||||
void setSystemMouseCursor(bool visible);
|
||||
Uint32 getWidth();
|
||||
Uint32 getHeight();
|
||||
bool getFullscreen();
|
||||
void makeScreenshot(const char* filename);
|
||||
private:
|
||||
void initGL();
|
||||
void initSDL();
|
||||
Uint32 width, height;
|
||||
Uint32 bpp;
|
||||
Uint32 videoFlags;
|
||||
float fieldOfView;
|
||||
float nearPlane;
|
||||
float farPlane;
|
||||
static const Uint32 defaultVideoFlags =
|
||||
SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE | SDL_HWACCEL;
|
||||
|
||||
SDL_Surface *surface;
|
||||
};
|
||||
|
||||
using namespace Loki;
|
||||
typedef SingletonHolder<Screen, CreateUsingNew, DefaultLifetime, SingleThreaded> ScreenHolder;
|
||||
}
|
||||
|
||||
#endif
|
261
gl_spritecache.cpp
Normal file
261
gl_spritecache.cpp
Normal file
@ -0,0 +1,261 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This software is provided as-is, without any express or implied *
|
||||
* warranty. In no event will the authors be held liable for any *
|
||||
* damages arising from the use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute *
|
||||
* it freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must *
|
||||
* not claim that you wrote the original software. If you use this *
|
||||
* software in a product, an acknowledgment in the product documentation *
|
||||
* would be appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must *
|
||||
* not be misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source *
|
||||
* distribution. *
|
||||
************************************************************************/
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
#include "gl_spritecache.h"
|
||||
#include "opengta.h"
|
||||
#include "dataholder.h"
|
||||
#include "buffercache.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace OpenGL {
|
||||
SpriteIdentifier::SpriteIdentifier() : sprNum(0), remap(-1), delta(0) {}
|
||||
SpriteIdentifier::SpriteIdentifier(PHYSFS_uint16 num, PHYSFS_sint16 map, PHYSFS_uint32 d) :
|
||||
sprNum(num), remap(map), delta(d) {}
|
||||
SpriteIdentifier::SpriteIdentifier(const SpriteIdentifier & other) :
|
||||
sprNum(other.sprNum), remap(other.remap), delta(other.delta) {}
|
||||
|
||||
bool SpriteIdentifier::operator ==(const SpriteIdentifier & other) const {
|
||||
if ((sprNum == other.sprNum) &&
|
||||
(remap == other.remap) &&
|
||||
(delta == other.delta))
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
bool SpriteIdentifier::operator <(const SpriteIdentifier & other) const {
|
||||
if (sprNum < other.sprNum)
|
||||
return true;
|
||||
else if (sprNum > other.sprNum)
|
||||
return false;
|
||||
if (remap < other.remap)
|
||||
return true;
|
||||
else if (remap > other.remap)
|
||||
return false;
|
||||
if (delta < other.delta)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
SpriteCache::SpriteCache() {
|
||||
#ifdef DO_SCALE2X
|
||||
doScale2x = true;
|
||||
#else
|
||||
doScale2x = false;
|
||||
#endif
|
||||
}
|
||||
|
||||
void SpriteCache::setScale2x(bool enabled) {
|
||||
#ifndef DO_SCALE2X
|
||||
if (enabled)
|
||||
// FIXME: for some reason I can not catch this exception, thus it only prints
|
||||
//throw E_NOTSUPPORTED("Scale2x feature disabled at compile time");
|
||||
ERROR << "scale2x feature disabled at compile time - ignoring request" << std::endl;
|
||||
#endif
|
||||
if (loadedSprites.begin() == loadedSprites.end()) {
|
||||
doScale2x = enabled;
|
||||
}
|
||||
else {
|
||||
ERROR << "scale2x cannot be set during game - ignoring request" << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
bool SpriteCache::getScale2x() {
|
||||
return doScale2x;
|
||||
}
|
||||
|
||||
SpriteCache::~SpriteCache() {
|
||||
clearAll();
|
||||
}
|
||||
|
||||
void SpriteCache::clearAll() {
|
||||
SpriteMapType::iterator i = loadedSprites.begin();
|
||||
while (i != loadedSprites.end()) {
|
||||
glDeleteTextures(1, &(*i).second.inPage);
|
||||
++i;
|
||||
}
|
||||
loadedSprites.clear();
|
||||
}
|
||||
|
||||
bool SpriteCache::has(PHYSFS_uint16 sprNum) {
|
||||
SpriteMapType::iterator i = loadedSprites.find(SpriteIdentifier(sprNum, -1, 0));
|
||||
if (i != loadedSprites.end())
|
||||
return true;
|
||||
INFO << "sprite not loaded sprnum: " << sprNum <<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SpriteCache::has(PHYSFS_uint16 sprNum, PHYSFS_sint16 remap) {
|
||||
SpriteMapType::iterator i = loadedSprites.find(SpriteIdentifier(sprNum, remap, 0));
|
||||
if (i != loadedSprites.end())
|
||||
return true;
|
||||
INFO << "sprite not loaded sprnum: " << sprNum << " remap: " << remap <<std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool SpriteCache::has(const SpriteIdentifier & si) {
|
||||
SpriteMapType::iterator i = loadedSprites.find(si);
|
||||
if (i != loadedSprites.end())
|
||||
return true;
|
||||
INFO << "sprite not loaded sprnum: " << si.sprNum << " remap: " << si.remap <<
|
||||
" delta: " << si.delta << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
PagedTexture & SpriteCache::get(PHYSFS_uint16 sprNum) {
|
||||
SpriteMapType::iterator i = loadedSprites.find(SpriteIdentifier(sprNum, -1, 0));
|
||||
assert(i != loadedSprites.end());
|
||||
return i->second;
|
||||
}
|
||||
|
||||
PagedTexture & SpriteCache::get(PHYSFS_uint16 sprNum, PHYSFS_sint16 remap) {
|
||||
SpriteMapType::iterator i = loadedSprites.find(SpriteIdentifier(sprNum, remap, 0));
|
||||
assert(i != loadedSprites.end());
|
||||
return i->second;
|
||||
}
|
||||
|
||||
PagedTexture & SpriteCache::get(const SpriteIdentifier & si) {
|
||||
SpriteMapType::iterator i = loadedSprites.find(si);
|
||||
assert(i != loadedSprites.end());
|
||||
return i->second;
|
||||
}
|
||||
|
||||
void SpriteCache::add(PHYSFS_uint16 sprNum, PHYSFS_sint16 remap, PagedTexture & t) {
|
||||
loadedSprites.insert(
|
||||
std::make_pair<SpriteIdentifier, PagedTexture>(
|
||||
SpriteIdentifier(sprNum, remap, 0), t));
|
||||
}
|
||||
|
||||
void SpriteCache::add(const SpriteIdentifier & si, PagedTexture & t) {
|
||||
loadedSprites.insert(std::make_pair<SpriteIdentifier, PagedTexture>(si, t));
|
||||
}
|
||||
|
||||
PagedTexture SpriteCache::create(PHYSFS_uint16 sprNum,
|
||||
OpenGTA::GraphicsBase::SpriteNumbers::SpriteTypes st, PHYSFS_sint16 remap = -1 ) {
|
||||
/*
|
||||
OpenGTA::GraphicsBase & style = OpenGTA::StyleHolder::Instance().get();
|
||||
PHYSFS_uint16 real_num = style.spriteNumbers.reIndex(sprNum, st);
|
||||
|
||||
OpenGTA::GraphicsBase::SpriteInfo* info = style.getSprite(real_num);
|
||||
assert(info);
|
||||
|
||||
OpenGL::PagedTexture t = createSprite(real_num, remap, info);
|
||||
add(real_num, remap, t);
|
||||
return t;
|
||||
*/
|
||||
return create(sprNum, st, remap, 0);
|
||||
}
|
||||
|
||||
PagedTexture SpriteCache::create(PHYSFS_uint16 sprNum,
|
||||
OpenGTA::GraphicsBase::SpriteNumbers::SpriteTypes st,
|
||||
PHYSFS_sint16 remap, PHYSFS_uint32 delta) {
|
||||
OpenGTA::GraphicsBase & style = OpenGTA::StyleHolder::Instance().get();
|
||||
PHYSFS_uint16 real_num = style.spriteNumbers.reIndex(sprNum, st);
|
||||
|
||||
OpenGTA::GraphicsBase::SpriteInfo* info = style.getSprite(real_num);
|
||||
assert(info);
|
||||
|
||||
OpenGL::PagedTexture t = createSprite(real_num, remap, delta, info);
|
||||
SpriteIdentifier si(real_num, remap, delta);
|
||||
add(si, t);
|
||||
return t;
|
||||
}
|
||||
|
||||
OpenGL::PagedTexture SpriteCache::createSprite(size_t sprite_num, PHYSFS_sint16 remap,
|
||||
PHYSFS_uint32 delta, OpenGTA::GraphicsBase::SpriteInfo* info) {
|
||||
INFO << "creating new sprite: " << sprite_num << " remap: " << remap << std::endl;
|
||||
unsigned char* src = OpenGTA::StyleHolder::Instance().get().
|
||||
getSpriteBitmap(sprite_num, remap , delta);
|
||||
unsigned int glwidth = 1;
|
||||
unsigned int glheight = 1;
|
||||
|
||||
while(glwidth < info->w)
|
||||
glwidth <<= 1;
|
||||
while(glheight < info->h)
|
||||
glheight <<= 1;
|
||||
unsigned char* dst = Util::BufferCacheHolder::Instance().requestBuffer(glwidth * glheight * 4);
|
||||
Util::BufferCacheHolder::Instance().unlockBuffer(src);
|
||||
assert(dst != NULL);
|
||||
unsigned char * t = dst;
|
||||
unsigned char * r = src;
|
||||
for (unsigned int i = 0; i < info->h; i++) {
|
||||
memcpy(t, r, info->w * 4);
|
||||
t += glwidth * 4;
|
||||
r += info->w * 4;
|
||||
}
|
||||
#ifdef DO_SCALE2X
|
||||
if (doScale2x) {
|
||||
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
|
||||
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
|
||||
|
||||
const int srcpitch = glwidth * 4;
|
||||
const int dstpitch = glwidth * 8;
|
||||
Uint8* srcpix = dst;
|
||||
Util::BufferCacheHolder::Instance().lockBuffer(dst);
|
||||
Uint8* dstpix = Util::BufferCacheHolder::Instance().requestBuffer(glwidth * glheight * 4 * 4);
|
||||
Uint32 E0, E1, E2, E3, B, D, E, F, H;
|
||||
for(unsigned int looph = 0; looph < glheight; ++looph)
|
||||
{
|
||||
for(unsigned int loopw = 0; loopw < glwidth; ++ loopw)
|
||||
{
|
||||
B = *(Uint32*)(srcpix + (MAX(0,looph-1)*srcpitch) + (4*loopw));
|
||||
D = *(Uint32*)(srcpix + (looph*srcpitch) + (4*MAX(0,loopw-1)));
|
||||
E = *(Uint32*)(srcpix + (looph*srcpitch) + (4*loopw));
|
||||
F = *(Uint32*)(srcpix + (looph*srcpitch) + (4*MIN(glwidth-1,loopw+1)));
|
||||
H = *(Uint32*)(srcpix + (MIN(glheight-1,looph+1)*srcpitch) + (4*loopw));
|
||||
|
||||
E0 = D == B && B != F && D != H ? D : E;
|
||||
E1 = B == F && B != D && F != H ? F : E;
|
||||
E2 = D == H && D != B && H != F ? D : E;
|
||||
E3 = H == F && D != H && B != F ? F : E;
|
||||
|
||||
*(Uint32*)(dstpix + looph*2*dstpitch + loopw*2*4) = E0;
|
||||
*(Uint32*)(dstpix + looph*2*dstpitch + (loopw*2+1)*4) = E1;
|
||||
*(Uint32*)(dstpix + (looph*2+1)*dstpitch + loopw*2*4) = E2;
|
||||
*(Uint32*)(dstpix + (looph*2+1)*dstpitch + (loopw*2+1)*4) = E3;
|
||||
}
|
||||
}
|
||||
Util::BufferCacheHolder::Instance().unlockBuffer(dst);
|
||||
dst = dstpix;
|
||||
}
|
||||
#endif
|
||||
|
||||
GLuint texid;
|
||||
glGenTextures(1, &texid);
|
||||
glBindTexture(GL_TEXTURE_2D, texid);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
#ifdef DO_SCALE2X
|
||||
if (doScale2x)
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glwidth*2, glheight*2, 0, GL_RGBA, GL_UNSIGNED_BYTE, dst);
|
||||
else
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glwidth, glheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, dst);
|
||||
#else
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, glwidth, glheight, 0, GL_RGBA, GL_UNSIGNED_BYTE, dst);
|
||||
#endif
|
||||
return OpenGL::PagedTexture(texid, 0, 0,
|
||||
float(info->w)/float(glwidth), float(info->h)/float(glheight));
|
||||
}
|
||||
|
||||
}
|
81
gl_spritecache.h
Normal file
81
gl_spritecache.h
Normal file
@ -0,0 +1,81 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This software is provided as-is, without any express or implied *
|
||||
* warranty. In no event will the authors be held liable for any *
|
||||
* damages arising from the use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute *
|
||||
* it freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must *
|
||||
* not claim that you wrote the original software. If you use this *
|
||||
* software in a product, an acknowledgment in the product documentation *
|
||||
* would be appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must *
|
||||
* not be misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source *
|
||||
* distribution. *
|
||||
************************************************************************/
|
||||
#ifndef SPRITE_CACHE_H
|
||||
#define SPRITE_CACHE_H
|
||||
#include <physfs.h>
|
||||
#include "Singleton.h"
|
||||
#include "gl_pagedtexture.h"
|
||||
#include "gl_texturecache.h"
|
||||
#include "opengta.h"
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
struct SpriteIdentifier;
|
||||
struct SpriteIdentifier {
|
||||
PHYSFS_uint16 sprNum;
|
||||
PHYSFS_sint16 remap;
|
||||
PHYSFS_uint32 delta;
|
||||
SpriteIdentifier();
|
||||
SpriteIdentifier(PHYSFS_uint16, PHYSFS_sint16, PHYSFS_uint32);
|
||||
SpriteIdentifier(const SpriteIdentifier & other);
|
||||
bool operator ==(const SpriteIdentifier & other) const;
|
||||
bool operator <(const SpriteIdentifier & other) const;
|
||||
};
|
||||
|
||||
class SpriteCache {
|
||||
public:
|
||||
SpriteCache();
|
||||
~SpriteCache();
|
||||
|
||||
void clearAll();
|
||||
bool getScale2x();
|
||||
void setScale2x(bool enabled);
|
||||
bool has(PHYSFS_uint16 sprNum);
|
||||
bool has(PHYSFS_uint16 sprNum, PHYSFS_sint16 remap);
|
||||
bool has(const SpriteIdentifier & si);
|
||||
PagedTexture & get(PHYSFS_uint16 sprNum);
|
||||
PagedTexture & get(PHYSFS_uint16 sprNum, PHYSFS_sint16 remap);
|
||||
PagedTexture & get(const SpriteIdentifier & si);
|
||||
void add(PHYSFS_uint16 sprNum, PagedTexture & t);
|
||||
void add(PHYSFS_uint16 sprNum, PHYSFS_sint16 remap, PagedTexture & t);
|
||||
void add(const SpriteIdentifier & si, PagedTexture & t);
|
||||
PagedTexture create(PHYSFS_uint16 sprNum,
|
||||
OpenGTA::GraphicsBase::SpriteNumbers::SpriteTypes, PHYSFS_sint16 remap);
|
||||
PagedTexture create(PHYSFS_uint16 sprNum,
|
||||
OpenGTA::GraphicsBase::SpriteNumbers::SpriteTypes,
|
||||
PHYSFS_sint16 remap, PHYSFS_uint32 delta);
|
||||
|
||||
OpenGL::PagedTexture SpriteCache::createSprite(size_t sprite_num, PHYSFS_sint16 remap,
|
||||
PHYSFS_uint32 delta, OpenGTA::GraphicsBase::SpriteInfo* info);
|
||||
private:
|
||||
|
||||
typedef std::map<SpriteIdentifier, PagedTexture> SpriteMapType;
|
||||
SpriteMapType loadedSprites;
|
||||
bool doScale2x;
|
||||
};
|
||||
|
||||
typedef Loki::SingletonHolder<SpriteCache, Loki::CreateUsingNew,
|
||||
Loki::DefaultLifetime, Loki::SingleThreaded> SpriteCacheHolder;
|
||||
}
|
||||
|
||||
#endif
|
250
gl_texturecache.cpp
Normal file
250
gl_texturecache.cpp
Normal file
@ -0,0 +1,250 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This software is provided as-is, without any express or implied *
|
||||
* warranty. In no event will the authors be held liable for any *
|
||||
* damages arising from the use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute *
|
||||
* it freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must *
|
||||
* not claim that you wrote the original software. If you use this *
|
||||
* software in a product, an acknowledgment in the product documentation *
|
||||
* would be appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must *
|
||||
* not be misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source *
|
||||
* distribution. *
|
||||
************************************************************************/
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <sstream>
|
||||
#include "gl_texturecache.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace OpenGL {
|
||||
template <typename key_type>
|
||||
TextureCache<key_type>::TextureCache(const char* with_name) : m_name(with_name) {
|
||||
instance_id = instance_count++;
|
||||
clearMagic = 0;
|
||||
has_cached_query = false;
|
||||
last_query_result = 0;
|
||||
minClearElements = 50;
|
||||
}
|
||||
template <typename key_type>
|
||||
TextureCache<key_type>::TextureCache() {
|
||||
instance_id = instance_count++;
|
||||
std::ostringstream stream;
|
||||
stream << "TextureCache_" << instance_count;
|
||||
m_name = stream.str();
|
||||
has_cached_query = false;
|
||||
clearMagic = 0;
|
||||
minClearElements = 50;
|
||||
}
|
||||
|
||||
template <typename key_type>
|
||||
TextureCache<key_type>::~TextureCache() {
|
||||
unsigned int ts = cached.size();
|
||||
clearAll();
|
||||
INFO << m_name << " exited - " << ts << " textures recycled" << std::endl;
|
||||
m_name.clear();
|
||||
instance_count--;
|
||||
}
|
||||
|
||||
template <typename key_type>
|
||||
void TextureCache<key_type>::clearAll() {
|
||||
typename std::map<key_type, texTuple*>::iterator i = cached.begin();
|
||||
while (i != cached.end()) {
|
||||
GLuint tid = (i->second->texId);
|
||||
glDeleteTextures(1, &tid);
|
||||
delete i->second;
|
||||
i++;
|
||||
}
|
||||
cached.clear();
|
||||
}
|
||||
|
||||
template <typename key_type>
|
||||
void TextureCache<key_type>::status() {
|
||||
std::cout << "* " << m_name << " status: " << cached.size() << " textures total" << std::endl
|
||||
<< "position = game_id : usage_count" << std::endl;
|
||||
printStats();
|
||||
}
|
||||
|
||||
template <typename key_type>
|
||||
void TextureCache<key_type>::sink() {
|
||||
typename std::map<key_type, texTuple*>::iterator i = cached.begin();
|
||||
while (i != cached.end()) {
|
||||
if (i->second->refCount <= 1)
|
||||
i->second->refCount = 0;
|
||||
else if (i->second->refCount < _max_4)
|
||||
i->second->refCount = i->second->refCount >> 1;
|
||||
else if (i->second->refCount < _max_2) {
|
||||
INFO << m_name << " texture id " << int(i->first) <<
|
||||
" -- half-count reached" << std::endl;
|
||||
i->second->refCount = i->second->refCount >> 2;
|
||||
}
|
||||
else {
|
||||
WARN << m_name << " texture id " << int(i->first) <<
|
||||
" -- going critical" << std::endl;
|
||||
i->second->refCount = i->second->refCount >> 3;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename key_type>
|
||||
void TextureCache<key_type>::clear() {
|
||||
if (clearMagic == 0)
|
||||
return;
|
||||
if (cached.size() < minClearElements)
|
||||
return;
|
||||
typename std::map<key_type, texTuple*>::iterator i = cached.begin();
|
||||
uint32_t numCleared = 0;
|
||||
while (i != cached.end()) {
|
||||
if (i->second->refCount < clearMagic) {
|
||||
//INFO <<"## " << m_name << " clearing: " << int(i->first) << " count: " << i->second->refCount << std::endl;
|
||||
GLuint tid = (i->second->texId);
|
||||
glDeleteTextures(1, &tid);
|
||||
delete i->second;
|
||||
cached.erase(i);
|
||||
numCleared++;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
INFO << m_name << " " << numCleared << " textures recycled" << std::endl;
|
||||
}
|
||||
|
||||
template <typename key_type>
|
||||
void TextureCache<key_type>::clearStats() {
|
||||
typename std::map<key_type, texTuple*>::iterator i = cached.begin();
|
||||
while (i != cached.end()) {
|
||||
i->second->refCount = 0;
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename key_type>
|
||||
void TextureCache<key_type>::printStats() {
|
||||
typename std::map<key_type, texTuple*>::iterator i = cached.begin();
|
||||
size_t c = 1;
|
||||
size_t c_active = 0;
|
||||
while (i != cached.end()) {
|
||||
if (i->second->refCount > 0) {
|
||||
std::cout << c << " = " << uint32_t(i->first) << " : " << i->second->refCount << std::endl;
|
||||
c_active++;
|
||||
}
|
||||
i++;
|
||||
c++;
|
||||
}
|
||||
std::cout << c_active << " different textures used" << std::endl;
|
||||
}
|
||||
|
||||
template <typename key_type>
|
||||
GLuint TextureCache<key_type>::getTextureWithId(key_type id) {
|
||||
if (matchingCachedQuery(id)) {
|
||||
last_query_result->refCount++;
|
||||
return last_query_result->texId;
|
||||
}
|
||||
typename std::map<key_type, texTuple*>::iterator i = cached.find(id);
|
||||
if (i == cached.end()) {
|
||||
ERROR << m_name << " failed to find texture " << int(id) << std::endl;
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
cacheQuery(id, i->second);
|
||||
i->second->refCount++;
|
||||
}
|
||||
/*
|
||||
* if (i->second->isAnimated) {
|
||||
AnimControl->lookup(i->second)
|
||||
* }
|
||||
*/
|
||||
return i->second->texId;
|
||||
}
|
||||
|
||||
template <typename key_type>
|
||||
bool TextureCache<key_type>::hasTexture(key_type id) {
|
||||
if (matchingCachedQuery(id))
|
||||
return true; // last_query_result;
|
||||
typename std::map<key_type, texTuple*>::iterator i = cached.find(id);
|
||||
if (i == cached.end())
|
||||
return false;
|
||||
cacheQuery(id, i->second);
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename key_type>
|
||||
void TextureCache<key_type>::setToAlpha(key_type id) {
|
||||
typename std::map<key_type, texTuple*>::iterator i = cached.find(id);
|
||||
if (i == cached.end()) {
|
||||
ERROR << m_name << " texture not found when trying to set alpha" << std::endl;
|
||||
return;
|
||||
}
|
||||
i->second->hasAlpha = true;
|
||||
}
|
||||
|
||||
template <typename key_type>
|
||||
void TextureCache<key_type>::setToAnimated(key_type id) {
|
||||
typename std::map<key_type, texTuple*>::iterator i = cached.find(id);
|
||||
if (i == cached.end()) {
|
||||
ERROR << m_name << " texture not found when trying to set animation" << std::endl;
|
||||
return;
|
||||
}
|
||||
i->second->isAnimated = true;
|
||||
}
|
||||
|
||||
template <typename key_type>
|
||||
void TextureCache<key_type>::addTexture(key_type id, GLuint texId) {
|
||||
/*
|
||||
std::map<uint8_t, texTuple*>::iterator i = cached.find(id);
|
||||
if (i == cached.end())
|
||||
return;*/
|
||||
texTuple* tt = new texTuple();
|
||||
tt->texId = texId;
|
||||
tt->refCount = 1;
|
||||
tt->hasAlpha = false;
|
||||
tt->isAnimated = false;
|
||||
cached[id] = tt;
|
||||
INFO << m_name << " GL texture " << texId << " added for key: " << int(id) << std::endl;
|
||||
}
|
||||
|
||||
template <typename key_type>
|
||||
void TextureCache<key_type>::cacheQuery(key_type id, texTuple *pos) {
|
||||
has_cached_query = true;
|
||||
last_query_id = id;
|
||||
last_query_result = pos;
|
||||
}
|
||||
|
||||
template <typename key_type>
|
||||
bool TextureCache<key_type>::matchingCachedQuery(key_type id) {
|
||||
return ((has_cached_query) && (id == last_query_id));
|
||||
}
|
||||
|
||||
template <typename key_type>
|
||||
void TextureCache<key_type>::setClearMagic(uint32_t removeLesser) {
|
||||
clearMagic = removeLesser;
|
||||
}
|
||||
|
||||
template <typename key_type>
|
||||
void TextureCache<key_type>::setMinClearElements(uint32_t minElements) {
|
||||
minClearElements = minElements;
|
||||
}
|
||||
|
||||
template <typename key_type>
|
||||
unsigned int TextureCache<key_type>::instance_count = 0;
|
||||
|
||||
std::numeric_limits<uint32_t> _countInfo;
|
||||
template <typename key_type>
|
||||
const uint32_t TextureCache<key_type>::_max_4 = _countInfo.max() / 4;
|
||||
template <typename key_type>
|
||||
const uint32_t TextureCache<key_type>::_max_2 = _countInfo.max() / 2;
|
||||
|
||||
template class TextureCache<uint8_t>;
|
||||
template class TextureCache<char>;
|
||||
template class TextureCache<uint16_t>;
|
||||
template class TextureCache<uint32_t>;
|
||||
}
|
142
gl_texturecache.h
Normal file
142
gl_texturecache.h
Normal file
@ -0,0 +1,142 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This software is provided as-is, without any express or implied *
|
||||
* warranty. In no event will the authors be held liable for any *
|
||||
* damages arising from the use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute *
|
||||
* it freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must *
|
||||
* not claim that you wrote the original software. If you use this *
|
||||
* software in a product, an acknowledgment in the product documentation *
|
||||
* would be appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must *
|
||||
* not be misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source *
|
||||
* distribution. *
|
||||
************************************************************************/
|
||||
#ifndef TEXTURECACHE_H
|
||||
#define TEXTURECACHE_H
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <SDL_opengl.h>
|
||||
|
||||
namespace OpenGL {
|
||||
|
||||
/** Helper for the render code.
|
||||
*
|
||||
* This class handles the storage of GLuint texture ids and
|
||||
* provides a mapping from the internal ids used by the map files.
|
||||
*/
|
||||
template <typename key_type> class TextureCache {
|
||||
public:
|
||||
/** Simple constructor.
|
||||
*
|
||||
* Name will be set to TextureCache_N, where N is the current instance count.
|
||||
*/
|
||||
TextureCache();
|
||||
|
||||
/** Constructor with a name.
|
||||
*
|
||||
* Set a name for this instance; to clarify status output with multiple caches.
|
||||
*/
|
||||
TextureCache(const char * with_name);
|
||||
|
||||
/** Just a simple destructor, nothing see here... move along.
|
||||
*
|
||||
* As a sidenote: this calls 'glDeleteTextures' on the images
|
||||
* stored inside.
|
||||
*/
|
||||
~TextureCache();
|
||||
|
||||
/** Check if texture is already cached.
|
||||
*
|
||||
* @param id key from map/block info
|
||||
* @return true if texture is found
|
||||
* @return false otherwise
|
||||
*/
|
||||
bool hasTexture(key_type id);
|
||||
|
||||
/** Maps internal id to GLuint texture id.
|
||||
*
|
||||
* @param id from map/block info
|
||||
* @return texture id
|
||||
*/
|
||||
GLuint getTextureWithId(key_type id);
|
||||
|
||||
/** Adds a texture to the cache and maps to internal id.
|
||||
*
|
||||
* @param id requested internal id from map/block info
|
||||
* @param texId texture id that contains the image
|
||||
*/
|
||||
void addTexture(key_type id, GLuint texId);
|
||||
|
||||
/** Set specified texture to hasAlpha.
|
||||
*
|
||||
* This doesn't do anything; you can just check for hasAlpha later on.
|
||||
*/
|
||||
void setToAlpha(key_type id);
|
||||
|
||||
/** probably stupid idea/going to go away
|
||||
*/
|
||||
void setToAnimated(key_type id);
|
||||
|
||||
/** Dumps some status info to stdout.
|
||||
*/
|
||||
void status();
|
||||
|
||||
/** Iterate over stored textures and modify refCount.
|
||||
*
|
||||
* This is optional functionality; you may skip this. If you don't,
|
||||
* call this *before* each rendering pass.
|
||||
*/
|
||||
void sink();
|
||||
|
||||
/** Remove unused textures from cache and video memory.
|
||||
*
|
||||
* Call this *after* a rendering pass, but not every frame!
|
||||
*
|
||||
* Handle with care, this code is experimental.
|
||||
*/
|
||||
void clear();
|
||||
|
||||
void clearAll();
|
||||
|
||||
void clearStats();
|
||||
void printStats();
|
||||
|
||||
void setClearMagic(uint32_t removeLesser);
|
||||
void setMinClearElements(uint32_t minElements);
|
||||
|
||||
protected:
|
||||
unsigned int clearMagic;
|
||||
unsigned int minClearElements;
|
||||
|
||||
typedef struct texTuple {
|
||||
GLuint texId;
|
||||
uint32_t refCount;
|
||||
bool hasAlpha;
|
||||
bool isAnimated;
|
||||
} texTuple;
|
||||
typedef std::map<key_type, texTuple*> CacheMapType;
|
||||
CacheMapType cached;
|
||||
std::string m_name;
|
||||
static unsigned int instance_count;
|
||||
unsigned int instance_id;
|
||||
const static uint32_t _max_4;
|
||||
const static uint32_t _max_2;
|
||||
bool has_cached_query;
|
||||
key_type last_query_id;
|
||||
texTuple* last_query_result;
|
||||
bool matchingCachedQuery(key_type id);
|
||||
void cacheQuery(key_type id, texTuple *pos);
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
64
license.txt
Normal file
64
license.txt
Normal file
@ -0,0 +1,64 @@
|
||||
Copyright (c) 2005-2006 tok@openlinux.org.uk
|
||||
|
||||
This software is provided 'as-is', without any express or implied warranty.
|
||||
In no event will the authors be held liable for any damages arising from
|
||||
the use of this software.
|
||||
|
||||
The act of running this software is not restricted; you may redistribute
|
||||
it and the corresponding machine-readable source code freely, subject to
|
||||
the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software.
|
||||
|
||||
2. You may not use the executable form in a commercial product.
|
||||
|
||||
3. A derived work must either inherit the non-commercial restriction or
|
||||
all the data structures copyrighted by DMA Design have to be replaced.
|
||||
Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
5. This notice may not be removed or altered from any distribution.
|
||||
|
||||
***************************************************************************
|
||||
The file formats of the data files are described in documentation released
|
||||
by DMA Design; this software would not exist without it.
|
||||
|
||||
It is my understanding that this documentation was meant for fans of the
|
||||
original game, thus I cannot place the implementing code under a free
|
||||
license.
|
||||
This restriction only applies to a few of the code files (marked as such).
|
||||
|
||||
***************************************************************************
|
||||
This software includes a number of libraries and smaller code blocks;
|
||||
these remain under their respective licenses.
|
||||
|
||||
* SDL - Simple DirectMedia Layer
|
||||
Copyright (C) 1997-2006 Sam Lantinga
|
||||
GNU Lesser General Public License
|
||||
|
||||
* SDL_image
|
||||
Copyright (C) 1999-2004 Sam Lantinga
|
||||
GNU Library General Public License
|
||||
|
||||
* PhysicsFS
|
||||
Copyright (c) 2003 Ryan C. Gordon and others
|
||||
This library is distributed under the terms of the zlib license
|
||||
|
||||
* The Loki Library
|
||||
Copyright (c) 2001 by Andrei Alexandrescu (and others)
|
||||
MIT license as well as the following:
|
||||
|
||||
Permission to use, copy, modify, distribute and sell this software for any
|
||||
purpose is hereby granted without fee, provided that the above copyright
|
||||
notice appear in all copies and that both that copyright notice and this
|
||||
permission notice appear in supporting documentation.
|
||||
|
||||
***************************************************************************
|
||||
Please do not redistribute the data files of the original game together
|
||||
with this software.
|
||||
|
||||
GTA is a trademark of Take 2 Interactive Software Inc.
|
||||
|
||||
This project is not affiliated with either Take 2 Interactive or DMA
|
||||
Design.
|
BIN
licenses/LGPL-2.1.gz
Normal file
BIN
licenses/LGPL-2.1.gz
Normal file
Binary file not shown.
BIN
licenses/LGPL-2.gz
Normal file
BIN
licenses/LGPL-2.gz
Normal file
Binary file not shown.
21
licenses/mit.txt
Normal file
21
licenses/mit.txt
Normal file
@ -0,0 +1,21 @@
|
||||
The MIT License
|
||||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a
|
||||
copy of this software and associated documentation files (the "Software"),
|
||||
to deal in the Software without restriction, including without limitation
|
||||
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
and/or sell copies of the Software, and to permit persons to whom the
|
||||
Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included
|
||||
in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
||||
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
||||
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||
OTHER DEALINGS IN THE SOFTWARE.
|
5
licenses/readme.txt
Normal file
5
licenses/readme.txt
Normal file
@ -0,0 +1,5 @@
|
||||
This directory contains a copy of the licenses covering the libraries
|
||||
used in this project.
|
||||
|
||||
To comply with the SDL license at least the GNU licenses have to be
|
||||
present in any distribution.
|
21
licenses/zlib.txt
Normal file
21
licenses/zlib.txt
Normal file
@ -0,0 +1,21 @@
|
||||
The zlib/libpng License
|
||||
|
||||
Copyright (c) <year> <copyright holders>
|
||||
|
||||
This software is provided as-is, without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not
|
||||
be misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source distribution.
|
90
lid_normal_data.h
Normal file
90
lid_normal_data.h
Normal file
@ -0,0 +1,90 @@
|
||||
// slope 0
|
||||
{ 0.000000, 1.000000, -0.000000 },
|
||||
// slope 1
|
||||
{ 0.000000, 0.894427, 0.447214 },
|
||||
// slope 2
|
||||
{ 0.000000, 0.894427, 0.447214 },
|
||||
// slope 3
|
||||
{ 0.000000, 0.894427, -0.447214 },
|
||||
// slope 4
|
||||
{ 0.000000, 0.894427, -0.447214 },
|
||||
// slope 5
|
||||
{ 0.447214, 0.894427, -0.000000 },
|
||||
// slope 6
|
||||
{ 0.447214, 0.894427, -0.000000 },
|
||||
// slope 7
|
||||
{ -0.447214, 0.894427, 0.000000 },
|
||||
// slope 8
|
||||
{ -0.447214, 0.894427, 0.000000 },
|
||||
// slope 9
|
||||
{ 0.000000, 0.991656, 0.128915 },
|
||||
// slope 10
|
||||
{ 0.000000, 0.992877, 0.119145 },
|
||||
// slope 11
|
||||
{ 0.000000, 0.991656, 0.128915 },
|
||||
// slope 12
|
||||
{ 0.000000, 0.992877, 0.119145 },
|
||||
// slope 13
|
||||
{ 0.000000, 0.991656, 0.128915 },
|
||||
// slope 14
|
||||
{ 0.000000, 0.992877, 0.119145 },
|
||||
// slope 15
|
||||
{ 0.000000, 0.991656, 0.128915 },
|
||||
// slope 16
|
||||
{ 0.000000, 0.992877, 0.119145 },
|
||||
// slope 17
|
||||
{ 0.000000, 0.991656, -0.128915 },
|
||||
// slope 18
|
||||
{ 0.000000, 0.992877, -0.119145 },
|
||||
// slope 19
|
||||
{ 0.000000, 0.991656, -0.128915 },
|
||||
// slope 20
|
||||
{ 0.000000, 0.992877, -0.119145 },
|
||||
// slope 21
|
||||
{ 0.000000, 0.991656, -0.128915 },
|
||||
// slope 22
|
||||
{ 0.000000, 0.992877, -0.119145 },
|
||||
// slope 23
|
||||
{ 0.000000, 0.991656, -0.128915 },
|
||||
// slope 24
|
||||
{ 0.000000, 0.992877, -0.119145 },
|
||||
// slope 25
|
||||
{ 0.128915, 0.991656, -0.000000 },
|
||||
// slope 26
|
||||
{ 0.119145, 0.992877, -0.000000 },
|
||||
// slope 27
|
||||
{ 0.128915, 0.991656, -0.000000 },
|
||||
// slope 28
|
||||
{ 0.119145, 0.992877, -0.000000 },
|
||||
// slope 29
|
||||
{ 0.128915, 0.991656, -0.000000 },
|
||||
// slope 30
|
||||
{ 0.119145, 0.992877, -0.000000 },
|
||||
// slope 31
|
||||
{ 0.128915, 0.991656, -0.000000 },
|
||||
// slope 32
|
||||
{ 0.119145, 0.992877, -0.000000 },
|
||||
// slope 33
|
||||
{ -0.128915, 0.991656, 0.000000 },
|
||||
// slope 34
|
||||
{ -0.119145, 0.992877, 0.000000 },
|
||||
// slope 35
|
||||
{ -0.128915, 0.991656, 0.000000 },
|
||||
// slope 36
|
||||
{ -0.119145, 0.992877, 0.000000 },
|
||||
// slope 37
|
||||
{ -0.128915, 0.991656, 0.000000 },
|
||||
// slope 38
|
||||
{ -0.119145, 0.992877, 0.000000 },
|
||||
// slope 39
|
||||
{ -0.128915, 0.991656, 0.000000 },
|
||||
// slope 40
|
||||
{ -0.119145, 0.992877, 0.000000 },
|
||||
// slope 41
|
||||
{ 0.000000, 0.707107, 0.707107 },
|
||||
// slope 42
|
||||
{ 0.000000, 0.707107, -0.707107 },
|
||||
// slope 43
|
||||
{ 0.707107, 0.707107, -0.000000 },
|
||||
// slope 44
|
||||
{ -0.707107, 0.707107, 0.000000 }
|
17
localplayer.h
Normal file
17
localplayer.h
Normal file
@ -0,0 +1,17 @@
|
||||
#ifndef OGTA_LOCAL_PLAYER_H
|
||||
#define OGTA_LOCAL_PLAYER_H
|
||||
#include "Singleton.h"
|
||||
#include "pedestrian.h"
|
||||
|
||||
namespace OpenGTA {
|
||||
|
||||
class PlayerController : public Pedestrian::Controller {
|
||||
public:
|
||||
PlayerController() { turn = 0; move = 0; }
|
||||
};
|
||||
|
||||
typedef Loki::SingletonHolder<PlayerController, Loki::CreateUsingNew,
|
||||
Loki::DefaultLifetime, Loki::SingleThreaded> LocalPlayer;
|
||||
}
|
||||
|
||||
#endif
|
15
loki.make
Normal file
15
loki.make
Normal file
@ -0,0 +1,15 @@
|
||||
VER = 0.1.5
|
||||
|
||||
all: loki/lib/libloki.a
|
||||
|
||||
loki-$(VER).tar.gz:
|
||||
wget http://surfnet.dl.sourceforge.net/sourceforge/loki-lib/loki-$(VER).tar.gz
|
||||
|
||||
loki-$(VER): loki-$(VER).tar.gz
|
||||
tar zxf loki-$(VER).tar.gz
|
||||
|
||||
loki: loki-$(VER)
|
||||
mv loki-$(VER) loki
|
||||
|
||||
loki/lib/libloki.a: loki
|
||||
make -C loki build-static
|
19
loki.make.w32_cross
Normal file
19
loki.make.w32_cross
Normal file
@ -0,0 +1,19 @@
|
||||
VER = 0.1.5
|
||||
|
||||
all: loki/lib/libloki.a
|
||||
|
||||
export CXX = i586-mingw32msvc-g++
|
||||
export AR = i586-mingw32msvc-ar
|
||||
|
||||
loki-$(VER).tar.gz:
|
||||
wget http://surfnet.dl.sourceforge.net/sourceforge/loki-lib/loki-$(VER).tar.gz
|
||||
|
||||
loki-$(VER): loki-$(VER).tar.gz
|
||||
tar zxf loki-$(VER).tar.gz
|
||||
|
||||
loki: loki-$(VER)
|
||||
mv loki-$(VER) loki
|
||||
|
||||
loki/lib/libloki.a: loki
|
||||
./tools/replace_in_files.sh 's/export OS ?= .*/export OS = Windows/' loki/Makefile
|
||||
make -C loki build-static build-shared
|
10
lua_addon/lua.hpp
Normal file
10
lua_addon/lua.hpp
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef LUA_CPP_H
|
||||
#define LUA_CPP_H
|
||||
|
||||
extern "C" {
|
||||
#include "lua.h"
|
||||
#include "lauxlib.h"
|
||||
#include "lualib.h"
|
||||
}
|
||||
|
||||
#endif
|
92
lua_addon/lua_camera.cpp
Normal file
92
lua_addon/lua_camera.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
#include "lua_camera.h"
|
||||
#define method(name) {#name, Camera::l_##name}
|
||||
|
||||
namespace OpenGTA {
|
||||
namespace Script {
|
||||
|
||||
using namespace OpenGL;
|
||||
|
||||
int Camera::l_setSpeed(lua_State *L) {
|
||||
float tmp = float(luaL_checknumber(L, 1));
|
||||
CameraHolder::Instance().setSpeed(tmp);
|
||||
return 0;
|
||||
}
|
||||
int Camera::l_setRotating(lua_State *L) {
|
||||
bool b = lua_toboolean(L, 1);
|
||||
CameraHolder::Instance().setRotating(b);
|
||||
return 0;
|
||||
}
|
||||
int Camera::l_getEye(lua_State *L) {
|
||||
Vector3D & e = CameraHolder::Instance().getEye();
|
||||
lua_pushnumber(L, e.x);
|
||||
lua_pushnumber(L, e.y);
|
||||
lua_pushnumber(L, e.z);
|
||||
return 3;
|
||||
}
|
||||
int Camera::l_setEye(lua_State *L) {
|
||||
Vector3D & e = CameraHolder::Instance().getEye();
|
||||
e.x = luaL_checknumber(L, 1);
|
||||
e.y = luaL_checknumber(L, 2);
|
||||
e.z = luaL_checknumber(L, 3);
|
||||
return 0;
|
||||
}
|
||||
int Camera::l_getCenter(lua_State *L) {
|
||||
Vector3D & e = CameraHolder::Instance().getCenter();
|
||||
lua_pushnumber(L, e.x);
|
||||
lua_pushnumber(L, e.y);
|
||||
lua_pushnumber(L, e.z);
|
||||
return 3;
|
||||
}
|
||||
int Camera::l_setCenter(lua_State *L) {
|
||||
Vector3D & e = CameraHolder::Instance().getCenter();
|
||||
e.x = luaL_checknumber(L, 1);
|
||||
e.y = luaL_checknumber(L, 2);
|
||||
e.z = luaL_checknumber(L, 3);
|
||||
return 0;
|
||||
}
|
||||
int Camera::l_getUp(lua_State *L) {
|
||||
Vector3D & e = CameraHolder::Instance().getUp();
|
||||
lua_pushnumber(L, e.x);
|
||||
lua_pushnumber(L, e.y);
|
||||
lua_pushnumber(L, e.z);
|
||||
return 0;
|
||||
}
|
||||
int Camera::l_setUp(lua_State *L) {
|
||||
Vector3D & e = CameraHolder::Instance().getUp();
|
||||
e.x = luaL_checknumber(L, 1);
|
||||
e.y = luaL_checknumber(L, 2);
|
||||
e.z = luaL_checknumber(L, 3);
|
||||
return 0;
|
||||
}
|
||||
int Camera::l_setGravityOn(lua_State *L) {
|
||||
bool v = lua_toboolean(L, 1);
|
||||
CameraHolder::Instance().setCamGravity(v);
|
||||
return 0;
|
||||
}
|
||||
int Camera::l_interpolateToPosition(lua_State *L) {
|
||||
float x, y, z;
|
||||
x = float(luaL_checknumber(L, 1));
|
||||
y = float(luaL_checknumber(L, 2));
|
||||
z = float(luaL_checknumber(L, 3));
|
||||
Uint32 msecInterval = Uint32(luaL_checkinteger(L, 4));
|
||||
CameraHolder::Instance().interpolate(Vector3D(x, y, z), 1, msecInterval);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
const luaL_reg Camera::methods[] = {
|
||||
method(setSpeed),
|
||||
method(setRotating),
|
||||
method(setEye),
|
||||
method(getEye),
|
||||
method(setCenter),
|
||||
method(getCenter),
|
||||
method(getUp),
|
||||
method(setUp),
|
||||
method(setGravityOn),
|
||||
method(interpolateToPosition),
|
||||
{NULL, NULL}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
31
lua_addon/lua_camera.h
Normal file
31
lua_addon/lua_camera.h
Normal file
@ -0,0 +1,31 @@
|
||||
#ifndef LUA_OGTA_CAMERA_H
|
||||
#define LUA_OGTA_CAMERA_H
|
||||
|
||||
#include "gl_camera.h"
|
||||
#include "lua.hpp"
|
||||
|
||||
namespace OpenGTA {
|
||||
namespace Script {
|
||||
|
||||
class Camera {
|
||||
public:
|
||||
static int l_setSpeed(lua_State *L);
|
||||
static int l_setRotating(lua_State *L);
|
||||
static int l_setGravityOn(lua_State *L);
|
||||
static int l_interpolateToPosition(lua_State *L);
|
||||
static int l_getEye(lua_State *L);
|
||||
static int l_setEye(lua_State *L);
|
||||
static int l_getCenter(lua_State *L);
|
||||
static int l_setCenter(lua_State *L);
|
||||
static int l_getUp(lua_State *L);
|
||||
static int l_setUp(lua_State *L);
|
||||
|
||||
/*static int mute(lua_State *L);
|
||||
static int unmute(lua_State *L);*/
|
||||
|
||||
|
||||
static const luaL_reg methods[];
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
71
lua_addon/lua_cityview.cpp
Normal file
71
lua_addon/lua_cityview.cpp
Normal file
@ -0,0 +1,71 @@
|
||||
#include "lua_cityview.h"
|
||||
|
||||
namespace OpenGTA {
|
||||
namespace Script {
|
||||
|
||||
int CityView::setCamPosition(lua_State *L) {
|
||||
float x = float(luaL_checknumber(L, 1));
|
||||
float y = float(luaL_checknumber(L, 2));
|
||||
float z = float(luaL_checknumber(L, 3));
|
||||
setPosition(x, y, z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CityView::getCamPosition(lua_State *L) {
|
||||
lua_pushnumber(L, camPos[0]);
|
||||
lua_pushnumber(L, camPos[1]);
|
||||
lua_pushnumber(L, camPos[2]);
|
||||
return 3;
|
||||
}
|
||||
|
||||
/*
|
||||
int CityView::setCamVector(lua_State *L) {
|
||||
float x = float(luaL_checknumber(L, 1));
|
||||
float y = float(luaL_checknumber(L, 2));
|
||||
float z = float(luaL_checknumber(L, 3));
|
||||
OpenGTA::CityView::setCamVector(x, y, z);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CityView::getCamVector(lua_State *L) {
|
||||
lua_pushnumber(L, camVec[0]);
|
||||
lua_pushnumber(L, camVec[1]);
|
||||
lua_pushnumber(L, camVec[2]);
|
||||
return 3;
|
||||
}
|
||||
*/
|
||||
|
||||
int CityView::setTopDownView(lua_State *L) {
|
||||
setViewMode(lua_toboolean(L, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CityView::setDrawHeadingArrows(lua_State *L) {
|
||||
OpenGTA::CityView::setDrawHeadingArrows(lua_toboolean(L, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CityView::setVisibleRange(lua_State *L) {
|
||||
OpenGTA::CityView::setVisibleRange(luaL_checkinteger(L, 1));
|
||||
return 0;
|
||||
}
|
||||
|
||||
int CityView::getVisibleRange(lua_State *L) {
|
||||
lua_pushnumber(L, visibleRange);
|
||||
return 1;
|
||||
}
|
||||
const char CityView::className[] = "CityView";
|
||||
#define method(name) {#name, &CityView::name}
|
||||
Lunar<CityView>::RegType CityView::methods[] = {
|
||||
method(setCamPosition),
|
||||
method(getCamPosition),
|
||||
// method(setCamVector),
|
||||
// method(getCamVector),
|
||||
method(setTopDownView),
|
||||
method(setVisibleRange),
|
||||
method(getVisibleRange),
|
||||
method(setDrawHeadingArrows),
|
||||
{0, 0}
|
||||
};
|
||||
}
|
||||
}
|
32
lua_addon/lua_cityview.h
Normal file
32
lua_addon/lua_cityview.h
Normal file
@ -0,0 +1,32 @@
|
||||
#ifndef OPENGTA_SCRIPT_CV_H
|
||||
#define OPENGTA_SCRIPT_CV_H
|
||||
|
||||
#include "gl_cityview.h"
|
||||
#include "lunar.h"
|
||||
|
||||
namespace OpenGTA {
|
||||
namespace Script {
|
||||
class CityView : public OpenGTA::CityView {
|
||||
public:
|
||||
int setCamPosition(lua_State *L);
|
||||
int getCamPosition(lua_State *L);
|
||||
|
||||
// int setCamVector(lua_State *L);
|
||||
// int getCamVector(lua_State *L);
|
||||
int setTopDownView(lua_State *L);
|
||||
|
||||
int setZoom(lua_State *L);
|
||||
int getZoom(lua_State *L);
|
||||
|
||||
int setVisibleRange(lua_State *L);
|
||||
int getVisibleRange(lua_State *L);
|
||||
int setDrawHeadingArrows(lua_State *L);
|
||||
|
||||
// --
|
||||
|
||||
static const char className[];
|
||||
static Lunar<CityView>::RegType methods[];
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
31
lua_addon/lua_screen.cpp
Normal file
31
lua_addon/lua_screen.cpp
Normal file
@ -0,0 +1,31 @@
|
||||
#include "lua_screen.h"
|
||||
|
||||
namespace OpenGTA {
|
||||
namespace Script {
|
||||
using namespace OpenGL;
|
||||
int Screen::getFullscreen(lua_State *L) {
|
||||
bool b = ScreenHolder::Instance().getFullscreen();
|
||||
lua_pushboolean(L, b);
|
||||
return 1;
|
||||
}
|
||||
int Screen::setFullscreen(lua_State *L) {
|
||||
bool b = ScreenHolder::Instance().getFullscreen();
|
||||
bool v = lua_toboolean(L, 1);
|
||||
if (b != v)
|
||||
ScreenHolder::Instance().toggleFullscreen();
|
||||
return 0;
|
||||
}
|
||||
int Screen::makeScreenShot(lua_State *L) {
|
||||
ScreenHolder::Instance().makeScreenshot(luaL_checkstring(L, 1));
|
||||
return 0;
|
||||
}
|
||||
#define method(name) {#name, Screen::name}
|
||||
const luaL_reg Screen::methods[] = {
|
||||
method(setFullscreen),
|
||||
method(getFullscreen),
|
||||
method(makeScreenShot),
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
}
|
||||
}
|
20
lua_addon/lua_screen.h
Normal file
20
lua_addon/lua_screen.h
Normal file
@ -0,0 +1,20 @@
|
||||
#ifndef LUA_OGTA_SCREEN_H
|
||||
#define LUA_OGTA_SCREEN_H
|
||||
|
||||
#include "gl_screen.h"
|
||||
#include "lua.hpp"
|
||||
|
||||
namespace OpenGTA {
|
||||
namespace Script {
|
||||
|
||||
class Screen {
|
||||
public:
|
||||
static int getFullscreen(lua_State *L);
|
||||
static int setFullscreen(lua_State *L);
|
||||
static int makeScreenShot(lua_State *L);
|
||||
|
||||
static const luaL_reg methods[];
|
||||
};
|
||||
}
|
||||
}
|
||||
#endif
|
22
lua_addon/lua_stackguard.cpp
Normal file
22
lua_addon/lua_stackguard.cpp
Normal file
@ -0,0 +1,22 @@
|
||||
#include <cassert>
|
||||
#include "lua_stackguard.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace Util {
|
||||
LuaStackguard::LuaStackguard(const char* f, int l, lua_State *L) {
|
||||
assert(L);
|
||||
m_state = L;
|
||||
i_file = f;
|
||||
i_line = l;
|
||||
m_top = lua_gettop(m_state);
|
||||
}
|
||||
|
||||
LuaStackguard::~LuaStackguard() {
|
||||
int now_top = lua_gettop(m_state);
|
||||
if (now_top > m_top) {
|
||||
Util::Log::warn(i_file, i_line) << "Stack-balance: " << now_top << " > " << m_top << std::endl;
|
||||
lua_settop(m_state, m_top);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
23
lua_addon/lua_stackguard.h
Normal file
23
lua_addon/lua_stackguard.h
Normal file
@ -0,0 +1,23 @@
|
||||
#ifndef LUA_STACK_GUARD_H
|
||||
#define LUA_STACK_GUARD_H
|
||||
|
||||
#include "lua.hpp"
|
||||
|
||||
namespace Util {
|
||||
|
||||
class LuaStackguard {
|
||||
public:
|
||||
LuaStackguard(const char* f, int l, lua_State *L);
|
||||
~LuaStackguard();
|
||||
private:
|
||||
int m_top;
|
||||
lua_State* m_state;
|
||||
// line number and filename where this instance was created
|
||||
int i_line;
|
||||
const char* i_file;
|
||||
};
|
||||
|
||||
#define LGUARD(L) LuaStackguard guard(__FILE__, __LINE__, L)
|
||||
|
||||
}
|
||||
#endif
|
126
lua_addon/lua_vm.cpp
Normal file
126
lua_addon/lua_vm.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
#include <string>
|
||||
#include "lua_vm.h"
|
||||
#include "lunar.h"
|
||||
#include "lua_cityview.h"
|
||||
#include "lua_stackguard.h"
|
||||
#include "lua_camera.h"
|
||||
#include "lua_screen.h"
|
||||
#include "lua_spritecache.h"
|
||||
#include "m_exceptions.h"
|
||||
|
||||
using namespace Util;
|
||||
|
||||
namespace OpenGTA {
|
||||
namespace Script {
|
||||
LuaVM::LuaVM() : L(NULL) {
|
||||
L = lua_open();
|
||||
if (L == NULL)
|
||||
throw E_SCRIPTERROR("Failed to create Lua state!");
|
||||
|
||||
luaopen_base(L);
|
||||
luaopen_math(L);
|
||||
_registered = false;
|
||||
lua_settop(L, 0);
|
||||
prepare();
|
||||
}
|
||||
|
||||
LuaVM::~LuaVM() {
|
||||
if (L != NULL)
|
||||
lua_close(L);
|
||||
L = NULL;
|
||||
}
|
||||
|
||||
void LuaVM::prepare() {
|
||||
LGUARD(L);
|
||||
if (!_registered) {
|
||||
Lunar<CityView>::Register2(L);
|
||||
luaL_openlib(L, "camera", Camera::methods, 0);
|
||||
luaL_openlib(L, "screen", Screen::methods, 0);
|
||||
luaL_openlib(L, "spritecache", SpriteCache::methods, 0);
|
||||
}
|
||||
_registered = true;
|
||||
}
|
||||
|
||||
void LuaVM::setCityView(OpenGTA::CityView & cv) {
|
||||
LGUARD(L);
|
||||
CityView *scv = static_cast<CityView*>(&cv);
|
||||
lua_gettable(L, LUA_GLOBALSINDEX);
|
||||
int scv_ref = Lunar<CityView>::push(L, scv, false);
|
||||
lua_pushliteral(L, "city_view");
|
||||
lua_pushvalue(L, scv_ref);
|
||||
lua_settable(L, LUA_GLOBALSINDEX);
|
||||
}
|
||||
|
||||
void LuaVM::runString(const char* _str) {
|
||||
LGUARD(L);
|
||||
if (!_str)
|
||||
return;
|
||||
if (luaL_loadbuffer(L, _str, strlen(_str), "cmd") ||
|
||||
lua_pcall(L, 0, 0, 0))
|
||||
throw E_SCRIPTERROR("Error running string: " + std::string(lua_tostring(L, -1)));
|
||||
}
|
||||
|
||||
void LuaVM::runFile(const char* filename) {
|
||||
LGUARD(L);
|
||||
if (luaL_loadfile(L, filename) || lua_pcall(L, 0, 0, 0))
|
||||
throw E_SCRIPTERROR("Error running file: " + std::string(lua_tostring(L, -1)));
|
||||
}
|
||||
|
||||
void LuaVM::callSimpleFunction(const char* func_name) {
|
||||
LGUARD(L);
|
||||
lua_getglobal(L, func_name);
|
||||
if (lua_type(L, -1) == LUA_TFUNCTION) {
|
||||
if (lua_pcall(L, 0, 0, 0) != 0)
|
||||
throw E_SCRIPTERROR(("Exception calling function: ") + std::string(lua_tostring(L, -1)));
|
||||
}
|
||||
else
|
||||
throw E_SCRIPTERROR("No such function: " + std::string(func_name));
|
||||
}
|
||||
|
||||
int LuaVM::getGlobalInt(const char* key) {
|
||||
LGUARD(L);
|
||||
lua_getglobal(L, key);
|
||||
if (!lua_isnumber(L, -1))
|
||||
throw E_SCRIPTERROR("Expected int value for key: " + std::string(key));
|
||||
int v = int(lua_tonumber(L, -1));
|
||||
return v;
|
||||
}
|
||||
|
||||
float LuaVM::getGlobalFloat(const char* key) {
|
||||
LGUARD(L);
|
||||
lua_getglobal(L, key);
|
||||
if (!lua_isnumber(L, -1))
|
||||
throw E_SCRIPTERROR("Expected float value for key: " + std::string(key));
|
||||
float v = float(lua_tonumber(L, -1));
|
||||
return v;
|
||||
}
|
||||
|
||||
const char* LuaVM::getGlobalString(const char* key) {
|
||||
LGUARD(L);
|
||||
lua_getglobal(L, key);
|
||||
if (!lua_isstring(L, -1))
|
||||
throw E_SCRIPTERROR("Expected string value for key: " + std::string(key));
|
||||
const char* v = lua_tostring(L, -1);
|
||||
return v;
|
||||
}
|
||||
|
||||
void LuaVM::setGlobalInt(const char* key, int v) {
|
||||
LGUARD(L);
|
||||
lua_pushnumber(L, v);
|
||||
lua_setglobal(L, key);
|
||||
}
|
||||
|
||||
void LuaVM::setGlobalFloat(const char* key, float v) {
|
||||
LGUARD(L);
|
||||
lua_pushnumber(L, v);
|
||||
lua_setglobal(L, key);
|
||||
}
|
||||
|
||||
void LuaVM::setGlobalString(const char* key, const char* v) {
|
||||
LGUARD(L);
|
||||
lua_pushstring(L, v);
|
||||
lua_setglobal(L, key);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
34
lua_addon/lua_vm.h
Normal file
34
lua_addon/lua_vm.h
Normal file
@ -0,0 +1,34 @@
|
||||
#ifndef OPENGTA_SCRIPT_VM_H
|
||||
#define OPENGTA_SCRIPT_VM_H
|
||||
|
||||
#include "lua.hpp"
|
||||
#include "Singleton.h"
|
||||
#include "gl_cityview.h"
|
||||
|
||||
namespace OpenGTA {
|
||||
namespace Script {
|
||||
class LuaVM {
|
||||
public:
|
||||
LuaVM();
|
||||
~LuaVM();
|
||||
void runString(const char*);
|
||||
void runFile(const char*);
|
||||
void callSimpleFunction(const char*);
|
||||
void prepare();
|
||||
void setCityView(OpenGTA::CityView &);
|
||||
int getGlobalInt(const char*);
|
||||
float getGlobalFloat(const char*);
|
||||
const char* getGlobalString(const char*);
|
||||
void setGlobalInt(const char*, int);
|
||||
void setGlobalFloat(const char*, float);
|
||||
void setGlobalString(const char*, const char*);
|
||||
protected:
|
||||
lua_State *L;
|
||||
private:
|
||||
bool _registered;
|
||||
};
|
||||
typedef Loki::SingletonHolder<LuaVM, Loki::CreateUsingNew, Loki::DefaultLifetime,
|
||||
Loki::SingleThreaded> LuaVMHolder;
|
||||
}
|
||||
}
|
||||
#endif
|
259
lua_addon/lunar.h
Normal file
259
lua_addon/lunar.h
Normal file
@ -0,0 +1,259 @@
|
||||
#ifndef LUNAR_H
|
||||
#define LUNAR_H
|
||||
|
||||
/** See: http://lua-users.org/wiki/CppBindingWithLunar .
|
||||
*
|
||||
* # include-guards
|
||||
* # fixed old-style cast
|
||||
* # Register2 function
|
||||
*
|
||||
*/
|
||||
|
||||
#include "lua.hpp"
|
||||
|
||||
template <typename T> class Lunar {
|
||||
typedef struct { T *pT; } userdataType;
|
||||
public:
|
||||
typedef int (T::*mfp)(lua_State *L);
|
||||
typedef struct { const char *name; mfp mfunc; } RegType;
|
||||
|
||||
static void Register(lua_State *L) {
|
||||
lua_newtable(L);
|
||||
int methods = lua_gettop(L);
|
||||
|
||||
luaL_newmetatable(L, T::className);
|
||||
int metatable = lua_gettop(L);
|
||||
|
||||
// store method table in globals so that
|
||||
// scripts can add functions written in Lua.
|
||||
lua_pushvalue(L, methods);
|
||||
set(L, LUA_GLOBALSINDEX, T::className);
|
||||
|
||||
// hide metatable from Lua getmetatable()
|
||||
lua_pushvalue(L, methods);
|
||||
set(L, metatable, "__metatable");
|
||||
|
||||
lua_pushvalue(L, methods);
|
||||
set(L, metatable, "__index");
|
||||
|
||||
lua_pushcfunction(L, tostring_T);
|
||||
set(L, metatable, "__tostring");
|
||||
|
||||
lua_pushcfunction(L, gc_T);
|
||||
set(L, metatable, "__gc");
|
||||
|
||||
lua_newtable(L); // mt for method table
|
||||
lua_pushcfunction(L, new_T);
|
||||
lua_pushvalue(L, -1); // dup new_T function
|
||||
set(L, methods, "new"); // add new_T to method table
|
||||
set(L, -3, "__call"); // mt.__call = new_T
|
||||
lua_setmetatable(L, methods);
|
||||
|
||||
// fill method table with methods from class T
|
||||
for (RegType *l = T::methods; l->name; l++) {
|
||||
lua_pushstring(L, l->name);
|
||||
lua_pushlightuserdata(L, static_cast<void*>(l));
|
||||
lua_pushcclosure(L, thunk, 1);
|
||||
lua_settable(L, methods);
|
||||
}
|
||||
|
||||
lua_pop(L, 2); // drop metatable and method table
|
||||
}
|
||||
|
||||
static void Register2(lua_State *L) {
|
||||
lua_newtable(L);
|
||||
int methods = lua_gettop(L);
|
||||
|
||||
luaL_newmetatable(L, T::className);
|
||||
int metatable = lua_gettop(L);
|
||||
|
||||
// store method table in globals so that
|
||||
// scripts can add functions written in Lua.
|
||||
lua_pushvalue(L, methods);
|
||||
set(L, LUA_GLOBALSINDEX, T::className);
|
||||
|
||||
// hide metatable from Lua getmetatable()
|
||||
lua_pushvalue(L, methods);
|
||||
set(L, metatable, "__metatable");
|
||||
|
||||
lua_pushvalue(L, methods);
|
||||
set(L, metatable, "__index");
|
||||
|
||||
lua_pushcfunction(L, tostring_T);
|
||||
set(L, metatable, "__tostring");
|
||||
|
||||
lua_pushcfunction(L, gc_T);
|
||||
set(L, metatable, "__gc");
|
||||
|
||||
lua_newtable(L); // mt for method table
|
||||
lua_setmetatable(L, methods);
|
||||
|
||||
// fill method table with methods from class T
|
||||
for (RegType *l = T::methods; l->name; l++) {
|
||||
lua_pushstring(L, l->name);
|
||||
lua_pushlightuserdata(L, static_cast<void*>(l));
|
||||
lua_pushcclosure(L, thunk, 1);
|
||||
lua_settable(L, methods);
|
||||
}
|
||||
|
||||
lua_pop(L, 2); // drop metatable and method table
|
||||
}
|
||||
|
||||
|
||||
// call named lua method from userdata method table
|
||||
static int call(lua_State *L, const char *method,
|
||||
int nargs=0, int nresults=LUA_MULTRET, int errfunc=0)
|
||||
{
|
||||
int base = lua_gettop(L) - nargs; // userdata index
|
||||
if (!luaL_checkudata(L, base, T::className)) {
|
||||
lua_settop(L, base-1); // drop userdata and args
|
||||
lua_pushfstring(L, "not a valid %s userdata", T::className);
|
||||
return -1;
|
||||
}
|
||||
|
||||
lua_pushstring(L, method); // method name
|
||||
lua_gettable(L, base); // get method from userdata
|
||||
if (lua_isnil(L, -1)) { // no method?
|
||||
lua_settop(L, base-1); // drop userdata and args
|
||||
lua_pushfstring(L, "%s missing method '%s'", T::className, method);
|
||||
return -1;
|
||||
}
|
||||
lua_insert(L, base); // put method under userdata, args
|
||||
|
||||
int status = lua_pcall(L, 1+nargs, nresults, errfunc); // call method
|
||||
if (status) {
|
||||
const char *msg = lua_tostring(L, -1);
|
||||
if (msg == NULL) msg = "(error with no message)";
|
||||
lua_pushfstring(L, "%s:%s status = %d\n%s",
|
||||
T::className, method, status, msg);
|
||||
lua_remove(L, base); // remove old message
|
||||
return -1;
|
||||
}
|
||||
return lua_gettop(L) - base + 1; // number of results
|
||||
}
|
||||
|
||||
// push onto the Lua stack a userdata containing a pointer to T object
|
||||
static int push(lua_State *L, T *obj, bool gc=false) {
|
||||
if (!obj) { lua_pushnil(L); return 0; }
|
||||
luaL_getmetatable(L, T::className); // lookup metatable in Lua registry
|
||||
if (lua_isnil(L, -1)) luaL_error(L, "%s missing metatable", T::className);
|
||||
int mt = lua_gettop(L);
|
||||
subtable(L, mt, "userdata", "v");
|
||||
userdataType *ud =
|
||||
static_cast<userdataType*>(pushuserdata(L, obj, sizeof(userdataType)));
|
||||
if (ud) {
|
||||
ud->pT = obj; // store pointer to object in userdata
|
||||
lua_pushvalue(L, mt);
|
||||
lua_setmetatable(L, -2);
|
||||
if (gc == false) {
|
||||
lua_checkstack(L, 3);
|
||||
subtable(L, mt, "do not trash", "k");
|
||||
lua_pushvalue(L, -2);
|
||||
lua_pushboolean(L, 1);
|
||||
lua_settable(L, -3);
|
||||
lua_pop(L, 1);
|
||||
}
|
||||
}
|
||||
lua_replace(L, mt);
|
||||
lua_settop(L, mt);
|
||||
return mt; // index of userdata containing pointer to T object
|
||||
}
|
||||
|
||||
// get userdata from Lua stack and return pointer to T object
|
||||
static T *check(lua_State *L, int narg) {
|
||||
userdataType *ud =
|
||||
static_cast<userdataType*>(luaL_checkudata(L, narg, T::className));
|
||||
if(!ud) luaL_typerror(L, narg, T::className);
|
||||
return ud->pT; // pointer to T object
|
||||
}
|
||||
|
||||
private:
|
||||
Lunar(); // hide default constructor
|
||||
|
||||
// member function dispatcher
|
||||
static int thunk(lua_State *L) {
|
||||
// stack has userdata, followed by method args
|
||||
T *obj = check(L, 1); // get 'self', or if you prefer, 'this'
|
||||
lua_remove(L, 1); // remove self so member function args start at index 1
|
||||
// get member function from upvalue
|
||||
RegType *l = static_cast<RegType*>(lua_touserdata(L, lua_upvalueindex(1)));
|
||||
return (obj->*(l->mfunc))(L); // call member function
|
||||
}
|
||||
|
||||
// create a new T object and
|
||||
// push onto the Lua stack a userdata containing a pointer to T object
|
||||
static int new_T(lua_State *L) {
|
||||
lua_remove(L, 1); // use classname:new(), instead of classname.new()
|
||||
T *obj = new T(L); // call constructor for T objects
|
||||
//push(L, obj, false); // gc_T will delete this object
|
||||
push(L, obj, true); // gc_T will delete this object
|
||||
return 1; // userdata containing pointer to T object
|
||||
}
|
||||
|
||||
// garbage collection metamethod
|
||||
static int gc_T(lua_State *L) {
|
||||
if (luaL_getmetafield(L, 1, "do not trash")) {
|
||||
lua_pushvalue(L, 1); // dup userdata
|
||||
lua_gettable(L, -2);
|
||||
if (!lua_isnil(L, -1)) return 0; // do not delete object
|
||||
}
|
||||
userdataType *ud = static_cast<userdataType*>(lua_touserdata(L, 1));
|
||||
T *obj = ud->pT;
|
||||
if (obj) delete obj; // call destructor for T objects
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tostring_T (lua_State *L) {
|
||||
char buff[32];
|
||||
userdataType *ud = static_cast<userdataType*>(lua_touserdata(L, 1));
|
||||
T *obj = ud->pT;
|
||||
sprintf(buff, "%p", obj);
|
||||
lua_pushfstring(L, "%s (%s)", T::className, buff);
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void set(lua_State *L, int table_index, const char *key) {
|
||||
lua_pushstring(L, key);
|
||||
lua_insert(L, -2); // swap value and key
|
||||
lua_settable(L, table_index);
|
||||
}
|
||||
|
||||
static void weaktable(lua_State *L, const char *mode) {
|
||||
lua_newtable(L);
|
||||
lua_pushvalue(L, -1); // table is its own metatable
|
||||
lua_setmetatable(L, -2);
|
||||
lua_pushliteral(L, "__mode");
|
||||
lua_pushstring(L, mode);
|
||||
lua_settable(L, -3); // metatable.__mode = mode
|
||||
}
|
||||
|
||||
static void subtable(lua_State *L, int tindex, const char *name, const char *mode) {
|
||||
lua_pushstring(L, name);
|
||||
lua_gettable(L, tindex);
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1);
|
||||
lua_checkstack(L, 3);
|
||||
weaktable(L, mode);
|
||||
lua_pushstring(L, name);
|
||||
lua_pushvalue(L, -2);
|
||||
lua_settable(L, tindex);
|
||||
}
|
||||
}
|
||||
|
||||
static void *pushuserdata(lua_State *L, void *key, size_t sz) {
|
||||
void *ud = 0;
|
||||
lua_pushlightuserdata(L, key);
|
||||
lua_gettable(L, -2); // lookup[key]
|
||||
if (lua_isnil(L, -1)) {
|
||||
lua_pop(L, 1); // drop nil
|
||||
lua_checkstack(L, 3);
|
||||
ud = lua_newuserdata(L, sz); // create new userdata
|
||||
lua_pushlightuserdata(L, key);
|
||||
lua_pushvalue(L, -2); // dup userdata
|
||||
lua_settable(L, -4); // lookup[key] = userdata
|
||||
}
|
||||
return ud;
|
||||
}
|
||||
};
|
||||
|
||||
#endif
|
32
main.cpp
Normal file
32
main.cpp
Normal file
@ -0,0 +1,32 @@
|
||||
#include <iostream>
|
||||
#include <SDL.h>
|
||||
|
||||
void on_exit();
|
||||
void run_main();
|
||||
void initGL();
|
||||
void initVideo(int w, int h, int bpp);
|
||||
|
||||
int global_EC = 0;
|
||||
int global_Done = 0;
|
||||
SDL_Surface* screen = NULL;
|
||||
SDL_Surface* surface = NULL;
|
||||
|
||||
int city_num = 0;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
|
||||
std::cerr << "Fatal error initialising SDL!" << std::endl;
|
||||
global_EC = 1;
|
||||
exit(1);
|
||||
}
|
||||
atexit(on_exit);
|
||||
if (argc == 2) {
|
||||
city_num = atoi(argv[1]);
|
||||
}
|
||||
SDL_EnableKeyRepeat( 100, SDL_DEFAULT_REPEAT_INTERVAL );
|
||||
initVideo(1024, 768, 32);
|
||||
initGL();
|
||||
|
||||
run_main();
|
||||
exit(0);
|
||||
}
|
58
main2.cpp
Normal file
58
main2.cpp
Normal file
@ -0,0 +1,58 @@
|
||||
#include <cstdlib>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include "m_exceptions.h"
|
||||
#include "log.h"
|
||||
|
||||
extern void parse_args(int argc, char* argv[]);
|
||||
extern void on_exit();
|
||||
extern void run_init();
|
||||
extern void run_main();
|
||||
|
||||
int global_EC = 0;
|
||||
int global_Done = 0;
|
||||
|
||||
#ifndef DONT_CATCH
|
||||
bool catch_exceptions = true;
|
||||
#else
|
||||
bool catch_exceptions = false;
|
||||
#endif
|
||||
|
||||
using namespace std;
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc > 1)
|
||||
parse_args(argc, argv);
|
||||
|
||||
atexit(on_exit);
|
||||
|
||||
if (!catch_exceptions)
|
||||
INFO << "ignoring exceptions" << std::endl;
|
||||
|
||||
if (!catch_exceptions)
|
||||
run_init();
|
||||
else {
|
||||
try {
|
||||
run_init();
|
||||
}
|
||||
catch (Exception & e) {
|
||||
ERROR << "Exception during startup: " << e.what() << endl;
|
||||
global_EC = 1;
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
if (!catch_exceptions)
|
||||
run_main();
|
||||
else {
|
||||
try {
|
||||
run_main();
|
||||
}
|
||||
catch (const Exception & e) {
|
||||
ERROR << "Exception during game: " << e.what() << endl;
|
||||
global_EC = 1;
|
||||
exit(1);
|
||||
}
|
||||
|
||||
}
|
||||
std::exit(0);
|
||||
}
|
78
makefile
Normal file
78
makefile
Normal file
@ -0,0 +1,78 @@
|
||||
include src_list.make
|
||||
|
||||
INC_EX_LIBS = $(PHYSFS_INC) $(SDL_INC) $(LUA_INC)
|
||||
INC_INTERN = -I. -Iloki/include/loki -Iutil -Icoldet -Imath
|
||||
|
||||
INC = $(INC_INTERN) $(INC_EX_LIBS)
|
||||
|
||||
FLAGS = $(WARN) $(DEBUG) $(OPT)
|
||||
|
||||
BUILD_FOR = $(shell if [ -n "$(HOST)" ]; then echo $(HOST) ; else echo "LINUX"; fi)
|
||||
|
||||
#SDL_GL_LIB = -lGL -lGLU
|
||||
|
||||
LOKI_LIB = -Wl,-Rloki/lib -Lloki/lib -lloki
|
||||
#COLDET_LIB = -Wl,-Rcoldet -Lcoldet -lcoldet
|
||||
|
||||
CXXFLAGS=$(FLAGS) $(DEFS) \
|
||||
$(INC)
|
||||
|
||||
src_list.make: prepare_build.sh
|
||||
./prepare_build.sh $(BUILD_FOR)
|
||||
$(MAKE) depend
|
||||
|
||||
%.o: %.cpp
|
||||
$(CXX) $(FLAGS) $(DEFS) \
|
||||
$(INC) \
|
||||
-c -o $@ $<
|
||||
|
||||
%.o: %.c
|
||||
$(CC) $(CCFLAGS) \
|
||||
-c -o $@ $<
|
||||
|
||||
loki:
|
||||
ifeq ($(BUILD_FOR), LINUX)
|
||||
make -f loki.make
|
||||
else
|
||||
make -f loki.make.w32_cross
|
||||
endif
|
||||
|
||||
ctags:
|
||||
ctags *.cpp util/*.cpp
|
||||
|
||||
coldet/libcoldet.a:
|
||||
make -C coldet -f makefile.g++ all
|
||||
|
||||
clean:
|
||||
rm -f tags depend *.o tools/*.o coldet/*.o lua_addon/*.o math/*.o util/*.o \
|
||||
spriteplayer gfxextract viewer $(TOOLS) objdump objdump_map minimap slopeview luaviewer g24
|
||||
|
||||
html: doxy_main.h
|
||||
doxygen
|
||||
doxygen: doxy_main.h
|
||||
doxygen
|
||||
|
||||
doxy_main.h: doc/hacking.txt tools/doxy_doc.sh
|
||||
./tools/doxy_doc.sh > doxy_main.h
|
||||
|
||||
doxyclean:
|
||||
$(RM) doxy_main.h -r doc/html
|
||||
|
||||
package:
|
||||
(cd .. && tar jvcf ogta_src_`date +%F`.tar.bz2 -T ogta/release_files_sorted)
|
||||
@echo "saved as: ogta_src_`date +%F.tar.bz2`"
|
||||
|
||||
rclean:
|
||||
make libclean
|
||||
make clean
|
||||
make doxyclean
|
||||
rm -f src_list.make
|
||||
|
||||
libclean:
|
||||
make -C coldet -f makefile.g++ clean
|
||||
|
||||
|
||||
depend: loki src_list.make
|
||||
$(RM) depend
|
||||
$(CXX) $(CXXFLAGS) -DGCC -E -MM $(GL_SRC) $(OGTA_SRC) $(UTIL_SRC) > depend
|
||||
|
114
math/basis.hpp
Normal file
114
math/basis.hpp
Normal file
@ -0,0 +1,114 @@
|
||||
#ifndef GOMEZ_Basis_H
|
||||
#define GOMEZ_Basis_H
|
||||
|
||||
/**
|
||||
* Taken from:
|
||||
* http://www.gamasutra.com/features/19990702/data_structures_01.htm
|
||||
* http://www.gamasutra.com/features/19991018/Gomez_1.htm
|
||||
*
|
||||
* Both by Miguel Gomez
|
||||
*/
|
||||
|
||||
|
||||
#include "matrix.hpp"
|
||||
|
||||
namespace GomezMath {
|
||||
// An orthonormal basis with respect to a parent
|
||||
//
|
||||
class Basis
|
||||
{
|
||||
public:
|
||||
Matrix R;
|
||||
public:
|
||||
Basis ()
|
||||
{
|
||||
}
|
||||
Basis (const Vector & v0,
|
||||
const Vector & v1, const Vector & v2):R (v0, v1, v2)
|
||||
{
|
||||
}
|
||||
Basis (const Matrix & m):R (m)
|
||||
{
|
||||
}
|
||||
const Vector & operator [] (long i) const
|
||||
{
|
||||
return R.C[i];
|
||||
}
|
||||
const Vector & x () const
|
||||
{
|
||||
return R.C[0];
|
||||
}
|
||||
const Vector & y () const
|
||||
{
|
||||
return R.C[1];
|
||||
}
|
||||
const Vector & z () const
|
||||
{
|
||||
return R.C[2];
|
||||
}
|
||||
const Matrix & basis () const
|
||||
{
|
||||
return R;
|
||||
}
|
||||
void basis (const Vector & v0, const Vector & v1, const Vector & v2)
|
||||
{
|
||||
this->R[0] = v0;
|
||||
this->R[1] = v1;
|
||||
this->R[2] = v2;
|
||||
}
|
||||
// Right-Handed Rotations
|
||||
void rotateAboutX (const Scalar & a)
|
||||
{
|
||||
if (0 != a) //don’t rotate by 0
|
||||
{
|
||||
Vector b1 = this->y () * cos (a) + this->z () * sin (a);
|
||||
Vector b2 = -this->y () * sin (a) + this->z () * cos (a);
|
||||
//set basis
|
||||
this->R[1] = b1;
|
||||
this->R[2] = b2;
|
||||
//x is unchanged
|
||||
}
|
||||
}
|
||||
void rotateAboutY (const Scalar & a)
|
||||
{
|
||||
if (0 != a) //don’t rotate by 0
|
||||
{
|
||||
Vector b2 = this->z () * cos (a) + this->x () * sin (a); //rotate z
|
||||
Vector b0 = -this->z () * sin (a) + this->x () * cos (a); //rotate x
|
||||
//set basis
|
||||
this->R[2] = b2;
|
||||
this->R[0] = b0;
|
||||
//y is unchanged
|
||||
}
|
||||
}
|
||||
void rotateAboutZ (const Scalar & a)
|
||||
{
|
||||
if (0 != a) //don’t rotate by 0
|
||||
{
|
||||
//don’t over-write basis before calculation is done
|
||||
Vector b0 = this->x () * cos (a) + this->y () * sin (a); //rotate x
|
||||
Vector b1 = -this->x () * sin (a) + this->y () * cos (a); //rotate y
|
||||
//set basis
|
||||
this->R[0] = b0;
|
||||
this->R[1] = b1;
|
||||
//z is unchanged
|
||||
}
|
||||
}
|
||||
//rotate the basis about the unit axis u by theta (radians)
|
||||
void rotate (const Scalar & theta, const Vector & u);
|
||||
//rotate, length of da is theta, unit direction of da is u
|
||||
void rotate (const Vector & da);
|
||||
|
||||
// Transformations
|
||||
const Vector transformVectorToLocal (const Vector & v) const
|
||||
{
|
||||
return Vector (R.C[0].dot (v), R.C[1].dot (v), R.C[2].dot (v));
|
||||
}
|
||||
const Point transformVectorToParent (const Vector & v) const
|
||||
{
|
||||
return R.C[0] * v.x + R.C[1] * v.y + R.C[2] * v.z;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
#endif
|
60
math/coord_frame.hpp
Normal file
60
math/coord_frame.hpp
Normal file
@ -0,0 +1,60 @@
|
||||
#ifndef GOMEZ_COORDFRAME_H
|
||||
#define GOMEZ_COORDFRAME_H
|
||||
|
||||
/**
|
||||
* Taken from:
|
||||
* http://www.gamasutra.com/features/19990702/data_structures_01.htm
|
||||
* http://www.gamasutra.com/features/19991018/Gomez_1.htm
|
||||
*
|
||||
* Both by Miguel Gomez
|
||||
*/
|
||||
|
||||
|
||||
#include "basis.hpp"
|
||||
namespace GomezMath {
|
||||
|
||||
// A coordinate frame (basis and origin) with respect to a parent
|
||||
//
|
||||
class CoordFrame:public Basis
|
||||
{
|
||||
public:
|
||||
Point O; //this coordinate frame’s origin, relative to its parent frame
|
||||
public:
|
||||
CoordFrame ()
|
||||
{
|
||||
}
|
||||
CoordFrame (const Point & o,
|
||||
const Vector & v0,
|
||||
const Vector & v1, const Vector & v2): Basis (v0, v1, v2), O(o)
|
||||
{
|
||||
}
|
||||
CoordFrame (const Point & o, const Basis & b): Basis (b), O(o)
|
||||
{
|
||||
}
|
||||
const Point & position () const
|
||||
{
|
||||
return O;
|
||||
}
|
||||
void position (const Point & p)
|
||||
{
|
||||
O = p;
|
||||
}
|
||||
const Point transformPointToLocal (const Point & p) const
|
||||
{
|
||||
//translate to this frame’s origin, then project onto this basis
|
||||
return transformVectorToLocal (p - O);
|
||||
}
|
||||
const Point transformPointToParent (const Point & p) const
|
||||
{
|
||||
//transform the coordinate vector and translate by this origin
|
||||
return transformVectorToParent (p) + O;
|
||||
}
|
||||
//translate the origin by the given vector
|
||||
void translate (const Vector & v)
|
||||
{
|
||||
O += v;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
11
math/makefile
Normal file
11
math/makefile
Normal file
@ -0,0 +1,11 @@
|
||||
GMATH_FILES = obb.cpp
|
||||
GMATH_OBJ = $(GMATH_FILES:%.cpp=%.o)
|
||||
|
||||
all: libgomezmath.a
|
||||
|
||||
libgomezmath.a: $(GMATH_OBJ)
|
||||
rm -f $@
|
||||
ar cq $@ $(GMATH_OBJ)
|
||||
|
||||
clean:
|
||||
rm -f libgomezmath.a $(GMATH_OBJ)
|
151
math/matrix.hpp
Normal file
151
math/matrix.hpp
Normal file
@ -0,0 +1,151 @@
|
||||
#ifndef GOMEZ_Matrix_H
|
||||
#define GOMEZ_Matrix_H
|
||||
|
||||
#include "vector.hpp"
|
||||
namespace GomezMath {
|
||||
/**
|
||||
* Taken from:
|
||||
* http://www.gamasutra.com/features/19990702/data_structures_01.htm
|
||||
* http://www.gamasutra.com/features/19991018/Gomez_1.htm
|
||||
*
|
||||
* Both by Miguel Gomez
|
||||
*/
|
||||
|
||||
|
||||
// A 3x3 matrix
|
||||
//
|
||||
class Matrix
|
||||
{
|
||||
public:
|
||||
Vector C[3]; //column vectors
|
||||
public:
|
||||
Matrix ()
|
||||
{
|
||||
//identity matrix
|
||||
C[0].x = 1;
|
||||
C[1].y = 1;
|
||||
C[2].z = 1;
|
||||
}
|
||||
Matrix (const Vector & c0, const Vector & c1, const Vector & c2)
|
||||
{
|
||||
C[0] = c0;
|
||||
C[1] = c1;
|
||||
C[2] = c2;
|
||||
}
|
||||
//index a column, allow assignment
|
||||
//NOTE: using this index operator along with the vector index
|
||||
//gives you M[column][row], not the standard M[row][column]
|
||||
Vector & operator [](long i)
|
||||
{
|
||||
return C[i];
|
||||
}
|
||||
//compare
|
||||
const bool operator == (const Matrix & m) const
|
||||
{
|
||||
return C[0] == m.C[0] && C[1] == m.C[1] && C[2] == m.C[2];
|
||||
}
|
||||
const bool operator != (const Matrix & m) const
|
||||
{
|
||||
return !(m == *this);
|
||||
}
|
||||
//assign
|
||||
const Matrix & operator = (const Matrix & m)
|
||||
{
|
||||
C[0] = m.C[0];
|
||||
C[1] = m.C[1];
|
||||
C[2] = m.C[2];
|
||||
return *this;
|
||||
}
|
||||
//increment
|
||||
const Matrix & operator += (const Matrix & m)
|
||||
{
|
||||
C[0] += m.C[0];
|
||||
C[1] += m.C[1];
|
||||
C[2] += m.C[2];
|
||||
return *this;
|
||||
}
|
||||
//decrement
|
||||
const Matrix & operator -= (const Matrix & m)
|
||||
{
|
||||
C[0] -= m.C[0];
|
||||
C[1] -= m.C[1];
|
||||
C[2] -= m.C[2];
|
||||
return *this;
|
||||
}
|
||||
//self-multiply by a scalar
|
||||
const Matrix & operator *= (const Scalar & s)
|
||||
{
|
||||
C[0] *= s;
|
||||
C[1] *= s;
|
||||
C[2] *= s;
|
||||
return *this;
|
||||
}
|
||||
//self-multiply by a matrix
|
||||
const Matrix & operator *= (const Matrix & m)
|
||||
{
|
||||
//NOTE: don’t change the columns
|
||||
//in the middle of the operation
|
||||
Matrix temp = (*this);
|
||||
C[0] = temp * m.C[0];
|
||||
C[1] = temp * m.C[1];
|
||||
C[2] = temp * m.C[2];
|
||||
return *this;
|
||||
}
|
||||
//add
|
||||
const Matrix operator + (const Matrix & m) const
|
||||
{
|
||||
return Matrix (C[0] + m.C[0], C[1] + m.C[1], C[2] + m.C[2]);
|
||||
}
|
||||
//subtract
|
||||
const Matrix operator - (const Matrix & m) const
|
||||
{
|
||||
return Matrix (C[0] - m.C[0], C[1] - m.C[1], C[2] - m.C[2]);
|
||||
}
|
||||
//post-multiply by a scalar
|
||||
const Matrix operator * (const Scalar & s) const
|
||||
{
|
||||
return Matrix (C[0] * s, C[1] * s, C[2] * s);
|
||||
}
|
||||
//pre-multiply by a scalar
|
||||
friend inline const Matrix operator * (const Scalar & s, const Matrix & m)
|
||||
{
|
||||
return m * s;
|
||||
}
|
||||
|
||||
//post-multiply by a vector
|
||||
const Vector operator * (const Vector & v) const
|
||||
{
|
||||
return (C[0] * v.x + C[1] * v.y + C[2] * v.z);
|
||||
}
|
||||
//pre-multiply by a vector
|
||||
inline friend const Vector operator * (const Vector & v, const Matrix & m)
|
||||
{
|
||||
return Vector (m.C[0].dot (v), m.C[1].dot (v), m.C[2].dot (v));
|
||||
}
|
||||
//post-multiply by a matrix
|
||||
const Matrix operator * (const Matrix & m) const
|
||||
{
|
||||
return Matrix ((*this) * m.C[0], (*this) * m.C[1], (*this) * m.C[2]);
|
||||
}
|
||||
//transpose
|
||||
Matrix transpose () const
|
||||
{
|
||||
//turn columns on their side
|
||||
return Matrix (Vector (C[0].x, C[1].x, C[2].x), //column 0
|
||||
Vector (C[0].y, C[1].y, C[2].y), //column 1
|
||||
Vector (C[0].z, C[1].z, C[2].z) //column 2
|
||||
);
|
||||
}
|
||||
//scalar determinant
|
||||
const Scalar determinant () const
|
||||
{
|
||||
//Lang, "Linear Algebra", p. 143
|
||||
return C[0].dot (C[1].cross (C[2]));
|
||||
}
|
||||
//matrix inverse
|
||||
const Matrix inverse () const;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
126
math/obb.cpp
Normal file
126
math/obb.cpp
Normal file
@ -0,0 +1,126 @@
|
||||
#ifndef GOMEZ_OBB_H
|
||||
#define GOMEZ_OBB_H
|
||||
|
||||
/**
|
||||
* Taken from:
|
||||
* http://www.gamasutra.com/features/19990702/data_structures_01.htm
|
||||
* http://www.gamasutra.com/features/19991018/Gomez_1.htm
|
||||
*
|
||||
* Both by Miguel Gomez
|
||||
*/
|
||||
|
||||
#include "obb.hpp"
|
||||
#include "vector.hpp"
|
||||
|
||||
namespace GomezMath {
|
||||
|
||||
//check if two oriented bounding boxes overlap
|
||||
const bool OBBOverlap (
|
||||
//A
|
||||
Vector & a, //extents
|
||||
Vector & Pa, //position
|
||||
Vector * A, //orthonormal basis
|
||||
//B
|
||||
Vector & b, //extents
|
||||
Vector & Pb, //position
|
||||
Vector * B //orthonormal basis
|
||||
)
|
||||
{
|
||||
//translation, in parent frame
|
||||
Vector v = Pb - Pa;
|
||||
//translation, in A's frame
|
||||
Vector T (v.dot (A[0]), v.dot (A[1]), v.dot (A[2]));
|
||||
//B's basis with respect to A's local frame
|
||||
Scalar R[3][3];
|
||||
float ra, rb, t;
|
||||
long i, k;
|
||||
//calculate rotation matrix
|
||||
for (i = 0; i < 3; i++)
|
||||
for (k = 0; k < 3; k++)
|
||||
R[i][k] = A[i].dot (B[k]);
|
||||
/*ALGORITHM: Use the separating axis test for all 15 potential
|
||||
separating axes. If a separating axis could not be found, the two
|
||||
boxes overlap. */
|
||||
//A's basis vectors
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
ra = a[i];
|
||||
rb =
|
||||
b[0] * fabs (R[i][0]) + b[1] * fabs (R[i][1]) + b[2] * fabs (R[i][2]);
|
||||
t = fabs (T[i]);
|
||||
if (t > ra + rb)
|
||||
return false;
|
||||
}
|
||||
//B's basis vectors
|
||||
for (k = 0; k < 3; k++)
|
||||
{
|
||||
ra =
|
||||
a[0] * fabs (R[0][k]) + a[1] * fabs (R[1][k]) + a[2] * fabs (R[2][k]);
|
||||
rb = b[k];
|
||||
t = fabs (T[0] * R[0][k] + T[1] * R[1][k] + T[2] * R[2][k]);
|
||||
if (t > ra + rb)
|
||||
return false;
|
||||
}
|
||||
//9 cross products
|
||||
//L = A0 x B0
|
||||
ra = a[1] * fabs (R[2][0]) + a[2] * fabs (R[1][0]);
|
||||
rb = b[1] * fabs (R[0][2]) + b[2] * fabs (R[0][1]);
|
||||
t = fabs (T[2] * R[1][0] - T[1] * R[2][0]);
|
||||
if (t > ra + rb)
|
||||
return false;
|
||||
//L = A0 x B1
|
||||
ra = a[1] * fabs (R[2][1]) + a[2] * fabs (R[1][1]);
|
||||
rb = b[0] * fabs (R[0][2]) + b[2] * fabs (R[0][0]);
|
||||
t = fabs (T[2] * R[1][1] - T[1] * R[2][1]);
|
||||
if (t > ra + rb)
|
||||
return false;
|
||||
//L = A0 x B2
|
||||
ra = a[1] * fabs (R[2][2]) + a[2] * fabs (R[1][2]);
|
||||
rb = b[0] * fabs (R[0][1]) + b[1] * fabs (R[0][0]);
|
||||
t = fabs (T[2] * R[1][2] - T[1] * R[2][2]);
|
||||
if (t > ra + rb)
|
||||
return false;
|
||||
//L = A1 x B0
|
||||
ra = a[0] * fabs (R[2][0]) + a[2] * fabs (R[0][0]);
|
||||
rb = b[1] * fabs (R[1][2]) + b[2] * fabs (R[1][1]);
|
||||
t = fabs (T[0] * R[2][0] - T[2] * R[0][0]);
|
||||
if (t > ra + rb)
|
||||
return false;
|
||||
//L = A1 x B1
|
||||
ra = a[0] * fabs (R[2][1]) + a[2] * fabs (R[0][1]);
|
||||
rb = b[0] * fabs (R[1][2]) + b[2] * fabs (R[1][0]);
|
||||
t = fabs (T[0] * R[2][1] - T[2] * R[0][1]);
|
||||
if (t > ra + rb)
|
||||
return false;
|
||||
//L = A1 x B2
|
||||
ra = a[0] * fabs (R[2][2]) + a[2] * fabs (R[0][2]);
|
||||
rb = b[0] * fabs (R[1][1]) + b[1] * fabs (R[1][0]);
|
||||
t = fabs (T[0] * R[2][2] - T[2] * R[0][2]);
|
||||
if (t > ra + rb)
|
||||
return false;
|
||||
//L = A2 x B0
|
||||
ra = a[0] * fabs (R[1][0]) + a[1] * fabs (R[0][0]);
|
||||
rb = b[1] * fabs (R[2][2]) + b[2] * fabs (R[2][1]);
|
||||
t = fabs (T[1] * R[0][0] - T[0] * R[1][0]);
|
||||
if (t > ra + rb)
|
||||
return false;
|
||||
//L = A2 x B1
|
||||
ra = a[0] * fabs (R[1][1]) + a[1] * fabs (R[0][1]);
|
||||
rb = b[0] * fabs (R[2][2]) + b[2] * fabs (R[2][0]);
|
||||
t = fabs (T[1] * R[0][1] - T[0] * R[1][1]);
|
||||
if (t > ra + rb)
|
||||
return false;
|
||||
//L = A2 x B2
|
||||
ra = a[0] * fabs (R[1][2]) + a[1] * fabs (R[0][2]);
|
||||
rb = b[0] * fabs (R[2][1]) + b[1] * fabs (R[2][0]);
|
||||
t = fabs (T[1] * R[0][2] - T[0] * R[1][2]);
|
||||
if (t > ra + rb)
|
||||
return false;
|
||||
/*no separating axis found,
|
||||
the two boxes overlap */
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
42
math/obb.hpp
Normal file
42
math/obb.hpp
Normal file
@ -0,0 +1,42 @@
|
||||
#ifndef GOMEZ_OBB_H
|
||||
#define GOMEZ_OBB_H
|
||||
|
||||
/**
|
||||
* Taken from:
|
||||
* http://www.gamasutra.com/features/19990702/data_structures_01.htm
|
||||
* http://www.gamasutra.com/features/19991018/Gomez_1.htm
|
||||
*
|
||||
* Both by Miguel Gomez
|
||||
*/
|
||||
|
||||
#include "coord_frame.hpp"
|
||||
|
||||
namespace GomezMath {
|
||||
class OBB : public CoordFrame
|
||||
{
|
||||
public:
|
||||
Vector E; //extents
|
||||
OBB (const Vector & e) : E (e)
|
||||
{
|
||||
}
|
||||
OBB (const Vector & e, const Vector & origin,
|
||||
const Vector & v0, const Vector & v1, const Vector & v2) :
|
||||
CoordFrame(origin, v0, v1, v2), E(e)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
const bool OBBOverlap (
|
||||
//A
|
||||
Vector & a, //extents
|
||||
Vector & Pa, //position
|
||||
Vector * A, //orthonormal basis
|
||||
//B
|
||||
Vector & b, //extents
|
||||
Vector & Pb, //position
|
||||
Vector * B //orthonormal basis
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
#endif
|
164
math/obox.cpp
Normal file
164
math/obox.cpp
Normal file
@ -0,0 +1,164 @@
|
||||
#include "obox.h"
|
||||
// --------------------------
|
||||
//
|
||||
// Oriented Bounding Box Class
|
||||
//
|
||||
// --------------------------
|
||||
|
||||
//
|
||||
// Check if a point is in this bounding box
|
||||
//
|
||||
bool OBox::IsPointInBox(const Vector3D &InP)
|
||||
{
|
||||
// Rotate the point into the box's coordinates
|
||||
Vector3D P = Transform(InP, m_M.Inverse());
|
||||
|
||||
// Now just use an axis-aligned check
|
||||
if ( fabs(P.x) < m_Extent.x && fabs(P.y) < m_Extent.y && fabs(P.z) < m_Extent.z )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Check if a sphere overlaps any part of this bounding box
|
||||
//
|
||||
bool OBox::IsSphereInBox( const Vector3D &InP, float fRadius)
|
||||
{
|
||||
float fDist;
|
||||
float fDistSq = 0;
|
||||
Vector3D P = Transform(InP, m_M.Inverse());
|
||||
|
||||
// Add distance squared from sphere centerpoint to box for each axis
|
||||
for ( int i = 0; i < 3; i++ )
|
||||
{
|
||||
if ( fabs(P[i]) > m_Extent[i] )
|
||||
{
|
||||
fDist = fabs(P[i]) - m_Extent[i];
|
||||
fDistSq += fDist*fDist;
|
||||
}
|
||||
}
|
||||
return ( fDistSq <= fRadius*fRadius );
|
||||
}
|
||||
|
||||
//
|
||||
// Check if the bounding box is completely behind a plane( defined by a normal and a point )
|
||||
//
|
||||
bool OBox::BoxOutsidePlane( const Vector3D &InNorm, const Vector3D &InP )
|
||||
{
|
||||
// Plane Normal in Box Space
|
||||
Vector3D Norm = rotateVector(InNorm, m_M.Inverse() );
|
||||
Norm = Vector3D( fabs( Norm.x ), fabs( Norm.y ), fabs( Norm.z ) );
|
||||
|
||||
float Extent = Norm * m_Extent; //Norm.Dot( m_Extent ); // Box Extent along the plane normal
|
||||
//float Distance = InNorm.Dot( GetCenterPoint() - InP ); // Distance from Box Center to the Plane
|
||||
float Distance = InNorm * (GetCenterPoint() - InP);
|
||||
|
||||
// If Box Centerpoint is behind the plane further than its extent, the Box is outside the plane
|
||||
if ( Distance < -Extent ) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Does the Line (L1, L2) intersect the Box?
|
||||
//
|
||||
bool OBox::IsLineInBox( const Vector3D& L1, const Vector3D& L2 )
|
||||
{
|
||||
// Put line in box space
|
||||
Matrix3D MInv = m_M.Inverse();
|
||||
Vector3D LB1 = Transform(L1, MInv);
|
||||
Vector3D LB2 = Transform(L2, MInv);
|
||||
|
||||
// Get line midpoint and extent
|
||||
Vector3D LMid = (LB1 + LB2) * 0.5f;
|
||||
Vector3D L = (LB1 - LMid);
|
||||
Vector3D LExt = Vector3D( fabs(L.x), fabs(L.y), fabs(L.z) );
|
||||
|
||||
// Use Separating Axis Test
|
||||
// Separation vector from box center to line center is LMid, since the line is in box space
|
||||
if ( fabs( LMid.x ) > m_Extent.x + LExt.x ) return false;
|
||||
if ( fabs( LMid.y ) > m_Extent.y + LExt.y ) return false;
|
||||
if ( fabs( LMid.z ) > m_Extent.z + LExt.z ) return false;
|
||||
// Crossproducts of line and each axis
|
||||
if ( fabs( LMid.y * L.z - LMid.z * L.y) > (m_Extent.y * LExt.z + m_Extent.z * LExt.y) ) return false;
|
||||
if ( fabs( LMid.x * L.z - LMid.z * L.x) > (m_Extent.x * LExt.z + m_Extent.z * LExt.x) ) return false;
|
||||
if ( fabs( LMid.x * L.y - LMid.y * L.x) > (m_Extent.x * LExt.y + m_Extent.y * LExt.x) ) return false;
|
||||
// No separating axis, the line intersects
|
||||
return true;
|
||||
}
|
||||
|
||||
//
|
||||
// Returns a 3x3 rotation matrix as vectors
|
||||
//
|
||||
inline void OBox::GetInvRot( Vector3D *pvRot )
|
||||
{
|
||||
pvRot[0] = Vector3D( m_M.m[0][0], m_M.m[0][1], m_M.m[0][2] );
|
||||
pvRot[1] = Vector3D( m_M.m[1][0], m_M.m[1][1], m_M.m[1][2] );
|
||||
pvRot[2] = Vector3D( m_M.m[2][0], m_M.m[2][1], m_M.m[2][2] );
|
||||
}
|
||||
|
||||
//
|
||||
// Check if any part of a box is inside any part of another box
|
||||
// Uses the separating axis test.
|
||||
//
|
||||
bool OBox::IsBoxInBox( OBox &BBox )
|
||||
{
|
||||
Vector3D SizeA = m_Extent;
|
||||
Vector3D SizeB = BBox.m_Extent;
|
||||
Vector3D RotA[3], RotB[3];
|
||||
GetInvRot( RotA );
|
||||
BBox.GetInvRot( RotB );
|
||||
|
||||
float R[3][3]; // Rotation from B to A
|
||||
float AR[3][3]; // absolute values of R matrix, to use with box extents
|
||||
float ExtentA, ExtentB, Separation;
|
||||
int i, k;
|
||||
|
||||
// Calculate B to A rotation matrix
|
||||
for( i = 0; i < 3; i++ )
|
||||
for( k = 0; k < 3; k++ )
|
||||
{
|
||||
R[i][k] = RotA[i] * RotB[k];
|
||||
AR[i][k] = fabs(R[i][k]);
|
||||
}
|
||||
|
||||
// Vector separating the centers of Box B and of Box A
|
||||
Vector3D vSepWS = BBox.GetCenterPoint() - GetCenterPoint();
|
||||
// Rotated into Box A's coordinates
|
||||
Vector3D vSepA( vSepWS * RotA[0], vSepWS * RotA[1], vSepWS * RotA[2] );
|
||||
|
||||
// Test if any of A's basis vectors separate the box
|
||||
for( i = 0; i < 3; i++ )
|
||||
{
|
||||
ExtentA = SizeA[i];
|
||||
ExtentB = SizeB * Vector3D( AR[i][0], AR[i][1], AR[i][2] );
|
||||
Separation = fabs( vSepA[i] );
|
||||
|
||||
if( Separation > ExtentA + ExtentB ) return false;
|
||||
}
|
||||
|
||||
// Test if any of B's basis vectors separate the box
|
||||
for( k = 0; k < 3; k++ )
|
||||
{
|
||||
ExtentA = SizeA * Vector3D( AR[0][k], AR[1][k], AR[2][k] );
|
||||
ExtentB = SizeB[k];
|
||||
Separation = fabs( vSepA * Vector3D(R[0][k],R[1][k],R[2][k]) );
|
||||
|
||||
if( Separation > ExtentA + ExtentB ) return false;
|
||||
}
|
||||
|
||||
// Now test Cross Products of each basis vector combination ( A[i], B[k] )
|
||||
for( i=0 ; i<3 ; i++ )
|
||||
for( k=0 ; k<3 ; k++ )
|
||||
{
|
||||
int i1 = (i+1)%3, i2 = (i+2)%3;
|
||||
int k1 = (k+1)%3, k2 = (k+2)%3;
|
||||
ExtentA = SizeA[i1] * AR[i2][k] + SizeA[i2] * AR[i1][k];
|
||||
ExtentB = SizeB[k1] * AR[i][k2] + SizeB[k2] * AR[i][k1];
|
||||
Separation = fabs( vSepA[i2] * R[i1][k] - vSepA[i1] * R[i2][k] );
|
||||
if( Separation > ExtentA + ExtentB ) return false;
|
||||
}
|
||||
|
||||
// No separating axis found, the boxes overlap
|
||||
return true;
|
||||
}
|
43
math/obox.h
Normal file
43
math/obox.h
Normal file
@ -0,0 +1,43 @@
|
||||
#include "math3d.h"
|
||||
|
||||
// see: from: http://www.3dkingdoms.com/weekly/weekly.php?a=21
|
||||
|
||||
// basically the same as bbox.h/.cpp but using coldet math
|
||||
|
||||
class OBox
|
||||
{
|
||||
public:
|
||||
OBox() {}
|
||||
OBox( const Matrix3D & m, const Vector3D & extent )
|
||||
{ Set( m, extent ); }
|
||||
OBox( const Matrix3D & m, const Vector3D & low, const Vector3D & high )
|
||||
{ Set( m, low, high ); }
|
||||
|
||||
void Set( const Matrix3D & m, const Vector3D & extent )
|
||||
{
|
||||
m_M = m;
|
||||
m_Extent = extent;
|
||||
}
|
||||
void Set( const Matrix3D & m, const Vector3D & low, const Vector3D & high )
|
||||
{
|
||||
m_M = m;
|
||||
m_M.Translate( 0.5f * (low + high) );
|
||||
m_Extent = 0.5f * (high - low);
|
||||
}
|
||||
|
||||
Vector3D GetSize()
|
||||
{ return 2.0f * m_Extent; }
|
||||
Vector3D GetCenterPoint()
|
||||
{ return m_M.GetTranslate(); }
|
||||
void GetInvRot( Vector3D *pvRot );
|
||||
|
||||
bool IsPointInBox( const Vector3D & p );
|
||||
bool IsBoxInBox( OBox & box );
|
||||
bool IsSphereInBox( const Vector3D & p, float fRadius );
|
||||
bool IsLineInBox( const Vector3D & l1, const Vector3D & l2 );
|
||||
bool BoxOutsidePlane( const Vector3D & normal, const Vector3D & p );
|
||||
|
||||
// Data
|
||||
Matrix3D m_M;
|
||||
Vector3D m_Extent;
|
||||
};
|
184
math/quaternion.h
Normal file
184
math/quaternion.h
Normal file
@ -0,0 +1,184 @@
|
||||
#ifndef QUATERNION_MATH
|
||||
#define QUATERNION_MATH
|
||||
#include <cmath>
|
||||
|
||||
namespace Util { namespace Math {
|
||||
/*!
|
||||
* \namespace Util::Math
|
||||
* \brief Vector/Matrix/Quaternion interpolation
|
||||
*
|
||||
* Found at http://www.flipcode.com/files/code/vquats.cpp
|
||||
*
|
||||
*
|
||||
* I think this is very sleek, so I kept it.
|
||||
*
|
||||
* Editor's note:
|
||||
* COTD Entry: Vector Math & Quaternions by Tim Sweeney [tim@epicgames.com]
|
||||
|
||||
This is some fairly generic vector math code. Here I want to
|
||||
illustrate two things:
|
||||
|
||||
1. The "vectorSpace" template is a nice way to represent the
|
||||
general mathematical notion of vectors without regard to
|
||||
particular data types. The idea is that you can declare
|
||||
a vector type (like vec4 below), and the vectorSpace template
|
||||
automatically generates the appropriate vector operators.
|
||||
|
||||
I wrote this code for clarity and generality. For performance, you would
|
||||
want to specialize the vectorSpace template for common types, like 4-
|
||||
component floating-point vectors. You could implement these using
|
||||
KNI and 3DNow instructions, for example.
|
||||
|
||||
2. Useful quaternion functions, most notably "exp" and "ln".
|
||||
|
||||
The traditional and limited way programmers used quaternion
|
||||
rotations in the past was to use "spherical linear interpolation",
|
||||
interpolating a rotational arc between two quaternions at a constant
|
||||
angular rate. Given quaternions q1 and q2, you might have used
|
||||
a function lik "slerp(q1,q2,0.25)" to find a rotation
|
||||
one-quarter between the two quaternions. This approach
|
||||
was unsatisfactory because it was difficult to perform
|
||||
smooth, higher order, i.e. hermite or bezier, interpolation
|
||||
between quaternions.
|
||||
|
||||
New approach: take the logarithm ("ln" function below) of
|
||||
your quaternions, then use ordinary linear interpolation
|
||||
(sampleLinear below) or any higher-order interpolation
|
||||
scheme -- and then take the exponent ("exp") of the result.
|
||||
The resulting rotations will have the desired smooth angular
|
||||
movement rates.
|
||||
|
||||
Why does this work? Read up on "geometric algebra" to find out.
|
||||
Unit quaternions are just a special 3-dimensional case of
|
||||
spinors, which are the most general representation of
|
||||
n-dimensional rotations possible.
|
||||
*/
|
||||
|
||||
// Template implementing a "vector space" (in the precise mathematical sense).
|
||||
// A vector space is a type "u", implemented as
|
||||
// an array of "n" elements of type "t".
|
||||
template<class t,int n,class u> struct vectorSpace {
|
||||
t x[n];
|
||||
vectorSpace() {for(int i=0; i<n; i++) x[i]=t();}
|
||||
inline t& operator[](int i) {/*assert(i>=0 && i<n);*/ return x[i];}
|
||||
inline const t& operator[](int i) const {/*assert(i>=0 && i<n);*/ return x[i];}
|
||||
friend bool operator== (const u& a,const u& b) {bool c=true; for(int i=0; i<n; i++) c=c&&a[i]==b[i]; return c;}
|
||||
friend bool operator!= (const u& a,const u& b) {bool c=false; for(int i=0; i<n; i++) c=c||a[i]!=b[i]; return c;}
|
||||
friend inline t vectorSum (const u& a ) {t c=0; for(int i=0; i<n; i++) c+=a[i]; return c;}
|
||||
friend inline t vectorProd(const u& a ) {t c=1; for(int i=0; i<n; i++) c*=a[i]; return c;}
|
||||
friend inline u operator- (const u& a ) {u c; for(int i=0; i<n; i++) c[i] = -a[i]; return c;}
|
||||
friend inline u operator+ (const u& a,const u& b) {u c; for(int i=0; i<n; i++) c[i] =a[i]+b[i]; return c;}
|
||||
friend inline u operator- (const u& a,const u& b) {u c; for(int i=0; i<n; i++) c[i] =a[i]-b[i]; return c;}
|
||||
friend inline u operator* (const float a,const u& b) {u c; for(int i=0; i<n; i++) c[i] =a *b[i]; return c;}
|
||||
friend inline u operator* (const u& a,const float b) {u c; for(int i=0; i<n; i++) c[i] =a[i]*b; return c;}
|
||||
friend inline u operator/ (const u& a,const float b) {u c; for(int i=0; i<n; i++) c[i] =a[i]/b; return c;}
|
||||
friend inline u operator+=( u& a,const u& b) { for(int i=0; i<n; i++) a[i]+=b[i]; return a;}
|
||||
friend inline u operator-=( u& a,const u& b) { for(int i=0; i<n; i++) a[i]-=b[i]; return a;}
|
||||
friend inline u operator*=( u& a,const float b) { for(int i=0; i<n; i++) a[i]*=b; return a;}
|
||||
friend inline u operator/=( u& a,const float b) { for(int i=0; i<n; i++) a[i]/=b; return a;}
|
||||
};
|
||||
template<class t> inline t sampleLinear(const t& a,const t& b,float s) {
|
||||
return (1-s)*a+s*b;
|
||||
}
|
||||
template<class t> inline t sampleHermite(const t& a,const t& b,const t& at,const t& bt,float s) {
|
||||
return
|
||||
(+2*s*s*s -3*s*s +1)*a+
|
||||
(-2*s*s*s +3*s*s )*b+
|
||||
(+1*s*s*s -2*s*s +s )*at+
|
||||
(+1*s*s*s -1*s*s )*bt;
|
||||
}
|
||||
template<class t> inline t sampleBezier(const t& a,const t& b,const t& ac,const t& bc,float s) {
|
||||
return
|
||||
(-1*s*s*s +3*s*s -3*s +1)*a+
|
||||
(+3*s*s*s -6*s*s +3*s )*b+
|
||||
(-3*s*s*s +3*s*s )*ac+
|
||||
(+1*s*s*s )*bc;
|
||||
}
|
||||
|
||||
// 4-component floating point vectors.
|
||||
struct vec4: public vectorSpace<float,4,vec4> {
|
||||
inline vec4() {x[0]=x[1]=x[2]=x[3]=0;}
|
||||
inline vec4(float _x,float _y,float _z,float _w) {x[0]=_x; x[1]=_y; x[2]=_z; x[3]=_w;}
|
||||
};
|
||||
|
||||
// 4x4 matrices.
|
||||
struct mtx44: public vectorSpace<vec4,4,mtx44> {
|
||||
mtx44() {}
|
||||
mtx44(const vec4& _x,const vec4& _y, const vec4& _z,const vec4& _w) {x[0]=_x; x[1]=_y; x[2]=_z; x[3]=_w;}
|
||||
};
|
||||
|
||||
// A 3-dimensional (4-component) quaternion.
|
||||
struct quat: public vectorSpace<float,4,quat> {
|
||||
quat() {x[0]=x[1]=x[2]=0; x[3]=0;}
|
||||
quat(float _x,float _y,float _z,float _w) {x[0]=_x; x[1]=_y; x[2]=_z; x[3]=_w;}
|
||||
};
|
||||
inline quat operator*(const quat& a,const quat& b) {
|
||||
return quat(
|
||||
+a[0]*b[3] +a[1]*b[2] -a[2]*b[1] +a[3]*b[0],
|
||||
-a[0]*b[2] +a[1]*b[3] +a[2]*b[0] +a[3]*b[1],
|
||||
+a[0]*b[1] -a[1]*b[0] +a[2]*b[3] +a[3]*b[2],
|
||||
-a[0]*b[0] -a[1]*b[1] -a[2]*b[2] +a[3]*b[3]
|
||||
);
|
||||
}
|
||||
inline float norm(const quat& a) {
|
||||
return a[0]*a[0] + a[1]*a[1] + a[2]*a[2] + a[3]*a[3];
|
||||
}
|
||||
inline float mag(const quat& a) {
|
||||
return sqrt(norm(a));
|
||||
}
|
||||
inline quat normal(const quat& a) {
|
||||
return a/mag(a);
|
||||
}
|
||||
inline quat conj(const quat& a) {
|
||||
return quat(-a[0],-a[1],-a[2],a[3]);
|
||||
}
|
||||
inline quat inv(const quat& a) {
|
||||
return 1.f/norm(a)*conj(a);
|
||||
}
|
||||
inline quat exp(const quat& a) {
|
||||
float r = sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);
|
||||
float et = std::exp(a[3]);
|
||||
float s = r>=0.00001f? et*sin(r)/r: 0.f;
|
||||
return quat(s*a[0],s*a[1],s*a[2],et*cos(r));
|
||||
}
|
||||
inline quat ln(const quat& a) {
|
||||
float r = sqrt(a[0]*a[0]+a[1]*a[1]+a[2]*a[2]);
|
||||
float t = r>0.00001f? atan2(r,a[3])/r: 0.f;
|
||||
return quat(t*a[0],t*a[1],t*a[2],0.5*log(norm(a)));
|
||||
}
|
||||
inline vec4 quatToRotationAxisAngle(const quat& a) {
|
||||
float t = a[3]*a[3];
|
||||
float rsa = t<0.99999999? 1.f/sqrt(1.f-t): 1.f;
|
||||
return vec4(a[0]*rsa,a[1]*rsa,a[2]*rsa,acos(a[3])*2.f);
|
||||
}
|
||||
inline quat quatFromRotationAxisAngle(const vec4& a) {
|
||||
float s = sin(a[3]/2.f);
|
||||
float c = cos(a[3]/2.f);
|
||||
return quat(a[0]*s,a[1]*s,a[2]*s,c);
|
||||
}
|
||||
inline mtx44 quatToRotationMatrix(const quat& a) {
|
||||
float xx=a[0]*a[0];
|
||||
float xy=a[0]*a[1], yy=a[1]*a[1];
|
||||
float xz=a[0]*a[2], yz=a[1]*a[2], zz=a[2]*a[2];
|
||||
float xw=a[0]*a[3], yw=a[1]*a[3], zw=a[2]*a[3], ww=a[3]*a[3];
|
||||
return mtx44(
|
||||
vec4(+xx-yy-zz+ww, +xy+zw+xy+zw, +xz-yw+xz-yw, 0),
|
||||
vec4(+xy-zw+xy-zw, -xx+yy-zz+ww, +yz+xw+yz+xw, 0),
|
||||
vec4(+xz+yw+xz+yw, +yz-xw+yz-xw, -xx-yy+zz+ww, 0),
|
||||
vec4(0 , 0 , 0 , 1)
|
||||
);
|
||||
}
|
||||
inline quat quatFromRotationMatrix(const mtx44& m) {
|
||||
float w=0.5*sqrt(m[0][0]+m[1][1]+m[2][2]+m[3][3]);
|
||||
float s=0.25/w;
|
||||
return quat(
|
||||
(m[1][2]-m[2][1])*s,
|
||||
(m[2][0]-m[0][2])*s,
|
||||
(m[0][1]-m[1][0])*s,
|
||||
w
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
159
math/vector.hpp
Normal file
159
math/vector.hpp
Normal file
@ -0,0 +1,159 @@
|
||||
#ifndef GOMEZ_Vector_H
|
||||
#define GOMEZ_Vector_H
|
||||
#include <cmath>
|
||||
/**
|
||||
* Taken from:
|
||||
* http://www.gamasutra.com/features/19990702/data_structures_01.htm
|
||||
* http://www.gamasutra.com/features/19991018/Gomez_1.htm
|
||||
*
|
||||
* Both by Miguel Gomez
|
||||
*/
|
||||
|
||||
namespace GomezMath {
|
||||
|
||||
// A floating point number
|
||||
//
|
||||
typedef float Scalar;
|
||||
|
||||
//
|
||||
// A 3D vector
|
||||
//
|
||||
class Vector
|
||||
{
|
||||
public:
|
||||
Scalar x, y, z; //x,y,z coordinates
|
||||
public:
|
||||
Vector ():x (0), y (0), z (0)
|
||||
{
|
||||
}
|
||||
Vector (const Scalar & a, const Scalar & b, const Scalar & c):x (a), y (b),
|
||||
z (c)
|
||||
{
|
||||
}
|
||||
//index a component
|
||||
//NOTE: returning a reference allows
|
||||
//you to assign the indexed element
|
||||
Scalar & operator [](const long i)
|
||||
{
|
||||
return *((&x) + i);
|
||||
}
|
||||
//compare
|
||||
const bool operator == (const Vector & v) const
|
||||
{
|
||||
return (v.x == x && v.y == y && v.z == z);
|
||||
}
|
||||
const bool operator != (const Vector & v) const
|
||||
{
|
||||
return !(v == *this);
|
||||
}
|
||||
//negate
|
||||
const Vector operator - () const
|
||||
{
|
||||
return Vector (-x, -y, -z);
|
||||
}
|
||||
//assign
|
||||
const Vector & operator = (const Vector & v)
|
||||
{
|
||||
x = v.x;
|
||||
y = v.y;
|
||||
z = v.z;
|
||||
return *this;
|
||||
}
|
||||
//increment
|
||||
const Vector & operator += (const Vector & v)
|
||||
{
|
||||
x += v.x;
|
||||
y += v.y;
|
||||
z += v.z;
|
||||
return *this;
|
||||
}
|
||||
//decrement
|
||||
const Vector & operator -= (const Vector & v)
|
||||
{
|
||||
x -= v.x;
|
||||
y -= v.y;
|
||||
z -= v.z;
|
||||
return *this;
|
||||
}
|
||||
//self-multiply
|
||||
const Vector & operator *= (const Scalar & s)
|
||||
{
|
||||
x *= s;
|
||||
y *= s;
|
||||
z *= s;
|
||||
return *this;
|
||||
}
|
||||
//self-divide
|
||||
const Vector & operator /= (const Scalar & s)
|
||||
{
|
||||
const Scalar r = 1 / s;
|
||||
x *= r;
|
||||
y *= r;
|
||||
z *= r;
|
||||
return *this;
|
||||
}
|
||||
//add
|
||||
const Vector operator + (const Vector & v) const
|
||||
{
|
||||
return Vector (x + v.x, y + v.y, z + v.z);
|
||||
}
|
||||
//subtract
|
||||
const Vector operator - (const Vector & v) const
|
||||
{
|
||||
return Vector (x - v.x, y - v.y, z - v.z);
|
||||
}
|
||||
//post-multiply by a scalar
|
||||
const Vector operator * (const Scalar & s) const
|
||||
{
|
||||
return Vector (x * s, y * s, z * s);
|
||||
}
|
||||
//pre-multiply by a scalar
|
||||
friend inline const Vector operator * (const Scalar & s, const Vector & v)
|
||||
{
|
||||
return v * s;
|
||||
}
|
||||
//divide
|
||||
const Vector operator / (Scalar s) const
|
||||
{
|
||||
s = 1 / s;
|
||||
return Vector (s * x, s * y, s * z);
|
||||
}
|
||||
//cross product
|
||||
const Vector cross (const Vector & v) const
|
||||
{
|
||||
//Davis, Snider, "Introduction to Vector Analysis", p. 44
|
||||
return Vector (y * v.z - z * v.y, z * v.x - x * v.z, x * v.y - y * v.x);
|
||||
}
|
||||
//scalar dot product
|
||||
const Scalar dot (const Vector & v) const
|
||||
{
|
||||
return x * v.x + y * v.y + z * v.z;
|
||||
}
|
||||
//length
|
||||
const Scalar length () const
|
||||
{
|
||||
return (Scalar) sqrt ((double) this->dot (*this));
|
||||
}
|
||||
//unit vector
|
||||
const Vector unit () const
|
||||
{
|
||||
return (*this) / length ();
|
||||
}
|
||||
//make this a unit vector
|
||||
void normalize ()
|
||||
{
|
||||
(*this) /= length ();
|
||||
}
|
||||
//equal within an error ‘e’
|
||||
const bool nearlyEquals (const Vector & v, const Scalar e) const
|
||||
{
|
||||
return fabs (x - v.x) < e && fabs (y - v.y) < e && fabs (z - v.z) < e;
|
||||
}
|
||||
};
|
||||
//
|
||||
// A 3D position
|
||||
//
|
||||
typedef Vector Point;
|
||||
|
||||
}
|
||||
#endif
|
184
navdata.cpp
Normal file
184
navdata.cpp
Normal file
@ -0,0 +1,184 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This file contains code derived from information copyrighted by *
|
||||
* DMA Design. It may not be used in a commercial product. *
|
||||
* *
|
||||
* See license.txt for details. *
|
||||
* *
|
||||
* This notice may not be removed or altered. *
|
||||
************************************************************************/
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include "navdata.h"
|
||||
#include "log.h"
|
||||
#include "m_exceptions.h"
|
||||
|
||||
namespace OpenGTA {
|
||||
Rect2D::Rect2D() {
|
||||
x = y = w = h = 0;
|
||||
}
|
||||
|
||||
Rect2D::Rect2D(PHYSFS_uint8 a, PHYSFS_uint8 b, PHYSFS_uint8 c, PHYSFS_uint8 d) {
|
||||
x = a;
|
||||
y = b;
|
||||
w = c;
|
||||
h = d;
|
||||
}
|
||||
|
||||
bool Rect2D::isInside(PHYSFS_uint8 _x, PHYSFS_uint8 _y) {
|
||||
if ((_x >= x ) && (_y >= y) &&
|
||||
(PHYSFS_uint16(_x) <= PHYSFS_uint16(x) + w) &&
|
||||
(PHYSFS_uint16(_y) <= PHYSFS_uint16(y) + h)) {
|
||||
lastSubLocation = subLocation(_x, _y);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
PHYSFS_uint16 Rect2D::getSize() {
|
||||
PHYSFS_uint16 res = w;
|
||||
res *= h;
|
||||
return res;
|
||||
}
|
||||
|
||||
// 0 = central, 1 = north, 2 = south, 4 = east, 8 = west
|
||||
PHYSFS_uint8 Rect2D::subLocation(PHYSFS_uint8 _x, PHYSFS_uint8 _y) {
|
||||
PHYSFS_uint8 in_x = _x - x; // offset in rect; assume: x <= _x
|
||||
PHYSFS_uint8 in_y = _y - y;
|
||||
float rel_x = float(in_x)/w;
|
||||
float rel_y = float(in_y)/h;
|
||||
PHYSFS_uint8 res = 0;
|
||||
#define ONE_THIRD 1.0f/3.0f
|
||||
#define TWO_THIRDS 2.0f/3.0f
|
||||
if (rel_x <= ONE_THIRD)
|
||||
// INFO << "west" << std::endl;
|
||||
res |= 8;
|
||||
else if (rel_x >= TWO_THIRDS)
|
||||
//INFO << "east" << std::endl;
|
||||
res |= 4;
|
||||
if (rel_y <= ONE_THIRD)
|
||||
res |= 1;
|
||||
//INFO << "north" << std::endl;
|
||||
else if (rel_y >= TWO_THIRDS)
|
||||
res |= 2;
|
||||
//INFO << "south" << std::endl;
|
||||
return res;
|
||||
}
|
||||
|
||||
NavData::Sector::Sector(PHYSFS_file* fd) : Rect2D() {
|
||||
sam = 0;
|
||||
isADummy = 0;
|
||||
std::memset(&name, 0, 30);
|
||||
assert(fd);
|
||||
PHYSFS_read(fd, static_cast<void*>(&x), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&y), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&w), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&h), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&sam), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&name), 30, 1);
|
||||
}
|
||||
|
||||
NavData::Sector::Sector() : Rect2D() {
|
||||
x = 0;
|
||||
y = 0;
|
||||
w = 255;
|
||||
h = 255;
|
||||
sam = 0;
|
||||
std::memset(&name, 0, 30);
|
||||
isADummy = 1;
|
||||
}
|
||||
|
||||
const char* NavData::Sector::getFullName() {
|
||||
if (isADummy)
|
||||
return "";
|
||||
std::string n;
|
||||
if (lastSubLocation == 0)
|
||||
n.append("Central ");
|
||||
else if (lastSubLocation == 1)
|
||||
n.append("North ");
|
||||
else if (lastSubLocation == 2)
|
||||
n.append("South ");
|
||||
else if (lastSubLocation == 4)
|
||||
n.append("East ");
|
||||
else if (lastSubLocation == 8)
|
||||
n.append("West ");
|
||||
else if (lastSubLocation == 9)
|
||||
n.append("Northwest ");
|
||||
else if (lastSubLocation == 10)
|
||||
n.append("Southwest ");
|
||||
else if (lastSubLocation == 5)
|
||||
n.append("Northeast ");
|
||||
else if (lastSubLocation == 6)
|
||||
n.append("Southeast ");
|
||||
|
||||
n.append(name);
|
||||
return n.c_str();
|
||||
}
|
||||
|
||||
NavData::NavData(PHYSFS_uint32 size, PHYSFS_file *fd) {
|
||||
if (size % 35) {
|
||||
std::ostringstream o;
|
||||
o << "Navdata size: " << size << " % 35 != 0";
|
||||
throw E_INVALIDFORMAT(o.str());
|
||||
//throw std::string("Invalid NavData size in mapfile");
|
||||
}
|
||||
PHYSFS_uint32 c = size / 35;
|
||||
assert(fd);
|
||||
for (PHYSFS_uint32 i = 0; i < c; ++i) {
|
||||
Sector *sec = new Sector(fd);
|
||||
if (sec->getSize() == 0) { // workaround for 'NYC.CMP' (empty sectors)
|
||||
delete sec;
|
||||
WARN << "skipping zero size sector" << std::endl;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
areas.insert(std::pair<PHYSFS_uint16, Sector*>(sec->getSize(), sec));
|
||||
}
|
||||
// dummy catch-all sector for gta london maps
|
||||
areas.insert(std::pair<PHYSFS_uint16, Sector*>(255*255, new Sector()));
|
||||
/*
|
||||
std::cout << "map areas (by size)" << std::endl;
|
||||
SectorMapType::iterator i = areas.begin();
|
||||
while (i != areas.end()) {
|
||||
std::cout << " " << i->first << " : " << i->second->name << " @ " <<
|
||||
int(i->second->x) << "," << int(i->second->y) << " " << int(i->second->w) << "x" <<
|
||||
int(i->second->h) << " sample " << int(i->second->sam) << std::endl;
|
||||
++i;
|
||||
}
|
||||
*/
|
||||
}
|
||||
NavData::~NavData() {
|
||||
clear();
|
||||
}
|
||||
|
||||
NavData::Sector* NavData::getSectorAt(PHYSFS_uint8 x, PHYSFS_uint8 y) {
|
||||
SectorMapType::iterator it = areas.begin();
|
||||
while (it != areas.end()) {
|
||||
if (it->second->isInside(x, y))
|
||||
return it->second;
|
||||
++it;
|
||||
}
|
||||
std::ostringstream o;
|
||||
o << "Querying invalid sector at " << int(x) << ", " << int(y);
|
||||
throw E_OUTOFRANGE(o.str());
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void NavData::clear() {
|
||||
SectorMapType::iterator it = areas.begin();
|
||||
while (it != areas.end()) {
|
||||
delete it->second;
|
||||
++it;
|
||||
}
|
||||
areas.clear();
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
int main(int argc, char* argv[]) {
|
||||
OpenGTA::Rect2D a(3, 4, 10, 20);
|
||||
a.subLocation(atoi(argv[1]), atoi(argv[2]));
|
||||
}
|
||||
#endif
|
97
navdata.h
Normal file
97
navdata.h
Normal file
@ -0,0 +1,97 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This file contains code derived from information copyrighted by *
|
||||
* DMA Design. It may not be used in a commercial product. *
|
||||
* *
|
||||
* See license.txt for details. *
|
||||
* *
|
||||
* This notice may not be removed or altered. *
|
||||
************************************************************************/
|
||||
#ifndef NAVDATA_H
|
||||
#define NAVDATA_H
|
||||
#include <map>
|
||||
#include <physfs.h>
|
||||
|
||||
namespace OpenGTA {
|
||||
|
||||
/** Helper class for area names.
|
||||
*
|
||||
* A simple box; beware uint8 overflow!
|
||||
*
|
||||
* @see NavData
|
||||
*/
|
||||
struct Rect2D {
|
||||
public:
|
||||
/** Zero-constructor.
|
||||
* Everything is 0
|
||||
*/
|
||||
Rect2D();
|
||||
/** Constructor with full params.
|
||||
* @param x
|
||||
* @param y
|
||||
* @param w
|
||||
* @param h
|
||||
*/
|
||||
Rect2D(PHYSFS_uint8, PHYSFS_uint8, PHYSFS_uint8, PHYSFS_uint8);
|
||||
/** Test: point-in-box.
|
||||
* @param x
|
||||
* @param y
|
||||
* @note If the point is inside 'lastSubLocation' is updated before returning.
|
||||
*/
|
||||
bool isInside(PHYSFS_uint8, PHYSFS_uint8);
|
||||
/** Calculate north/south/east/west/central of point (which has to be inside).
|
||||
* @param x
|
||||
* @param y
|
||||
* @return uint8 bitfield
|
||||
*/
|
||||
PHYSFS_uint8 subLocation(PHYSFS_uint8, PHYSFS_uint8);
|
||||
PHYSFS_uint16 getSize();
|
||||
PHYSFS_uint8 x, y;
|
||||
PHYSFS_uint8 w, h;
|
||||
/** Last sub-area location.
|
||||
* 0 = central
|
||||
* 1 = north
|
||||
* 2 = south
|
||||
* 4 = east
|
||||
* 8 = west
|
||||
* ... valid combinations of the last four
|
||||
*/
|
||||
PHYSFS_uint8 lastSubLocation;
|
||||
};
|
||||
|
||||
/** Container of all named sectors.
|
||||
* @see Sector
|
||||
*/
|
||||
class NavData {
|
||||
public:
|
||||
/** A named sector of the map.
|
||||
*/
|
||||
struct Sector : public Rect2D {
|
||||
/** Constructor from valid PHYSFS handle.
|
||||
*/
|
||||
Sector(PHYSFS_file*);
|
||||
Sector();
|
||||
/** Sample number.
|
||||
* 1) see $LANGUAGE.FXT file for actual name
|
||||
* 2) probably sound?
|
||||
*/
|
||||
PHYSFS_uint8 sam; // sample number
|
||||
char name[30]; // FIXME: should not be used
|
||||
/** Returns the name prefixed with sub-area location.
|
||||
*/
|
||||
const char* getFullName();
|
||||
private:
|
||||
bool isADummy;
|
||||
};
|
||||
NavData(PHYSFS_uint32 size, PHYSFS_file *fd);
|
||||
~NavData();
|
||||
Sector* getSectorAt(PHYSFS_uint8, PHYSFS_uint8);
|
||||
private:
|
||||
void clear();
|
||||
typedef std::multimap<PHYSFS_uint16, Sector*> SectorMapType;
|
||||
SectorMapType areas;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
523
opengta.h
Normal file
523
opengta.h
Normal file
@ -0,0 +1,523 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This file contains code derived from information copyrighted by *
|
||||
* DMA Design. It may not be used in a commercial product. *
|
||||
* *
|
||||
* See license.txt for details. *
|
||||
* *
|
||||
* This notice may not be removed or altered. *
|
||||
************************************************************************/
|
||||
#ifndef OPENGTA_MAIN_H
|
||||
#define OPENGTA_MAIN_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <SDL.h>
|
||||
#include <physfs.h>
|
||||
#include "set.h"
|
||||
|
||||
namespace OpenGTA {
|
||||
|
||||
/** The common class for all graphics wrappers.
|
||||
* Contains a number of common variables; does essentially nothing.
|
||||
*/
|
||||
class GraphicsBase {
|
||||
public:
|
||||
GraphicsBase();
|
||||
virtual ~GraphicsBase();
|
||||
|
||||
typedef struct ObjectInfo {
|
||||
PHYSFS_uint32 width, height, depth;
|
||||
PHYSFS_uint16 sprNum, weight, aux;
|
||||
PHYSFS_sint8 status;
|
||||
PHYSFS_uint8 numInto;
|
||||
//PHYSFS_uint16 into[255]; // FIXME: MAX_INTO ???
|
||||
} ObjectInfo;
|
||||
typedef struct LoadedAnim {
|
||||
LoadedAnim(size_t size) : frame(size) {}
|
||||
PHYSFS_uint8 block;
|
||||
PHYSFS_uint8 which;
|
||||
PHYSFS_uint8 speed;
|
||||
PHYSFS_uint8 frameCount;
|
||||
std::vector<PHYSFS_uint8> frame;
|
||||
} LoadedAnim;
|
||||
|
||||
typedef struct DoorInfo {
|
||||
PHYSFS_sint16 rpx, rpy;
|
||||
PHYSFS_sint16 object;
|
||||
PHYSFS_sint16 delta;
|
||||
} DoorInfo;
|
||||
|
||||
typedef struct HlsInfo {
|
||||
PHYSFS_sint16 h, l, s;
|
||||
} HlsInfo;
|
||||
|
||||
typedef struct CarInfo {
|
||||
PHYSFS_sint16 width, height, depth;
|
||||
PHYSFS_sint16 sprNum;
|
||||
PHYSFS_sint16 weightDescriptor;
|
||||
PHYSFS_sint16 maxSpeed, minSpeed;
|
||||
PHYSFS_sint16 acceleration, braking;
|
||||
PHYSFS_sint16 grip, handling;
|
||||
// ... remaps
|
||||
HlsInfo remap24[12];
|
||||
PHYSFS_uint8 remap8[12];
|
||||
PHYSFS_uint8 vtype;
|
||||
PHYSFS_uint8 model;
|
||||
PHYSFS_uint8 turning;
|
||||
PHYSFS_uint8 damagable;
|
||||
PHYSFS_uint16 value[4];
|
||||
PHYSFS_sint8 cx,cy;
|
||||
PHYSFS_uint32 moment;
|
||||
float rbpMass;
|
||||
float g1_Thrust;
|
||||
float tyreAdhesionX, tyreAdhesionY;
|
||||
float handBrakeFriction;
|
||||
float footBrakeFriction;
|
||||
float frontBrakeBias;
|
||||
PHYSFS_sint16 turnRatio;
|
||||
PHYSFS_sint16 driveWheelOffset;
|
||||
PHYSFS_sint16 steeringWheelOffset;
|
||||
float backEndSlideValue;
|
||||
float handBrakeSlideValue;
|
||||
PHYSFS_uint8 convertible;
|
||||
PHYSFS_uint8 engine;
|
||||
PHYSFS_uint8 radio;
|
||||
PHYSFS_uint8 horn;
|
||||
PHYSFS_uint8 soundFunction;
|
||||
PHYSFS_uint8 fastChangeFlag;
|
||||
PHYSFS_sint16 numDoors;
|
||||
DoorInfo door[4]; // FIXME: MAX_DOORS
|
||||
} CarInfo;
|
||||
/*
|
||||
* float->fixed:
|
||||
* fixed = int(floatnum * 65536)
|
||||
*
|
||||
* fixed->float
|
||||
* float = float(fixedNum)/65536
|
||||
*
|
||||
* int->fixed
|
||||
* fixed = intNum << 16
|
||||
*
|
||||
* fixed->int
|
||||
* int = fixedNum >> 16
|
||||
*/
|
||||
|
||||
typedef struct DeltaInfo {
|
||||
PHYSFS_uint16 size;
|
||||
unsigned char* ptr;
|
||||
} DeltaInfo;
|
||||
|
||||
typedef struct SpriteInfo {
|
||||
PHYSFS_uint8 w;
|
||||
PHYSFS_uint8 h;
|
||||
PHYSFS_uint8 deltaCount;
|
||||
PHYSFS_uint16 size;
|
||||
PHYSFS_uint16 clut;
|
||||
PHYSFS_uint8 xoffset;
|
||||
PHYSFS_uint8 yoffset;
|
||||
PHYSFS_uint16 page;
|
||||
//unsigned char* ptr;
|
||||
DeltaInfo delta[33]; //FIXME: GTA_SPRITE_MAX_DELTAS
|
||||
} SpriteInfo;
|
||||
|
||||
typedef struct SpriteNumbers {
|
||||
PHYSFS_uint16 GTA_SPRITE_ARROW;
|
||||
PHYSFS_uint16 GTA_SPRITE_DIGITS;
|
||||
PHYSFS_uint16 GTA_SPRITE_BOAT;
|
||||
PHYSFS_uint16 GTA_SPRITE_BOX;
|
||||
PHYSFS_uint16 GTA_SPRITE_BUS;
|
||||
PHYSFS_uint16 GTA_SPRITE_CAR;
|
||||
PHYSFS_uint16 GTA_SPRITE_OBJECT;
|
||||
PHYSFS_uint16 GTA_SPRITE_PED;
|
||||
PHYSFS_uint16 GTA_SPRITE_SPEEDO;
|
||||
PHYSFS_uint16 GTA_SPRITE_TANK;
|
||||
PHYSFS_uint16 GTA_SPRITE_TRAFFIC_LIGHTS;
|
||||
PHYSFS_uint16 GTA_SPRITE_TRAIN;
|
||||
PHYSFS_uint16 GTA_SPRITE_TRDOORS;
|
||||
PHYSFS_uint16 GTA_SPRITE_BIKE;
|
||||
PHYSFS_uint16 GTA_SPRITE_TRAM;
|
||||
PHYSFS_uint16 GTA_SPRITE_WBUS;
|
||||
PHYSFS_uint16 GTA_SPRITE_WCAR;
|
||||
PHYSFS_uint16 GTA_SPRITE_EX;
|
||||
PHYSFS_uint16 GTA_SPRITE_TUMCAR;
|
||||
PHYSFS_uint16 GTA_SPRITE_TUMTRUCK;
|
||||
PHYSFS_uint16 GTA_SPRITE_FERRY;
|
||||
|
||||
enum SpriteTypes {
|
||||
ARROW = 0,
|
||||
DIGIT,
|
||||
BOAT,
|
||||
BOX,
|
||||
BUS,
|
||||
CAR,
|
||||
OBJECT,
|
||||
PED,
|
||||
SPEEDO,
|
||||
TANK,
|
||||
TRAFFIC_LIGHT,
|
||||
TRAIN,
|
||||
TRDOOR,
|
||||
BIKE,
|
||||
TRAM,
|
||||
WBUS,
|
||||
WCAR,
|
||||
EX,
|
||||
TUMCAR,
|
||||
TUMTRUCK,
|
||||
FERRY
|
||||
};
|
||||
|
||||
PHYSFS_uint16 reIndex(const PHYSFS_uint16 & id, const enum SpriteTypes & st) const;
|
||||
PHYSFS_uint16 countByType(const SpriteTypes & t) const;
|
||||
} SpriteNumbers;
|
||||
|
||||
bool isAnimatedBlock(uint8_t area_code, uint8_t id);
|
||||
|
||||
void prepareSideTexture(unsigned int idx, unsigned char* dst);
|
||||
void prepareLidTexture(unsigned int idx, unsigned char* dst);
|
||||
void prepareAuxTexture(unsigned int idx, unsigned char* dst);
|
||||
|
||||
SpriteNumbers spriteNumbers;
|
||||
|
||||
CarInfo* findCarByModel(PHYSFS_uint8);
|
||||
unsigned char* getTmpBuffer(bool rgba);
|
||||
SpriteInfo* getSprite(size_t id) { return spriteInfos[id]; }
|
||||
|
||||
virtual unsigned char* getSide(unsigned int idx, unsigned int palIdx, bool rgba) = 0;
|
||||
virtual unsigned char* getLid(unsigned int idx, unsigned int palIdx, bool rgba) = 0;
|
||||
virtual unsigned char* getAux(unsigned int idx, unsigned int palIdx, bool rgba) = 0;
|
||||
|
||||
virtual unsigned char* getSpriteBitmap(size_t id, int remap, Uint32 delta) = 0;
|
||||
|
||||
std::vector<LoadedAnim*> animations;
|
||||
std::vector<SpriteInfo*> spriteInfos;
|
||||
std::vector<ObjectInfo*> objectInfos;
|
||||
std::vector<CarInfo*> carInfos;
|
||||
|
||||
bool getDeltaHandling();
|
||||
void setDeltaHandling(bool delta_as_set);
|
||||
|
||||
bool isBlockingSide(uint8_t id);
|
||||
void setupBlocking(const std::string & file);
|
||||
|
||||
protected:
|
||||
void loadTileTextures();
|
||||
void loadAnim();
|
||||
|
||||
void loadObjectInfo_shared(PHYSFS_uint64 offset);
|
||||
void loadSpriteNumbers_shared(PHYSFS_uint64 offset);
|
||||
void loadCarInfo_shared(PHYSFS_uint64 offset);
|
||||
void loadSpriteInfo_shared(PHYSFS_uint64 offset);
|
||||
|
||||
void handleDeltas(const SpriteInfo & spriteinfo, unsigned char* buffer,
|
||||
Uint32 delta);
|
||||
void applyDelta(const SpriteInfo & spriteInfo, unsigned char* buffer,
|
||||
Uint32 offset, const DeltaInfo & deltaInfo, bool mirror = false);
|
||||
|
||||
PHYSFS_file* fd;
|
||||
unsigned char* rawTiles;
|
||||
unsigned char* rawSprites;
|
||||
|
||||
PHYSFS_uint32 sideSize;
|
||||
PHYSFS_uint32 lidSize;
|
||||
PHYSFS_uint32 auxSize;
|
||||
PHYSFS_uint32 animSize;
|
||||
PHYSFS_uint32 objectInfoSize;
|
||||
PHYSFS_uint32 carInfoSize;
|
||||
PHYSFS_uint32 spriteInfoSize;
|
||||
PHYSFS_uint32 spriteGraphicsSize;
|
||||
PHYSFS_uint32 spriteNumberSize;
|
||||
|
||||
PHYSFS_uint32 auxBlockTrailSize;
|
||||
|
||||
/*
|
||||
int loadSide();
|
||||
int loadLid();
|
||||
int loadAux();
|
||||
int loadAnim();
|
||||
int loadObject();
|
||||
int loadCar();
|
||||
int loadSpriteInfo();
|
||||
int loadSpriteGraphics();
|
||||
int loadSpriteNumbers();*/
|
||||
|
||||
PHYSFS_uint8 _topHeaderSize;
|
||||
|
||||
unsigned char tileTmp[4096];
|
||||
unsigned char tileTmpRGB[4096*3];
|
||||
unsigned char tileTmpRGBA[4096*4];
|
||||
|
||||
bool delta_is_a_set;
|
||||
|
||||
Util::Set sideTexBlockMove;
|
||||
};
|
||||
|
||||
// just a forward declaration
|
||||
class CityView;
|
||||
|
||||
/** Loader for STYLE*.GRY files.
|
||||
*
|
||||
* Implements loading the 8-bit graphic files.
|
||||
*/
|
||||
class Graphics8Bit : public GraphicsBase {
|
||||
/** allow renderer direct access to members */
|
||||
friend class CityView;
|
||||
public:
|
||||
/** Constructor for graphics loader.
|
||||
* @param style a valid filename (maybe uppercase depending on your files)
|
||||
*/
|
||||
Graphics8Bit(const std::string& style);
|
||||
/** Destructor cleans all rawdata caches. */
|
||||
~Graphics8Bit();
|
||||
|
||||
/** Helper to apply palettes to various raw bitmaps.
|
||||
* @see Graphics8Bit
|
||||
* @see Font
|
||||
*/
|
||||
class RGBPalette {
|
||||
private:
|
||||
unsigned char data[256*3];
|
||||
public:
|
||||
/** Empty constructor.
|
||||
* You HAVE to call loadFromFile() function when using this constructor!.
|
||||
*/
|
||||
RGBPalette();
|
||||
/** Formerly private member, now exposed for Font class; take care.
|
||||
* @param fd PHYSFS_file* handle.
|
||||
*/
|
||||
int loadFromFile(PHYSFS_file* fd);
|
||||
/** Constructor from PHYFS_file.
|
||||
* @param fd PHYSFS_file* handle
|
||||
*/
|
||||
RGBPalette(PHYSFS_file* fd);
|
||||
/** Constructor from filename.
|
||||
* @param filename a palette file name
|
||||
*/
|
||||
RGBPalette(const std::string& palette);
|
||||
/** Transforms an input buffer using the palette stored in this instance.
|
||||
* @param len length of the src buffer (in byte)
|
||||
* @param src pointer to src buffer
|
||||
* @param dst pointer to dst buffer (must exist and be large enough)
|
||||
* @param rgba use 'true' to create a RGBA image, or 'false' (default) for RGB
|
||||
*/
|
||||
void apply(unsigned int len, const unsigned char* src, unsigned char* dst, bool rgba = false);
|
||||
};
|
||||
|
||||
unsigned char* getSide(unsigned int idx, unsigned int palIdx, bool rgba);
|
||||
unsigned char* getLid(unsigned int idx, unsigned int palIdx, bool rgba);
|
||||
unsigned char* getAux(unsigned int idx, unsigned int palIdx, bool rgba);
|
||||
|
||||
unsigned char* getSpriteBitmap(size_t id, int remap, Uint32 delta);
|
||||
|
||||
void dump();
|
||||
|
||||
private:
|
||||
PHYSFS_uint32 paletteSize;
|
||||
PHYSFS_uint32 remapSize;
|
||||
PHYSFS_uint32 remapIndexSize;
|
||||
protected:
|
||||
void loadHeader();
|
||||
void loadPalette();
|
||||
void loadRemapTables();
|
||||
void loadRemapIndex();
|
||||
void loadObjectInfo();
|
||||
void loadCarInfo();
|
||||
void loadSpriteInfo();
|
||||
void loadSpriteGraphics();
|
||||
void loadSpriteNumbers();
|
||||
void applyRemap(unsigned int len, unsigned int which, unsigned char* buffer);
|
||||
RGBPalette* masterRGB;
|
||||
PHYSFS_uint8 remapTables[256][256];
|
||||
PHYSFS_uint8 remapIndex[256][4];
|
||||
|
||||
};
|
||||
|
||||
class Graphics24Bit : public GraphicsBase {
|
||||
public:
|
||||
Graphics24Bit(const std::string & style);
|
||||
~Graphics24Bit();
|
||||
|
||||
unsigned char* getSide(unsigned int idx, unsigned int palIdx, bool rgba);
|
||||
unsigned char* getLid(unsigned int idx, unsigned int palIdx, bool rgba);
|
||||
unsigned char* getAux(unsigned int idx, unsigned int palIdx, bool rgba);
|
||||
|
||||
unsigned char* getSpriteBitmap(size_t id, int remap, Uint32 delta);
|
||||
|
||||
void dumpClut(const char* fname);
|
||||
|
||||
protected:
|
||||
void loadHeader();
|
||||
void loadClut();
|
||||
void loadPalIndex();
|
||||
void loadObjectInfo();
|
||||
void loadCarInfo();
|
||||
void loadSpriteInfo();
|
||||
void loadSpriteGraphics();
|
||||
void loadSpriteNumbers();
|
||||
|
||||
void applyClut(unsigned char* src, unsigned char* dst,
|
||||
const size_t & len, const PHYSFS_uint16 & clutIdx, bool rgba);
|
||||
|
||||
private:
|
||||
PHYSFS_uint32 clutSize;
|
||||
PHYSFS_uint32 pagedClutSize;
|
||||
PHYSFS_uint32 tileclutSize;
|
||||
PHYSFS_uint32 spriteclutSize;
|
||||
PHYSFS_uint32 newcarclutSize;
|
||||
PHYSFS_uint32 fontclutSize;
|
||||
PHYSFS_uint32 paletteIndexSize;
|
||||
|
||||
unsigned char* rawClut;
|
||||
PHYSFS_uint16* palIndex;
|
||||
};
|
||||
|
||||
class NavData; // see navdata.h
|
||||
|
||||
#define GTA_MAP_MAXDIMENSION 256
|
||||
/** the wrapper for the CMP (compressed map) files */
|
||||
class Map {
|
||||
friend class MapViewGL;
|
||||
public:
|
||||
Map(const std::string& filename);
|
||||
~Map();
|
||||
|
||||
typedef struct BlockInfo {
|
||||
PHYSFS_uint16 typeMap;
|
||||
PHYSFS_uint8 typeMapExt;
|
||||
PHYSFS_uint8 left, right, top, bottom, lid;
|
||||
|
||||
inline bool upOk() { return (typeMap & 1); }
|
||||
inline bool downOk() { return (typeMap & 2); }
|
||||
inline bool leftOk() { return (typeMap & 4); }
|
||||
inline bool rightOk() { return (typeMap & 8); }
|
||||
inline uint8_t blockType() { return ((typeMap & 16 ? 1 : 0) + (typeMap & 32 ? 2 : 0) + (typeMap & 64 ? 4 : 0)); }
|
||||
inline bool isFlat() { return (typeMap & 128); }
|
||||
inline uint8_t slopeType() { return ((typeMap & 256 ? 1 : 0) + (typeMap & 512 ? 2 : 0) +
|
||||
(typeMap & 1024 ? 4 : 0) + (typeMap & 2048 ? 8 : 0) + (typeMap & 4096 ? 16 : 0) + (typeMap & 8192 ? 32 : 0));}
|
||||
inline uint8_t rotation() { return ((typeMap & 16384 ? 1 : 0) + (typeMap & 32768 ? 2 : 0)); }
|
||||
/* m1win seems to indicate:
|
||||
* 000 - Nothing
|
||||
* 001 - traffic lights
|
||||
* 010 - invalid
|
||||
* 011 - invalid
|
||||
* 100 - railway end turn
|
||||
* 101 - railway start turn
|
||||
* 110 - railway station
|
||||
* 111 - railway station train
|
||||
*/
|
||||
inline bool trafficLights() { return (typeMapExt & 1); }
|
||||
inline bool railEndTurn() { return (typeMapExt & 4); }
|
||||
inline bool railStartTurn() { return ((typeMapExt & 4) && (typeMapExt &1)); }
|
||||
inline bool railStation() { return ((typeMapExt & 4) && (typeMapExt & 2));}
|
||||
inline bool railStationTrain() { return ((typeMapExt & 4) && (typeMapExt & 2) && (typeMapExt & 1)); }
|
||||
inline uint8_t remapIndex() { return ((typeMapExt & 8 ? 1 : 0) + (typeMapExt & 16 ? 2 : 0));}
|
||||
inline bool flipTopBottom() { return (typeMapExt & 32); }
|
||||
inline bool flipLeftRight() { return (typeMapExt & 64); }
|
||||
inline bool railway() { return (typeMapExt & 128); }
|
||||
|
||||
} BlockInfo;
|
||||
typedef struct {
|
||||
PHYSFS_uint16 x, y, z;
|
||||
PHYSFS_uint8 type;
|
||||
PHYSFS_uint8 remap;
|
||||
PHYSFS_uint16 rotation; // see: cds.doc
|
||||
PHYSFS_uint16 pitch;
|
||||
PHYSFS_uint16 roll;
|
||||
} ObjectPosition;
|
||||
typedef struct Location {
|
||||
Location();
|
||||
Location(const Location & other);
|
||||
PHYSFS_uint8 x, y, z;
|
||||
} Location;
|
||||
typedef std::multimap<PHYSFS_uint8, Location*> LocationMap;
|
||||
//...
|
||||
PHYSFS_uint16 getNumBlocksAt(PHYSFS_uint8 x, PHYSFS_uint8 y);
|
||||
PHYSFS_uint16 getNumBlocksAtNew(PHYSFS_uint8 x, PHYSFS_uint8 y);
|
||||
BlockInfo* getBlockAt(PHYSFS_uint8 x, PHYSFS_uint8 y, PHYSFS_uint8 z);
|
||||
BlockInfo* getBlockAtNew(PHYSFS_uint8 x, PHYSFS_uint8 y, PHYSFS_uint8 z);
|
||||
BlockInfo* getBlockByInternalId(PHYSFS_uint16 id);
|
||||
PHYSFS_uint16 getInternalIdAt(PHYSFS_uint8 x, PHYSFS_uint8 y, PHYSFS_uint8 z);
|
||||
void dump();
|
||||
NavData *nav;
|
||||
ObjectPosition *objects;
|
||||
PHYSFS_uint16 numObjects;
|
||||
protected:
|
||||
|
||||
PHYSFS_uint32 base[GTA_MAP_MAXDIMENSION][GTA_MAP_MAXDIMENSION];
|
||||
PHYSFS_uint16 *column;
|
||||
BlockInfo *block;
|
||||
LocationMap locations;
|
||||
|
||||
private:
|
||||
PHYSFS_file* fd;
|
||||
|
||||
PHYSFS_uint8 styleNumber;
|
||||
PHYSFS_uint32 routeSize;
|
||||
PHYSFS_uint32 objectPosSize;
|
||||
PHYSFS_uint32 columnSize;
|
||||
PHYSFS_uint32 blockSize;
|
||||
PHYSFS_uint32 navDataSize;
|
||||
|
||||
int loadHeader();
|
||||
int loadBase();
|
||||
int loadColumn();
|
||||
int loadBlock();
|
||||
void loadObjects();
|
||||
void loadRoutes();
|
||||
void loadLocations();
|
||||
void loadNavData();
|
||||
static const PHYSFS_uint8 _topHeaderSize = 28;
|
||||
static const PHYSFS_uint64 _baseSize = 262144;
|
||||
};
|
||||
|
||||
class MessageDB {
|
||||
public:
|
||||
MessageDB();
|
||||
MessageDB(const std::string &file);
|
||||
~MessageDB();
|
||||
void load(const std::string &file);
|
||||
const std::string& getText(const char* id);
|
||||
const std::string& getText(const std::string &id);
|
||||
const std::string& getText(const uint32_t id);
|
||||
private:
|
||||
std::map<std::string, std::string> messages;
|
||||
std::string _error;
|
||||
};
|
||||
|
||||
class Font {
|
||||
public:
|
||||
class Character {
|
||||
public:
|
||||
Character(PHYSFS_file*, uint8_t);
|
||||
~Character();
|
||||
uint8_t width;
|
||||
uint8_t *rawData;
|
||||
};
|
||||
Font(const std::string &file);
|
||||
~Font();
|
||||
uint8_t getNumChars() { return numChars; }
|
||||
uint8_t getCharHeight() { return charHeight; }
|
||||
Character *getCharById(size_t num) ;
|
||||
size_t getIdByChar(const char c) ;
|
||||
uint8_t getMoveWidth(const char c);
|
||||
|
||||
void addMapping(char c, size_t num);
|
||||
|
||||
void dumpAs(const char* filename, size_t id) ;
|
||||
unsigned char* getCharacterBitmap(size_t num, unsigned int *width,
|
||||
unsigned int *height);
|
||||
private:
|
||||
void loadMapping(const std::string &name);
|
||||
void readHeader(PHYSFS_file*);
|
||||
uint8_t charHeight;
|
||||
uint8_t numChars;
|
||||
std::vector<Character*> chars;
|
||||
std::map<char, size_t> mapping;
|
||||
Graphics8Bit::RGBPalette palette;
|
||||
unsigned char *workBuffer;
|
||||
};
|
||||
}
|
||||
#endif
|
515
pedestrian.cpp
Normal file
515
pedestrian.cpp
Normal file
@ -0,0 +1,515 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This software is provided as-is, without any express or implied *
|
||||
* warranty. In no event will the authors be held liable for any *
|
||||
* damages arising from the use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute *
|
||||
* it freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must *
|
||||
* not claim that you wrote the original software. If you use this *
|
||||
* software in a product, an acknowledgment in the product documentation *
|
||||
* would be appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must *
|
||||
* not be misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source *
|
||||
* distribution. *
|
||||
************************************************************************/
|
||||
#include "pedestrian.h"
|
||||
#include "spritemanager.h"
|
||||
#include "opengta.h"
|
||||
#include "dataholder.h"
|
||||
#include "log.h"
|
||||
|
||||
float slope_height_offset(unsigned char slope_type, float dx, float dz);
|
||||
namespace OpenGTA {
|
||||
Projectile::Projectile(uint8_t id, float r, Vector3D p, Vector3D d, Uint32 now) :
|
||||
typeId(id), rot(r), pos(p), delta(d), endsAtTick(now + 5000) {}
|
||||
|
||||
SpriteObject::Animation::Animation() :
|
||||
Util::Animation(7, 7),
|
||||
firstFrameOffset(0), moveSpeed(0.0f) {}
|
||||
|
||||
SpriteObject::Animation::Animation(const Animation & other) :
|
||||
Util::Animation(other.numFrames, 1000 / other.delay),
|
||||
firstFrameOffset(other.firstFrameOffset),
|
||||
//numFrames(other.numFrames),
|
||||
moveSpeed(other.moveSpeed) {}
|
||||
|
||||
SpriteObject::Animation::Animation(Uint16 foff, Uint8 num) :
|
||||
Util::Animation(num, 7),
|
||||
firstFrameOffset(foff), moveSpeed(0.0f) {}
|
||||
|
||||
SpriteObject::Animation::Animation(Uint16 foff, Uint8 num, float speed) :
|
||||
Util::Animation(num, 7),
|
||||
firstFrameOffset(foff), moveSpeed(speed) {}
|
||||
|
||||
SpriteObject::SpriteObject(const Vector3D & p) :
|
||||
pos(p), //animRef(&SpriteManagerHolder::Instance().getAnimationById(0)) {
|
||||
anim(SpriteManagerHolder::Instance().getAnimationById(0)) {
|
||||
sprNum = 0;
|
||||
remap = -1;
|
||||
//curFrame = 0;
|
||||
lastFrameUpdateAt = 0;
|
||||
lastUpdateAt = 0;
|
||||
rot = 0.0f;
|
||||
animActive = false;
|
||||
sprType = GraphicsBase::SpriteNumbers::ARROW;
|
||||
}
|
||||
|
||||
Uint8 SpriteObject::calcCurrentFrame(Uint32 ticks) {
|
||||
Uint32 delta = ticks - lastFrameUpdateAt;
|
||||
//assert(animRef);
|
||||
if (delta > 100) {
|
||||
//curFrame += 1;
|
||||
//INFO << "new frame: " << int(curFrame) << " total: " << sprNum + curFrame + anim.firstFrameOffset << std::endl;
|
||||
lastFrameUpdateAt = ticks;
|
||||
}
|
||||
/*
|
||||
if (curFrame > anim.numFrames)
|
||||
curFrame = 0;
|
||||
*/
|
||||
return 0;//curFrame;
|
||||
}
|
||||
|
||||
SpriteObject::SpriteObject(const SpriteObject & other) :
|
||||
pos(other.pos), anim(other.anim) {
|
||||
copyValues(other);
|
||||
}
|
||||
|
||||
void SpriteObject::copyValues(const SpriteObject & other) {
|
||||
sprNum = other.sprNum;
|
||||
//curFrame = other.curFrame;
|
||||
remap = other.remap;
|
||||
lastFrameUpdateAt = other.lastFrameUpdateAt;
|
||||
lastUpdateAt = other.lastUpdateAt;
|
||||
rot = other.rot;
|
||||
sprType = other.sprType;
|
||||
animActive = other.animActive;
|
||||
}
|
||||
|
||||
float SpriteObject::heightOverTerrain(const Vector3D & v) {
|
||||
float x, y, z;
|
||||
x = floor(v.x);
|
||||
y = floor(v.y);
|
||||
z = floor(v.z);
|
||||
PHYSFS_uint8 x_b, z_b;
|
||||
x_b = (PHYSFS_uint8)x;
|
||||
z_b = (PHYSFS_uint8)z;
|
||||
if (y < 0.0f) {
|
||||
ERROR << "Below level! at coords: " << v.x << ", " << v.y << ", " << v.z << std::endl;
|
||||
return 1.0f;
|
||||
}
|
||||
OpenGTA::Map & map = OpenGTA::MapHolder::Instance().get();
|
||||
while (y >= map.getNumBlocksAtNew(x_b, z_b) && y > 0.0f)
|
||||
y -= 1.0f;
|
||||
while (y < map.getNumBlocksAtNew(x_b, z_b) && y > 0.0f) {
|
||||
OpenGTA::Map::BlockInfo * block = map.getBlockAtNew(x_b, z_b, (PHYSFS_uint8)y);
|
||||
assert(block);
|
||||
if (block->blockType() > 0) {
|
||||
float bz = slope_height_offset(block->slopeType(), v.x - x, v.z - z);
|
||||
if (block->slopeType() == 0 && block->blockType() != 5)
|
||||
bz -= 1.0f;
|
||||
return v.y - (y + bz);
|
||||
}
|
||||
y -= 1.0f;
|
||||
}
|
||||
y = floor(v.y) + 1.0f;
|
||||
while (y < map.getNumBlocksAtNew(x_b, z_b) && y > 0.0f) {
|
||||
OpenGTA::Map::BlockInfo * block = map.getBlockAtNew(x_b, z_b, (PHYSFS_uint8)y);
|
||||
assert(block);
|
||||
if (block->blockType() > 0) {
|
||||
float bz = slope_height_offset(block->slopeType(), v.x - x, v.z - z);
|
||||
if (block->slopeType() == 0 && block->blockType() != 5)
|
||||
bz -= 1.0f;
|
||||
return v.y - (y + bz);
|
||||
}
|
||||
y += 1.0f;
|
||||
}
|
||||
INFO << "should this be reached?" << std::endl;
|
||||
return 1.0f;
|
||||
}
|
||||
|
||||
Pedestrian::Pedestrian(const Vector3D & e,
|
||||
const Vector3D & p) : SpriteObject(p),
|
||||
OBox(RollMatrix3D(0), e * 0.5f) {
|
||||
m_M.Translate(p);
|
||||
pedId = 0;
|
||||
m_control = 0;
|
||||
animId = 0;
|
||||
inGroundContact = 0;
|
||||
sprType = GraphicsBase::SpriteNumbers::PED;
|
||||
activeWeapon = 0;
|
||||
speedForces = Vector3D(0, 0, 0);
|
||||
weaponReloadedAt = 0;
|
||||
}
|
||||
|
||||
Pedestrian::Pedestrian(const Vector3D & e,
|
||||
const Vector3D & p, const Uint32 & asId) : SpriteObject(p),
|
||||
OBox(RollMatrix3D(0), e * 0.5f) {
|
||||
m_M.Translate(p);
|
||||
pedId = asId;
|
||||
m_control = 0;
|
||||
animId = 0;
|
||||
inGroundContact = 0;
|
||||
sprType = GraphicsBase::SpriteNumbers::PED;
|
||||
activeWeapon = 0;
|
||||
speedForces = Vector3D(0, 0, 0);
|
||||
weaponReloadedAt = 0;
|
||||
}
|
||||
|
||||
Pedestrian::Pedestrian(const Pedestrian & other) : SpriteObject(other),
|
||||
OBox(other.m_M, other.m_Extent) {
|
||||
//animRef(SpriteManagerHolder::Instance().getAnimationById(other.animId)) {
|
||||
copyValues(other);
|
||||
}
|
||||
|
||||
void Pedestrian::switchToAnim(const Uint32 & newId) {
|
||||
anim = Animation(SpriteManagerHolder::Instance().getAnimationById(newId));
|
||||
anim.set(Util::Animation::PLAY_FORWARD, Util::Animation::LOOP);
|
||||
animId = newId;
|
||||
//curFrame = 0;
|
||||
}
|
||||
|
||||
void SpriteObject::setAnimation(Animation & otherAnim) {
|
||||
anim = Animation(otherAnim);
|
||||
//curFrame = 0;
|
||||
// FIXME: animId?
|
||||
}
|
||||
|
||||
void Pedestrian::copyValues(const Pedestrian & other) {
|
||||
|
||||
m_control = other.m_control;
|
||||
animId = other.animId;
|
||||
pedId = other.pedId;
|
||||
inGroundContact = other.inGroundContact;
|
||||
sprType = other.sprType;
|
||||
speedForces = other.speedForces;
|
||||
activeWeapon = other.activeWeapon;
|
||||
inventory = other.inventory;
|
||||
weaponReloadedAt = other.weaponReloadedAt;
|
||||
}
|
||||
|
||||
void Pedestrian::giveItem(uint8_t id, uint32_t amount) {
|
||||
InventoryType::iterator i = inventory.find(id);
|
||||
if (i == inventory.end())
|
||||
inventory[id] = amount;
|
||||
else
|
||||
i->second += amount;
|
||||
}
|
||||
|
||||
void Pedestrian::tryMove(Vector3D nPos) {
|
||||
float x, y, z;
|
||||
x = floor(nPos.x);
|
||||
y = floor(nPos.y);
|
||||
z = floor(nPos.z);
|
||||
OpenGTA::Map & map = OpenGTA::MapHolder::Instance().get();
|
||||
OpenGTA::GraphicsBase & graphics = OpenGTA::StyleHolder::Instance().get();
|
||||
//INFO << heightOverTerrain(nPos) << std::endl;
|
||||
float hot = heightOverTerrain(nPos);
|
||||
if (hot > 0.3f)
|
||||
inGroundContact = 0;
|
||||
else if (hot < 0.0) {
|
||||
INFO << "gone below: " << hot << " at " << nPos.x << ", " << nPos.y << ", " << nPos.z << std::endl;
|
||||
nPos.y -= (hot - 0.3f);
|
||||
INFO << nPos.y << std::endl;
|
||||
inGroundContact = 1;
|
||||
}
|
||||
else {
|
||||
inGroundContact = 1;
|
||||
}
|
||||
if (y < map.getNumBlocksAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z)) && y > 0.0f) {
|
||||
//INFO << x << ", " << y << ", " << z << ": " << int(map.getNumBlocksAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z))) << std::endl;
|
||||
OpenGTA::Map::BlockInfo * block = map.getBlockAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z), PHYSFS_uint8(y));
|
||||
assert(block);/*
|
||||
if (block->blockType() > 0) {
|
||||
float bz = slope_height_offset(block->slopeType(), nPos.x - x, nPos.z - z);
|
||||
if (block->slopeType() == 0)
|
||||
bz -= 1.0f;
|
||||
if (inGroundContact) {
|
||||
nPos.y = y + bz + 0.3f;
|
||||
//pos = nPos;
|
||||
}
|
||||
else if (nPos.y - y - bz < 0.3f) {
|
||||
INFO << "ped near ground (type: " << int(block->blockType()) << " float-pos: "
|
||||
<< nPos.x << ", " << nPos.y << ", " << nPos.z << std::endl;
|
||||
inGroundContact = 1;
|
||||
nPos.y = y + bz + 0.3f;
|
||||
INFO << "height rewritten to: " << nPos.y << std::endl;
|
||||
//pos = nPos;
|
||||
|
||||
}
|
||||
}
|
||||
else {
|
||||
inGroundContact = 0;
|
||||
INFO << "lost footing: " << x << ", " << y << ", " << z << std::endl;
|
||||
}*/
|
||||
if (block->left && graphics.isBlockingSide(block->left)) { // && block->isFlat() == false) {
|
||||
if (block->isFlat()) {
|
||||
//INFO << "xblock left: " << x - pos.x << std::endl;
|
||||
if (x - pos.x < 0 && x - pos.x > -0.2f) {
|
||||
nPos.x = (nPos.x < pos.x) ? pos.x : nPos.x;
|
||||
}
|
||||
else if (x - pos.x > 0 && x - pos.x < 0.2f)
|
||||
nPos.x = pos.x;
|
||||
}
|
||||
else {
|
||||
INFO << "xblock left: " << x - pos.x << " tex: " << int(block->left) << std::endl;
|
||||
if (x - pos.x > 0 && x - pos.x < 0.2f)
|
||||
nPos.x = pos.x;
|
||||
else if (x - pos.x < 0 && x - pos.x > -0.2f)
|
||||
nPos.x = (nPos.x < pos.x) ? pos.x : nPos.x;
|
||||
}
|
||||
}
|
||||
if (block->right && block->isFlat() == false) {
|
||||
INFO << "xblock right: " << pos.x - x - 1 << " tex: " << int(block->right) << std::endl;
|
||||
if (pos.x - x - 1 > 0 && pos.x - x - 1 < 0.2f) {
|
||||
nPos.x = pos.x;
|
||||
}
|
||||
else if (pos.x - x - 1 < 0 && pos.x - x - 1 > -0.2f)
|
||||
nPos.x = (nPos.x > pos.x) ? pos.x : nPos.x;
|
||||
}
|
||||
if (block->top && graphics.isBlockingSide(block->top)) { // && block->isFlat() == false) {
|
||||
if (block->isFlat()) {
|
||||
INFO << "zblock top: " << z - pos.z << " tex: " << int(block->top) << std::endl;
|
||||
if (z - pos.z > 0 && z - pos.z < 0.2f)
|
||||
nPos.z = pos.z;
|
||||
else if (z - pos.z < 0 && z - pos.z > -0.2f)
|
||||
nPos.z = (nPos.z < pos.z) ? pos.z : nPos.z;
|
||||
}
|
||||
else {
|
||||
INFO << "zblock top: " << z - pos.z << " tex: " << int(block->top)<< std::endl;
|
||||
if (z - pos.z > 0 && z - pos.z < 0.2f)
|
||||
nPos.z = pos.z;
|
||||
else if (z - pos.z < 0 && z - pos.z > -0.2f)
|
||||
nPos.z = (nPos.z < pos.z) ? pos.z : nPos.z;
|
||||
}
|
||||
}
|
||||
if (block->bottom && block->isFlat() == false) {
|
||||
INFO << "zblock bottom: " << pos.z - z - 1<< " tex: " << int(block->bottom)<< std::endl;
|
||||
if (pos.z - z - 1 > 0 && pos.z - z - 1 < 0.2f) {
|
||||
nPos.z = pos.z;
|
||||
}
|
||||
else if (pos.z - z - 1 < 0 && pos.z - z - 1 > -0.2f)
|
||||
nPos.z = (nPos.z > pos.z) ? pos.z : nPos.z;
|
||||
}
|
||||
if (x >= 1 && y < map.getNumBlocksAtNew(PHYSFS_uint8(x-1), PHYSFS_uint8(z))) {
|
||||
block = map.getBlockAtNew(PHYSFS_uint8(x-1), PHYSFS_uint8(z), PHYSFS_uint8(y));
|
||||
if (block->right && block->isFlat() == false) {
|
||||
INFO << "xblock right: " << pos.x - x << " tex: " << int(block->right)<< std::endl;
|
||||
if (pos.x - x < 0.2f) {
|
||||
nPos.x = (nPos.x < pos.x ? pos.x : nPos.x);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (x < 255 && y < map.getNumBlocksAtNew(PHYSFS_uint8(x+1), PHYSFS_uint8(z))) {
|
||||
block = map.getBlockAtNew(PHYSFS_uint8(x+1), PHYSFS_uint8(z), PHYSFS_uint8(y));
|
||||
if (block->left && graphics.isBlockingSide(block->left)) { // && block->isFlat() == false) {
|
||||
INFO << "xblock left: " << x + 1 - pos.x << " tex: " << int(block->left)<< std::endl;
|
||||
if (block->isFlat()) {
|
||||
if (x + 1 - pos.x > 0 && x + 1 - pos.x < 0.2f)
|
||||
nPos.x = (nPos.x < pos.x ? nPos.x : pos.x);
|
||||
}
|
||||
else {
|
||||
if (x + 1 - pos.x < 0.2f)
|
||||
nPos.x = (nPos.x < pos.x ? nPos.x : pos.x);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (z >= 1 && y < map.getNumBlocksAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z-1))) {
|
||||
block = map.getBlockAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z-1), PHYSFS_uint8(y));
|
||||
if (block->bottom && block->isFlat() == false) {
|
||||
INFO << "zblock bottom: " << pos.z - z<< " tex: " << int(block->bottom)<< std::endl;
|
||||
if (pos.z - z < 0.2f) {
|
||||
nPos.z = (nPos.z < pos.z ? pos.z : nPos.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (z < 255 && y < map.getNumBlocksAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z+1))) {
|
||||
block = map.getBlockAtNew(PHYSFS_uint8(x), PHYSFS_uint8(z+1), PHYSFS_uint8(y));
|
||||
if (block->top && graphics.isBlockingSide(block->top)) { // && block->isFlat() == false) {
|
||||
INFO << "zblock top: " << z + 1 - pos.z<< " tex: " << int(block->top) << std::endl;
|
||||
if (block->isFlat()) {
|
||||
if (z + 1 - pos.z > 0 && z + 1 - pos.z < 0.2f)
|
||||
nPos.z = (nPos.z < pos.z ? nPos.z : pos.z);
|
||||
}
|
||||
else {
|
||||
if (z + 1 - pos.z < 0.2f)
|
||||
nPos.z = (nPos.z < pos.z ? nPos.z : pos.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
//if (inGroundContact)
|
||||
// pos = nPos;
|
||||
}
|
||||
if (inGroundContact)
|
||||
pos = nPos;
|
||||
//else
|
||||
// inGroundContact = 0;
|
||||
|
||||
}
|
||||
|
||||
void Pedestrian::equip(uint8_t id) {
|
||||
if (id == 0) {
|
||||
activeWeapon = 0;
|
||||
}
|
||||
else {
|
||||
InventoryType::iterator i = inventory.find(id);
|
||||
if (i != inventory.end()) {
|
||||
activeWeapon = i->first;
|
||||
}
|
||||
else
|
||||
ERROR << "Ped does not have item type " << int(id) << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void Pedestrian::fireWeapon(Uint32 ticks) {
|
||||
if (activeWeapon == 0)
|
||||
return; // FIXME: punching!
|
||||
InventoryType::iterator i = inventory.find(activeWeapon);
|
||||
if (i->second == 0)
|
||||
return; // no ammo
|
||||
if (ticks < weaponReloadedAt)
|
||||
return;
|
||||
|
||||
weaponReloadedAt = ticks + 2000;
|
||||
OpenGTA::SpriteManagerHolder::Instance().createProjectile(i->first, rot, pos, Vector3D(0.2f, 0, 0.2f), ticks);
|
||||
|
||||
}
|
||||
|
||||
void Pedestrian::update(Uint32 ticks) {
|
||||
// update the animation
|
||||
if (m_control) {
|
||||
switch(m_control->move) {
|
||||
case 1:
|
||||
if (!(animId == 2u + activeWeapon*3))
|
||||
switchToAnim(2 + activeWeapon*3);
|
||||
break;
|
||||
case 2:
|
||||
if (!(animId == 3u + activeWeapon*3))
|
||||
switchToAnim(3 + activeWeapon*3);
|
||||
break;
|
||||
case 0:
|
||||
if (!(animId == 1u + activeWeapon*3))
|
||||
switchToAnim(1 + activeWeapon*3);
|
||||
break;
|
||||
case -1:
|
||||
if (!(animId == 2u + activeWeapon*3)) {
|
||||
switchToAnim(2 + activeWeapon*3);
|
||||
anim.set(Util::Animation::PLAY_BACKWARD, Util::Animation::LOOP);
|
||||
}
|
||||
}
|
||||
}
|
||||
anim.update(ticks);
|
||||
// update position/rotation
|
||||
Uint32 delta = ticks - lastUpdateAt;
|
||||
Vector3D moveDelta(0, 0, 0);
|
||||
if (m_control) {
|
||||
switch(m_control->turn) {
|
||||
case -1:
|
||||
rot -= 0.2f * delta;
|
||||
break;
|
||||
case 1:
|
||||
rot += 0.2f * delta;
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
if (rot >= 360.0f)
|
||||
rot -= 360.0f;
|
||||
if (rot < 0.0f)
|
||||
rot += 360.0f;
|
||||
switch(m_control->move) {
|
||||
case -1:
|
||||
moveDelta.x -= sin(rot * M_PI / 180.0f) * anim.moveSpeed * delta;
|
||||
moveDelta.z -= cos(rot * M_PI / 180.0f) * anim.moveSpeed * delta;
|
||||
break;
|
||||
case 1:
|
||||
moveDelta.x += sin(rot * M_PI / 180.0f) * anim.moveSpeed * delta;
|
||||
moveDelta.z += cos(rot * M_PI / 180.0f) * anim.moveSpeed * delta;
|
||||
break;
|
||||
case 2:
|
||||
moveDelta.x += sin(rot * M_PI / 180.0f) * anim.moveSpeed * delta;
|
||||
moveDelta.z += cos(rot * M_PI / 180.0f) * anim.moveSpeed * delta;
|
||||
break;
|
||||
case 0:
|
||||
break;
|
||||
}
|
||||
}
|
||||
tryMove(pos + moveDelta);
|
||||
if (!inGroundContact) {
|
||||
speedForces.y += 0.1f;
|
||||
pos.y -= speedForces.y;
|
||||
if (speedForces.y < 0.2f)
|
||||
INFO << "bridge step? height: " << pos.y << " speed: " << speedForces.y << std::endl;
|
||||
else
|
||||
INFO << "FALLING" << pos.y << " speed " << speedForces.y << std::endl;
|
||||
}
|
||||
else {
|
||||
if (speedForces.y > 0.1)
|
||||
INFO << "impacting with speed: " << speedForces.y << std::endl;
|
||||
speedForces.y = 0.0f;
|
||||
}
|
||||
lastUpdateAt = ticks;
|
||||
|
||||
}
|
||||
|
||||
#define INT2FLOAT_WRLD(c) (float(c >> 6) + float(c % 64) / 64.0f)
|
||||
#define INT2F_DIV64(v) (float(v) / 64.0f)
|
||||
#define INT2F_DIV128(v) (float(v) / 128.0f)
|
||||
|
||||
Car::Car(const OpenGTA::Map::ObjectPosition & op) :
|
||||
SpriteObject(Vector3D(INT2FLOAT_WRLD(op.x), 6.05f-INT2FLOAT_WRLD(op.z), INT2FLOAT_WRLD(op.y))),
|
||||
OBox(RollMatrix3D(0), Vector3D()),
|
||||
c_info(*StyleHolder::Instance().get().findCarByModel(op.type)) {
|
||||
type = op.type;
|
||||
sprType = GraphicsBase::SpriteNumbers::CAR;
|
||||
sprNum = c_info.sprNum;
|
||||
m_Extent = Vector3D(INT2F_DIV128(c_info.width),
|
||||
INT2F_DIV128(c_info.depth),
|
||||
INT2F_DIV128(c_info.height));
|
||||
m_M.Translate(pos);
|
||||
rot = op.rotation * 360 / 1024;
|
||||
}
|
||||
|
||||
Car::Car(const Car & other) : SpriteObject(other),
|
||||
OBox(other.m_M, other.m_Extent),
|
||||
c_info(*StyleHolder::Instance().get().findCarByModel(other.type)) {
|
||||
copyValues(other);
|
||||
}
|
||||
|
||||
void Car::copyValues(const Car & other) {
|
||||
sprType = other.sprType;
|
||||
delta = other.delta;
|
||||
carId = other.carId;
|
||||
type = other.type;
|
||||
}
|
||||
|
||||
GameObject::GameObject(const OpenGTA::Map::ObjectPosition & op) :
|
||||
SpriteObject(Vector3D(INT2FLOAT_WRLD(op.x), 6.05f-INT2FLOAT_WRLD(op.z), INT2FLOAT_WRLD(op.y))),
|
||||
OBox(RollMatrix3D(0), Vector3D()) {
|
||||
sprType = GraphicsBase::SpriteNumbers::OBJECT;
|
||||
GraphicsBase & style = StyleHolder::Instance().get();
|
||||
sprNum = style.objectInfos[op.type]->sprNum;
|
||||
m_Extent = Vector3D(INT2F_DIV128(style.objectInfos[op.type]->width),
|
||||
INT2F_DIV128(style.objectInfos[op.type]->depth),
|
||||
INT2F_DIV128(style.objectInfos[op.type]->height));
|
||||
m_M.Translate(pos);
|
||||
rot = op.rotation * 360 / 1024;
|
||||
|
||||
}
|
||||
|
||||
GameObject::GameObject(const GameObject & other) : SpriteObject(other),
|
||||
OBox(other.m_M, other.m_Extent) {
|
||||
copyValues(other);
|
||||
}
|
||||
|
||||
void GameObject::copyValues(const GameObject & other) {
|
||||
sprType = other.sprType;
|
||||
}
|
||||
}
|
134
pedestrian.h
Normal file
134
pedestrian.h
Normal file
@ -0,0 +1,134 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This software is provided as-is, without any express or implied *
|
||||
* warranty. In no event will the authors be held liable for any *
|
||||
* damages arising from the use of this software. *
|
||||
* *
|
||||
* Permission is granted to anyone to use this software for any purpose, *
|
||||
* including commercial applications, and to alter it and redistribute *
|
||||
* it freely, subject to the following restrictions: *
|
||||
* *
|
||||
* 1. The origin of this software must not be misrepresented; you must *
|
||||
* not claim that you wrote the original software. If you use this *
|
||||
* software in a product, an acknowledgment in the product documentation *
|
||||
* would be appreciated but is not required. *
|
||||
* *
|
||||
* 2. Altered source versions must be plainly marked as such, and must *
|
||||
* not be misrepresented as being the original software. *
|
||||
* *
|
||||
* 3. This notice may not be removed or altered from any source *
|
||||
* distribution. *
|
||||
************************************************************************/
|
||||
#ifndef OGTA_PEDESTRIAN_H
|
||||
#define OGTA_PEDESTRIAN_H
|
||||
|
||||
#include <SDL.h>
|
||||
#include "math3d.h"
|
||||
#include "obox.h"
|
||||
#include "animation.h"
|
||||
#include "opengta.h"
|
||||
|
||||
namespace OpenGTA {
|
||||
struct Projectile {
|
||||
Projectile(uint8_t, float, Vector3D, Vector3D, Uint32);
|
||||
uint8_t typeId;
|
||||
float rot;
|
||||
Vector3D pos;
|
||||
Vector3D delta;
|
||||
Uint32 endsAtTick;
|
||||
};
|
||||
class SpriteObject {
|
||||
public:
|
||||
SpriteObject(const Vector3D & p);
|
||||
SpriteObject(const SpriteObject & other);
|
||||
struct Animation : public Util::Animation {
|
||||
Animation();
|
||||
Animation(const Animation & other);
|
||||
Animation(Uint16 foff, Uint8 num);
|
||||
Animation(Uint16 foff, Uint8 num, float speed);
|
||||
Uint16 firstFrameOffset;
|
||||
//Uint8 numFrames;
|
||||
float moveSpeed;
|
||||
};
|
||||
Vector3D pos;
|
||||
//Uint8 curFrame;
|
||||
Uint16 sprNum;
|
||||
Sint16 remap;
|
||||
//Animation * animRef;
|
||||
Animation anim;
|
||||
bool animActive;
|
||||
void update(Uint32 ticks);
|
||||
Uint32 lastFrameUpdateAt;
|
||||
Uint32 lastUpdateAt;
|
||||
float rot;
|
||||
GraphicsBase::SpriteNumbers::SpriteTypes sprType;
|
||||
void setAnimation(Animation & otherAnim);
|
||||
protected:
|
||||
Uint8 calcCurrentFrame(Uint32 ticks);
|
||||
float heightOverTerrain(const Vector3D & v);
|
||||
private:
|
||||
void copyValues(const SpriteObject & other);
|
||||
SpriteObject & operator = (const SpriteObject & other) { return *this; }
|
||||
};
|
||||
|
||||
class Pedestrian : public SpriteObject, public OBox {
|
||||
public:
|
||||
struct Controller {
|
||||
// turn, move,
|
||||
// run/walk/swim/crawl
|
||||
// jump, shoot/punch,
|
||||
Sint8 turn;
|
||||
Sint8 move;
|
||||
};
|
||||
Pedestrian(const Vector3D & e, const Vector3D & pos);
|
||||
Pedestrian(const Vector3D & e, const Vector3D & pos, const Uint32 & asId);
|
||||
Pedestrian(const Pedestrian & other);
|
||||
Uint32 pedId;
|
||||
Controller* m_control;
|
||||
Uint32 animId;
|
||||
Vector3D speedForces;
|
||||
void switchToAnim(const Uint32 & newId);
|
||||
|
||||
void update(Uint32 ticks);
|
||||
void equip(uint8_t eq_id);
|
||||
void giveItem(uint8_t id, uint32_t amount);
|
||||
void fireWeapon(Uint32 ticks);
|
||||
private:
|
||||
typedef std::map<uint8_t, uint32_t> InventoryType;
|
||||
InventoryType inventory;
|
||||
uint8_t activeWeapon;
|
||||
bool inGroundContact;
|
||||
void tryMove(Vector3D nPos);
|
||||
void copyValues(const Pedestrian & other);
|
||||
Uint32 weaponReloadedAt;
|
||||
//Uint8 calcCurrentFrame(Uint32 ticks);
|
||||
Pedestrian & operator = (const Pedestrian & other) { return *this; }
|
||||
};
|
||||
|
||||
class Car : public SpriteObject, public OBox {
|
||||
public:
|
||||
Car(const OpenGTA::Map::ObjectPosition & op);
|
||||
Car(const Car & other);
|
||||
Uint32 delta;
|
||||
Uint32 carId;
|
||||
Uint8 type;
|
||||
private:
|
||||
GraphicsBase::CarInfo & c_info;
|
||||
void copyValues(const Car & other);
|
||||
Car & operator = (const Car & other) { return *this; }
|
||||
|
||||
};
|
||||
|
||||
class GameObject : public SpriteObject, public OBox {
|
||||
public:
|
||||
GameObject(const OpenGTA::Map::ObjectPosition & op);
|
||||
GameObject(const GameObject & other);
|
||||
Uint32 objId;
|
||||
private:
|
||||
void copyValues(const GameObject & other);
|
||||
GameObject & operator = (const GameObject & o) { return *this; }
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
277
prepare_build.sh
Executable file
277
prepare_build.sh
Executable file
@ -0,0 +1,277 @@
|
||||
#!/bin/bash
|
||||
|
||||
function program_exists() {
|
||||
$1 $2 1>/dev/null 2>&1
|
||||
if [ $? -eq 127 ]; then
|
||||
return 0
|
||||
fi
|
||||
upname=$(echo $1 | tr '[a-z]' '[A-Z]' | tr '-' '_')
|
||||
eval "$upname=$1"
|
||||
return 1
|
||||
}
|
||||
|
||||
function print_make_file_list() {
|
||||
FOO=GL_SRC
|
||||
FOOO=GL_OBJ
|
||||
( grep -l "^namespace OpenGL" *.cpp ; echo "gl_frustum.cpp";echo "math/obox.cpp coldet/math3d.cpp" ) | sort | xargs echo "$FOO ="
|
||||
echo "$FOOO = \${$FOO:.cpp=.o}"
|
||||
FOO=OGTA_SRC
|
||||
FOOO=OGTA_OBJ
|
||||
( grep -l "^namespace OpenGTA" *.cpp ; echo "slope_height_func.cpp" ) | sort | xargs echo "$FOO ="
|
||||
echo "$FOOO = \${$FOO:.cpp=.o}"
|
||||
|
||||
UTIL_SRC=$(ls util/*.cpp | grep -v color.cpp | grep -v sound | xargs echo)
|
||||
SOUND_SRC=$(ls util/*.cpp | grep sound.* | xargs echo)
|
||||
LUA_SRC=$(ls lua_addon/*.cpp | xargs echo)
|
||||
|
||||
cat <<EOF
|
||||
|
||||
|
||||
# list of used source files
|
||||
UTIL_SRC = $UTIL_SRC
|
||||
UTIL_OBJ = \${UTIL_SRC:.cpp=.o}
|
||||
LUA_SRC = $LUA_SRC
|
||||
LUA_OBJ = \${LUA_SRC:.cpp=.o}
|
||||
SOUND_SRC = $SOUND_SRC
|
||||
SOUND_OBJ = \${SOUND_SRC:.cpp=.o}
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
if [ "$1" == "WIN32" ]; then
|
||||
EXE_PFIX=.exe
|
||||
fi
|
||||
|
||||
function print_target_list() {
|
||||
cat <<EOF
|
||||
|
||||
# list of make targets (programs)
|
||||
|
||||
TARGETS = viewer${EXE_PFIX}
|
||||
LUA_TARGETS = luaviewer${EXE_PFIX}
|
||||
all: loki \${TARGETS}
|
||||
|
||||
gfxextract${EXE_PFIX}: gfx_extract.cpp read_gry.o read_g24.o read_cmp.o navdata.o dataholder.o \
|
||||
\$(UTIL_OBJ)
|
||||
\$(CXX) \$(CATCH_E) \$(GFX_DDUMP) \$(FLAGS) \$(DEFS) \$(LINK_LAZY) \\
|
||||
\$(INC) \\
|
||||
-o \$@ \$+ \\
|
||||
\$(SDL_LIB) \$(SDL_GL_LIB) \$(SDL_IMG_LIB) \$(PHYSFS_LIB) \$(LOKI_LIB)
|
||||
|
||||
viewer${EXE_PFIX}: main2.cpp viewer.o \$(OGTA_OBJ) \$(GL_OBJ) \$(UTIL_OBJ)
|
||||
\$(CXX) \$(CATCH_E) \$(FLAGS) \$(DEFS) \\
|
||||
\$(INC) \\
|
||||
-o \$@ \$+ \\
|
||||
\$(SDL_LIB) \$(SDL_GL_LIB) \$(PHYSFS_LIB) \$(LOKI_LIB) \$(COLDET_LIB)
|
||||
|
||||
luaviewer${EXE_PFIX}: main2.cpp viewer.cpp \$(OGTA_OBJ) \$(GL_OBJ) \$(UTIL_OBJ) \
|
||||
\$(LUA_OBJ)
|
||||
\$(CXX) \$(CATCH_E) -DWITH_LUA \$(FLAGS) \$(DEFS) \\
|
||||
\$(INC) \\
|
||||
-o \$@ \$+ \\
|
||||
\$(SDL_LIB) \$(SDL_GL_LIB) \$(PHYSFS_LIB) \$(LOKI_LIB) \$(COLDET_LIB) \$(LUA_LIB)
|
||||
|
||||
|
||||
spriteplayer${EXE_PFIX}: sprite_anim_player.o \$(OGTA_OBJ) \$(GL_OBJ) \$(UTIL_OBJ) main2.cpp
|
||||
\$(CXX) \$(CATCH_E) \$(FLAGS) \$(DEFS) \\
|
||||
\$(INC) \\
|
||||
-o \$@ \$+ \\
|
||||
\$(SDL_LIB) \$(SDL_GL_LIB) \$(PHYSFS_LIB) \$(LOKI_LIB) \$(COLDET_LIB)
|
||||
|
||||
slopeview: main.o tools/display_slopes.o navdata.o read_cmp.o \
|
||||
\$(UTIL_OBJ) common_sdl_gl.o
|
||||
\$(CXX) \$(CXXFLAGS) -o \$@ \$+ \$(SDL_LIB) \$(PHYSFS_LIB) -lSDL_image
|
||||
|
||||
g24: read_g24.cpp read_gry.o \$(UTIL_OBJ)
|
||||
\$(CXX) -DG24_DUMPER \$(CXXFLAGS) -o \$@ \$+ \$(SDL_LIB) \$(PHYSFS_LIB)
|
||||
|
||||
objdump: tools/obj_dump.cpp read_gry.o \$(UTIL_OBJ) main2.o
|
||||
\$(CXX) \$(CXXFLAGS) -o \$@ \$+ \$(SDL_LIB) \$(PHYSFS_LIB)
|
||||
|
||||
objdump_map: tools/obj_dump.cpp read_gry.o \$(UTIL_OBJ) main2.o read_cmp.o navdata.o
|
||||
\$(CXX) \$(CXXFLAGS) -DDUMP_OBJ_IN_MAP -o \$@ \$+ \$(SDL_LIB) \$(PHYSFS_LIB)
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
#print_make_file_list > src_list.make
|
||||
#print_target_list >> src_list.make
|
||||
|
||||
function pkg_config_haslib () {
|
||||
$PKG_CONFIG $1 1>/dev/null 2>&1
|
||||
if [ $? -eq 0 ]; then
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
}
|
||||
|
||||
function check_sdl () {
|
||||
program_exists sdl-config
|
||||
if [ $? -eq 1 ]; then
|
||||
SDL_INC=$($SDL_CONFIG --cflags)
|
||||
SDL_LIB=$($SDL_CONFIG --libs)
|
||||
else
|
||||
program_exists pkg-config
|
||||
if [ $? -eq 1 ]; then
|
||||
pkg_config_try_multiple SDL SDL sdl
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function pkg_config_try_multiple () {
|
||||
local _prefixName=$1
|
||||
shift
|
||||
while [ $# -gt 0 ]; do
|
||||
pkg_config_haslib $1
|
||||
if [ $? -eq 1 ]; then
|
||||
eval "${_prefixName}_INC=\$($PKG_CONFIG --cflags $1)"
|
||||
eval "${_prefixName}_LIB=\$($PKG_CONFIG --libs $1)"
|
||||
return
|
||||
fi
|
||||
shift
|
||||
done
|
||||
}
|
||||
|
||||
function check_lua () {
|
||||
program_exists pkg-config
|
||||
if [ $? -eq 1 ]; then
|
||||
pkg_config_try_multiple LUA lua5.1 lua51 lua5 lua
|
||||
else
|
||||
program_exists lua-config
|
||||
if [ $? -eq 1 ]; then
|
||||
LUA_INC=$($LUA_CONFIG --include)
|
||||
LUA_LIB=$($LUA_CONFIG --libs)
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
function check_physfs () {
|
||||
program_exists pkg-config
|
||||
if [ $? -eq 1 ]; then
|
||||
pkg_config_try_multiple PHYSFS physfs
|
||||
fi
|
||||
}
|
||||
|
||||
function check_compiler () {
|
||||
g++ 1>/dev/null 2>&1
|
||||
if [ $? -eq 1 ]; then
|
||||
CXX=g++
|
||||
else
|
||||
CXX=
|
||||
fi
|
||||
gcc 1>/dev/null 2>&1
|
||||
if [ $? -eq 1 ]; then
|
||||
CC=gcc
|
||||
else
|
||||
CC=
|
||||
fi
|
||||
}
|
||||
|
||||
# defaults
|
||||
|
||||
DEBUG=-ggdb
|
||||
WARN=-Wall
|
||||
OPT=-O2
|
||||
if [ "$1" == "LINUX" ]; then
|
||||
DEFS="-DLINUX -DDO_SCALEX"
|
||||
else
|
||||
DEFS="-DWIN32 -DDO_SCALEX"
|
||||
fi
|
||||
PHYSFS_LIB=-lphysfs
|
||||
SDL_LIB=-lSDL
|
||||
LUA_LIB=-llua51
|
||||
|
||||
function print_detected() {
|
||||
cat <<EOF
|
||||
# using these compilers
|
||||
CXX = $CXX
|
||||
CC = $CC
|
||||
|
||||
DEBUG = $DEBUG
|
||||
OPT = $OPT
|
||||
WARN = $WARN
|
||||
DEFS = $DEFS -DGCC
|
||||
|
||||
# def only for 'main' programs to let gdb handle the exception
|
||||
#CATCH_E = -DDONT_CATCH
|
||||
|
||||
#GFX_DDUMP = -DDUMP_DELTA_DEBUG
|
||||
|
||||
# the external libraries
|
||||
PHYSFS_INC = $PHYSFS_INC
|
||||
PHYSFS_LIB = $PHYSFS_LIB
|
||||
|
||||
SDL_INC = $SDL_INC
|
||||
SDL_LIB = $SDL_LIB
|
||||
|
||||
SDL_GL_LIB = -lGL -lGLU
|
||||
SDL_IMG_LIB = -lSDL_image
|
||||
|
||||
# this better be lua >= 5.1 (but not 5.0); not detected
|
||||
LUA_INC = $LUA_INC
|
||||
LUA_LIB = $LUA_LIB
|
||||
|
||||
LINK_LAZY = -Xlinker --unresolved-symbols -Xlinker ignore-all
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
function print_w32settings() {
|
||||
cat <<EOF
|
||||
# using these compilers
|
||||
CXX = i586-mingw32msvc-g++
|
||||
CC = i586-mingw32msvc-gcc
|
||||
|
||||
#DEBUG = $DEBUG
|
||||
OPT = $OPT
|
||||
WARN = $WARN
|
||||
DEFS = $DEFS -DGCC
|
||||
|
||||
# def only for 'main' programs to let gdb handle the exception
|
||||
#CATCH_E = -DDONT_CATCH
|
||||
|
||||
#GFX_DDUMP = -DDUMP_DELTA_DEBUG
|
||||
|
||||
# the external libraries
|
||||
PHYSFS_INC = -Iinc
|
||||
PHYSFS_LIB = -Llibs -lphysfs -lz
|
||||
|
||||
SDL_INC = -Iinc -D_GNU_SOURCE=1 -D_REENTRANT
|
||||
SDL_LIB = -Llibs -lSDLmain -lSDL
|
||||
|
||||
SDL_GL_LIB = -lopengl32 -lglu32
|
||||
SDL_IMG_LIB = -lSDL_image
|
||||
|
||||
# this better be lua >= 5.1 (but not 5.0); not detected
|
||||
LUA_INC = $LUA_INC
|
||||
LUA_LIB = $LUA_LIB
|
||||
|
||||
# good idea here?
|
||||
LINK_LAZY = -Xlinker --unresolved-symbols -Xlinker ignore-all
|
||||
|
||||
EOF
|
||||
}
|
||||
|
||||
function print_all() {
|
||||
check_sdl
|
||||
check_lua
|
||||
check_physfs
|
||||
check_compiler
|
||||
print_detected
|
||||
print_make_file_list
|
||||
print_target_list
|
||||
cat <<EOF
|
||||
|
||||
include depend
|
||||
EOF
|
||||
}
|
||||
|
||||
if [ "$1" == "LINUX" ]; then
|
||||
echo "*** LINUX ***"
|
||||
print_all > src_list.make
|
||||
else
|
||||
echo "*** WIN32 ***"
|
||||
print_w32settings > src_list.make
|
||||
print_make_file_list >> src_list.make
|
||||
print_target_list >> src_list.make
|
||||
fi
|
284
read_cmp.cpp
Normal file
284
read_cmp.cpp
Normal file
@ -0,0 +1,284 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This file contains code derived from information copyrighted by *
|
||||
* DMA Design. It may not be used in a commercial product. *
|
||||
* *
|
||||
* See license.txt for details. *
|
||||
* *
|
||||
* This notice may not be removed or altered. *
|
||||
************************************************************************/
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include "opengta.h"
|
||||
#include "navdata.h"
|
||||
#include "log.h"
|
||||
#include "m_exceptions.h"
|
||||
|
||||
/* see http://members.aol.com/form1/fixed.htm for fixed point floats:
|
||||
* int_var = (long) fixed_var >> 8; // for 8 bits after point
|
||||
*/
|
||||
namespace OpenGTA {
|
||||
|
||||
Map::Map(const std::string& filename) {
|
||||
nav = 0;
|
||||
fd = PHYSFS_openRead(filename.c_str());
|
||||
if (fd == NULL) {
|
||||
std::string f2(filename);
|
||||
transform(f2.begin(), f2.end(), f2.begin(), tolower);
|
||||
fd = PHYSFS_openRead(f2.c_str());
|
||||
}
|
||||
if (!fd) {
|
||||
//throw std::string("FileNotFound: ") + filename;
|
||||
std::ostringstream o;
|
||||
o << filename << " with error: " << SDL_GetError();
|
||||
throw E_FILENOTFOUND(o.str());
|
||||
}
|
||||
loadHeader();
|
||||
loadBase();
|
||||
loadColumn();
|
||||
loadBlock();
|
||||
loadObjects();
|
||||
loadRoutes();
|
||||
loadLocations();
|
||||
loadNavData();
|
||||
//dump();
|
||||
}
|
||||
Map::~Map() {
|
||||
if (column) delete [] column;
|
||||
if (block) delete [] block;
|
||||
if (objects) delete [] objects;
|
||||
if (nav) delete nav;
|
||||
LocationMap::iterator i = locations.begin();
|
||||
while (i != locations.end()) {
|
||||
delete i->second;
|
||||
++i;
|
||||
}
|
||||
locations.clear();
|
||||
if (fd)
|
||||
PHYSFS_close(fd);
|
||||
}
|
||||
int Map::loadHeader() {
|
||||
PHYSFS_uint32 vc;
|
||||
PHYSFS_readULE32(fd, &vc);
|
||||
//INFO << "Map version code: " << vc << std::endl;
|
||||
PHYSFS_uint8 sn;
|
||||
PHYSFS_read(fd, static_cast<void*>(&styleNumber), 1, 1);
|
||||
//INFO << "Style number: " << int(styleNumber) << std::endl;
|
||||
PHYSFS_read(fd, static_cast<void*>(&sn), 1, 1);
|
||||
//INFO << "Sample number: " << int(sn) << std::endl;
|
||||
PHYSFS_uint16 reserved;
|
||||
PHYSFS_readULE16(fd, &reserved);
|
||||
PHYSFS_readULE32(fd, &routeSize);
|
||||
PHYSFS_readULE32(fd, &objectPosSize);
|
||||
PHYSFS_readULE32(fd, &columnSize);
|
||||
PHYSFS_readULE32(fd, &blockSize);
|
||||
PHYSFS_readULE32(fd, &navDataSize);
|
||||
/*
|
||||
INFO << "Route size: " << routeSize << std::endl;
|
||||
INFO << "Object size: " << objectPosSize << std::endl;
|
||||
INFO << "Column size: " << columnSize << std::endl;
|
||||
INFO << "Block size: " << blockSize << " (" <<
|
||||
blockSize / sizeof(BlockInfo) << " blocks " << blockSize % sizeof(BlockInfo)
|
||||
<< " overcount)" << std::endl;
|
||||
INFO << "Navdata size: " << navDataSize << std::endl;
|
||||
*/
|
||||
|
||||
column = new PHYSFS_uint16[columnSize/2];
|
||||
block = new BlockInfo[blockSize / sizeof(BlockInfo) ];
|
||||
|
||||
objects = new ObjectPosition[objectPosSize / sizeof(ObjectPosition)];
|
||||
|
||||
|
||||
return 0;
|
||||
}
|
||||
int Map::loadBase() {
|
||||
PHYSFS_seek(fd, static_cast<PHYSFS_uint64>(_topHeaderSize));
|
||||
for (int y = 0; y < GTA_MAP_MAXDIMENSION; y++) {
|
||||
for(int x = 0; x < GTA_MAP_MAXDIMENSION; x++) {
|
||||
PHYSFS_readULE32(fd, &base[x][y]);
|
||||
//std::cout << x << "," << y << " : " << base[x][y] << std::endl;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int Map::loadColumn() {
|
||||
if (!PHYSFS_seek(fd, _baseSize + _topHeaderSize)) {
|
||||
//throw std::string("IO Error while seeking in mapfile");
|
||||
throw E_IOERROR(PHYSFS_getLastError());
|
||||
}
|
||||
//PHYSFS_uint16 v;
|
||||
for (unsigned int i = 0; i < columnSize/2; i++) {
|
||||
PHYSFS_readULE16(fd, &column[i]);
|
||||
//std::cout << i << ": " << v << std::endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
int Map::loadBlock() {
|
||||
PHYSFS_seek(fd, _baseSize + columnSize + _topHeaderSize);
|
||||
int i, max;
|
||||
max = blockSize / sizeof(BlockInfo);
|
||||
//uint8_t tmp;
|
||||
for (i = 0; i < max; i++) {
|
||||
PHYSFS_readULE16(fd, &block[i].typeMap);
|
||||
PHYSFS_read(fd, static_cast<void*>(&block[i].typeMapExt), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&block[i].left), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&block[i].right), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&block[i].top), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&block[i].bottom), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&block[i].lid), 1, 1);
|
||||
//block[i].animMode = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
void Map::loadObjects() {
|
||||
PHYSFS_seek(fd, _baseSize + columnSize + _topHeaderSize + blockSize);
|
||||
int c = objectPosSize / sizeof(ObjectPosition);
|
||||
numObjects = c;
|
||||
assert(objectPosSize % sizeof(ObjectPosition) == 0);
|
||||
for (int i=0; i < c; i++) {
|
||||
PHYSFS_readULE16(fd, &objects[i].x);
|
||||
PHYSFS_readULE16(fd, &objects[i].y);
|
||||
PHYSFS_readULE16(fd, &objects[i].z);
|
||||
PHYSFS_read(fd, static_cast<void*>(&objects[i].type), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&objects[i].remap), 1, 1);
|
||||
PHYSFS_readULE16(fd, &objects[i].rotation);
|
||||
PHYSFS_readULE16(fd, &objects[i].pitch);
|
||||
PHYSFS_readULE16(fd, &objects[i].roll);
|
||||
|
||||
// shift every coord? or just if any > 255
|
||||
/*
|
||||
objects[i].x = objects[i].x >> 6;
|
||||
objects[i].y = objects[i].y >> 6;
|
||||
objects[i].z = objects[i].z >> 6;*/
|
||||
/*
|
||||
std::cout << objects[i].x << "," << objects[i].y << "," << objects[i].z << " " << int(objects[i].type)
|
||||
<< " remap " << int(objects[i].remap)
|
||||
<< " rot " << objects[i].rotation << " " << objects[i].pitch << " " << objects[i].roll << std::endl;
|
||||
*/
|
||||
}
|
||||
}
|
||||
void Map::loadRoutes() {
|
||||
//FIXME: missing
|
||||
PHYSFS_uint32 _si = _baseSize + columnSize + _topHeaderSize +
|
||||
objectPosSize + blockSize;
|
||||
PHYSFS_seek(fd, _si);
|
||||
PHYSFS_uint32 _counted = 0;
|
||||
while (_counted < routeSize) {
|
||||
PHYSFS_uint8 num_vertices = 0;
|
||||
PHYSFS_uint8 route_type = 0;
|
||||
PHYSFS_read(fd, static_cast<void*>(&num_vertices), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&route_type), 1, 1);
|
||||
//INFO << "route-t " << int(route_type) << " with " << int(num_vertices) << " vertices" << std::endl;
|
||||
PHYSFS_uint8 x, y, z;
|
||||
for (int i=0; i < num_vertices; i++) {
|
||||
PHYSFS_read(fd, static_cast<void*>(&x), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&y), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&z), 1, 1);
|
||||
//INFO << int(x) << "," << int(y) << "," << int(z) << std::endl;
|
||||
_counted += 3;
|
||||
}
|
||||
|
||||
_counted += 2;
|
||||
}
|
||||
}
|
||||
Map::Location::Location() : x(0), y(0), z(0) {}
|
||||
Map::Location::Location(const Map::Location & other) : x(other.x), y(other.y), z(other.z) {}
|
||||
void Map::loadLocations() {
|
||||
//FIXME: missing
|
||||
PHYSFS_uint32 _si = _baseSize + columnSize + _topHeaderSize +
|
||||
objectPosSize + routeSize + blockSize;
|
||||
PHYSFS_seek(fd, _si);
|
||||
// police
|
||||
// hospital
|
||||
// unused
|
||||
// unused
|
||||
// fire
|
||||
// unused
|
||||
Location loc;
|
||||
PHYSFS_uint8 loc_type = 0;
|
||||
for (int i = 0; i < 36; ++i) {
|
||||
PHYSFS_read(fd, static_cast<void*>(&loc.x), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&loc.y), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&loc.z), 1, 1);
|
||||
if ((loc.x == 0) && (loc.y == 0) && (loc.z == 0))
|
||||
continue;
|
||||
if (i < 6)
|
||||
loc_type = 0;
|
||||
else if ((i >= 6) && (i < 12))
|
||||
loc_type = 1;
|
||||
else if ((i >= 24) && (i < 30))
|
||||
loc_type = 2;
|
||||
else
|
||||
continue;
|
||||
//std::cout << int(loc_type) <<": " << int(loc.x) << ", " << int(loc.y) << ", " << int(loc.z) << std::endl;
|
||||
locations.insert(std::pair<PHYSFS_uint8, Location*>(loc_type, new Location(loc)));
|
||||
}
|
||||
|
||||
}
|
||||
void Map::loadNavData() {
|
||||
PHYSFS_uint32 _si = _baseSize + columnSize + _topHeaderSize +
|
||||
objectPosSize + routeSize + 3 * 6 * 6 + blockSize;
|
||||
PHYSFS_seek(fd, _si);
|
||||
nav = new NavData(navDataSize, fd);
|
||||
assert(nav);
|
||||
}
|
||||
PHYSFS_uint16 Map::getNumBlocksAt(PHYSFS_uint8 x, PHYSFS_uint8 y) {
|
||||
return column[base[x][y] / 2];
|
||||
}
|
||||
PHYSFS_uint16 Map::getNumBlocksAtNew(PHYSFS_uint8 x, PHYSFS_uint8 y) {
|
||||
return 6 - column[base[x][y] / 2];
|
||||
}
|
||||
Map::BlockInfo* Map::getBlockAt(PHYSFS_uint8 x, PHYSFS_uint8 y, PHYSFS_uint8 z) {
|
||||
PHYSFS_uint16 v = column[base[x][y] / 2 + z];
|
||||
return &block[v];
|
||||
}
|
||||
Map::BlockInfo* Map::getBlockAtNew(PHYSFS_uint8 x, PHYSFS_uint8 y, PHYSFS_uint8 z) {
|
||||
PHYSFS_uint16 idx0 = 6 - column[base[x][y] / 2];
|
||||
if (idx0 > z)
|
||||
idx0 -= z;
|
||||
else
|
||||
assert(idx0 > z);
|
||||
idx0 = column[base[x][y] / 2 + idx0];
|
||||
return &block[idx0];
|
||||
}
|
||||
PHYSFS_uint16 Map::getInternalIdAt(PHYSFS_uint8 x, PHYSFS_uint8 y, PHYSFS_uint8 z) {
|
||||
return column[base[x][y] / 2 + z];
|
||||
}
|
||||
Map::BlockInfo* Map::getBlockByInternalId(PHYSFS_uint16 id) {
|
||||
return &block[id];
|
||||
}
|
||||
void Map::dump() {
|
||||
for (int y = 0; y < GTA_MAP_MAXDIMENSION; y++) {
|
||||
for(int x = 0; x < GTA_MAP_MAXDIMENSION; x++) {
|
||||
std::cout << x << "," << y << ":" << column[base[x][y] / 2] << "||";
|
||||
PHYSFS_uint16 ts = column[base[x][y] / 2];
|
||||
std::cout << "(";
|
||||
for(int t=1; t <= (6 - ts); t++) {
|
||||
BlockInfo *info = &block[column[base[x][y] / 2 + t]];
|
||||
std::cout << int(info->slopeType()) << ", ";
|
||||
|
||||
}
|
||||
std::cout << ")" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
#include <stdlib.h>
|
||||
void do_exit() {
|
||||
PHYSFS_deinit();
|
||||
}
|
||||
int main(int argc, char* argv[]) {
|
||||
PHYSFS_init(argv[0]);
|
||||
atexit(do_exit);
|
||||
std::cout << "Physfs-Base: " << PHYSFS_getBaseDir() << std::endl;
|
||||
PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1);
|
||||
std::cout << "Has: " << argv[1] << " : " << PHYSFS_exists(argv[1]) << std::endl;
|
||||
OpenGTA::Map a(argv[1]);
|
||||
a.dump();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
428
read_fnt.cpp
Normal file
428
read_fnt.cpp
Normal file
@ -0,0 +1,428 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This file contains code derived from information copyrighted by *
|
||||
* DMA Design. It may not be used in a commercial product. *
|
||||
* *
|
||||
* See license.txt for details. *
|
||||
* *
|
||||
* This notice may not be removed or altered. *
|
||||
************************************************************************/
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include "cistring.h"
|
||||
#include "opengta.h"
|
||||
#include "m_exceptions.h"
|
||||
#include "log.h"
|
||||
|
||||
namespace OpenGTA {
|
||||
Font::Font(const std::string &file) {
|
||||
PHYSFS_file *fd = PHYSFS_openRead(file.c_str());
|
||||
if (fd == NULL) {
|
||||
std::string f2(file);
|
||||
transform(f2.begin(), f2.end(), f2.begin(), tolower);
|
||||
fd = PHYSFS_openRead(f2.c_str());
|
||||
}
|
||||
if (!fd)
|
||||
throw E_FILENOTFOUND(file);
|
||||
//throw std::string("FileNotFound: ") + file;
|
||||
readHeader(fd);
|
||||
int ww = 0;
|
||||
int lw = 0;
|
||||
for (uint8_t i = 0; i < numChars; i++) {
|
||||
Character * ch = new Character(fd, charHeight);
|
||||
ww += ch->width;
|
||||
if (ch->width > lw)
|
||||
lw = ch->width;
|
||||
chars.push_back(ch);
|
||||
}
|
||||
INFO << "total width " << ww << " largest width " << lw << std::endl;
|
||||
palette.loadFromFile(fd);
|
||||
PHYSFS_close(fd);
|
||||
size_t ih = charHeight;
|
||||
while (ww > 1024) {
|
||||
ih *= 2;
|
||||
ww /= 2;
|
||||
}
|
||||
workBuffer = new unsigned char[lw*charHeight*4];
|
||||
loadMapping(file);
|
||||
}
|
||||
Font::~Font() {
|
||||
std::vector<Character*>::iterator i = chars.begin();
|
||||
while(i != chars.end()) {
|
||||
delete *i;
|
||||
i++;
|
||||
}
|
||||
chars.clear();
|
||||
delete [] workBuffer;
|
||||
}
|
||||
void Font::readHeader(PHYSFS_file *fd) {
|
||||
PHYSFS_read(fd, static_cast<void*>(&numChars), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&charHeight), 1, 1);
|
||||
INFO << "Font contains " << int(numChars) <<
|
||||
" characters of height " << int(charHeight) << std::endl;
|
||||
}
|
||||
void Font::addMapping(char c, size_t num) {
|
||||
mapping[c] = num;
|
||||
}
|
||||
Font::Character* Font::getCharById(size_t num) {
|
||||
return chars[num];
|
||||
}
|
||||
size_t Font::getIdByChar(const char c) {
|
||||
std::map<char, size_t>::iterator i = mapping.find(c);
|
||||
if (i == mapping.end())
|
||||
return 0;
|
||||
else
|
||||
return i->second;
|
||||
}
|
||||
uint8_t Font::getMoveWidth(const char c) {
|
||||
std::map<char, size_t>::iterator i = mapping.find(c);
|
||||
if (i == mapping.end()) {
|
||||
return chars[0]->width;
|
||||
}
|
||||
return chars[i->second]->width;
|
||||
}
|
||||
|
||||
unsigned char* Font::getCharacterBitmap(size_t num, unsigned int *width, unsigned int *height) {
|
||||
unsigned int len = chars[num]->width;
|
||||
len *= charHeight;
|
||||
palette.apply(len, chars[num]->rawData, workBuffer, true);
|
||||
if (width != NULL)
|
||||
*width = chars[num]->width;
|
||||
if (height != NULL)
|
||||
*height = charHeight;
|
||||
return workBuffer;
|
||||
/*
|
||||
unsigned int glwidth = 1;
|
||||
unsigned int glheight = 1;
|
||||
|
||||
while(glwidth < chars[num]->width)
|
||||
glwidth <<= 1;
|
||||
|
||||
while(glheight < charHeight)
|
||||
glheight <<= 1;
|
||||
unsigned char *res = new unsigned char[glwidth*glheight*4];
|
||||
*/
|
||||
}
|
||||
void Font::dumpAs(const char* filename, size_t id) {
|
||||
unsigned int len = chars[id]->width;
|
||||
len *= charHeight;
|
||||
palette.apply(len, chars[id]->rawData, workBuffer, true);
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
#define rmask 0xff000000
|
||||
#define gmask 0x00ff0000
|
||||
#define bmask 0x0000ff00
|
||||
#define amask 0x000000ff
|
||||
#else
|
||||
#define rmask 0x000000ff
|
||||
#define gmask 0x0000ff00
|
||||
#define bmask 0x00ff0000
|
||||
#define amask 0xff000000
|
||||
#endif
|
||||
SDL_Surface* s = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA,
|
||||
chars[id]->width, charHeight, 32, rmask, gmask, bmask, amask);
|
||||
SDL_LockSurface(s);
|
||||
unsigned char* dst = static_cast<unsigned char*>(s->pixels);
|
||||
unsigned char * rp = workBuffer;
|
||||
for (unsigned int i=0; i<len; i++) {
|
||||
*dst = *rp; ++dst;++rp;
|
||||
*dst = *rp; ++dst;++rp;
|
||||
*dst = *rp; ++dst;++rp;
|
||||
//*dst = 0xff; ++dst;
|
||||
*dst = *rp; ++dst;++rp;
|
||||
}
|
||||
SDL_UnlockSurface(s);
|
||||
SDL_SaveBMP(s, filename);
|
||||
SDL_FreeSurface(s);
|
||||
}
|
||||
Font::Character::Character(PHYSFS_file *fd, uint8_t height) {
|
||||
PHYSFS_read(fd, static_cast<void*>(&width), 1, 1);
|
||||
int c = int(width);
|
||||
c *= int(height);
|
||||
//std::cout <<"width " << int(width) << " going to read " << c << " bytes" << std::endl;
|
||||
rawData = new uint8_t[c];
|
||||
PHYSFS_read(fd, static_cast<void*>(rawData), 1, c);
|
||||
}
|
||||
Font::Character::~Character() {
|
||||
delete [] rawData;
|
||||
}
|
||||
|
||||
void Font::loadMapping(const std::string & name) {
|
||||
Util::ci_string name2(name.c_str());
|
||||
#define chr(n) ((char)(n))
|
||||
if (name2.find("big1.fon") != std::string::npos) {
|
||||
INFO << "found mapping: big1.fon - " << name << std::endl;
|
||||
addMapping('!', 0);
|
||||
addMapping('-', 12);
|
||||
for (int j = 65; j < 91; j++) {
|
||||
addMapping(chr(j), j - 33);
|
||||
}
|
||||
for (int j = 192; j < 195; j++) {
|
||||
addMapping(chr(j), j - 97);
|
||||
}
|
||||
addMapping(196, 98);
|
||||
addMapping(198, 99);
|
||||
addMapping(199, 100);
|
||||
for (int j=200; j < 208; j++)
|
||||
addMapping(j, j - 99);
|
||||
for (int j=210; j < 213; j++)
|
||||
addMapping(j, j - 101);
|
||||
addMapping(214, 112);
|
||||
for (int j=217; j < 221; j++)
|
||||
addMapping(j, j - 104);
|
||||
addMapping(223, 117);
|
||||
}
|
||||
else if ((name2.find("pager1.fon") != std::string::npos) ||
|
||||
(name2.find("pager2.fon") != std::string::npos)) {
|
||||
addMapping('!', 0);
|
||||
addMapping('"', 1);
|
||||
addMapping('$', 3);
|
||||
addMapping('\'', 6);
|
||||
addMapping('(', 7);
|
||||
addMapping(')', 8);
|
||||
addMapping(',', 11);
|
||||
addMapping('.', 13);
|
||||
for (int j = 48; j < 58; j++) {
|
||||
addMapping(chr(j), j - 33);
|
||||
}
|
||||
addMapping(':', 25);
|
||||
addMapping(';', 26);
|
||||
addMapping('<', 27);
|
||||
addMapping('>', 29);
|
||||
addMapping('?', 30);
|
||||
addMapping('_', 62);
|
||||
for (int j = 65; j < 91; j++) {
|
||||
addMapping(chr(j), j - 33);
|
||||
}
|
||||
for (int j = 192; j < 195; j++) {
|
||||
addMapping(chr(j), j - 97);
|
||||
}
|
||||
addMapping(196, 98);
|
||||
addMapping(198, 99);
|
||||
addMapping(199, 100);
|
||||
for (int j=200; j < 208; j++)
|
||||
addMapping(j, j - 99);
|
||||
for (int j=210; j < 213; j++)
|
||||
addMapping(j, j - 101);
|
||||
addMapping(214, 112);
|
||||
for (int j=217; j < 221; j++)
|
||||
addMapping(j, j - 104);
|
||||
addMapping(223, 117);
|
||||
}
|
||||
else if (name2.find("street1.fon") != std::string::npos) {
|
||||
INFO << "found mapping: street1.fon - " << name << std::endl;
|
||||
for (int j = 65; j < 91; j++) {
|
||||
addMapping(chr(j), j - 33);
|
||||
}
|
||||
for (int j = 48; j < 58; j++) {
|
||||
addMapping(chr(j), j - 33);
|
||||
}
|
||||
for (int j = 97; j < 123; j++) {
|
||||
addMapping(chr(j), j - 33);
|
||||
}
|
||||
WARN << "incomplete mapping" << std::endl;
|
||||
}
|
||||
else if ((name2.find("m_mmiss.fon") != std::string::npos)) {
|
||||
addMapping('!', 0);
|
||||
addMapping('"', 1);
|
||||
addMapping('#', 2);
|
||||
addMapping('$', 3);
|
||||
addMapping('\'', 6);
|
||||
addMapping('(', 7);
|
||||
addMapping(')', 8);
|
||||
addMapping('+', 10);
|
||||
addMapping(',', 11);
|
||||
addMapping('.', 13);
|
||||
addMapping('/', 14);
|
||||
addMapping(':', 25);
|
||||
addMapping(';', 26);
|
||||
addMapping('<', 27);
|
||||
addMapping('=', 28);
|
||||
addMapping('>', 29);
|
||||
addMapping('?', 30);
|
||||
addMapping('\\', 59);
|
||||
addMapping('[', 58);
|
||||
addMapping(']', 60);
|
||||
addMapping('|', 91);
|
||||
addMapping('~', 93);
|
||||
for (int j = 65; j < 91; j++) {
|
||||
addMapping(chr(j), j - 33);
|
||||
}
|
||||
for (int j = 97; j < 123; j++) {
|
||||
addMapping(chr(j), j - 33);
|
||||
}
|
||||
for (int j = 48; j < 58; j++) {
|
||||
addMapping(chr(j), j - 33);
|
||||
}
|
||||
for (int j = 192; j < 195; j++) {
|
||||
addMapping(chr(j), j - 97);
|
||||
}
|
||||
// incomplete
|
||||
}
|
||||
else if ((name2.find("f_mtext.fon") != std::string::npos)) {
|
||||
addMapping('!', 0);
|
||||
addMapping('"', 1);
|
||||
addMapping('#', 2);
|
||||
addMapping('$', 3);
|
||||
addMapping('%', 4);
|
||||
addMapping('\'', 6);
|
||||
addMapping('(', 7);
|
||||
addMapping(')', 8);
|
||||
addMapping(169, 9); // copyright
|
||||
addMapping(',', 11);
|
||||
addMapping('-', 12);
|
||||
addMapping('.', 13);
|
||||
addMapping('/', 14);
|
||||
addMapping(':', 25);
|
||||
addMapping(';', 26);
|
||||
addMapping('<', 27);
|
||||
addMapping('=', 28);
|
||||
addMapping('>', 29);
|
||||
addMapping('?', 30);
|
||||
for (int j = 48; j < 58; j++) {
|
||||
addMapping(chr(j), j - 33);
|
||||
}
|
||||
addMapping('\\', 59);
|
||||
for (int j = 65; j < 91; j++) {
|
||||
addMapping(chr(j), j - 33);
|
||||
}
|
||||
for (int j = 97; j < 123; j++) {
|
||||
addMapping(chr(j), j - 33);
|
||||
}
|
||||
// incomplete
|
||||
|
||||
}
|
||||
else if ((name2.find("f_mhead.fon") != std::string::npos)) {
|
||||
addMapping('!', 0);
|
||||
addMapping('"', 1);
|
||||
addMapping('#', 2);
|
||||
addMapping('$', 3);
|
||||
addMapping('\'', 6);
|
||||
addMapping('(', 7);
|
||||
addMapping(')', 8);
|
||||
addMapping(',', 11);
|
||||
addMapping('.', 13);
|
||||
addMapping('/', 14);
|
||||
addMapping(':', 25);
|
||||
addMapping(';', 26);
|
||||
addMapping('<', 27);
|
||||
addMapping('>', 29);
|
||||
addMapping('?', 30);
|
||||
addMapping('\\', 59);
|
||||
for (int j = 65; j < 91; j++) {
|
||||
addMapping(chr(j), j - 33);
|
||||
}
|
||||
for (int j = 97; j < 123; j++) {
|
||||
addMapping(chr(j), j - 33);
|
||||
}
|
||||
for (int j = 48; j < 58; j++) {
|
||||
addMapping(chr(j), j - 33);
|
||||
}
|
||||
for (int j = 192; j < 195; j++) {
|
||||
addMapping(chr(j), j - 97);
|
||||
}
|
||||
addMapping(196, 98);
|
||||
addMapping(198, 99);
|
||||
addMapping(199, 100);
|
||||
for (int j=200; j < 208; j++)
|
||||
addMapping(j, j - 99);
|
||||
for (int j=210; j < 213; j++)
|
||||
addMapping(j, j - 101);
|
||||
addMapping(214, 112);
|
||||
for (int j=217; j < 221; j++)
|
||||
addMapping(j, j - 104);
|
||||
addMapping(223, 117);
|
||||
for (int j=224; j < 227; j++)
|
||||
addMapping(j, j - 106);
|
||||
addMapping(228, 121);
|
||||
for (int j=230; j < 240; j++)
|
||||
addMapping(j, j - 108);
|
||||
for (int j=242; j < 245; j++)
|
||||
addMapping(j, j - 110);
|
||||
addMapping(246, 135);
|
||||
for (int j=249; j < 253; j++)
|
||||
addMapping(j, j - 113);
|
||||
|
||||
}
|
||||
else if ((name2.find("sub1.fon") != std::string::npos) ||
|
||||
(name2.find("sub2.fon") != std::string::npos)) {
|
||||
addMapping('!', 0);
|
||||
addMapping('"', 1);
|
||||
addMapping('$', 3);
|
||||
addMapping('\'', 6); // ´
|
||||
addMapping('(', 7);
|
||||
addMapping(')', 8);
|
||||
addMapping(',', 11);
|
||||
addMapping('-', 12); // not in street1/2
|
||||
addMapping('.', 13);
|
||||
addMapping('/', 14);
|
||||
addMapping(':', 25);
|
||||
addMapping(';', 26);
|
||||
addMapping('<', 27);
|
||||
addMapping('>', 29);
|
||||
addMapping('?', 30);
|
||||
|
||||
for (int j = 65; j < 91; j++) {
|
||||
addMapping(chr(j), j - 33);
|
||||
}
|
||||
for (int j = 97; j < 123; j++) {
|
||||
addMapping(chr(j), j - 33);
|
||||
}
|
||||
for (int j = 48; j < 58; j++) {
|
||||
addMapping(chr(j), j - 33);
|
||||
}
|
||||
for (int j = 192; j < 195; j++) {
|
||||
addMapping(chr(j), j - 97);
|
||||
}
|
||||
addMapping(196, 98);
|
||||
addMapping(198, 99);
|
||||
addMapping(199, 100);
|
||||
for (int j=200; j < 208; j++)
|
||||
addMapping(j, j - 99);
|
||||
for (int j=210; j < 213; j++)
|
||||
addMapping(j, j - 101);
|
||||
addMapping(214, 112);
|
||||
for (int j=217; j < 221; j++)
|
||||
addMapping(j, j - 104);
|
||||
addMapping(223, 117);
|
||||
for (int j=224; j < 227; j++)
|
||||
addMapping(j, j - 106);
|
||||
addMapping(228, 121);
|
||||
for (int j=230; j < 240; j++)
|
||||
addMapping(j, j - 108);
|
||||
for (int j=242; j < 245; j++)
|
||||
addMapping(j, j - 110);
|
||||
addMapping(246, 135);
|
||||
for (int j=249; j < 253; j++)
|
||||
addMapping(j, j - 113);
|
||||
}
|
||||
else if ((name2.find("score1.fon") != std::string::npos)||
|
||||
(name2.find("score2.fon") != std::string::npos) ||
|
||||
(name2.find("score8.fon") != std::string::npos)) {
|
||||
for (int j = 48; j < 58; j++) {
|
||||
addMapping(chr(j), j - 48);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ERROR << "mapping for font " << name << " is not known" << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FONT_DUMP_TOOL
|
||||
#include <stdlib.h>
|
||||
void do_exit() {
|
||||
PHYSFS_deinit();
|
||||
}
|
||||
int main(int argc, char* argv[]) {
|
||||
PHYSFS_init(argv[0]);
|
||||
atexit(do_exit);
|
||||
std::cout << "Physfs-Base: " << PHYSFS_getBaseDir() << std::endl;
|
||||
PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1);
|
||||
PHYSFS_addToSearchPath("gtadata.zip", 1);
|
||||
std::cout << "Has: " << argv[1] << " : " << PHYSFS_exists(argv[1]) << std::endl;
|
||||
OpenGTA::Font a(argv[1]);
|
||||
a.dumpAs("out.bmp", atoi(argv[2]));
|
||||
return 0;
|
||||
}
|
||||
#endif
|
135
read_fxt.cpp
Normal file
135
read_fxt.cpp
Normal file
@ -0,0 +1,135 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This file contains code derived from information copyrighted by *
|
||||
* DMA Design. It may not be used in a commercial product. *
|
||||
* *
|
||||
* See license.txt for details. *
|
||||
* *
|
||||
* This notice may not be removed or altered. *
|
||||
************************************************************************/
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include "opengta.h"
|
||||
|
||||
namespace OpenGTA {
|
||||
MessageDB::MessageDB() {
|
||||
load("ENGLISH.FXT");
|
||||
_error = "ERROR";
|
||||
}
|
||||
MessageDB::MessageDB(const std::string &file) {
|
||||
load(file);
|
||||
}
|
||||
MessageDB::~MessageDB() {
|
||||
messages.clear();
|
||||
}
|
||||
void MessageDB::load(const std::string &file) {
|
||||
PHYSFS_file* f = PHYSFS_openRead(file.c_str());
|
||||
if (f == NULL) {
|
||||
std::string f2(file);
|
||||
transform(f2.begin(), f2.end(), f2.begin(), tolower);
|
||||
f = PHYSFS_openRead(f2.c_str());
|
||||
}
|
||||
if (f == NULL) {
|
||||
std::cerr << "Error: could not open " << file << " for reading" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
messages.clear();
|
||||
|
||||
unsigned char v;
|
||||
int c = -1;
|
||||
unsigned char addVal = 0;
|
||||
char buff[200];
|
||||
int i = 0;
|
||||
std::string tmp;
|
||||
while (!PHYSFS_eof(f)) {
|
||||
PHYSFS_read(f, static_cast<void*>(&v), 1, 1);
|
||||
|
||||
/* thanks to: Michael Mendelsohn
|
||||
* http://gta.mendelsohn.de/
|
||||
*/
|
||||
|
||||
v--; // decode: decrease by one
|
||||
c++; // helper: count bytes read
|
||||
if (c <= 7) // polyalphabetic code for the first 8 bytes
|
||||
v -= (0x63 << c);
|
||||
/* another twist: skip and add 64 (minus decoding) to next */
|
||||
if (v == 195) {
|
||||
addVal = 64;
|
||||
}
|
||||
else {
|
||||
v += addVal;
|
||||
addVal = 0;
|
||||
if (v == '[') {
|
||||
i = 0;
|
||||
}
|
||||
else if (v == ']') {
|
||||
buff[i] = 0x00;
|
||||
tmp = std::string(buff);
|
||||
i = 0;
|
||||
}
|
||||
else if (v == 0x00) {
|
||||
buff[i] = 0x00;
|
||||
if (tmp.length() > 0)
|
||||
messages[tmp] = std::string(buff);
|
||||
//std::cout << tmp << " : " << buff << std::endl;
|
||||
/*else
|
||||
std::cout << "Skipping: " << tmp << ": " << buff << std::endl;*/
|
||||
}
|
||||
else {
|
||||
buff[i] = v;
|
||||
i++;
|
||||
if (i>199)
|
||||
i=0;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
PHYSFS_close(f);
|
||||
}
|
||||
|
||||
const std::string& MessageDB::getText(const char* id) {
|
||||
std::map<std::string, std::string>::iterator i = messages.find(std::string(id));
|
||||
if (i == messages.end()) {
|
||||
std::cerr << "Error: string lookup failed for key: " << id << std::endl;
|
||||
return _error;
|
||||
}
|
||||
return i->second;
|
||||
}
|
||||
|
||||
const std::string& MessageDB::getText(const std::string &id) {
|
||||
std::map<std::string, std::string>::iterator i = messages.find(id);
|
||||
if (i == messages.end()) {
|
||||
std::cerr << "Error: string lookup failed for key: " << id << std::endl;
|
||||
return _error;
|
||||
}
|
||||
return i->second;
|
||||
}
|
||||
|
||||
const std::string& MessageDB::getText(const uint32_t id) {
|
||||
char tmp[10];
|
||||
snprintf(reinterpret_cast<char*>(&tmp), 10, "%i", id);
|
||||
std::map<std::string, std::string>::iterator i = messages.find(std::string(tmp));
|
||||
if (i == messages.end()) {
|
||||
std::cerr << "Error: string lookup failed for key: " << id << std::endl;
|
||||
return _error;
|
||||
}
|
||||
return i->second;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#if FXT_TEST
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
PHYSFS_init(argv[0]);
|
||||
PHYSFS_addToSearchPath("gtadata.zip", 1);
|
||||
OpenGTA::MessageDB* strings = new OpenGTA::MessageDB();
|
||||
std::cout << strings->getText(1001) << std::endl;
|
||||
|
||||
delete strings;
|
||||
PHYSFS_deinit();
|
||||
}
|
||||
|
||||
#endif
|
473
read_g24.cpp
Normal file
473
read_g24.cpp
Normal file
@ -0,0 +1,473 @@
|
||||
/************************************************************************
|
||||
* Copyright (c) 2005-2006 tok@openlinux.org.uk *
|
||||
* *
|
||||
* This file contains code derived from information copyrighted by *
|
||||
* DMA Design. It may not be used in a commercial product. *
|
||||
* *
|
||||
* See license.txt for details. *
|
||||
* *
|
||||
* This notice may not be removed or altered. *
|
||||
************************************************************************/
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
#include "opengta.h"
|
||||
#include "buffercache.h"
|
||||
#include "log.h"
|
||||
|
||||
using namespace Util;
|
||||
namespace OpenGTA {
|
||||
|
||||
#define GTA_GRAPHICS_GRX 290
|
||||
#define GTA_GRAPHICS_GRY 325
|
||||
#define GTA_GRAPHICS_G24 336
|
||||
|
||||
Graphics24Bit::Graphics24Bit(const std::string& style) : GraphicsBase() {
|
||||
fd = PHYSFS_openRead(style.c_str());
|
||||
assert(fd!=NULL);
|
||||
_topHeaderSize = 64;
|
||||
rawClut = NULL;
|
||||
palIndex = NULL;
|
||||
loadHeader();
|
||||
setupBlocking(style);
|
||||
}
|
||||
|
||||
Graphics24Bit::~Graphics24Bit() {
|
||||
if (rawClut)
|
||||
delete [] rawClut;
|
||||
if (palIndex)
|
||||
delete [] palIndex;
|
||||
PHYSFS_close(fd);
|
||||
}
|
||||
|
||||
void Graphics24Bit::loadHeader() {
|
||||
PHYSFS_uint32 vc;
|
||||
PHYSFS_readULE32(fd, &vc);
|
||||
if(vc != GTA_GRAPHICS_G24) {
|
||||
ERROR << "graphics file specifies version " << vc <<
|
||||
" instead of " << GTA_GRAPHICS_G24 << std::endl;
|
||||
return;
|
||||
}
|
||||
PHYSFS_readULE32(fd, &sideSize);
|
||||
PHYSFS_readULE32(fd, &lidSize);
|
||||
PHYSFS_readULE32(fd, &auxSize);
|
||||
PHYSFS_readULE32(fd, &animSize);
|
||||
PHYSFS_readULE32(fd, &clutSize);
|
||||
PHYSFS_readULE32(fd, &tileclutSize);
|
||||
PHYSFS_readULE32(fd, &spriteclutSize);
|
||||
PHYSFS_readULE32(fd, &newcarclutSize);
|
||||
PHYSFS_readULE32(fd, &fontclutSize);
|
||||
PHYSFS_readULE32(fd, &paletteIndexSize);
|
||||
PHYSFS_readULE32(fd, &objectInfoSize);
|
||||
PHYSFS_readULE32(fd, &carInfoSize);
|
||||
PHYSFS_readULE32(fd, &spriteInfoSize);
|
||||
PHYSFS_readULE32(fd, &spriteGraphicsSize);
|
||||
PHYSFS_readULE32(fd, &spriteNumberSize);
|
||||
|
||||
/*
|
||||
INFO << "Version: " << vc << std::endl << " Block textures: S " << sideSize / 4096 << " L " <<
|
||||
lidSize / 4096 << " A " << auxSize / 4096 << std::endl;
|
||||
*/
|
||||
if (sideSize % 4096 != 0) {
|
||||
ERROR << "Side-Block texture size is not a multiple of 4096" << std::endl;
|
||||
return;
|
||||
}
|
||||
if (lidSize % 4096 != 0) {
|
||||
ERROR << "Lid-Block texture size is not a multiple of 4096" << std::endl;
|
||||
return;
|
||||
}
|
||||
if (auxSize % 4096 != 0) {
|
||||
ERROR << "Aux-Block texture size is not a multiple of 4096" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
PHYSFS_uint32 tmp = sideSize / 4096 + lidSize / 4096 + auxSize / 4096;
|
||||
tmp = tmp % 4;
|
||||
if (tmp) {
|
||||
auxBlockTrailSize = (4 - tmp) * 4096;
|
||||
INFO << "adjusting aux-block by " << auxBlockTrailSize << std::endl;
|
||||
}
|
||||
INFO << "Anim size: " << animSize << std::endl;
|
||||
INFO << "Obj-info size: " << objectInfoSize << " car-size: " << carInfoSize <<
|
||||
" sprite-info size: " << spriteInfoSize << " graphic size: " << spriteGraphicsSize <<
|
||||
" numbers s: " << spriteNumberSize << std::endl;
|
||||
if (spriteNumberSize != 42) {
|
||||
ERROR << "spriteNumberSize is " << spriteNumberSize << " (should be 42)" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
INFO << " clut: " << clutSize << " tileclut: " << tileclutSize << " spriteclut: "<< spriteclutSize <<
|
||||
" newcar: " << newcarclutSize << " fontclut: " << fontclutSize << std::endl <<
|
||||
|
||||
"Obj-info size: " << objectInfoSize << " car-size: " << carInfoSize <<
|
||||
" pal-index size: " << paletteIndexSize <<
|
||||
std::endl;
|
||||
|
||||
loadTileTextures();
|
||||
loadAnim();
|
||||
loadClut();
|
||||
loadPalIndex();
|
||||
loadObjectInfo();
|
||||
loadCarInfo();
|
||||
loadSpriteInfo();
|
||||
loadSpriteGraphics();
|
||||
loadSpriteNumbers();
|
||||
}
|
||||
|
||||
void Graphics24Bit::loadClut() {
|
||||
PHYSFS_uint64 st = static_cast<PHYSFS_uint64>(_topHeaderSize) +
|
||||
sideSize + lidSize + auxSize + auxBlockTrailSize + animSize;
|
||||
PHYSFS_seek(fd, st);
|
||||
pagedClutSize = clutSize;
|
||||
if (clutSize % 65536 != 0)
|
||||
pagedClutSize += (65536 - (clutSize % 65536));
|
||||
rawClut = new unsigned char[pagedClutSize];
|
||||
assert(rawClut);
|
||||
PHYSFS_read(fd, rawClut, 1, pagedClutSize);
|
||||
//write(2, rawClut, pagedClutSize);
|
||||
}
|
||||
|
||||
void Graphics24Bit::loadPalIndex() {
|
||||
PHYSFS_uint64 st = static_cast<PHYSFS_uint64>(_topHeaderSize) +
|
||||
sideSize + lidSize + auxSize + auxBlockTrailSize + animSize +
|
||||
pagedClutSize;
|
||||
PHYSFS_seek(fd, st);
|
||||
PHYSFS_uint16 pal_index_count = paletteIndexSize / 2;
|
||||
assert(paletteIndexSize % 2 == 0);
|
||||
palIndex = new PHYSFS_uint16[pal_index_count];
|
||||
for (PHYSFS_uint16 i = 0; i < pal_index_count; i++) {
|
||||
PHYSFS_readULE16(fd, &palIndex[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics24Bit::loadCarInfo() {
|
||||
PHYSFS_uint64 st = static_cast<PHYSFS_uint64>(_topHeaderSize) +
|
||||
sideSize + lidSize + auxSize + auxBlockTrailSize + animSize +
|
||||
pagedClutSize + paletteIndexSize + objectInfoSize;
|
||||
loadCarInfo_shared(st);
|
||||
}
|
||||
|
||||
void Graphics24Bit::loadSpriteInfo() {
|
||||
PHYSFS_uint64 st = static_cast<PHYSFS_uint64>(_topHeaderSize) +
|
||||
sideSize + lidSize + auxSize + auxBlockTrailSize + animSize +
|
||||
pagedClutSize + paletteIndexSize + objectInfoSize +
|
||||
carInfoSize;
|
||||
PHYSFS_seek(fd, st);
|
||||
|
||||
PHYSFS_uint8 v;
|
||||
PHYSFS_uint32 w;
|
||||
PHYSFS_uint32 _bytes_read = 0;
|
||||
while (_bytes_read < spriteInfoSize) {
|
||||
SpriteInfo *si = new SpriteInfo();
|
||||
PHYSFS_read(fd, static_cast<void*>(&si->w), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&si->h), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&si->deltaCount), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&v), 1, 1);
|
||||
PHYSFS_readULE16(fd, &si->size);
|
||||
_bytes_read += 6;
|
||||
PHYSFS_readULE16(fd, &si->clut);
|
||||
PHYSFS_read(fd, static_cast<void*>(&si->xoffset), 1, 1);
|
||||
PHYSFS_read(fd, static_cast<void*>(&si->yoffset), 1, 1);
|
||||
PHYSFS_readULE16(fd, &si->page);
|
||||
_bytes_read += 6;
|
||||
/*
|
||||
std::cout << "sprite: " << int(si->w) << "x" << int(si->h) << " deltas: " << int(si->deltaCount)
|
||||
<< " clut: " << si->clut << " x: " << int(si->xoffset) << " y: " << int(si->yoffset) <<
|
||||
" page: " << si->page << std::endl;
|
||||
*/
|
||||
// sanity check
|
||||
if (v)
|
||||
WARN << "Compression flag active in sprite!" << std::endl;
|
||||
if (int(si->w) * int(si->h) != int(si->size)) {
|
||||
ERROR << "Sprite info size mismatch: " << int(si->w) << "x" << int(si->h) <<
|
||||
" != " << si->size << std::endl;
|
||||
return;
|
||||
}
|
||||
if (si->deltaCount > 32) {
|
||||
ERROR << "Delta count of sprite is " << si->deltaCount << std::endl;
|
||||
return;
|
||||
}
|
||||
for (PHYSFS_uint8 j = 0; j < si->deltaCount; j++) {
|
||||
si->delta[j].size = 0;
|
||||
si->delta[j].ptr = 0;
|
||||
if (si->deltaCount && (j < si->deltaCount)) {
|
||||
PHYSFS_readULE16(fd, &si->delta[j].size);
|
||||
PHYSFS_readULE32(fd, &w);
|
||||
_bytes_read += 6;
|
||||
si->delta[j].ptr = reinterpret_cast<unsigned char*>(w);
|
||||
}
|
||||
}
|
||||
spriteInfos.push_back(si);
|
||||
}
|
||||
st = static_cast<PHYSFS_uint64>(_topHeaderSize) +
|
||||
sideSize + lidSize + auxSize + auxBlockTrailSize + animSize +
|
||||
pagedClutSize + paletteIndexSize + objectInfoSize +
|
||||
carInfoSize + spriteInfoSize;
|
||||
assert(PHYSFS_tell(fd) == PHYSFS_sint64(st));
|
||||
|
||||
}
|
||||
|
||||
void Graphics24Bit::loadSpriteNumbers() {
|
||||
PHYSFS_uint64 st = static_cast<PHYSFS_uint64>(_topHeaderSize) +
|
||||
sideSize + lidSize + auxSize + auxBlockTrailSize + animSize +
|
||||
pagedClutSize + paletteIndexSize + objectInfoSize +
|
||||
carInfoSize + spriteInfoSize + spriteGraphicsSize;
|
||||
loadSpriteNumbers_shared(st);
|
||||
}
|
||||
|
||||
void Graphics24Bit::loadSpriteGraphics() {
|
||||
PHYSFS_uint64 st = static_cast<PHYSFS_uint64>(_topHeaderSize) +
|
||||
sideSize + lidSize + auxSize + auxBlockTrailSize + animSize +
|
||||
pagedClutSize + paletteIndexSize + objectInfoSize +
|
||||
carInfoSize + spriteInfoSize;
|
||||
PHYSFS_seek(fd, st);
|
||||
|
||||
rawSprites = new unsigned char[spriteGraphicsSize];
|
||||
assert(rawSprites != NULL);
|
||||
PHYSFS_read(fd, static_cast<void*>(rawSprites), spriteGraphicsSize, 1);
|
||||
|
||||
std::vector<SpriteInfo*>::const_iterator i = spriteInfos.begin();
|
||||
std::vector<SpriteInfo*>::const_iterator end = spriteInfos.end();
|
||||
PHYSFS_uint32 _pagewise = 256 * 256;
|
||||
while (i != end) {
|
||||
SpriteInfo *info = *i;
|
||||
for (uint8_t k = 0; k < info->deltaCount; ++k) {
|
||||
PHYSFS_uint32 offset = reinterpret_cast<PHYSFS_uint32>(info->delta[k].ptr);
|
||||
PHYSFS_uint32 page = offset / 65536;
|
||||
PHYSFS_uint32 y = (offset % 65536) / 256;
|
||||
PHYSFS_uint32 x = (offset % 65536) % 256;
|
||||
info->delta[k].ptr = rawSprites + page * _pagewise + 256 * y + x;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics24Bit::loadObjectInfo() {
|
||||
PHYSFS_uint64 st = static_cast<PHYSFS_uint64>(_topHeaderSize) +
|
||||
sideSize + lidSize + auxSize + auxBlockTrailSize + animSize +
|
||||
pagedClutSize + paletteIndexSize;
|
||||
loadObjectInfo_shared(st);
|
||||
}
|
||||
|
||||
void Graphics24Bit::applyClut(unsigned char* src, unsigned char* dst,
|
||||
const size_t & len, const PHYSFS_uint16 & clutIdx, bool rgba) {
|
||||
PHYSFS_uint32 off = 65536 * (clutIdx / 64) + 4 * (clutIdx % 64);
|
||||
for (size_t i= 0; i < len; i++) {
|
||||
PHYSFS_uint32 coff = PHYSFS_uint32(*src) * 256 + off;
|
||||
*dst = rawClut[coff+2];
|
||||
++dst;
|
||||
*dst = rawClut[coff+1];
|
||||
++dst;
|
||||
*dst = rawClut[coff+0];
|
||||
++dst;
|
||||
if (rgba) {
|
||||
if (*src == 0)
|
||||
*dst = 0;
|
||||
else
|
||||
*dst = 0xff;
|
||||
++dst;
|
||||
}
|
||||
++src;
|
||||
}
|
||||
}
|
||||
|
||||
unsigned char *Graphics24Bit::getLid(unsigned int idx, unsigned int _not_used, bool rgba = false) {
|
||||
prepareLidTexture(idx - 1, reinterpret_cast<unsigned char*>(tileTmp));
|
||||
unsigned char* src = tileTmp;
|
||||
unsigned char* dst = (rgba) ? tileTmpRGBA : tileTmpRGB;
|
||||
PHYSFS_uint16 clutIdx = palIndex[4 * (idx + sideSize / 4096)];
|
||||
applyClut(src, dst, 4096, clutIdx, rgba);
|
||||
|
||||
return (rgba) ? tileTmpRGBA : tileTmpRGB;
|
||||
}
|
||||
|
||||
unsigned char *Graphics24Bit::getSide(unsigned int idx, unsigned int _not_used, bool rgba = false) {
|
||||
prepareSideTexture(idx-1, reinterpret_cast<unsigned char*>(tileTmp));
|
||||
unsigned char* src = tileTmp;
|
||||
unsigned char* dst = (rgba) ? tileTmpRGBA : tileTmpRGB;
|
||||
PHYSFS_uint16 clutIdx = palIndex[idx*4];
|
||||
applyClut(src, dst, 4096, clutIdx, rgba);
|
||||
|
||||
return (rgba) ? tileTmpRGBA : tileTmpRGB;
|
||||
}
|
||||
|
||||
unsigned char *Graphics24Bit::getAux(unsigned int idx, unsigned int _not_used, bool rgba = false) {
|
||||
prepareAuxTexture(idx - 1, reinterpret_cast<unsigned char*>(tileTmp));
|
||||
|
||||
unsigned char* src = tileTmp;
|
||||
unsigned char* dst = (rgba) ? tileTmpRGBA : tileTmpRGB;
|
||||
PHYSFS_uint16 clutIdx = palIndex[4 * (idx + sideSize / 4096 + lidSize / 4096)];
|
||||
applyClut(src, dst, 4096, clutIdx, rgba);
|
||||
|
||||
return (rgba) ? tileTmpRGBA : tileTmpRGB;
|
||||
}
|
||||
|
||||
void Graphics24Bit::dumpClut(const char* fname) {
|
||||
assert(pagedClutSize % 1024 == 0);
|
||||
//PHYSFS_uint32 num_clut = pagedClutSize / 1024;
|
||||
PHYSFS_uint32 num_pal = paletteIndexSize / 2;
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
#define rmask 0xff000000
|
||||
#define gmask 0x00ff0000
|
||||
#define bmask 0x0000ff00
|
||||
#define amask 0x000000ff
|
||||
#else
|
||||
#define rmask 0x000000ff
|
||||
#define gmask 0x0000ff00
|
||||
#define bmask 0x00ff0000
|
||||
#define amask 0xff000000
|
||||
#endif
|
||||
SDL_Surface* s = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA,
|
||||
num_pal, 256, 32, rmask, gmask, bmask, amask);
|
||||
SDL_LockSurface(s);
|
||||
unsigned char* dst = static_cast<unsigned char*>(s->pixels);
|
||||
|
||||
for (PHYSFS_uint32 color = 0; color < 256; color++) {
|
||||
|
||||
for (PHYSFS_uint32 pal_id = 0; pal_id < num_pal; pal_id++) {
|
||||
PHYSFS_uint32 clut_id = palIndex[pal_id];
|
||||
PHYSFS_uint32 off = 65536 * (clut_id / 64) + 4 * (clut_id % 64);
|
||||
|
||||
*dst = rawClut[off+color*256];
|
||||
++dst;
|
||||
*dst = rawClut[off+color*256+1];
|
||||
++dst;
|
||||
*dst = rawClut[off+color*256+2];
|
||||
++dst;
|
||||
*dst = 0xff;
|
||||
++dst;
|
||||
}
|
||||
|
||||
}
|
||||
SDL_UnlockSurface(s);
|
||||
SDL_SaveBMP(s, fname);
|
||||
SDL_FreeSurface(s);
|
||||
}
|
||||
|
||||
unsigned char* Graphics24Bit::getSpriteBitmap(size_t id, int remap = -1, Uint32 delta = 0) {
|
||||
const SpriteInfo *info = spriteInfos[id];
|
||||
assert(info != NULL);
|
||||
const PHYSFS_uint32 y = info->yoffset;
|
||||
const PHYSFS_uint32 x = info->xoffset;
|
||||
const PHYSFS_uint32 page_size = 256 * 256;
|
||||
|
||||
unsigned char * page_start = rawSprites + info->page * page_size;
|
||||
|
||||
BufferCache & bcache = BufferCacheHolder::Instance();
|
||||
unsigned char * dest = bcache.requestBuffer(page_size);
|
||||
bcache.lockBuffer(dest);
|
||||
memcpy(dest, page_start, page_size);
|
||||
if (delta > 0) {
|
||||
handleDeltas(*info, dest, delta);
|
||||
/*
|
||||
assert(delta < info->deltaCount);
|
||||
DeltaInfo & di = info->delta[delta];
|
||||
applyDelta(*info, dest+256*y+x, di);
|
||||
*/
|
||||
}
|
||||
|
||||
unsigned char* bigbuf = bcache.requestBuffer(page_size * 4);
|
||||
unsigned char* result = dest;
|
||||
unsigned int skip_cluts = 0;
|
||||
if (remap > -1)
|
||||
skip_cluts = spriteclutSize / 1024 + remap + 1;
|
||||
|
||||
PHYSFS_uint16 clutIdx = palIndex[info->clut + tileclutSize / 1024] + skip_cluts;
|
||||
// PHYSFS_uint16 clutIdx = palIndex[info->clut + (spriteclutSize + tileclutSize) / 1024] + (remap > -1 ? remap+2 : 0);
|
||||
applyClut(dest, bigbuf, page_size, clutIdx, true);
|
||||
assert(page_size > PHYSFS_uint32(info->w * info->h * 4));
|
||||
for (uint16_t i = 0; i < info->h; i++) {
|
||||
memcpy(result, bigbuf+(256*y+x)*4, info->w * 4);
|
||||
result += info->w * 4;
|
||||
bigbuf += 256 * 4;
|
||||
}
|
||||
|
||||
return dest;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef G24_DUMPER
|
||||
|
||||
SDL_Surface* image = NULL;
|
||||
|
||||
void on_exit() {
|
||||
if (image)
|
||||
SDL_FreeSurface(image);
|
||||
PHYSFS_deinit();
|
||||
SDL_Quit();
|
||||
}
|
||||
|
||||
SDL_Surface* get_image(unsigned char* rp, unsigned int w, unsigned int h) {
|
||||
assert(rp);
|
||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||
#define rmask 0xff000000
|
||||
#define gmask 0x00ff0000
|
||||
#define bmask 0x0000ff00
|
||||
#define amask 0x000000ff
|
||||
#else
|
||||
#define rmask 0x000000ff
|
||||
#define gmask 0x0000ff00
|
||||
#define bmask 0x00ff0000
|
||||
#define amask 0xff000000
|
||||
#endif
|
||||
SDL_Surface* s = SDL_CreateRGBSurface(SDL_SWSURFACE|SDL_SRCALPHA,
|
||||
w, h, 32, rmask, gmask, bmask, amask);
|
||||
SDL_LockSurface(s);
|
||||
unsigned char* dst = static_cast<unsigned char*>(s->pixels);
|
||||
for (unsigned int i=0; i<w*h; i++) {
|
||||
*dst = *rp; ++dst;++rp;
|
||||
*dst = *rp; ++dst;++rp;
|
||||
*dst = *rp; ++dst;++rp;
|
||||
*dst = *rp; ++dst;++rp;
|
||||
//*dst = 0xff; ++dst;
|
||||
}
|
||||
SDL_UnlockSurface(s);
|
||||
return s;
|
||||
}
|
||||
|
||||
void display_image(SDL_Surface* s) {
|
||||
SDL_Surface *screen = SDL_SetVideoMode(640, 480, 32, SDL_DOUBLEBUF);
|
||||
SDL_Event event;
|
||||
SDL_BlitSurface(s, NULL, screen, NULL);
|
||||
SDL_Flip(screen);
|
||||
while (1) {
|
||||
while (SDL_PollEvent(&event)) {
|
||||
switch(event.type) {
|
||||
case SDL_QUIT:
|
||||
return;
|
||||
case SDL_KEYDOWN:
|
||||
if (event.key.keysym.sym == SDLK_ESCAPE)
|
||||
return;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
SDL_Delay(100);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char* argv[]) {
|
||||
PHYSFS_init(argv[0]);
|
||||
SDL_Init(SDL_INIT_VIDEO);
|
||||
atexit(on_exit);
|
||||
int idx = 0;
|
||||
|
||||
PHYSFS_addToSearchPath(PHYSFS_getBaseDir(), 1);
|
||||
PHYSFS_addToSearchPath("gtadata.zip", 1);
|
||||
|
||||
OpenGTA::Graphics24Bit graphics(argv[1]);
|
||||
graphics.dumpClut("foo.bmp");
|
||||
if (argc > 2)
|
||||
idx = atoi(argv[2]);
|
||||
//image = get_image(graphics.getAux(idx, 0, true), 64,64);
|
||||
OpenGTA::GraphicsBase::SpriteInfo * sinfo = graphics.getSprite(idx);
|
||||
image = get_image(graphics.getSpriteBitmap(idx, -1, 0), sinfo->w, sinfo->h);
|
||||
if (argc == 4)
|
||||
SDL_SaveBMP(image, argv[3]);
|
||||
else
|
||||
display_image(image);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
1009
read_gry.cpp
Normal file
1009
read_gry.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user