This repository has been archived on 2022-06-27. You can view files and clone it, but cannot push or open issues or pull requests.
Xash3DArchive/physic/utils.c

382 lines
9.2 KiB
C

//=======================================================================
// Copyright XashXT Group 2007 ©
// utils.c - physics callbacks
//=======================================================================
#include "physic.h"
#include <math.h>
#include <gl/gl.h>
long _ftol( double );
long _ftol2( double dblSource )
{
return _ftol( dblSource );
}
int numsurfaces;
int numverts, numedges;
int *map_surfedges;
csurface_t *map_surfaces;
dvertex_t *map_vertices;
dedge_t *map_edges;
byte *pmod_base;
NewtonBody *m_level;
NewtonCollision *collision;
void* Palloc (int size )
{
return Mem_Alloc( physpool, size );
}
void Pfree (void *ptr, int size )
{
Mem_Free( ptr );
}
_inline void ConvertDimensionToPhysic( vec3_t v )
{
vec3_t tmp;
VectorCopy(v, tmp);
v[0] = INCH2METER(tmp[0]);
v[1] = INCH2METER(tmp[1]);
v[2] = INCH2METER(tmp[2]);
}
_inline void ConvertDimensionToServer( vec3_t v )
{
vec3_t tmp;
VectorCopy(v, tmp);
v[0] = METER2INCH(tmp[0]);
v[1] = METER2INCH(tmp[1]);
v[2] = METER2INCH(tmp[2]);
}
_inline void ConvertPositionToPhysic( vec3_t v )
{
vec3_t tmp;
VectorCopy(v, tmp);
v[0] = INCH2METER(tmp[0]);
v[1] = INCH2METER(tmp[2]);
v[2] = INCH2METER(tmp[1]);
}
_inline void ConvertPositionToServer( vec3_t v )
{
vec3_t tmp;
VectorCopy(v, tmp);
v[2] = METER2INCH(tmp[1]);
v[1] = METER2INCH(tmp[2]);
v[0] = METER2INCH(tmp[0]);
}
_inline void ConvertDirectionToPhysic( vec3_t v )
{
vec3_t tmp;
VectorCopy(v, tmp);
v[0] = tmp[0];
v[1] = tmp[2];
v[2] = tmp[1];
}
_inline void ConvertDirectionToServer( vec3_t v )
{
vec3_t tmp;
VectorCopy(v, tmp);
v[0] = tmp[0];
v[1] = tmp[2];
v[2] = tmp[1];
}
/*
================
GL_BuildPolygonFromSurface
================
*/
void Phys_BuildPolygonFromSurface(csurface_t *fa)
{
int i, lindex;
dedge_t *cur_edge;
float *vec;
vec3_t face[256];// max 256 edges on a face
// reconstruct the polygon
for(i = 0; i < fa->numedges; i++ )
{
lindex = map_surfedges[fa->firstedge + i];
if (lindex > 0)
{
cur_edge = &map_edges[lindex];
vec = map_vertices[cur_edge->v[0]].point;
}
else
{
cur_edge = &map_edges[-lindex];
vec = map_vertices[cur_edge->v[1]].point;
}
// newton requires reverse vertex order
VectorCopy (vec, face[i]);
ConvertPositionToPhysic( face[i] );// inches to meters
}
// add newton polygon
NewtonTreeCollisionAddFace(collision, fa->numedges, (float *)face[0], sizeof(vec3_t), 1);
}
void Phys_LoadVerts( lump_t *l )
{
dvertex_t *in, *out;
int i, count;
in = (void *)(pmod_base + l->fileofs);
if (l->filelen % sizeof(*in)) Host_Error("MOD_LoadBmodel: funny lump size\n");
count = l->filelen / sizeof(*in);
out = Mem_Alloc( physpool, count * sizeof(*out));
map_vertices = out;
numverts = count;
for ( i = 0; i < count; i++, in++, out++)
{
out->point[0] = LittleFloat (in->point[0]);
out->point[1] = LittleFloat (in->point[1]);
out->point[2] = LittleFloat (in->point[2]);
}
}
void Phys_LoadFaces( lump_t *l )
{
dface_t *in;
csurface_t *out;
int side, count, surfnum;
in = (void *)(pmod_base + l->fileofs);
if (l->filelen % sizeof(*in)) Host_Error("MOD_LoadBmodel: funny lump size\n");
count = l->filelen / sizeof(*in);
out = Mem_Alloc( physpool, count * sizeof(*out));
map_surfaces = out;
numsurfaces = count;
for ( surfnum = 0; surfnum < count; surfnum++, in++, out++)
{
out->firstedge = LittleLong(in->firstedge);
out->numedges = LittleShort(in->numedges);
out->flags = 0;
side = LittleShort(in->side);
if (side) out->flags |= SURF_PLANEBACK;
Phys_BuildPolygonFromSurface( out );
}
}
void Phys_LoadEdges (lump_t *l)
{
dedge_t *in, *out;
int i, count;
in = (void *)(pmod_base + l->fileofs);
if (l->filelen % sizeof(*in)) Host_Error("MOD_LoadBmodel: funny lump size\n");
count = l->filelen / sizeof(*in);
out = Mem_Alloc( physpool, count * sizeof(*out));
map_edges = out;
numedges = count;
for ( i = 0; i < count; i++, in++, out++)
{
out->v[0] = (word)LittleShort(in->v[0]);
out->v[1] = (word)LittleShort(in->v[1]);
}
}
/*
=================
Mod_LoadSurfedges
=================
*/
void Phys_LoadSurfedges (lump_t *l)
{
int i, count;
int *in, *out;
in = (void *)(pmod_base + l->fileofs);
if (l->filelen % sizeof(*in)) Host_Error("MOD_LoadBmodel: funny lump size\n");
count = l->filelen / sizeof(*in);
if (count < 1 || count >= MAX_MAP_SURFEDGES) Host_Error("MOD_LoadBmodel: funny lump size\n");
map_surfedges = out = Mem_Alloc( physpool, count * sizeof(*out));
for ( i = 0; i < count; i++) out[i] = LittleLong (in[i]);
}
void Phys_LoadBSP( uint *buffer )
{
dheader_t header;
matrix4x4 m_matrix;
vec3_t boxP0, boxP1;
vec3_t extra = {10.0f, 10.0f, 10.0f};
header = *(dheader_t *)buffer;
pmod_base = (byte *)buffer;
// create the collsion tree geometry
collision = NewtonCreateTreeCollision( gWorld, NULL );
NewtonTreeCollisionBeginBuild( collision );
Phys_LoadVerts(&header.lumps[LUMP_VERTEXES]);
Phys_LoadEdges(&header.lumps[LUMP_EDGES]);
Phys_LoadSurfedges(&header.lumps[LUMP_SURFEDGES]);
Phys_LoadFaces(&header.lumps[LUMP_FACES]);
NewtonTreeCollisionEndBuild(collision, 1);
m_level = NewtonCreateBody(gWorld, collision); // create the level ridif body
NewtonReleaseCollision (gWorld, collision);
NewtonBodyGetMatrix (m_level, &m_matrix[0][0]); // set the global position of this body
NewtonCollisionCalculateAABB (collision, &m_matrix[0][0], &boxP0[0], &boxP1[0]);
VectorSubtract( boxP0, extra, boxP0 );
VectorAdd( boxP1, extra, boxP1 );
NewtonSetWorldSize( gWorld, &boxP0[0], &boxP1[0] );
MsgDev(D_INFO, "physic map generated\n");
Mem_Free( map_surfedges );
Mem_Free( map_edges );
Mem_Free( map_surfaces );
Mem_Free( map_vertices );
}
void Phys_FreeBSP( void )
{
if(m_level)
{
Msg("physic map released\n");
NewtonDestroyBody( gWorld, m_level );
m_level = NULL;
}
}
void Phys_Frame( float time )
{
NewtonUpdate(gWorld, time );
}
void Phys_ApplyForce(const NewtonBody* body)
{
float mass;
vec3_t size, force, torque;
NewtonBodyGetMassMatrix (body, &mass, &size[0], &size[1], &size[2]);
VectorSet( torque, 0.0f, 0.0f, 0.0f );
VectorSet( force, 0.0f, -9.8f * mass, 0.0f );
NewtonBodyAddForce (body, force);
NewtonBodyAddTorque (body, torque);
}
void Phys_ApplyTransform( const NewtonBody* body, const float* matrix )
{
sv_edict_t *edict = (sv_edict_t *)NewtonBodyGetUserData( body );
matrix4x4 translate;// obj matrix
vec3_t origin, angles;
Mem_Copy(translate, (float *)matrix, sizeof(matrix4x4));
ConvertDirectionToServer( translate[0]);
ConvertDirectionToServer( translate[1]);
ConvertDirectionToServer( translate[2]);
ConvertPositionToServer( translate[3] );
MatrixAngles( translate, origin, angles );
pi.Transform( edict, origin, angles );
}
void Phys_CreateBOX( sv_edict_t *ed, vec3_t mins, vec3_t maxs, vec3_t org, vec3_t ang, NewtonCollision **newcol, NewtonBody **newbody )
{
NewtonCollision *col;
NewtonBody *body;
matrix4x4 trans, offset;
vec3_t origin, angles, size, center;
MatrixLoadIdentity( trans );
MatrixLoadIdentity( offset );
VectorCopy( org, origin );
ConvertPositionToPhysic( origin );
VectorCopy( ang, angles );
ConvertDirectionToPhysic( angles );
AngleVectors( angles, trans[0], trans[1], trans[2] );
VectorSubtract (maxs, mins, size );
VectorAdd(mins, maxs, center );
ConvertDimensionToPhysic( size );
ConvertDimensionToPhysic( center );
VectorScale( center, 0.5, center );
VectorNegate( center, center );
VectorCopy(origin, trans[3] );
VectorCopy(center, offset[3] );
col = NewtonCreateBox( gWorld, size[0], size[1], size[2], &offset[0][0] );
body = NewtonCreateBody( gWorld, col );
NewtonBodySetUserData( body, ed );
NewtonBodySetMassMatrix( body, 10.0f, size[0], size[1], size[2] ); // 10 kg
// Setup generic callback to engine.dll
NewtonBodySetTransformCallback(body, Phys_ApplyTransform );
NewtonBodySetForceAndTorqueCallback(body, Phys_ApplyForce );
NewtonBodySetMatrix(body, &trans[0][0]);// origin
if(newcol) *newcol = col;
if(body) *newbody = body;
}
void Phys_RemoveBOX( NewtonBody *body )
{
if(body)
{
Msg("remove box\n");
NewtonDestroyBody( gWorld, body );
}
}
void DebugShowGeometryCollision(const NewtonBody* body, int vertexCount, const float* faceVertec, int id)
{
int i = vertexCount - 1;
vec3_t p0, p1;
VectorSet(p0, faceVertec[i * 3 + 0], faceVertec[i * 3 + 1], faceVertec[i * 3 + 2]);
ConvertPositionToServer( p0 );
for (i = 0; i < vertexCount; i ++)
{
VectorSet(p1, faceVertec[i * 3 + 0], faceVertec[i * 3 + 1], faceVertec[i * 3 + 2]);
ConvertPositionToServer( p1 );
glVertex3fv(p0);
glVertex3fv(p1);
VectorCopy(p1, p0);
}
}
void DebugShowBodyCollision (const NewtonBody* body)
{
NewtonBodyForEachPolygonDo (body, DebugShowGeometryCollision);
}
// show all collision geometry
void DebugShowCollision ( void )
{
//return;
glDisable(GL_TEXTURE_2D);
glColor3f (1, 0.7f, 0);
glBegin(GL_LINES);
NewtonWorldForEachBodyDo (gWorld, DebugShowBodyCollision);
glEnd();
glEnable (GL_TEXTURE_2D);
}