From 1dda197ca3914496a348295bac6a7480233fe403 Mon Sep 17 00:00:00 2001 From: Josh Holtrop Date: Sun, 19 Dec 2010 00:11:35 -0500 Subject: [PATCH] split Engine::Object functions into their own .cc file --- Engine.cc | 593 +++-------------------------------------------- Engine_Object.cc | 562 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 595 insertions(+), 560 deletions(-) create mode 100644 Engine_Object.cc diff --git a/Engine.cc b/Engine.cc index bc2c965..22bf17c 100644 --- a/Engine.cc +++ b/Engine.cc @@ -1,23 +1,26 @@ +#include /* exit() */ +#include +#include +#include +#include +#include /* fabs(), tan() */ +#include +#include +#include "SDL.h" + +#include +#include +#include +#include + #include "ag.h" #include "anaglym.h" #include "Engine.h" #include "AV.h" #include "PhyObj/PhyObj.h" #include "sdl_keymap.h" -#include -#include /* exit() */ -#include -#include -#include -#include -#include -#include -#include -#include /* fabs(), tan() */ -#include -#include -#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 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 > 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 geom = m_phy->getGeom(i); - refptr< vector > 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) diff --git a/Engine_Object.cc b/Engine_Object.cc new file mode 100644 index 0000000..b9d9c88 --- /dev/null +++ b/Engine_Object.cc @@ -0,0 +1,562 @@ + +#include +#include +#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 > 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 geom = m_phy->getGeom(i); + refptr< vector > 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); + } +}