//-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~ HeightfieldCollisionShape::HeightfieldCollisionShape(dSpaceID _spaceId, pTerrainChunk_type _pTerrainChunk) : m_pTerrainChunk(_pTerrainChunk) , CollisionShape(NULL) { m_heightfieldDataId = dGeomHeightfieldDataCreate(); dGeomHeightfieldDataBuildCallback( m_heightfieldDataId, this, getHeightCallback, m_pTerrainChunk->getWorldWidth(), m_pTerrainChunk->getWorldWidth(), m_pTerrainChunk->getWidth(), m_pTerrainChunk->getWidth(), 1.0f, m_pTerrainChunk->getOffset(), m_pTerrainChunk->getSkirtSize(), 0 ); dGeomHeightfieldDataSetBounds( m_heightfieldDataId, m_pTerrainChunk->getMinHeight(), m_pTerrainChunk->getMaxHeight() ); dGeomID geometryId = dCreateHeightfield( _spaceId, m_heightfieldDataId, 1 ); Zen::Math::Vector3& position(m_pTerrainChunk->getPosition()); dGeomSetPosition( geometryId, position.m_x, position.m_y, position.m_z ); /// TODO Set rotation of terrain for cases where it is not /// planar with the X and Z axes. setGeometryId(geometryId); }
int main (int argc, char **argv) { printf("ODE configuration: %s\n", dGetConfiguration()); // Is trimesh support built into this ODE? g_allow_trimesh = dCheckConfiguration( "ODE_EXT_trimesh" ); // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = &command; fn.stop = 0; fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH; // create world dInitODE2(0); world = dWorldCreate(); space = dHashSpaceCreate (0); contactgroup = dJointGroupCreate (0); dWorldSetGravity (world,0,0,-0.05); dWorldSetCFM (world,1e-5); dWorldSetAutoDisableFlag (world,1); dWorldSetContactMaxCorrectingVel (world,0.1); dWorldSetContactSurfaceLayer (world,0.001); memset (obj,0,sizeof(obj)); #if 1 dWorldSetAutoDisableAverageSamplesCount( world, 1 ); #endif // base plane to catch overspill dCreatePlane( space, 0, 0, 1, 0 ); // our heightfield floor dHeightfieldDataID heightid = dGeomHeightfieldDataCreate(); // Create an finite heightfield. dGeomHeightfieldDataBuildCallback( heightid, NULL, heightfield_callback, HFIELD_WIDTH, HFIELD_DEPTH, HFIELD_WSTEP, HFIELD_DSTEP, REAL( 1.0 ), REAL( 0.0 ), REAL( 0.0 ), 0 ); // Give some very bounds which, while conservative, // makes AABB computation more accurate than +/-INF. dGeomHeightfieldDataSetBounds( heightid, REAL( -4.0 ), REAL( +6.0 ) ); gheight = dCreateHeightfield( space, heightid, 1 ); dVector3 pos; pos[ 0 ] = 0; pos[ 1 ] = 0; pos[ 2 ] = 0; // Rotate so Z is up, not Y (which is the default orientation) dMatrix3 R; dRSetIdentity( R ); dRFromAxisAndAngle( R, 1, 0, 0, DEGTORAD * 90 ); // Place it. dGeomSetRotation( gheight, R ); dGeomSetPosition( gheight, pos[0], pos[1], pos[2] ); // run simulation dsSimulationLoop (argc,argv,352,288,&fn); dJointGroupDestroy (contactgroup); dSpaceDestroy (space); dWorldDestroy (world); // destroy heightfield data, because _we_ own it not ODE dGeomHeightfieldDataDestroy( heightid ); dCloseODE(); return 0; }
void cPhysicsObject::CreateHeightmap(cWorld* pWorld, const game::cTerrainHeightMap& loader, size_t width, size_t length, const physvec_t& scale, const physvec_t& pos, const physvec_t& rot) { // NOTE: Actual heightmap doesn't seem to be working at the moment so we use a trimesh instead #if 1 // TODO: Shared indices const float fScale = scale.x; std::vector<spitfire::math::cVec3> tempVertices; std::vector<uint32_t> tempIndices; tempVertices.reserve(length * width * 4); tempIndices.reserve(length * width * 6); size_t index = 0; for (size_t y = 0; y < length; y++) { for (size_t x = 0; x < width; x++) { const float fX = float(x) * fScale; const float fY = float(y) * fScale; tempVertices.push_back(spitfire::math::cVec3(fX, fY, loader.GetHeight(fX, fY))); tempVertices.push_back(spitfire::math::cVec3(fX + fScale, fY, loader.GetHeight(fX + fScale, fY))); tempVertices.push_back(spitfire::math::cVec3(fX + fScale, fY + fScale, loader.GetHeight(fX + fScale, fY + fScale))); tempVertices.push_back(spitfire::math::cVec3(fX, fY + fScale, loader.GetHeight(fX, fY + fScale))); tempIndices.push_back(index + 0); tempIndices.push_back(index + 1); tempIndices.push_back(index + 2); tempIndices.push_back(index + 2); tempIndices.push_back(index + 3); tempIndices.push_back(index + 0); index += 4; } } CreateTrimesh(pWorld, tempVertices, tempIndices, pos, rot); #else DestroyHeightfield(); bBody = false; bDynamic = false; // Heightfields are always static v[0] = 0.0f; v[1] = 0.0f; v[2] = 0.0f; fWidth = float(width) * scale.x; fLength = float(length) * scale.y; fHeight = 1.0f * scale.z; const size_t height = length; pHeightfieldData = new float[width * height]; for (size_t y = 0; y < height; y++) { for (size_t x = 0; x < width; x++) { pHeightfieldData[(width * y) + x] = 200.0f * (sinf(float(x)) + cosf(float(y)));// 10.0f * loader.GetHeight(x, y); } } heightfield = dGeomHeightfieldDataCreate(); // TODO: Last parameter, tile indefinitely int copyHeightData = 1; // 0 = we are keeping our own copy (Dynamic), 1 = copy the data to ODE (static) int wrap = 1; // 0 = don't wrap, 1 = wrap indefinitely float fThickness = 10.0f; // The thickness of the "shell" of the heightmap dGeomHeightfieldDataBuildSingle( heightfield, pHeightfieldData, copyHeightData, fWidth, fLength, width, height, scale.z, pos.z, fThickness, wrap ); // Set finite AABB dGeomHeightfieldDataSetBounds(heightfield, 0.0f, 1000.0f); int movable = 1; // 1 = true, 0 = false geom = dCreateHeightfield(pWorld->GetSpaceStatic(), heightfield, movable); ASSERT(geom != 0); InitCommon(pWorld, pos, rot); #endif }