split Engine::Object functions into their own .cc file
This commit is contained in:
parent
225d147b79
commit
1dda197ca3
593
Engine.cc
593
Engine.cc
@ -1,23 +1,26 @@
|
||||
|
||||
#include <stdlib.h> /* exit() */
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h> /* fabs(), tan() */
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include "SDL.h"
|
||||
|
||||
#include <lua.hpp>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
|
||||
#include "ag.h"
|
||||
#include "anaglym.h"
|
||||
#include "Engine.h"
|
||||
#include "AV.h"
|
||||
#include "PhyObj/PhyObj.h"
|
||||
#include "sdl_keymap.h"
|
||||
#include <lua.hpp>
|
||||
#include <stdlib.h> /* exit() */
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <math.h> /* fabs(), tan() */
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include "SDL.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#define AG_EVENT_PREFIX "__ag_event_"
|
||||
@ -35,12 +38,29 @@ using namespace std;
|
||||
#define HOOK_STEPS 250000000
|
||||
#define FONT_NAME "FreeSans.ttf"
|
||||
|
||||
#ifdef DEBUG_GL_ERROR
|
||||
#define checkGLError() checkGLErrorLine(__FUNCTION__, __LINE__)
|
||||
static void checkGLErrorLine(const char * function, int line)
|
||||
{
|
||||
GLenum err = glGetError();
|
||||
if (err != 0)
|
||||
{
|
||||
std::cerr << "gl error in " << function
|
||||
<< ": " << err << " (0x" << std::hex << err << ") at line "
|
||||
<< std::dec << line << std::endl;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define checkGLError()
|
||||
#endif
|
||||
|
||||
#define FP_EQ(a,b) (fabsf(a - b) < 0.0001)
|
||||
|
||||
/* Global data */
|
||||
Engine * g_engine;
|
||||
|
||||
/* static helper functions */
|
||||
|
||||
static void cross_product(dVector3 result, dVector3 first, dVector3 second)
|
||||
{
|
||||
result[0] = first[1] * second[2] - first[2] * second[1];
|
||||
@ -83,23 +103,6 @@ static vector<string> split(const string & str, char delim)
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define DEBUG_GL_ERROR
|
||||
#ifdef DEBUG_GL_ERROR
|
||||
#define checkGLError() checkGLErrorLine(__FUNCTION__, __LINE__)
|
||||
static void checkGLErrorLine(const char * function, int line)
|
||||
{
|
||||
GLenum err = glGetError();
|
||||
if (err != 0)
|
||||
{
|
||||
cerr << "gl error in " << function
|
||||
<< ": " << err << " (0x" << hex << err << ") at line "
|
||||
<< dec << line << endl;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define checkGLError()
|
||||
#endif
|
||||
|
||||
|
||||
/******** Engine functions ********/
|
||||
|
||||
@ -1244,536 +1247,6 @@ void Engine::drawObjects()
|
||||
}
|
||||
}
|
||||
|
||||
/******** Engine::Object functions ********/
|
||||
|
||||
/* used for objects loaded directly from model files */
|
||||
Engine::Object::Object(bool is_static, bool is_reference, bool enable_blending,
|
||||
OdeWorld & world, WFObj * obj, float scale)
|
||||
: m_world(world)
|
||||
{
|
||||
m_is_reference = is_reference;
|
||||
if (m_is_reference)
|
||||
{
|
||||
m_ode_object = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ode_object = world.createObject(is_static, scale);
|
||||
m_ode_object->setUserData(this);
|
||||
}
|
||||
m_is_static = is_static;
|
||||
m_enable_blending = enable_blending;
|
||||
m_display_list = obj->render(true, enable_blending);
|
||||
const float * obj_aabb = obj->getAABB();
|
||||
for (int i = 0; i < 6; i++)
|
||||
m_aabb[i] = scale * obj_aabb[i];
|
||||
m_display_list_refcnt = new int;
|
||||
*m_display_list_refcnt = 1;
|
||||
m_is_visible = true;
|
||||
m_scale = scale;
|
||||
m_is_scaled = ! (fabs(scale - 1.0) < 0.0001);
|
||||
m_is_managed = false;
|
||||
m_mass = 0.0;
|
||||
m_mass_is_set = false;
|
||||
m_gravity_mode = true;
|
||||
}
|
||||
|
||||
/* used for "managed" objects with one geom */
|
||||
Engine::Object::Object(bool is_static, bool is_reference, bool enable_blending,
|
||||
OdeWorld & world, OdeWorld::GeomType geom_type,
|
||||
refptr< std::vector<float> > args)
|
||||
: m_world(world)
|
||||
{
|
||||
m_is_reference = is_reference;
|
||||
m_enable_blending = enable_blending;
|
||||
m_is_static = geom_type == OdeWorld::PLANE ? false : is_static;
|
||||
m_is_visible = true;
|
||||
m_scale = 1.0f;
|
||||
m_is_scaled = false;
|
||||
m_display_list = 0;
|
||||
m_display_list_refcnt = NULL;
|
||||
if (m_is_reference)
|
||||
{
|
||||
m_ode_object = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ode_object = world.createObject(m_is_static, m_scale);
|
||||
m_ode_object->setUserData(this);
|
||||
}
|
||||
m_is_managed = true;
|
||||
m_geom_type = geom_type;
|
||||
m_args = args;
|
||||
for (int i = 0; i < 4; i++)
|
||||
m_color[i] = 1.0f;
|
||||
m_texture = 0;
|
||||
m_texture_scale = 1.0f;
|
||||
createManagedObject();
|
||||
render();
|
||||
m_mass = 0.0;
|
||||
m_mass_is_set = false;
|
||||
m_gravity_mode = true;
|
||||
}
|
||||
|
||||
/* used to clone objects */
|
||||
Engine::Object::Object(const Engine::Object & orig)
|
||||
: m_world(orig.m_world)
|
||||
{
|
||||
m_is_reference = false;
|
||||
m_is_visible = orig.m_is_visible;
|
||||
m_is_static = orig.m_is_static;
|
||||
m_enable_blending = orig.m_enable_blending;
|
||||
m_scale = orig.m_scale;
|
||||
m_is_scaled = orig.m_is_scaled;
|
||||
m_phy = orig.m_phy;
|
||||
m_is_managed = orig.m_is_managed;
|
||||
if (m_is_managed)
|
||||
m_display_list = 0;
|
||||
else
|
||||
m_display_list = orig.m_display_list;
|
||||
m_display_list_refcnt = orig.m_display_list_refcnt;
|
||||
if (m_display_list_refcnt != NULL)
|
||||
(*m_display_list_refcnt)++;
|
||||
m_geom_type = orig.m_geom_type;
|
||||
m_args = orig.m_args;
|
||||
for (int i = 0; i < 4; i++)
|
||||
m_color[i] = orig.m_color[i];
|
||||
m_texture = orig.m_texture;
|
||||
m_texture_scale = orig.m_texture_scale;
|
||||
if (orig.m_is_reference)
|
||||
{
|
||||
m_ode_object = m_world.createObject(m_is_static, m_scale);
|
||||
instantiatePhy();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ode_object = new OdeWorld::Object(*orig.m_ode_object);
|
||||
}
|
||||
m_ode_object->setUserData(this);
|
||||
if (m_is_managed)
|
||||
{
|
||||
createManagedObject();
|
||||
render();
|
||||
}
|
||||
m_mass = orig.m_mass;
|
||||
m_mass_is_set = orig.m_mass_is_set;
|
||||
if (m_mass_is_set)
|
||||
{
|
||||
setMass(orig.getMass());
|
||||
}
|
||||
m_gravity_mode = orig.m_gravity_mode;
|
||||
setGravityMode(m_gravity_mode);
|
||||
}
|
||||
|
||||
Engine::Object::~Object()
|
||||
{
|
||||
if (m_ode_object != NULL)
|
||||
delete m_ode_object;
|
||||
if (m_display_list_refcnt != NULL)
|
||||
{
|
||||
(*m_display_list_refcnt)--;
|
||||
if (*m_display_list_refcnt < 1)
|
||||
{
|
||||
/* we hold the last reference to the OpenGL display list */
|
||||
delete m_display_list_refcnt;
|
||||
glDeleteLists(m_display_list, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
glDeleteLists(m_display_list, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::Object::createManagedObject()
|
||||
{
|
||||
switch (m_geom_type)
|
||||
{
|
||||
case OdeWorld::BOX: {
|
||||
while (m_args->size() < 9)
|
||||
m_args->push_back(0);
|
||||
if (m_ode_object != NULL)
|
||||
m_ode_object->addBox(m_args);
|
||||
float aabb[6] = {-(*m_args)[0], -(*m_args)[1], -(*m_args)[2],
|
||||
(*m_args)[0], (*m_args)[1], (*m_args)[2]};
|
||||
for (int i = 0; i < 6; i++)
|
||||
aabb[i] /= 2.0f;
|
||||
memcpy(m_aabb, aabb, sizeof(m_aabb));
|
||||
break;
|
||||
}
|
||||
case OdeWorld::SPHERE: {
|
||||
while (m_args->size() < 4)
|
||||
m_args->push_back(0);
|
||||
if (m_ode_object != NULL)
|
||||
m_ode_object->addSphere(m_args);
|
||||
float aabb[6] = {-(*m_args)[0], -(*m_args)[0], -(*m_args)[0],
|
||||
(*m_args)[0], (*m_args)[0], (*m_args)[0]};
|
||||
memcpy(m_aabb, aabb, sizeof(m_aabb));
|
||||
break;
|
||||
}
|
||||
case OdeWorld::PLANE: {
|
||||
while (m_args->size() < 4 || m_args->size() == 5)
|
||||
m_args->push_back(0);
|
||||
if (m_ode_object != NULL)
|
||||
m_ode_object->addPlane(m_args);
|
||||
for (int i = 0; i < 6; i++)
|
||||
m_aabb[i] = 0.0f;
|
||||
break;
|
||||
}
|
||||
case OdeWorld::CYLINDER: {
|
||||
while (m_args->size() < 8)
|
||||
m_args->push_back(0);
|
||||
if (m_ode_object != NULL)
|
||||
m_ode_object->addCylinder(m_args);
|
||||
float aabb[6] = {-(*m_args)[0], -(*m_args)[0], -(*m_args)[1],
|
||||
(*m_args)[0], (*m_args)[0], (*m_args)[1]};
|
||||
memcpy(m_aabb, aabb, sizeof(m_aabb));
|
||||
break;
|
||||
}
|
||||
case OdeWorld::CAPSULE: {
|
||||
while (m_args->size() < 8)
|
||||
m_args->push_back(0);
|
||||
if (m_ode_object != NULL)
|
||||
m_ode_object->addCapsule(m_args);
|
||||
float aabb[6] = {-(*m_args)[0], -(*m_args)[0], -(*m_args)[1],
|
||||
(*m_args)[0], (*m_args)[0], (*m_args)[1]};
|
||||
memcpy(m_aabb, aabb, sizeof(m_aabb));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_ode_object != NULL)
|
||||
{
|
||||
m_ode_object->finalize();
|
||||
}
|
||||
if (!m_is_reference)
|
||||
{
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
/* render a managed object */
|
||||
/* prerequisite: m_args->size() is big enough */
|
||||
void Engine::Object::render()
|
||||
{
|
||||
if (!m_is_managed || m_is_reference)
|
||||
return;
|
||||
GLUquadric * quad = gluNewQuadric();
|
||||
if (m_display_list <= 0)
|
||||
{
|
||||
m_display_list = glGenLists(1);
|
||||
}
|
||||
checkGLError();
|
||||
glNewList(m_display_list, GL_COMPILE);
|
||||
int attrib_flags = GL_ENABLE_BIT;
|
||||
if (m_enable_blending)
|
||||
{
|
||||
attrib_flags |= GL_COLOR_BUFFER_BIT | GL_TEXTURE_BIT;
|
||||
}
|
||||
glPushAttrib(attrib_flags);
|
||||
if (m_enable_blending)
|
||||
{
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
}
|
||||
if (m_texture != 0)
|
||||
{
|
||||
gluQuadricTexture(quad, 1);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, m_texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, m_color);
|
||||
}
|
||||
switch (m_geom_type)
|
||||
{
|
||||
case OdeWorld::BOX: {
|
||||
const static struct {
|
||||
float norm[3];
|
||||
float verts[4][3];
|
||||
} sides[] = {
|
||||
{ {1, 0, 0}, /* right */
|
||||
{{1, -1, -1}, {1, 1, -1}, {1, 1, 1}, {1, -1, 1}} },
|
||||
{ {-1, 0, 0}, /* left */
|
||||
{{-1, 1, -1}, {-1, -1, -1}, {-1, -1, 1}, {-1, 1, 1}} },
|
||||
{ {0, 1, 0}, /* back */
|
||||
{{1, 1, -1}, {-1, 1, -1}, {-1, 1, 1}, {1, 1, 1}} },
|
||||
{ {0, -1, 0}, /* front */
|
||||
{{-1, -1, -1}, {1, -1, -1}, {1, -1, 1}, {-1, -1, 1}} },
|
||||
{ {0, 0, 1}, /* top */
|
||||
{{-1, -1, 1}, {1, -1, 1}, {1, 1, 1}, {-1, 1, 1}} },
|
||||
{ {0, 0, -1}, /* bottom */
|
||||
{{1, -1, -1}, {-1, -1, -1}, {-1, 1, -1}, {1, 1, -1}} }
|
||||
};
|
||||
const float tex_coords[4][2] = {
|
||||
{0, 0}, {1, 0}, {1, 1}, {0, 1}
|
||||
};
|
||||
glBegin(GL_QUADS);
|
||||
float width = (*m_args)[0];
|
||||
float depth = (*m_args)[1];
|
||||
float height = (*m_args)[2];
|
||||
for (unsigned int s = 0;
|
||||
s < (sizeof(sides)/sizeof(sides[0]));
|
||||
s++)
|
||||
{
|
||||
glNormal3fv(sides[s].norm);
|
||||
for (int v = 0; v < 4; v++)
|
||||
{
|
||||
if (m_texture != 0)
|
||||
{
|
||||
glTexCoord2f(tex_coords[v][0] * m_texture_scale,
|
||||
tex_coords[v][1] * m_texture_scale);
|
||||
}
|
||||
glVertex3f(sides[s].verts[v][0] * width / 2.0,
|
||||
sides[s].verts[v][1] * depth / 2.0,
|
||||
sides[s].verts[v][2] * height / 2.0);
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
break;
|
||||
case OdeWorld::SPHERE:
|
||||
gluSphere(quad, (*m_args)[0], 16, 8);
|
||||
break;
|
||||
case OdeWorld::PLANE: {
|
||||
dVector3 normal;
|
||||
dVector3 rotated_x;
|
||||
dVector3 rotated_y;
|
||||
float x_o, y_o, z_o;
|
||||
if (m_args->size() == 6)
|
||||
{
|
||||
dMatrix3 r;
|
||||
dRFromEulerAngles(r, (*m_args)[3], (*m_args)[4], (*m_args)[5]);
|
||||
dVector3 default_plane_direction = {0, 0, 1, 0};
|
||||
dVector3 default_x = {1, 0, 0, 0};
|
||||
dVector3 default_y = {0, 1, 0, 0};
|
||||
dMultiply0(normal, r, default_plane_direction, 3, 3, 1);
|
||||
dMultiply0(rotated_x, r, default_x, 3, 3, 1);
|
||||
dMultiply0(rotated_y, r, default_y, 3, 3, 1);
|
||||
x_o = (*m_args)[0];
|
||||
y_o = (*m_args)[1];
|
||||
z_o = (*m_args)[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
normal[0] = (*m_args)[0];
|
||||
normal[1] = (*m_args)[1];
|
||||
normal[2] = (*m_args)[2];
|
||||
float d = (*m_args)[3];
|
||||
float len = normal[0] * normal[0]
|
||||
+ normal[1] * normal[1]
|
||||
+ normal[2] * normal[2];
|
||||
if (! FP_EQ(len, 1.0)) /* normalize if necessary */
|
||||
{
|
||||
len = sqrtf(len);
|
||||
normal[0] /= len;
|
||||
normal[1] /= len;
|
||||
normal[2] /= len;
|
||||
d /= len;
|
||||
}
|
||||
int min_component = 0;
|
||||
float comp = 10000.0f;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (normal[i] < comp)
|
||||
{
|
||||
min_component = i;
|
||||
comp = normal[i];
|
||||
}
|
||||
}
|
||||
dVector3 cross_vec;
|
||||
for (int i = 0; i < 3; i++)
|
||||
cross_vec[i] = (i == min_component) ? 1 : 0;
|
||||
cross_product(rotated_x, normal, cross_vec);
|
||||
cross_product(rotated_y, normal, rotated_x);
|
||||
x_o = normal[0] * d;
|
||||
y_o = normal[1] * d;
|
||||
z_o = normal[2] * d;
|
||||
}
|
||||
|
||||
/* plane equation: ax + by + cz = d, plane normal: (a, b, c) */
|
||||
|
||||
const int num_sections = 10;
|
||||
const float section_size = 100.0f;
|
||||
#ifdef dSINGLE
|
||||
glNormal3fv(normal);
|
||||
#else
|
||||
glNormal3dv(normal);
|
||||
#endif
|
||||
for (int x = 0; x < num_sections; x++)
|
||||
{
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
for (int y = 0; y <= num_sections; y++)
|
||||
{
|
||||
float half_span = num_sections * section_size / 2.0;
|
||||
float x_c = x * section_size - half_span;
|
||||
float y_c = y * section_size - half_span;
|
||||
glTexCoord2f(0.0, y * m_texture_scale);
|
||||
glVertex3f(x_o + rotated_x[0] * x_c + rotated_y[0] * y_c,
|
||||
y_o + rotated_x[1] * x_c + rotated_y[1] * y_c,
|
||||
z_o + rotated_x[2] * x_c + rotated_y[2] * y_c);
|
||||
x_c += section_size;
|
||||
glTexCoord2f(1.0, y * m_texture_scale);
|
||||
glVertex3f(x_o + rotated_x[0] * x_c + rotated_y[0] * y_c,
|
||||
y_o + rotated_x[1] * x_c + rotated_y[1] * y_c,
|
||||
z_o + rotated_x[2] * x_c + rotated_y[2] * y_c);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OdeWorld::CYLINDER: {
|
||||
glPushMatrix();
|
||||
float half_span = (*m_args)[1] / 2.0;
|
||||
glTranslatef(0, 0, -half_span);
|
||||
gluCylinder(quad, (*m_args)[0], (*m_args)[0], (*m_args)[1], 12, 1);
|
||||
gluDisk(quad, 0.0, (*m_args)[0], 12, 4);
|
||||
glTranslatef(0, 0, 2 * half_span);
|
||||
gluDisk(quad, 0.0, (*m_args)[0], 12, 4);
|
||||
glPopMatrix();
|
||||
}
|
||||
break;
|
||||
case OdeWorld::CAPSULE: {
|
||||
glPushAttrib(GL_TRANSFORM_BIT); /* save current clip planes */
|
||||
double halfheight = (*m_args)[1] / 2.0;
|
||||
glPushMatrix();
|
||||
glTranslatef(0, 0, -halfheight);
|
||||
gluCylinder(quad, (*m_args)[0], (*m_args)[0], (*m_args)[1], 12, 1);
|
||||
|
||||
double clip_plane[] = {0, 0, -1, halfheight};
|
||||
glClipPlane(GL_CLIP_PLANE0, clip_plane);
|
||||
glEnable(GL_CLIP_PLANE0);
|
||||
gluSphere(quad, (*m_args)[0], 12, 8);
|
||||
glTranslatef(0, 0, 2*halfheight);
|
||||
clip_plane[2] = 1.0;
|
||||
glClipPlane(GL_CLIP_PLANE0, clip_plane);
|
||||
gluSphere(quad, (*m_args)[0], 12, 8);
|
||||
glPopMatrix();
|
||||
glPopAttrib();
|
||||
}
|
||||
break;
|
||||
}
|
||||
gluDeleteQuadric(quad);
|
||||
glPopAttrib();
|
||||
glEndList();
|
||||
checkGLError();
|
||||
}
|
||||
|
||||
void Engine::Object::setPosition(double x, double y, double z)
|
||||
{
|
||||
if (m_ode_object != NULL)
|
||||
m_ode_object->setPosition(x, y, z);
|
||||
}
|
||||
|
||||
void Engine::Object::getPosition(double * x, double * y, double * z)
|
||||
{
|
||||
if (m_ode_object != NULL)
|
||||
m_ode_object->getPosition(x, y, z);
|
||||
else
|
||||
*x = *y = *z = 0.0;
|
||||
}
|
||||
|
||||
void Engine::Object::loadPhy(FileLoader * fl, const FileLoader::Path & path)
|
||||
{
|
||||
m_phy = new PhyObj();
|
||||
m_phy->load(fl, path);
|
||||
if (!m_is_managed)
|
||||
instantiatePhy();
|
||||
}
|
||||
|
||||
void Engine::Object::instantiatePhy()
|
||||
{
|
||||
if (m_ode_object != NULL && !m_is_managed && !m_phy.isNull())
|
||||
{
|
||||
for (int i = 0, sz = m_phy->getNumGeoms(); i < sz; i++)
|
||||
{
|
||||
refptr<PhyObj::Geom> geom = m_phy->getGeom(i);
|
||||
refptr< vector<float> > args = geom->getArgs();
|
||||
switch (geom->getType())
|
||||
{
|
||||
case PhyObj::BOX:
|
||||
m_ode_object->addBox(args);
|
||||
break;
|
||||
case PhyObj::SPHERE:
|
||||
m_ode_object->addSphere(args);
|
||||
break;
|
||||
case PhyObj::CAPSULE:
|
||||
m_ode_object->addCapsule(args);
|
||||
break;
|
||||
case PhyObj::PLANE:
|
||||
m_ode_object->addPlane(args);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_ode_object->finalize();
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::Object::setTexture(GLuint tex)
|
||||
{
|
||||
if (m_is_managed)
|
||||
{
|
||||
m_texture = tex;
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::Object::draw()
|
||||
{
|
||||
if (!m_is_reference && m_is_visible)
|
||||
{
|
||||
checkGLError();
|
||||
const dReal * pos = m_ode_object->getPosition();
|
||||
const dReal * rot = m_ode_object->getRotation();
|
||||
bool transform = (pos != NULL && rot != NULL);
|
||||
|
||||
if (transform)
|
||||
OdeWorld::pushTransform(pos, rot);
|
||||
|
||||
if (m_is_scaled)
|
||||
{
|
||||
glPushAttrib(GL_TRANSFORM_BIT);
|
||||
glEnable(GL_NORMALIZE);
|
||||
glPushMatrix();
|
||||
glScalef(m_scale, m_scale, m_scale);
|
||||
}
|
||||
|
||||
checkGLError();
|
||||
glCallList(m_display_list);
|
||||
checkGLError();
|
||||
|
||||
if (m_is_scaled)
|
||||
{
|
||||
glPopMatrix();
|
||||
glPopAttrib();
|
||||
}
|
||||
|
||||
if (transform)
|
||||
glPopMatrix();
|
||||
checkGLError();
|
||||
}
|
||||
}
|
||||
|
||||
dReal Engine::Object::getMass() const
|
||||
{
|
||||
return (m_ode_object != NULL) ? m_ode_object->getMass() : m_mass;
|
||||
}
|
||||
|
||||
void Engine::Object::setMass(dReal mass)
|
||||
{
|
||||
m_mass = mass;
|
||||
m_mass_is_set = true;
|
||||
if (m_ode_object != NULL)
|
||||
{
|
||||
m_ode_object->setMass(mass);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/******** Engine::EngineFileLoader functions ********/
|
||||
|
||||
Engine::EngineFileLoader::EngineFileLoader(Engine * engine)
|
||||
|
562
Engine_Object.cc
Normal file
562
Engine_Object.cc
Normal file
@ -0,0 +1,562 @@
|
||||
|
||||
#include <GL/gl.h>
|
||||
#include <GL/glu.h>
|
||||
#include "SDL.h"
|
||||
|
||||
#include "Engine.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
#ifdef DEBUG_GL_ERROR
|
||||
#define checkGLError() checkGLErrorLine(__FUNCTION__, __LINE__)
|
||||
static void checkGLErrorLine(const char * function, int line)
|
||||
{
|
||||
GLenum err = glGetError();
|
||||
if (err != 0)
|
||||
{
|
||||
std::cerr << "gl error in " << function
|
||||
<< ": " << err << " (0x" << std::hex << err << ") at line "
|
||||
<< std::dec << line << std::endl;
|
||||
}
|
||||
}
|
||||
#else
|
||||
#define checkGLError()
|
||||
#endif
|
||||
|
||||
#define FP_EQ(a,b) (fabsf(a - b) < 0.0001)
|
||||
|
||||
/* static helper functions */
|
||||
|
||||
static void cross_product(dVector3 result, dVector3 first, dVector3 second)
|
||||
{
|
||||
result[0] = first[1] * second[2] - first[2] * second[1];
|
||||
result[1] = first[2] * second[0] - first[0] * second[2];
|
||||
result[2] = first[0] * second[1] - first[1] * second[0];
|
||||
}
|
||||
|
||||
/* used for objects loaded directly from model files */
|
||||
Engine::Object::Object(bool is_static, bool is_reference, bool enable_blending,
|
||||
OdeWorld & world, WFObj * obj, float scale)
|
||||
: m_world(world)
|
||||
{
|
||||
m_is_reference = is_reference;
|
||||
if (m_is_reference)
|
||||
{
|
||||
m_ode_object = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ode_object = world.createObject(is_static, scale);
|
||||
m_ode_object->setUserData(this);
|
||||
}
|
||||
m_is_static = is_static;
|
||||
m_enable_blending = enable_blending;
|
||||
m_display_list = obj->render(true, enable_blending);
|
||||
const float * obj_aabb = obj->getAABB();
|
||||
for (int i = 0; i < 6; i++)
|
||||
m_aabb[i] = scale * obj_aabb[i];
|
||||
m_display_list_refcnt = new int;
|
||||
*m_display_list_refcnt = 1;
|
||||
m_is_visible = true;
|
||||
m_scale = scale;
|
||||
m_is_scaled = ! (fabs(scale - 1.0) < 0.0001);
|
||||
m_is_managed = false;
|
||||
m_mass = 0.0;
|
||||
m_mass_is_set = false;
|
||||
m_gravity_mode = true;
|
||||
}
|
||||
|
||||
/* used for "managed" objects with one geom */
|
||||
Engine::Object::Object(bool is_static, bool is_reference, bool enable_blending,
|
||||
OdeWorld & world, OdeWorld::GeomType geom_type,
|
||||
refptr< std::vector<float> > args)
|
||||
: m_world(world)
|
||||
{
|
||||
m_is_reference = is_reference;
|
||||
m_enable_blending = enable_blending;
|
||||
m_is_static = geom_type == OdeWorld::PLANE ? false : is_static;
|
||||
m_is_visible = true;
|
||||
m_scale = 1.0f;
|
||||
m_is_scaled = false;
|
||||
m_display_list = 0;
|
||||
m_display_list_refcnt = NULL;
|
||||
if (m_is_reference)
|
||||
{
|
||||
m_ode_object = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ode_object = world.createObject(m_is_static, m_scale);
|
||||
m_ode_object->setUserData(this);
|
||||
}
|
||||
m_is_managed = true;
|
||||
m_geom_type = geom_type;
|
||||
m_args = args;
|
||||
for (int i = 0; i < 4; i++)
|
||||
m_color[i] = 1.0f;
|
||||
m_texture = 0;
|
||||
m_texture_scale = 1.0f;
|
||||
createManagedObject();
|
||||
render();
|
||||
m_mass = 0.0;
|
||||
m_mass_is_set = false;
|
||||
m_gravity_mode = true;
|
||||
}
|
||||
|
||||
/* used to clone objects */
|
||||
Engine::Object::Object(const Engine::Object & orig)
|
||||
: m_world(orig.m_world)
|
||||
{
|
||||
m_is_reference = false;
|
||||
m_is_visible = orig.m_is_visible;
|
||||
m_is_static = orig.m_is_static;
|
||||
m_enable_blending = orig.m_enable_blending;
|
||||
m_scale = orig.m_scale;
|
||||
m_is_scaled = orig.m_is_scaled;
|
||||
m_phy = orig.m_phy;
|
||||
m_is_managed = orig.m_is_managed;
|
||||
if (m_is_managed)
|
||||
m_display_list = 0;
|
||||
else
|
||||
m_display_list = orig.m_display_list;
|
||||
m_display_list_refcnt = orig.m_display_list_refcnt;
|
||||
if (m_display_list_refcnt != NULL)
|
||||
(*m_display_list_refcnt)++;
|
||||
m_geom_type = orig.m_geom_type;
|
||||
m_args = orig.m_args;
|
||||
for (int i = 0; i < 4; i++)
|
||||
m_color[i] = orig.m_color[i];
|
||||
m_texture = orig.m_texture;
|
||||
m_texture_scale = orig.m_texture_scale;
|
||||
if (orig.m_is_reference)
|
||||
{
|
||||
m_ode_object = m_world.createObject(m_is_static, m_scale);
|
||||
instantiatePhy();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_ode_object = new OdeWorld::Object(*orig.m_ode_object);
|
||||
}
|
||||
m_ode_object->setUserData(this);
|
||||
if (m_is_managed)
|
||||
{
|
||||
createManagedObject();
|
||||
render();
|
||||
}
|
||||
m_mass = orig.m_mass;
|
||||
m_mass_is_set = orig.m_mass_is_set;
|
||||
if (m_mass_is_set)
|
||||
{
|
||||
setMass(orig.getMass());
|
||||
}
|
||||
m_gravity_mode = orig.m_gravity_mode;
|
||||
setGravityMode(m_gravity_mode);
|
||||
}
|
||||
|
||||
Engine::Object::~Object()
|
||||
{
|
||||
if (m_ode_object != NULL)
|
||||
delete m_ode_object;
|
||||
if (m_display_list_refcnt != NULL)
|
||||
{
|
||||
(*m_display_list_refcnt)--;
|
||||
if (*m_display_list_refcnt < 1)
|
||||
{
|
||||
/* we hold the last reference to the OpenGL display list */
|
||||
delete m_display_list_refcnt;
|
||||
glDeleteLists(m_display_list, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
glDeleteLists(m_display_list, 1);
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::Object::createManagedObject()
|
||||
{
|
||||
switch (m_geom_type)
|
||||
{
|
||||
case OdeWorld::BOX: {
|
||||
while (m_args->size() < 9)
|
||||
m_args->push_back(0);
|
||||
if (m_ode_object != NULL)
|
||||
m_ode_object->addBox(m_args);
|
||||
float aabb[6] = {-(*m_args)[0], -(*m_args)[1], -(*m_args)[2],
|
||||
(*m_args)[0], (*m_args)[1], (*m_args)[2]};
|
||||
for (int i = 0; i < 6; i++)
|
||||
aabb[i] /= 2.0f;
|
||||
memcpy(m_aabb, aabb, sizeof(m_aabb));
|
||||
break;
|
||||
}
|
||||
case OdeWorld::SPHERE: {
|
||||
while (m_args->size() < 4)
|
||||
m_args->push_back(0);
|
||||
if (m_ode_object != NULL)
|
||||
m_ode_object->addSphere(m_args);
|
||||
float aabb[6] = {-(*m_args)[0], -(*m_args)[0], -(*m_args)[0],
|
||||
(*m_args)[0], (*m_args)[0], (*m_args)[0]};
|
||||
memcpy(m_aabb, aabb, sizeof(m_aabb));
|
||||
break;
|
||||
}
|
||||
case OdeWorld::PLANE: {
|
||||
while (m_args->size() < 4 || m_args->size() == 5)
|
||||
m_args->push_back(0);
|
||||
if (m_ode_object != NULL)
|
||||
m_ode_object->addPlane(m_args);
|
||||
for (int i = 0; i < 6; i++)
|
||||
m_aabb[i] = 0.0f;
|
||||
break;
|
||||
}
|
||||
case OdeWorld::CYLINDER: {
|
||||
while (m_args->size() < 8)
|
||||
m_args->push_back(0);
|
||||
if (m_ode_object != NULL)
|
||||
m_ode_object->addCylinder(m_args);
|
||||
float aabb[6] = {-(*m_args)[0], -(*m_args)[0], -(*m_args)[1],
|
||||
(*m_args)[0], (*m_args)[0], (*m_args)[1]};
|
||||
memcpy(m_aabb, aabb, sizeof(m_aabb));
|
||||
break;
|
||||
}
|
||||
case OdeWorld::CAPSULE: {
|
||||
while (m_args->size() < 8)
|
||||
m_args->push_back(0);
|
||||
if (m_ode_object != NULL)
|
||||
m_ode_object->addCapsule(m_args);
|
||||
float aabb[6] = {-(*m_args)[0], -(*m_args)[0], -(*m_args)[1],
|
||||
(*m_args)[0], (*m_args)[0], (*m_args)[1]};
|
||||
memcpy(m_aabb, aabb, sizeof(m_aabb));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (m_ode_object != NULL)
|
||||
{
|
||||
m_ode_object->finalize();
|
||||
}
|
||||
if (!m_is_reference)
|
||||
{
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
/* render a managed object */
|
||||
/* prerequisite: m_args->size() is big enough */
|
||||
void Engine::Object::render()
|
||||
{
|
||||
if (!m_is_managed || m_is_reference)
|
||||
return;
|
||||
GLUquadric * quad = gluNewQuadric();
|
||||
if (m_display_list <= 0)
|
||||
{
|
||||
m_display_list = glGenLists(1);
|
||||
}
|
||||
checkGLError();
|
||||
glNewList(m_display_list, GL_COMPILE);
|
||||
int attrib_flags = GL_ENABLE_BIT;
|
||||
if (m_enable_blending)
|
||||
{
|
||||
attrib_flags |= GL_COLOR_BUFFER_BIT | GL_TEXTURE_BIT;
|
||||
}
|
||||
glPushAttrib(attrib_flags);
|
||||
if (m_enable_blending)
|
||||
{
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||
}
|
||||
if (m_texture != 0)
|
||||
{
|
||||
gluQuadricTexture(quad, 1);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glBindTexture(GL_TEXTURE_2D, m_texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, m_color);
|
||||
}
|
||||
switch (m_geom_type)
|
||||
{
|
||||
case OdeWorld::BOX: {
|
||||
const static struct {
|
||||
float norm[3];
|
||||
float verts[4][3];
|
||||
} sides[] = {
|
||||
{ {1, 0, 0}, /* right */
|
||||
{{1, -1, -1}, {1, 1, -1}, {1, 1, 1}, {1, -1, 1}} },
|
||||
{ {-1, 0, 0}, /* left */
|
||||
{{-1, 1, -1}, {-1, -1, -1}, {-1, -1, 1}, {-1, 1, 1}} },
|
||||
{ {0, 1, 0}, /* back */
|
||||
{{1, 1, -1}, {-1, 1, -1}, {-1, 1, 1}, {1, 1, 1}} },
|
||||
{ {0, -1, 0}, /* front */
|
||||
{{-1, -1, -1}, {1, -1, -1}, {1, -1, 1}, {-1, -1, 1}} },
|
||||
{ {0, 0, 1}, /* top */
|
||||
{{-1, -1, 1}, {1, -1, 1}, {1, 1, 1}, {-1, 1, 1}} },
|
||||
{ {0, 0, -1}, /* bottom */
|
||||
{{1, -1, -1}, {-1, -1, -1}, {-1, 1, -1}, {1, 1, -1}} }
|
||||
};
|
||||
const float tex_coords[4][2] = {
|
||||
{0, 0}, {1, 0}, {1, 1}, {0, 1}
|
||||
};
|
||||
glBegin(GL_QUADS);
|
||||
float width = (*m_args)[0];
|
||||
float depth = (*m_args)[1];
|
||||
float height = (*m_args)[2];
|
||||
for (unsigned int s = 0;
|
||||
s < (sizeof(sides)/sizeof(sides[0]));
|
||||
s++)
|
||||
{
|
||||
glNormal3fv(sides[s].norm);
|
||||
for (int v = 0; v < 4; v++)
|
||||
{
|
||||
if (m_texture != 0)
|
||||
{
|
||||
glTexCoord2f(tex_coords[v][0] * m_texture_scale,
|
||||
tex_coords[v][1] * m_texture_scale);
|
||||
}
|
||||
glVertex3f(sides[s].verts[v][0] * width / 2.0,
|
||||
sides[s].verts[v][1] * depth / 2.0,
|
||||
sides[s].verts[v][2] * height / 2.0);
|
||||
}
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
break;
|
||||
case OdeWorld::SPHERE:
|
||||
gluSphere(quad, (*m_args)[0], 16, 8);
|
||||
break;
|
||||
case OdeWorld::PLANE: {
|
||||
dVector3 normal;
|
||||
dVector3 rotated_x;
|
||||
dVector3 rotated_y;
|
||||
float x_o, y_o, z_o;
|
||||
if (m_args->size() == 6)
|
||||
{
|
||||
dMatrix3 r;
|
||||
dRFromEulerAngles(r, (*m_args)[3], (*m_args)[4], (*m_args)[5]);
|
||||
dVector3 default_plane_direction = {0, 0, 1, 0};
|
||||
dVector3 default_x = {1, 0, 0, 0};
|
||||
dVector3 default_y = {0, 1, 0, 0};
|
||||
dMultiply0(normal, r, default_plane_direction, 3, 3, 1);
|
||||
dMultiply0(rotated_x, r, default_x, 3, 3, 1);
|
||||
dMultiply0(rotated_y, r, default_y, 3, 3, 1);
|
||||
x_o = (*m_args)[0];
|
||||
y_o = (*m_args)[1];
|
||||
z_o = (*m_args)[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
normal[0] = (*m_args)[0];
|
||||
normal[1] = (*m_args)[1];
|
||||
normal[2] = (*m_args)[2];
|
||||
float d = (*m_args)[3];
|
||||
float len = normal[0] * normal[0]
|
||||
+ normal[1] * normal[1]
|
||||
+ normal[2] * normal[2];
|
||||
if (! FP_EQ(len, 1.0)) /* normalize if necessary */
|
||||
{
|
||||
len = sqrtf(len);
|
||||
normal[0] /= len;
|
||||
normal[1] /= len;
|
||||
normal[2] /= len;
|
||||
d /= len;
|
||||
}
|
||||
int min_component = 0;
|
||||
float comp = 10000.0f;
|
||||
for (int i = 0; i < 3; i++)
|
||||
{
|
||||
if (normal[i] < comp)
|
||||
{
|
||||
min_component = i;
|
||||
comp = normal[i];
|
||||
}
|
||||
}
|
||||
dVector3 cross_vec;
|
||||
for (int i = 0; i < 3; i++)
|
||||
cross_vec[i] = (i == min_component) ? 1 : 0;
|
||||
cross_product(rotated_x, normal, cross_vec);
|
||||
cross_product(rotated_y, normal, rotated_x);
|
||||
x_o = normal[0] * d;
|
||||
y_o = normal[1] * d;
|
||||
z_o = normal[2] * d;
|
||||
}
|
||||
|
||||
/* plane equation: ax + by + cz = d, plane normal: (a, b, c) */
|
||||
|
||||
const int num_sections = 10;
|
||||
const float section_size = 100.0f;
|
||||
#ifdef dSINGLE
|
||||
glNormal3fv(normal);
|
||||
#else
|
||||
glNormal3dv(normal);
|
||||
#endif
|
||||
for (int x = 0; x < num_sections; x++)
|
||||
{
|
||||
glBegin(GL_QUAD_STRIP);
|
||||
for (int y = 0; y <= num_sections; y++)
|
||||
{
|
||||
float half_span = num_sections * section_size / 2.0;
|
||||
float x_c = x * section_size - half_span;
|
||||
float y_c = y * section_size - half_span;
|
||||
glTexCoord2f(0.0, y * m_texture_scale);
|
||||
glVertex3f(x_o + rotated_x[0] * x_c + rotated_y[0] * y_c,
|
||||
y_o + rotated_x[1] * x_c + rotated_y[1] * y_c,
|
||||
z_o + rotated_x[2] * x_c + rotated_y[2] * y_c);
|
||||
x_c += section_size;
|
||||
glTexCoord2f(1.0, y * m_texture_scale);
|
||||
glVertex3f(x_o + rotated_x[0] * x_c + rotated_y[0] * y_c,
|
||||
y_o + rotated_x[1] * x_c + rotated_y[1] * y_c,
|
||||
z_o + rotated_x[2] * x_c + rotated_y[2] * y_c);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
}
|
||||
break;
|
||||
case OdeWorld::CYLINDER: {
|
||||
glPushMatrix();
|
||||
float half_span = (*m_args)[1] / 2.0;
|
||||
glTranslatef(0, 0, -half_span);
|
||||
gluCylinder(quad, (*m_args)[0], (*m_args)[0], (*m_args)[1], 12, 1);
|
||||
gluDisk(quad, 0.0, (*m_args)[0], 12, 4);
|
||||
glTranslatef(0, 0, 2 * half_span);
|
||||
gluDisk(quad, 0.0, (*m_args)[0], 12, 4);
|
||||
glPopMatrix();
|
||||
}
|
||||
break;
|
||||
case OdeWorld::CAPSULE: {
|
||||
glPushAttrib(GL_TRANSFORM_BIT); /* save current clip planes */
|
||||
double halfheight = (*m_args)[1] / 2.0;
|
||||
glPushMatrix();
|
||||
glTranslatef(0, 0, -halfheight);
|
||||
gluCylinder(quad, (*m_args)[0], (*m_args)[0], (*m_args)[1], 12, 1);
|
||||
|
||||
double clip_plane[] = {0, 0, -1, halfheight};
|
||||
glClipPlane(GL_CLIP_PLANE0, clip_plane);
|
||||
glEnable(GL_CLIP_PLANE0);
|
||||
gluSphere(quad, (*m_args)[0], 12, 8);
|
||||
glTranslatef(0, 0, 2*halfheight);
|
||||
clip_plane[2] = 1.0;
|
||||
glClipPlane(GL_CLIP_PLANE0, clip_plane);
|
||||
gluSphere(quad, (*m_args)[0], 12, 8);
|
||||
glPopMatrix();
|
||||
glPopAttrib();
|
||||
}
|
||||
break;
|
||||
}
|
||||
gluDeleteQuadric(quad);
|
||||
glPopAttrib();
|
||||
glEndList();
|
||||
checkGLError();
|
||||
}
|
||||
|
||||
void Engine::Object::setPosition(double x, double y, double z)
|
||||
{
|
||||
if (m_ode_object != NULL)
|
||||
m_ode_object->setPosition(x, y, z);
|
||||
}
|
||||
|
||||
void Engine::Object::getPosition(double * x, double * y, double * z)
|
||||
{
|
||||
if (m_ode_object != NULL)
|
||||
m_ode_object->getPosition(x, y, z);
|
||||
else
|
||||
*x = *y = *z = 0.0;
|
||||
}
|
||||
|
||||
void Engine::Object::loadPhy(FileLoader * fl, const FileLoader::Path & path)
|
||||
{
|
||||
m_phy = new PhyObj();
|
||||
m_phy->load(fl, path);
|
||||
if (!m_is_managed)
|
||||
instantiatePhy();
|
||||
}
|
||||
|
||||
void Engine::Object::instantiatePhy()
|
||||
{
|
||||
if (m_ode_object != NULL && !m_is_managed && !m_phy.isNull())
|
||||
{
|
||||
for (int i = 0, sz = m_phy->getNumGeoms(); i < sz; i++)
|
||||
{
|
||||
refptr<PhyObj::Geom> geom = m_phy->getGeom(i);
|
||||
refptr< vector<float> > args = geom->getArgs();
|
||||
switch (geom->getType())
|
||||
{
|
||||
case PhyObj::BOX:
|
||||
m_ode_object->addBox(args);
|
||||
break;
|
||||
case PhyObj::SPHERE:
|
||||
m_ode_object->addSphere(args);
|
||||
break;
|
||||
case PhyObj::CAPSULE:
|
||||
m_ode_object->addCapsule(args);
|
||||
break;
|
||||
case PhyObj::PLANE:
|
||||
m_ode_object->addPlane(args);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_ode_object->finalize();
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::Object::setTexture(GLuint tex)
|
||||
{
|
||||
if (m_is_managed)
|
||||
{
|
||||
m_texture = tex;
|
||||
render();
|
||||
}
|
||||
}
|
||||
|
||||
void Engine::Object::draw()
|
||||
{
|
||||
if (!m_is_reference && m_is_visible)
|
||||
{
|
||||
checkGLError();
|
||||
const dReal * pos = m_ode_object->getPosition();
|
||||
const dReal * rot = m_ode_object->getRotation();
|
||||
bool transform = (pos != NULL && rot != NULL);
|
||||
|
||||
if (transform)
|
||||
OdeWorld::pushTransform(pos, rot);
|
||||
|
||||
if (m_is_scaled)
|
||||
{
|
||||
glPushAttrib(GL_TRANSFORM_BIT);
|
||||
glEnable(GL_NORMALIZE);
|
||||
glPushMatrix();
|
||||
glScalef(m_scale, m_scale, m_scale);
|
||||
}
|
||||
|
||||
checkGLError();
|
||||
glCallList(m_display_list);
|
||||
checkGLError();
|
||||
|
||||
if (m_is_scaled)
|
||||
{
|
||||
glPopMatrix();
|
||||
glPopAttrib();
|
||||
}
|
||||
|
||||
if (transform)
|
||||
glPopMatrix();
|
||||
checkGLError();
|
||||
}
|
||||
}
|
||||
|
||||
dReal Engine::Object::getMass() const
|
||||
{
|
||||
return (m_ode_object != NULL) ? m_ode_object->getMass() : m_mass;
|
||||
}
|
||||
|
||||
void Engine::Object::setMass(dReal mass)
|
||||
{
|
||||
m_mass = mass;
|
||||
m_mass_is_set = true;
|
||||
if (m_ode_object != NULL)
|
||||
{
|
||||
m_ode_object->setMass(mass);
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user