critterding-beta12.1/0000755000175000017500000000000011347266053013544 5ustar bobkebobkecritterding-beta12.1/Makefile.am0000644000175000017500000000047111344065077015602 0ustar bobkebobke# not a GNU package. You can remove this line, if # have all needed files, that a GNU package needs AUTOMAKE_OPTIONS = foreign 1.4 SUBDIRS = src pixmapsdir = @datadir@/critterding/pixmaps pixmaps_DATA = share/critterding/pixmaps/cd.bmp fontsdir = @datadir@/critterding/ fonts_DATA = share/critterding/font.ttf critterding-beta12.1/src/0000755000175000017500000000000011347266042014331 5ustar bobkebobkecritterding-beta12.1/src/math/0000755000175000017500000000000011347266042015262 5ustar bobkebobkecritterding-beta12.1/src/math/Makefile.am0000644000175000017500000000032011302272704017302 0ustar bobkebobkeINCLUDES = $(all_includes) METASOURCES = AUTO noinst_LTLIBRARIES = libmath.la noinst_HEADERS = vector3f.h \ vector2i.h \ vector2f.h libmath_la_SOURCES = vector3f.cpp \ vector2i.cpp \ vector2f.cpp critterding-beta12.1/src/math/vector3f.cpp0000644000175000017500000000263011262226147017520 0ustar bobkebobke#include "vector3f.h" Vector3f::Vector3f() { x = 0; y = 0; z = 0; } Vector3f::Vector3f(const Vector3f &other) { x = other.x; y = other.y; z = other.z; } Vector3f::Vector3f(const float xv, const float yv, const float zv) { x = xv; y = yv; z = zv; } bool Vector3f::operator==(const Vector3f& other) const { if (x != other.x) return false; if (y != other.y) return false; if (z != other.z) return false; return true; } Vector3f Vector3f::operator-(const Vector3f& other) const { Vector3f r(*this); r.x -= other.x; r.y -= other.y; r.z -= other.z; return r; } Vector3f & Vector3f::operator/=(const float scalar) { x /= scalar; y /= scalar; z /= scalar; return (*this); } Vector3f & Vector3f::operator/=(const Vector3f &other) { x /= other.x; y /= other.y; z /= other.z; return (*this); } float Vector3f::lengthsquared() const { return (2.0f*x) + (2.0f*y) + (2.0f*z); } float Vector3f::length() const { return sqrt((2.0f*x) + (2.0f*y) + (2.0f*z)); } void Vector3f::normalize() { float l = length(); x /= l; y /= l; z /= l; } float Vector3f::dot(const Vector3f& vector) { return ( (x*vector.x) + (y*vector.y) + (z*vector.z) ); } // void Vector3f::crossproduct(const Vector3f& v1, const Vector3f& v2) // { // float vx = v1.y*v2.z - v1.z*v2.y; // float vy = v1.z*v2.x - v1.x*v2.z; // float vz = v1.x*v2.y - v1.y*v2.x; // } Vector3f::~Vector3f() { } critterding-beta12.1/src/math/vector2f.cpp0000644000175000017500000000025511302274671017520 0ustar bobkebobke#include "vector2f.h" Vector2f::Vector2f() { x = 0.0f; y = 0.0f; } Vector2f::Vector2f(const float& xv, const float& yv) { x = xv; y = yv; } Vector2f::~Vector2f() { } critterding-beta12.1/src/math/vector3f.h0000644000175000017500000000121311262226147017161 0ustar bobkebobke#ifndef VECTOR3F_H #define VECTOR3F_H #include class Vector3f { public: Vector3f(); ~Vector3f(); // other constructors Vector3f(const Vector3f &other); Vector3f(const float xv, const float yv, const float zv); bool operator==(const Vector3f &other) const; Vector3f operator-(const Vector3f &other) const; Vector3f & operator/=(const float scalar); Vector3f & operator/=(const Vector3f &other); float length() const; float lengthsquared() const; void normalize(); float dot(const Vector3f& vector); // void crossproduct(const Vector3f& v1, const Vector3f& v2); float x; float y; float z; }; #endif critterding-beta12.1/src/math/vector2f.h0000644000175000017500000000026111302274671017162 0ustar bobkebobke#ifndef VECTOR2F_H #define VECTOR2F_H class Vector2f { public: Vector2f(); Vector2f(const float& xv, const float& yv); ~Vector2f(); float x; float y; }; #endif critterding-beta12.1/src/math/vector2i.cpp0000644000175000017500000000024111264467060017521 0ustar bobkebobke#include "vector2i.h" Vector2i::Vector2i() { x = 0; y = 0; } Vector2i::Vector2i(const int xv, const int yv) { x = xv; y = yv; } Vector2i::~Vector2i() { } critterding-beta12.1/src/math/vector2i.h0000644000175000017500000000024711264467060017174 0ustar bobkebobke#ifndef VECTOR2I_H #define VECTOR2I_H class Vector2i { public: Vector2i(); Vector2i(const int xv, const int yv); ~Vector2i(); int x; int y; }; #endif critterding-beta12.1/src/Makefile.am0000644000175000017500000000114111346046106016356 0ustar bobkebobkebin_PROGRAMS = critterding # set the include path found by configure INCLUDES = $(all_includes) -I./utils/bullet # the library search path. SUBDIRS = utils math brainz gl gui scenes critterding_SOURCES = critterding.cpp critterding_LDADD = $(top_builddir)/src/gl/libgl.la \ $(top_builddir)/src/scenes/libscenes.la \ $(top_builddir)/src/utils/libutils.la \ $(top_builddir)/src/math/libmath.la \ $(top_builddir)/src/gui/libgui.la \ $(HOST_LIBS) # -lGL -lfreetype -lSDL # -lBulletDynamics -lBulletCollision -lLinearMath # -lftgl critterding_LDFLAGS = -avoid-version -no-undefined -fopenmp critterding-beta12.1/src/scenes/0000755000175000017500000000000011347266042015611 5ustar bobkebobkecritterding-beta12.1/src/scenes/Makefile.am0000644000175000017500000000077511337071441017652 0ustar bobkebobkeINCLUDES = $(all_includes) -I../utils/bullet -fopenmp METASOURCES = AUTO noinst_LTLIBRARIES = libscenes.la libscenes_la_SOURCES = evolution.cpp libscenes_la_LIBADD = $(top_builddir)/src/brainz/libbrainz.la \ $(top_builddir)/src/gl/libgl.la \ $(top_builddir)/src/gui/libgui.la \ $(top_builddir)/src/scenes/gui/libcdgui.la \ $(top_builddir)/src/scenes/entities/libentities.la \ $(top_builddir)/src/scenes/modes/libmodes.la \ $(top_builddir)/src/utils/libutils.la SUBDIRS = gui entities modes critterding-beta12.1/src/scenes/evolution.cpp0000644000175000017500000003406011345021566020342 0ustar bobkebobke#ifdef _WIN32 #include #endif #include "evolution.h" # include Evolution::Evolution() { cmd = Commands::Instance(); settings = Settings::Instance(); events = Events::Instance(); drawscene = settings->getCVarPtr("drawscene"); benchmark = settings->getCVarPtr("benchmark"); if ( *benchmark == 1 ) { canvas.active = false; // canvas.children["hud"]->active = false; settings->setCVar("startseed", 11); } if ( settings->getCVar("race") == 1 ) world = new WorldRace(); else if ( settings->getCVar("roundworld") == 1 ) world = new Roundworld(); else world = new WorldB(); world->mousex = &oldx; world->mousey = &oldy; cmd->world = world; if ( !*world->headless ) { static_cast(canvas.children["hud"])->world = world; static_cast(canvas.children["critterview"])->world = world; cmd->canvas = &canvas; } else { // check if raycastvision is enabled, if not die if ( settings->getCVar("critter_raycastvision") == 0 ) { cerr << "headless mode requires critter_raycastvision to be enabled" << endl; exit(1); } } pause = false; // drawCVNeurons = false; unsigned int delay = 200; unsigned int speedup = 2; // events events->registerEvent(SDLK_TAB, "swapspeciespanel", execcmd.gen("gui_togglepanel", "speciesview"), 0, 0, 0 ); events->registerEvent(SDLK_ESCAPE, "swapexitpanel", execcmd.gen("gui_togglepanel", "exitpanel"), 0, 0, 0 ); events->registerEvent(SDLK_F1, "swaphelpinfo", execcmd.gen("gui_togglepanel", "helpinfo"), 0, 0, 0 ); events->registerEvent(SDLK_F2, "swapinfobar", execcmd.gen("gui_togglepanel", "infobar"), 0, 0, 0 ); events->registerEvent(SDLK_F3, "swapinfostats", execcmd.gen("gui_togglepanel", "infostats"), 0, 0, 0 ); events->registerEvent(SDLK_F4, "swaptextverbosemessage", execcmd.gen("gui_togglepanel", "textverbosemessage"), 0, 0, 0 ); events->registerEvent(SDLK_F5, "swapstatsgraph", execcmd.gen("gui_togglepanel", "statsgraph"), 0, 0, 0 ); events->registerEvent(SDLK_F6, "swapglobalsettingspanel", execcmd.gen("gui_togglepanel", "globalsettingspanel"), 0, 0, 0 ); events->registerEvent(SDLK_F7, "swapsettingsbrainpanel", execcmd.gen("gui_togglepanel", "settingsbrainpanel"), 0, 0, 0 ); events->registerEvent(SDLK_F8, "swaphud", execcmd.gen("gui_togglepanel", "hud"), 0, 0, 0 ); events->registerEvent(SDLK_r, "toggle_drawscene", execcmd.gen("settings_increase", "drawscene"), 0, 0, 0 ); events->registerEvent(SDLK_h, "swapcanvas", execcmd.gen("gui_toggle"), 0, 0, 0 ); // events->registerEvent(SDLK_F5, "dec_critters", execcmd.gen("settings_decrease", "mincritters"), delay, 0, speedup ); // events->registerEvent(SDLK_F6, "inc_critters", execcmd.gen("settings_increase", "mincritters"), delay, 0, speedup ); // events->registerEvent(SDLK_F7, "dec_killhalftrigger", execcmd.gen("settings_decrease", "critter_killhalfat"), delay, 0, speedup ); // events->registerEvent(SDLK_F8, "inc_killhalftrigger", execcmd.gen("settings_increase", "critter_killhalfat"), delay, 0, speedup ); events->registerEvent(SDLK_KP_DIVIDE, "dec_camerasensitivity", execcmd.gen("settings_decrease", "camerasensitivity"), delay, 0, speedup ); events->registerEvent(SDLK_KP_MULTIPLY, "inc_camerasensitivity", execcmd.gen("settings_increase", "camerasensitivity"), delay, 0, speedup ); events->registerEvent(SDLK_c, "inc_colormode", execcmd.gen("settings_increase", "colormode"), 0, 0, 0 ); events->registerEvent(SDLK_F9, "dec_body_mutationrate", execcmd.gen("settings_decrease", "body_mutationrate"), delay, 0, speedup ); events->registerEvent(SDLK_F10, "inc_body_mutationrate", execcmd.gen("settings_increase", "body_mutationrate"), delay, 0, speedup ); events->registerEvent(SDLK_F11, "dec_brain_mutationrate", execcmd.gen("settings_decrease", "brain_mutationrate"), delay, 0, speedup ); events->registerEvent(SDLK_F12, "inc_brain_mutationrate", execcmd.gen("settings_increase", "brain_mutationrate"), delay, 0, speedup ); events->registerEvent(SDLK_BACKSPACE, "resetcamera", execcmd.gen("camera_resetposition"), 0, 0, 0 ); events->registerEvent(SDLK_PAGEUP, "keyloadAllCritters", execcmd.gen("loadallcritters"), 0, 0, 0 ); events->registerEvent(SDLK_PAGEDOWN, "keysaveAllCritters", execcmd.gen("saveallcritters"), 0, 0, 0 ); events->registerEvent(SDLK_i, "keyinsertCritter", execcmd.gen("insertcritter"), 0, 0, 0 ); events->registerEvent(SDLK_k, "keykillhalfOfcritters", execcmd.gen("killhalfofcritters"), 0, 0, 0 ); events->registerEvent(SDLK_MINUS, "keydecreaseenergy", execcmd.gen("decreaseenergy"), delay, 0, speedup ); events->registerEvent(SDLK_PLUS, "keyincreaseenergy", execcmd.gen("increaseenergy"), delay, 0, speedup ); events->registerEvent(SDLK_KP_MINUS, "keydecreaseenergykp", execcmd.gen("decreaseenergy"), delay, 0, speedup ); events->registerEvent(SDLK_KP_PLUS, "keyincreaseenergykp", execcmd.gen("increaseenergy"), delay, 0, speedup ); sharedTimer* t = events->registerSharedtimer( 20 ); events->registerEvent(SDLK_HOME, "keycamera_moveup", execcmd.gen("camera_moveup"), t ); events->registerEvent(SDLK_END, "keycamera_movedown", execcmd.gen("camera_movedown"), t ); events->registerEvent(SDLK_UP, "keycamera_moveforward", execcmd.gen("camera_moveforward"), t ); events->registerEvent(SDLK_DOWN, "keycamera_movebackward", execcmd.gen("camera_movebackward"), t ); events->registerEvent(SDLK_LEFT, "keycamera_moveleft", execcmd.gen("camera_moveleft"), t ); events->registerEvent(SDLK_RIGHT, "keycamera_moveright", execcmd.gen("camera_moveright"), t ); events->registerEvent(SDLK_KP2, "keycamera_lookup", execcmd.gen("camera_lookup"), t ); events->registerEvent(SDLK_KP8, "keycamera_lookdown", execcmd.gen("camera_lookdown"), t ); events->registerEvent(SDLK_KP4, "keycamera_lookleft", execcmd.gen("camera_lookleft"), t ); events->registerEvent(SDLK_KP6, "keycamera_lookright", execcmd.gen("camera_lookright"), t ); events->registerEvent(SDLK_KP1, "keycamera_rollleft", execcmd.gen("camera_rollleft"), t ); events->registerEvent(SDLK_KP3, "keycamera_rollright", execcmd.gen("camera_rollright"), t ); events->registerEvent(SDLK_f, "inc_fullscreen", execcmd.gen("settings_increase", "fullscreen"), 0, 0, 0 ); mouselook = false; oldx = -100; oldy = -100; frameCounter = 0; world->init(); // lightwaveFrame = 0; } void Evolution::draw() { if ( pause ) { usleep(20000); return; } frameCounter++; Timer::Instance()->mark(); sleeper.mark(); if ( *benchmark == 1 ) { if ( frameCounter == 10000 ) { float ms = Timer::Instance()->sdl_lasttime - Timer::Instance()->sdl_firsttime; cerr << "benchmark: ran " << frameCounter << " frames in " << ms/1000 << " sec, avg: " << (float)frameCounter / ms * 1000 << endl; cerr << "and btw, freeEnergy: " << world->freeEnergy << ", critters: " << world->critters.size() << endl; exit(0); } } if ( !*world->headless ) { handleEvents(); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // 3D // GLfloat ambientLight[] = {0.5f, 0.5f, 0.5f, 1.0f}; GLfloat ambientLight[] = {0.6f, 0.6f, 0.6f, 0.0f}; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambientLight); // GLfloat lightColor[] = { 0.1f, 0.1f, 0.1f, 1.0f }; /* lightwaveFrame+=0.001f; if (lightwaveFrame >=3.1415 ) lightwaveFrame = 0; float lightwaveFrameSine = sin(lightwaveFrame) * 0.2f; GLfloat lightColor[] = { lightwaveFrameSine, lightwaveFrameSine, lightwaveFrameSine, 0.0f };*/ GLfloat lightColor[] = { 0.04f, 0.04f, 0.04f, 0.0f }; GLfloat lightPos[] = { 0.5f * *world->worldsizeX, 50.0f, 0.5f * *world->worldsizeY, 1.0f }; // GLfloat lightPos1[] = { 0.0f, 20.0f, 0.5f*settings->getCVar("worldsizeY"), 1.0f }; // GLfloat lightPos2[] = { settings->getCVar("worldsizeX")+1.0f, 20, 0.5f*settings->getCVar("worldsizeY"), 1.0f }; glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor); glLightfv(GL_LIGHT0, GL_POSITION, lightPos); // glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor); // glLightfv(GL_LIGHT0, GL_POSITION, lightPos1); // glLightfv(GL_LIGHT1, GL_DIFFUSE, lightColor); // glLightfv(GL_LIGHT1, GL_POSITION, lightPos2); glEnable(GL_DEPTH_TEST); glEnable(GL_COLOR_MATERIAL); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); // glEnable(GL_LIGHT1); // glEnable(GL_CULL_FACE); // glCullFace(GL_BACK); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_FASTEST); // glHint(GL_FOG_HINT, GL_FASTEST); // glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); glShadeModel(GL_FLAT); // glShadeModel(GL_SMOOTH); glDisable(GL_DITHER); glDisable(GL_POLYGON_SMOOTH); } world->process(); world->getGeneralStats(); if ( !*world->headless ) { // if (world->critters.size() > 1 ) // { // world->camera.follow( (btDefaultMotionState*)world->critters[0]->body.mouths[0]->body->getMotionState() ); // world->drawWithoutFaces(); // // world->critters[0]->printVision(); // } world->camera.place(); if ( *drawscene == 1 ) { world->drawWithGrid(); // draw selected info btScalar position[16]; btTransform trans; trans.setIdentity(); btTransform up; up.setIdentity(); up.setOrigin( btVector3(0.0f, 0.2f, 0.0f) ); for ( unsigned int i=0; i < world->critterselection->clist.size(); i++ ) { trans.setOrigin(world->critterselection->clist[i]->body.mouths[0]->ghostObject->getWorldTransform().getOrigin()); trans.getOrigin().setY(trans.getOrigin().getY()+0.5f); trans.setBasis(world->camera.position.getBasis()); trans *= up; trans.getOpenGLMatrix(position); glPushMatrix(); glMultMatrixf(position); glColor3f(1.5f, 1.5f, 1.5f); glBegin(GL_LINES); glVertex2f(-0.2f, 0.05f); glVertex2f(-0.2f,-0.05f); glVertex2f(-0.2f,-0.05f); glVertex2f(0.2f, -0.05f); glVertex2f(0.2f, -0.05f); glVertex2f(0.2f, 0.05f); glVertex2f(0.2f, 0.05f); glVertex2f(-0.2f, 0.05f); glEnd(); glPopMatrix(); } } // 2D if ( canvas.active ) { glDisable(GL_DEPTH_TEST); glDisable (GL_LIGHTING); glDisable(GL_LIGHT0); // glDisable(GL_LIGHT1); glDisable(GL_COLOR_MATERIAL); // glDisable(GL_DITHER); // glDisable(GL_CULL_FACE); glPushMatrix(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, *Settings::Instance()->winWidth, *Settings::Instance()->winHeight, 0, 0, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); canvas.draw(); if ( *drawscene == 1 ) { world->mouseRayHit = false; if (!mouselook && !canvas.mouseFocus ) world->castMouseRay(); // hover test if ( world->mouseRayHit ) { unsigned int margin = 20; unsigned int rmargindistance = 70; unsigned int vspacer = 12; glColor3f(1.0f, 1.0f, 1.0f); if ( world->mouseRayHitEntity->type == 1 ) { Textprinter::Instance()->print( oldx+margin, oldy, "food"); Textprinter::Instance()->print( oldx+margin, oldy+vspacer, "energy"); Textprinter::Instance()->print(oldx+rmargindistance, oldy+vspacer, "%1.1f", static_cast(world->mouseRayHitEntity)->energyLevel); } else if ( world->mouseRayHitEntity->type == 0 ) { CritterB* c = static_cast(world->mouseRayHitEntity); Textprinter::Instance()->print( oldx+margin, oldy, "critter"); Textprinter::Instance()->print(oldx+rmargindistance, oldy, "%1i", c->critterID); Textprinter::Instance()->print( oldx+margin, oldy+vspacer, "energy"); Textprinter::Instance()->print(oldx+rmargindistance, oldy+vspacer, "%1.1f", c->energyLevel); } } } glPopMatrix(); } SDL_GL_SwapBuffers(); } if ( world->critters.size() == 0 && settings->getCVar("exit_if_empty") ) { cerr << "world is empty, exiting..." << endl; cmd->quit(); } } void Evolution::handlekeyPressed(const SDLKey& key) { if ( pause && key != SDLK_p ) return; switch (key) { case SDLK_m: { mouselook = !mouselook; if ( mouselook ) { #ifdef _WIN32 SDL_WarpMouse(0,0); #endif SDL_WM_GrabInput(SDL_GRAB_ON); SDL_ShowCursor(SDL_DISABLE); // clear remaining poll events { SDL_Event e; while (SDL_PollEvent(&e)) {} }; // release picked objects world->mousepicker->detach(); } else { SDL_ShowCursor(SDL_ENABLE); SDL_WM_GrabInput(SDL_GRAB_OFF); } } break; case SDLK_p: pause = !pause; break; case SDLK_s: // FIXME make use of savedir (declared in world) { settings->saveProfile(); stringstream buf; buf << "Profile saved to: " << world->dirlayout->savedir << "/" << settings->profileName << "/" << settings->profileName << ".pro"; Logbuffer::Instance()->add(buf); cerr << buf.str() << endl; } break; case SDLK_l: sleeper.swap(); break; default: events->activateEvent(key); events->handlecommands(); break; } } void Evolution::handlekeyReleased(const SDLKey& key) { events->deactivateEvent(key); } void Evolution::handlemousebuttonPressed(int x, int y, const int& button) { // cerr << "button " << button << " clicked at " << x << "x" << y << endl; if ( !mouselook ) { canvas.buttonPress(button); if ( button == 1 ) world->selectBody( x, y ); else if ( button == 2 ) world->resetCamera(); else if ( button == 3 ) world->pickBody( x, y ); else if ( button == 4 ) world->moveInMouseDirection(true); else if ( button == 5 ) world->moveInMouseDirection(false); } } void Evolution::handlemousebuttonReleased(int x, int y, const int& button) { // cerr << "button " << button << " released at " << x << "x" << y << endl; canvas.buttonRelease(button); if ( button == 1 ) ; else if ( button == 3 ) world->mousepicker->detach(); } void Evolution::handleMouseMotionAbs(int x, int y) { if ( !mouselook ) { oldx = x; oldy = y; // gui mouse dynamics canvas.moveMouse(x, y); // world mouse dynamics world->calcMouseDirection(); world->movePickedBodyTo(); } } void Evolution::handleMouseMotionRel(int x, int y) { if ( mouselook ) { if ( x > 0 ) world->camera.lookRight( (float)x/3000 ); else if ( x != 0 ) world->camera.lookLeft( (float)x/-3000 ); if ( y > 0 ) world->camera.lookDown( (float)y/3000 ); else if ( y != 0 ) world->camera.lookUp( (float)y/-3000 ); } } void Evolution::handleEvents() { events->processSharedTimers(); events->handlecommands(); } Evolution::~Evolution() { delete world; } critterding-beta12.1/src/scenes/modes/0000755000175000017500000000000011347266042016720 5ustar bobkebobkecritterding-beta12.1/src/scenes/modes/race.cpp0000644000175000017500000002432411343530351020334 0ustar bobkebobke#include "race.h" WorldRace::WorldRace() { } void WorldRace::init() { testcounter = 1; cerr << endl << "Initializing run " << testcounter << " ... " << endl; // insert Floor makeFloor(); // autoload critters if ( settings->getCVar("autoload") ) loadAllCritters(); // insert first batch of critters for ( unsigned int i=critters.size(); i < settings->getCVar("mincritters"); i++ ) insRandomCritter( i ); // insert food for ( unsigned int i=0; i < settings->getCVar("mincritters"); i++ ) insFood( i ); framecounter = 0; haveWinner = false; cerr<< "Running" << " ... " << endl; } void WorldRace::process() { autosaveCritters(); // do a bullet step m_dynamicsWorld->stepSimulation(0.016667f, 0, 0.016667f); // m_dynamicsWorld->stepSimulation(0.016667f); // m_dynamicsWorld->stepSimulation(Timer::Instance()->bullet_ms / 1000.f); // render critter vision, optimized for this sim renderVision(); // Read pixels into retina grabVision(); // process all critters for( unsigned int i=0; i < critters.size(); i++) { CritterB *c = critters[i]; // TOUCH inputs and references -> find overlappings checkCollisions( c ); // process c->process(); // process Output Neurons if ( c->eat && c->touchingFood ) { Food* f = static_cast(c->touchedEntity); float eaten = *critter_maxenergy / 100.0f; if ( c->energyLevel + eaten > *critter_maxenergy ) eaten -= (c->energyLevel + eaten) - *critter_maxenergy; if ( f->energyLevel - eaten < 0 ) eaten = f->energyLevel; c->energyLevel += eaten; f->energyLevel -= eaten; // if a food unit has no more energy left, we have a winner, the race is over if ( f->energyLevel == 0.0f ) haveWinner = true; } } framecounter++; if ( (haveWinner || framecounter >= settings->getCVar("critter_maxlifetime")) ) { if ( haveWinner ) cerr << "we have a WINNER after " << framecounter << " frames" << endl; cerr << "Evaluating..." << endl; // measure their distances from their respective food targets for ( unsigned int i=0; i < critters.size(); i++ ) { // fitness function 1: distance to food cube btDefaultMotionState* cmyMotionState = (btDefaultMotionState*)critters[i]->body.mouths[0]->body->getMotionState(); btVector3 cposi = cmyMotionState->m_graphicsWorldTrans.getOrigin(); btDefaultMotionState* fmyMotionState = (btDefaultMotionState*)food[i]->body.bodyparts[0]->body->getMotionState(); btVector3 fposi = fmyMotionState->m_graphicsWorldTrans.getOrigin(); critters[i]->fitness_index = 1.0f /(cposi.distance(fposi) + 0.0000001); // fitness function 2: energy of food consumed critters[i]->fitness_index += ( (float)settings->getCVar("food_maxenergy") /(food[i]->energyLevel + 0.0000001)); } // initialize sort indices vector indices ( critters.size(), 0 ); for ( unsigned int i = 0; i < critters.size(); i++ ) indices[i] = i; // sort results for ( int i = critters.size(); i>0; i-- ) for ( int j = 0; j < i-1; j++ ) if ( critters[indices[j]]->fitness_index < critters[indices[j+1]]->fitness_index ) { unsigned keepI = indices[j]; indices[j] = indices[j+1]; indices[j+1] = keepI; } // display results for ( unsigned int i=0; i < critters.size(); i++ ) cerr << "c " << indices[i] << " : " << critters[indices[i]]->fitness_index << endl; cerr << endl << "Initializing run " << ++testcounter << " ... " << endl; // backup the 50% best critters vector best; unsigned int bestNum = critters.size()/2; if ( critters.size() == 1 ) bestNum = 1; for ( unsigned int i=0; i < bestNum; i++ ) best.push_back( new CritterB(*critters[indices[i]], critters[indices[i]]->critterID, btVector3( 0.0f, 0.0f, 0.0f ), false, false) ); // remove critters and food for ( unsigned int i=0; i < critters.size(); i++ ) { stringstream buf; buf << setw(4) << critters[i]->critterID << " old"; Textverbosemessage::Instance()->addDeath(buf); if ( critters[i]->isPicked ) mousepicker->detach(); // FIXME on windows, we segfault here 1/10 after the first run critterselection->unregisterCritterID(critters[i]->critterID); critterselection->deselectCritter(critters[i]->critterID); delete critters[i]; // FIXME } critters.clear(); for ( unsigned int i=0; i < food.size(); i++ ) { if ( food[i]->isPicked ) mousepicker->detach(); delete food[i]; } food.clear(); // clear floor and remake it makeFloor(); // reinsert the best critters for ( unsigned int i=0; i < best.size() && i < settings->getCVar("mincritters"); i++ ) insMutatedCritter( *best[i], critters.size(), best[i]->critterID, false, false ); // insert the mutants unsigned int count = 0; while ( critters.size() < settings->getCVar("mincritters") ) { if ( best.size() > 0 ) { bool brainmutant = false; bool bodymutant = false; if ( randgen->Instance()->get(1,100) <= settings->getCVar("brain_mutationrate") ) brainmutant = true; if ( randgen->Instance()->get(1,100) <= settings->getCVar("body_mutationrate") ) bodymutant = true; insMutatedCritter( *best[count], critters.size(), currentCritterID++, brainmutant, bodymutant ); CritterB* c = best[count]; CritterB* nc = critters[critters.size()-1]; stringstream buf; buf << setw(4) << c->critterID << " : " << setw(4) << nc->critterID; buf << " ad: " << setw(4) << nc->genotype->adamdist; buf << " n: " << setw(4) << nc->brain.totalNeurons << " s: " << setw(5) << nc->brain.totalSynapses; count++; if ( count == best.size() && count > 0 ) count = 0; if ( brainmutant || bodymutant ) { buf << " "; if ( brainmutant ) buf << "brain"; if ( brainmutant && bodymutant ) buf << "+"; if ( bodymutant ) buf << "body"; buf << " mutant"; } Textverbosemessage::Instance()->addBirth(buf); } else insRandomCritter( critters.size() ); } // remove best again for ( unsigned int i=0; i < best.size(); i++ ) delete best[i]; // reinsert respective food units for ( unsigned int i=0; i < settings->getCVar("mincritters"); i++ ) insFood( i ); framecounter = 0; haveWinner = false; cerr << "Running... " << endl; } } void WorldRace::makeFloor() { for ( unsigned int i=0; i < walls.size(); i++ ) delete walls[i]; walls.clear(); critterspacing = (float)settings->getCVar("worldsizeX") / settings->getCVar("mincritters"); makeDefaultFloor(); // seperator walls float WallWidth = 0.2f; float WallHalfWidth = WallWidth/2.0f; float WallHeight = 1.0f; float WallHalfHeight = WallHeight/2.0f; for ( unsigned int i=1; i < settings->getCVar("mincritters"); i++ ) { btVector3 position = btVector3 ( 0.0f-WallHalfWidth + (critterspacing*i), WallHalfHeight-WallWidth, settings->getCVar("worldsizeY")/2.0f ); Wall* w = new Wall( WallWidth, WallHeight, settings->getCVar("worldsizeY"), position, m_dynamicsWorld ); w->color.r = 0.34f; w->color.g = 0.25f; w->color.b = 0.11f; walls.push_back(w); } } void WorldRace::insRandomCritter(int nr) { CritterB *c = new CritterB(m_dynamicsWorld, currentCritterID++, btVector3( (critterspacing/2)+(critterspacing*nr), 1.0f, settings->getCVar("worldsizeY")-2.0f ), retina); c->energyLevel = settings->getCVar("critter_maxenergy") / 2; critters.push_back( c ); c->calcFramePos(critters.size()-1); } void WorldRace::insMutatedCritter(CritterB& other, int nr, unsigned int id, bool mutateBrain, bool mutateBody) { CritterB *nc = new CritterB(other, id, btVector3( (critterspacing/2)+(critterspacing*nr), 1.0f, settings->getCVar("worldsizeY")-2.0f ), mutateBrain, mutateBody); nc->energyLevel = settings->getCVar("critter_maxenergy") / 2; critters.push_back( nc ); nc->calcFramePos(critters.size()-1); } void WorldRace::insFood(int nr) { Food *f = new Food; f->energyLevel = settings->getCVar("food_maxenergy"); f->createBody( m_dynamicsWorld, btVector3( (critterspacing/2)+(critterspacing*nr), 1.0f, 2.0f ) ); food.push_back( f ); } void WorldRace::insertCritter() { cerr << "inserting critters is disabled during race" << endl; } void WorldRace::loadAllCritters() { if ( critters.size() > 0 ) { stringstream buf; buf << "use --autoload 1 at commandline to autoload critters into a race"; Logbuffer::Instance()->add(buf); cerr << "use --autoload 1 at commandline to autoload critters into a race" << endl; } else { vector files; dirH.listContentsFull(dirlayout->loaddir, files); unsigned int inserted = 0; for ( unsigned int i = 0; i < files.size() && inserted < settings->getCVar("mincritters"); i++ ) { if ( parseH->Instance()->endMatches( ".cr", files[i] ) ) { stringstream buf; buf << "loading " << files[i]; Logbuffer::Instance()->add(buf); string content; fileH.open( files[i], content ); critterspacing = (float)settings->getCVar("worldsizeX") / settings->getCVar("mincritters"); CritterB *c = new CritterB(content, m_dynamicsWorld, btVector3( (critterspacing/2)+(critterspacing*critters.size()), 1.0f, settings->getCVar("worldsizeY")-(settings->getCVar("worldsizeY")/4) ), retina); unsigned int error = 0; if ( c->genotype->bodyArch->retinasize != *critter_retinasize ) error = 1; if ( !error) { critters.push_back( c ); c->critterID = currentCritterID++; c->calcFramePos(critters.size()-1); c->energyLevel = settings->getCVar("critter_maxenergy") / 2; inserted++; } else { delete c; if ( error == 1 ) { stringstream buf; buf << "ERROR: critter retinasize (" << c->genotype->bodyArch->retinasize << ") doesn't fit world retinasize (" << *critter_retinasize << ")" << files[i]; Logbuffer::Instance()->add(buf); cerr << "ERROR: critter retinasize (" << c->genotype->bodyArch->retinasize << ") doesn't fit world retinasize (" << *critter_retinasize << ")" << endl; } } } } stringstream buf; buf << "Loaded critters from " << dirlayout->loaddir; Logbuffer::Instance()->add(buf); //cerr << endl << "Loaded critters from " << loaddir << endl << endl; } } WorldRace::~WorldRace() { } critterding-beta12.1/src/scenes/modes/Makefile.am0000644000175000017500000000036111343530351020745 0ustar bobkebobkeINCLUDES = $(all_includes) -I../../utils/bullet -fopenmp METASOURCES = AUTO noinst_LTLIBRARIES = libmodes.la noinst_HEADERS = race.h \ testworld1.h \ roundworld.h libmodes_la_SOURCES = race.cpp \ testworld1.cpp \ roundworld.cpp critterding-beta12.1/src/scenes/modes/testworld1.cpp0000644000175000017500000000376511343530351021540 0ustar bobkebobke#include "testworld1.h" TestWorld1::TestWorld1() { } void TestWorld1::init() { makeFloor(); // extra Ground Floor float WallWidth = 0.1f; float WallHalfWidth = WallWidth/2.0f; decSizeFactor = 0.5f; elevations = 10; insertHight = 1.0f + (WallWidth*elevations); for ( unsigned int i=0; i < elevations; i++ ) { btVector3 position( (float)settings->getCVar("worldsizeX")/2.0f, (i*WallWidth)+WallHalfWidth, (float)settings->getCVar("worldsizeY")/2.0f ); Wall* w = new Wall( (float)settings->getCVar("worldsizeX")/(decSizeFactor*(i+2)), WallWidth, (float)settings->getCVar("worldsizeY")/(decSizeFactor*(i+2)), position, m_dynamicsWorld ); w->color.r = 0.34f+(0.005f*i); w->color.g = 0.25f+(0.005f*i); w->color.b = 0.11f+(0.005f*i); walls.push_back(w); } } void TestWorld1::process() { killHalf(); expireFood(); autoinsertFood(); expireCritters(); autosaveCritters(); autoinsertCritters(); // m_dynamicsWorld->stepSimulation(0.016667f); m_dynamicsWorld->stepSimulation(0.016667f, 0, 0.016667f); // m_dynamicsWorld->stepSimulation(Timer::Instance()->bullet_ms / 1000.f); renderVision(); grabVision(); unsigned int lmax = critters.size(); for( unsigned int i=0; i < lmax; i++) { CritterB *c = critters[i]; checkCollisions( c ); c->process(); freeEnergy += c->energyUsed; eat(c); procreate(c); } } btVector3 TestWorld1::findPosition() { for ( unsigned int i=0; i < elevations; i++ ) { if ( randgen->Instance()->get( i, elevations-1 ) == i ) { return btVector3( (float)settings->getCVar("worldsizeX")/2.0f - (float)settings->getCVar("worldsizeX")/(decSizeFactor*2*(i+2)) + ((float)randgen->Instance()->get( 0, (float)settings->getCVar("worldsizeX")/(decSizeFactor*(i+2))*100 ) / 100), insertHight, (float)settings->getCVar("worldsizeY")/2.0f - (float)settings->getCVar("worldsizeY")/(decSizeFactor*2*(i+2)) + ((float)randgen->Instance()->get( 0, (float)settings->getCVar("worldsizeY")/(decSizeFactor*(i+2))*100 ) / 100) ); } } } TestWorld1::~TestWorld1() { } critterding-beta12.1/src/scenes/modes/race.h0000644000175000017500000000105011266206502017772 0ustar bobkebobke#ifndef WORLDRACE_H #define WORLDRACE_H #include "../entities/worldb.h" class WorldRace : public WorldB { public: WorldRace(); ~WorldRace(); void process(); void init(); void insertCritter(); void loadAllCritters(); private: void makeFloor(); void insRandomCritter(int nr); void insMutatedCritter(CritterB& other, int nr, unsigned int id, bool mutateBrain, bool mutateBody); void insFood(int nr); float critterspacing; bool haveWinner; unsigned int framecounter; unsigned int testcounter; }; #endif critterding-beta12.1/src/scenes/modes/roundworld.h0000644000175000017500000000077311343530351021270 0ustar bobkebobke#ifndef ROUNDWORLD_H #define ROUNDWORLD_H #include "../entities/worldb.h" class Roundworld : public WorldB { public: Roundworld(); ~Roundworld(); void process(); void init(); void drawWithGrid(); private: void drawSphere(btScalar radius, int lats, int longs); btVector3 findPosition(); void makeFloor(); void drawfloor(); void childPositionOffset(btVector3* v); btCollisionObject* fixedGround; btCollisionShape* groundShape; btTransform groundTransform; }; #endif critterding-beta12.1/src/scenes/modes/roundworld.cpp0000644000175000017500000001122611347254352021626 0ustar bobkebobke#include "roundworld.h" Roundworld::Roundworld() { } void Roundworld::init() { //makeFloor(); groundTransform.setIdentity(); groundTransform.setOrigin( btVector3(0,0,0) ); groundShape = new btSphereShape(btScalar( *worldsizeX )); fixedGround = new btCollisionObject(); fixedGround->setUserPointer(this); fixedGround->setCollisionShape(groundShape); fixedGround->setWorldTransform(groundTransform); m_dynamicsWorld->addCollisionObject(fixedGround); if ( settings->getCVar("autoload") ) loadAllCritters(); } void Roundworld::process() { killHalf(); expireFood(); autoinsertFood(); expireCritters(); autoexchangeCritters(); autosaveCritters(); autoinsertCritters(); // adjust gravity vectors of all entities' rigid bodies unsigned int j, b; Food* f; CritterB* bod; btRigidBody* bo; unsigned int biggest = food.size(); if ( critters.size() > biggest ) biggest = critters.size(); // #pragma omp parallel for private(j, b, f, bod, bo) for ( j=0; j < biggest; j++ ) { // for( j=0; j < food.size(); j++) if( j < food.size() ) { f = food[j]; for( b=0; b < f->body.bodyparts.size(); b++) { bo = f->body.bodyparts[b]->body; bo->setGravity( -(bo->getCenterOfMassPosition().normalized()*10) ); } } // #pragma omp parallel for private(j, b) // for( j=0; j < critters.size(); j++) if( j < critters.size() ) { bod = critters[j]; for( b=0; b < bod->body.bodyparts.size(); b++) { bo = bod->body.bodyparts[b]->body; bo->setGravity( -(bo->getCenterOfMassPosition().normalized()*10) ); } } } if ( *critter_raycastvision == 0 ) { renderVision(); grabVision(); } // do a bullet step m_dynamicsWorld->stepSimulation(0.016667f, 0, 0.016667f); // m_dynamicsWorld->stepSimulation(Timer::Instance()->bullet_ms / 1000.f); int lmax = (int)critters.size(); CritterB *c; float freeEnergyc = 0.0f; // FIXME USE FROM WORLDB omp_set_num_threads( *threads ); #pragma omp parallel for ordered shared(freeEnergyc, lmax) private(c) // ordered for( int i=0; i < lmax; i++) { c = critters[i]; omp_set_lock(&my_lock1); checkCollisions( c ); omp_unset_lock(&my_lock1); // process c->process(); // record critter used energy freeEnergyc += c->energyUsed; // process Output Neurons eat(c); // procreation if procreation energy trigger is hit omp_set_lock(&my_lock1); procreate(c); omp_unset_lock(&my_lock1); } freeEnergy += freeEnergyc; } void Roundworld::makeFloor() { m_dynamicsWorld->removeCollisionObject(fixedGround); delete groundShape; delete fixedGround; groundShape = new btSphereShape(btScalar( *worldsizeX )); fixedGround = new btCollisionObject(); fixedGround->setUserPointer(this); fixedGround->setCollisionShape(groundShape); fixedGround->setWorldTransform(groundTransform); m_dynamicsWorld->addCollisionObject(fixedGround); } void Roundworld::drawWithGrid() { // drawfloor(); glPushMatrix(); glTranslatef(0,0,0); glColor4f( 0.3f, 0.2f, 0.1f, 1.0f ); drawSphere( *worldsizeX, (12.56637* *worldsizeX / 6), (12.56637* *worldsizeX / 3) ); glPopMatrix(); for( unsigned int i=0; i < critters.size(); i++) critters[i]->draw(true); for( unsigned int i=0; i < food.size(); i++) food[i]->draw(); } void Roundworld::childPositionOffset(btVector3* v) { *v+= (v->normalized()*insertHight); } btVector3 Roundworld::findPosition() { return btVector3( ((float)randgen->Instance()->get( 0, 200 )-100.0f) / 100, ((float)randgen->Instance()->get( 0, 200 )-100.0f) / 100, ((float)randgen->Instance()->get( 0, 200 )-100.0f) / 100 ).normalized() * ( *worldsizeX + insertHight); } void Roundworld::drawfloor() { glPushMatrix(); glTranslatef(0,0,0); glColor4f( 0.3f, 0.2f, 0.1f, 1.0f ); drawSphere( *worldsizeX, (12.56637* *worldsizeX / 12), (12.56637* *worldsizeX / 6) ); glPopMatrix(); } void Roundworld::drawSphere(btScalar radius, int lats, int longs) { int i, j; for(i = 0; i <= lats; i++) { btScalar lat0 = SIMD_PI * (-btScalar(0.5) + (btScalar) (i - 1) / lats); btScalar z0 = radius*sin(lat0); btScalar zr0 = radius*cos(lat0); btScalar lat1 = SIMD_PI * (-btScalar(0.5) + (btScalar) i / lats); btScalar z1 = radius*sin(lat1); btScalar zr1 = radius*cos(lat1); glBegin(GL_QUAD_STRIP); for(j = 0; j <= longs; j++) { btScalar lng = 2 * SIMD_PI * (btScalar) (j - 1) / longs; btScalar x = cos(lng); btScalar y = sin(lng); glNormal3f(x * zr1, y * zr1, z1); glVertex3f(x * zr1, y * zr1, z1); glNormal3f(x * zr0, y * zr0, z0); glVertex3f(x * zr0, y * zr0, z0); } glEnd(); } } Roundworld::~Roundworld() { m_dynamicsWorld->removeCollisionObject(fixedGround); delete groundShape; delete fixedGround; } critterding-beta12.1/src/scenes/modes/testworld1.h0000644000175000017500000000044111255546753021210 0ustar bobkebobke#ifndef TESTWORLD1_H #define TESTWORLD1_H #include "../entities/worldb.h" class TestWorld1 : public WorldB { public: TestWorld1(); ~TestWorld1(); void process(); void init(); private: btVector3 findPosition(); float decSizeFactor; unsigned int elevations; }; #endif critterding-beta12.1/src/scenes/evolution.h0000644000175000017500000000252111343530351017777 0ustar bobkebobke#ifndef EVOLUTION_H #define EVOLUTION_H #include #include "../gl/glscene.h" #include "../utils/timer.h" #include "../utils/sleeper.h" #include "../utils/fps.h" #include "../utils/settings.h" #include "../utils/events.h" #include "entities/worldb.h" #include "modes/race.h" #include "modes/roundworld.h" // #include // #include // #include // #include // #include #include "gui/maincanvas.h" #include "../utils/commands.h" #include "../utils/execcmd.h" using std::cerr; using std::endl; class Evolution : public GLScene { public: Evolution(); ~Evolution(); bool pause; void draw(); // glwindow passes events to the scene void handlekeyPressed(const SDLKey& key); void handlekeyReleased(const SDLKey& key); void handlemousebuttonPressed(int x, int y, const int&); void handlemousebuttonReleased(int x, int y, const int&); void handleMouseMotionRel(int x, int y); void handleMouseMotionAbs(int x, int y); WorldB* world; Execcmd execcmd; private: Settings *settings; const unsigned int* drawscene; const unsigned int* benchmark; Commands *cmd; Events *events; Sleeper sleeper; Maincanvas canvas; int mouse_x; int mouse_y; int oldx; int oldy; bool mouselook; // events void handleEvents(); long long frameCounter; }; #endif critterding-beta12.1/src/scenes/entities/0000755000175000017500000000000011347266042017435 5ustar bobkebobkecritterding-beta12.1/src/scenes/entities/bodyarch.h0000644000175000017500000000275111340265263021403 0ustar bobkebobke#ifndef BODYARCH_H #define BODYARCH_H #include "../../utils/randgen.h" #include "../../utils/parser.h" #include "../../utils/settings.h" #include "../../utils/color.h" #include "archbodypart.h" #include "archconstraint.h" #include "archmouth.h" #include #include #include using namespace std; class BodyArch { public: BodyArch(); ~BodyArch(); // load save architecture (serialize) void buildArch(); void setArch(string* content); string* getArch(); void copyFrom(const BodyArch* otherBody); void mutate(unsigned int runs); vector archBodyparts; vector archConstraints; vector archMouths; Color color; unsigned int retinasize; float totalWeight; int findBodypart(unsigned int id); int findMouth( unsigned int id ); private: Parser *parseH; RandGen *randgen; Settings *settings; float bodypartspacer; void repositiontoConstraints( archBodypart* bp ); void repositiontoConstraints( archMouth* bp ); // mutation helpers void addRandomMouth(); void addRandomBodypart(); void addRandomConstraint(unsigned int connID1, unsigned int connID2, bool isMouth); void removeBodypart(unsigned int id); void removeMouth(unsigned int id); void randomConstraintPosition(archConstraint* co, unsigned int OneOrTwo, unsigned int connID); unsigned int getUniqueBodypartID(); unsigned int getUniqueConstraintID(); string archBuffer; }; #endif critterding-beta12.1/src/scenes/entities/body.h0000644000175000017500000000352511337071441020544 0ustar bobkebobke#ifndef BODY_H #define BODY_H // #include "../../utils/timer.h" // #include "../../utils/randgen.h" // #include "../../utils/parser.h" // #include "../../utils/settings.h" #include "bodyarch.h" #include "bodypart.h" #include "constraint.h" #include "mouth.h" #include "GL/gl.h" // #include #include #include // #include #include "btBulletDynamicsCommon.h" using namespace std; class Body { public: Body(); ~Body(); void wireArch(BodyArch* bodyArch, void* owner, btDynamicsWorld* ownerWorld, const btVector3& startOffset); vector bodyparts; // void addBodyPart_Capsule(void* owner, float width, float height, float weight, btTransform& offset, btTransform& transform); void addBodyPart_Box(void* owner, float x, float y, float z, float weight, btTransform& offset, btTransform& transform); vector mouths; void addMouth(void* owner, float x, float y, float z, float weight, btTransform& offset, btTransform& transform); vector constraints; void addConstraint(unsigned int bodypartID1, unsigned int bodypartID2, btTransform& localA, btTransform& localB, double limitA, double limitB); void addConeTwistConstraint(unsigned int bodypartID1, unsigned int bodypartID2, btTransform& localA, btTransform& localB, double limitA, double limitB, double limitC); void add6DConstraint(unsigned int bodypartID1, unsigned int bodypartID2, btTransform& localA, btTransform& localB, const btVector3& lowerLimit, const btVector3& upperLimit); void addMouthConstraint(unsigned int mouthID, unsigned int bodypartID, btTransform& localA, btTransform& localB, double limitA, double limitB); void motorateExpand(unsigned int constraintID); void motorateContract(unsigned int constraintID); btDynamicsWorld* m_ownerWorld; float totalWeight; private: }; #endif critterding-beta12.1/src/scenes/entities/Makefile.am0000644000175000017500000000124311337071441021465 0ustar bobkebobkeINCLUDES = $(all_includes) -I../../utils/bullet -fopenmp METASOURCES = AUTO noinst_LTLIBRARIES = libentities.la noinst_HEADERS = camera.h \ entity.h \ genotype.h \ genotypes.h \ critterb.h \ food.h \ archbodypart.h \ archconstraint.h \ archmouth.h \ bodypart.h \ constraint.h \ mouth.h \ bodyarch.h \ body.h \ wall.h \ worldb.h libentities_la_SOURCES =camera.cpp \ entity.cpp \ genotype.cpp \ genotypes.cpp \ critterb.cpp \ food.cpp \ archbodypart.cpp \ archconstraint.cpp \ archmouth.cpp \ bodypart.cpp \ constraint.cpp \ mouth.cpp \ bodyarch.cpp \ body.cpp \ wall.cpp \ worldb.cpp critterding-beta12.1/src/scenes/entities/bodypart.cpp0000644000175000017500000000205511337071441021763 0ustar bobkebobke#include "bodypart.h" Bodypart::Bodypart(btDynamicsWorld* ownerWorld, void* owner, const btVector3& dimensions, float weight, btTransform& offset, btTransform& transform) { m_ownerWorld = ownerWorld; shape = new btBoxShape( dimensions ); btVector3 localInertia(0,0,0); if (weight != 0.f) // weight of non zero = dynamic shape->calculateLocalInertia(weight,localInertia); myMotionState = new btDefaultMotionState(offset*transform); btRigidBody::btRigidBodyConstructionInfo rbInfo(weight,myMotionState,shape,localInertia); body = new btRigidBody(rbInfo); body->setUserPointer(owner); body->setDamping(0.05, 0.85); body->setDeactivationTime(0.001); body->setSleepingThresholds(1.6, 2.5); m_ownerWorld->addRigidBody(body); } Bodypart::~Bodypart() { // Remove all bodies and shapes m_ownerWorld->getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(body->getBroadphaseHandle(),m_ownerWorld->getDispatcher()); m_ownerWorld->removeRigidBody(body); delete myMotionState; delete shape; // delete body->getMotionState(); delete body; } critterding-beta12.1/src/scenes/entities/bodyarch.cpp0000644000175000017500000014371011342625205021735 0ustar bobkebobke#include "bodyarch.h" BodyArch::BodyArch() { settings = Settings::Instance(); totalWeight = 0.0f; bodypartspacer = 2.2f; } void BodyArch::buildArch() { // string original; // original.append("b 99999 box 0 75 75 200\n"); // original.append("b 99998 box 0 75 75 200\n"); // original.append("b 99997 box 0 75 75 200\n"); // original.append("m 99999 50, 50, 100\n"); // original.append("c 99999 99998 99999 1.5707 0 0 0 0 -0.25 -0.7853 99998 1.5707 0 0 0 0 0.25 0.7853\n"); // original.append("c 99997 99996 99998 1.5707 0 0 0 0 -0.25 -0.7853 99997 1.5707 0 0 0 0 0.25 0.7853\n"); // original.append("cm 99995 99994 99997 0 1.5707 0 0 0 -0.15 -0.7853 99999 0 1.5707 0 0 0 0.25 0.7853\n"); // setArch(&original); // string fourlegged; // // body // fourlegged.append("b 99999 box 0 200 100 400\n"); // // 4 long legs // fourlegged.append("b 99998 box 0 150 40 40\n"); // fourlegged.append("b 99997 box 0 150 40 40\n"); // fourlegged.append("b 99996 box 0 150 40 40\n"); // fourlegged.append("b 99995 box 0 150 40 40\n"); // // mouth // fourlegged.append("m 99999 50, 50, 100\n"); // // connections // fourlegged.append("c 99999 99998 99999 0 0 0.7853 -0.2 0 -0.325 -0.7853 99998 0 0 0 0.25 0 0 0.7853\n"); // fourlegged.append("c 99997 99996 99999 0 0 0.7853 -0.2 0 0.325 -0.7853 99997 0 0 0 0.25 0 0 0.7853\n"); // fourlegged.append("c 99995 99994 99999 0 0 -0.7853 0.2 0 -0.325 -0.7853 99996 0 0 0 -0.25 0 0 0.7853\n"); // fourlegged.append("c 99993 99992 99999 0 0 -0.7853 0.2 0 0.325 -0.7853 99995 0 0 0 -0.25 0 0 0.7853\n"); // fourlegged.append("cm 99991 99990 99999 1.5707 0 0 0 0 -0.15 -0.3926 99999 1.5707 0 0 0 0 0.45 0.3926\n"); // setArch(&fourlegged); // string original; // original.append("b 1000 box 0 200 200 200\n"); // original.append("b 1001 box 0 100 100 100\n"); // original.append("b 1002 box 0 100 100 100\n"); // original.append("b 1003 box 0 100 100 100\n"); // original.append("b 1004 box 0 100 100 100\n"); // original.append("m 99999 50, 50, 100\n"); // // -x // original.append("c 1000 1001 1000 0.5707 1.3707 0.7707 -0.3 0 0 -0.7853 1001 1.1707 0.0707 0.5707 0.15 0 0 0.7853\n"); // -z // original.append("c 1002 1003 1000 1.5707 1.5707 1.5707 0 0 -0.3 -0.7853 1002 1.5707 1.5707 1.5707 0 0 0.15 0.7853\n"); // +z // original.append("c 1004 1005 1000 1.5707 0 0 0 0 0.3 -0.7853 1003 1.5707 0 0 0 0 -0.15 0.7853\n"); // +x // original.append("c 1006 1007 1000 1.5707 0 0 0.3 0 0 -0.7853 1004 1.5707 0 0 -0.15 0 0 0.7853\n"); // setArch(&original); // Create a central body archBodyparts.push_back( archBodypart() ); archBodypart *bp = &archBodyparts[archBodyparts.size()-1]; bp->id = 1000; bp->type = 0; bp->materialID = 0; bp->x = randgen->Instance()->get( settings->getCVar("body_minbodypartsize"), settings->getCVar("body_maxbodypartsize") ); bp->y = randgen->Instance()->get( settings->getCVar("body_minbodypartsize"), settings->getCVar("body_maxbodypartsize") ); bp->z = randgen->Instance()->get( settings->getCVar("body_minbodypartsize"), settings->getCVar("body_maxbodypartsize") ); // add random more unsigned int runs = randgen->Instance()->get( 0, settings->getCVar("body_maxbodypartsatbuildtime")-1 ); // -1 -> central bodypart for ( unsigned int i=0; i < runs; i++ ) addRandomBodypart(); addRandomMouth(); } void BodyArch::removeBodypart(unsigned int id) { // cerr << "requested removal of bodypart id " << id << endl; // find constraints where this bodypart is id1, in order to remove connected bodyparts for ( unsigned int i = 0; i < archConstraints.size(); i++ ) { archConstraint* c = &archConstraints[i]; if ( c->id_1 == id ) { // cerr << " is connected to " << c->isMouthConstraint << " " << c->id_2 << endl; if ( c->isMouthConstraint ) removeMouth( findMouth(c->id_2) ); else removeBodypart( c->id_2 ); } } // cerr << "really removing " << id << " which is " << findBodypart( id ) << endl; archBodyparts.erase( archBodyparts.begin() + findBodypart(id) ); } void BodyArch::removeMouth(unsigned int id) { // cerr << "removing mouth " << id << endl; archMouths.erase(archMouths.begin()+id); } void BodyArch::addRandomMouth() { // Throw in a mouth archMouths.push_back( archMouth() ); archMouth* mo = &archMouths[archMouths.size()-1]; mo->id = 1000; mo->x = randgen->Instance()->get( settings->getCVar("body_minheadsize"), settings->getCVar("body_maxheadsize") ); mo->y = randgen->Instance()->get( settings->getCVar("body_minheadsize"), settings->getCVar("body_maxheadsize") ); mo->z = randgen->Instance()->get( settings->getCVar("body_minheadsize"), settings->getCVar("body_maxheadsize") ); // Get it connected somehow unsigned int connID1 = randgen->Instance()->get( 0, archBodyparts.size()-1 ); unsigned int connID2 = archMouths.size()-1; addRandomConstraint(connID1, connID2, true); } void BodyArch::addRandomBodypart() { // Throw in a bodypart archBodyparts.push_back( archBodypart() ); archBodypart *bp = &archBodyparts[archBodyparts.size()-1]; bp->id = 0; // to avoid uninitialized id bp->id = getUniqueBodypartID(); bp->type = 0; bp->materialID = 0; bp->x = randgen->Instance()->get( settings->getCVar("body_minbodypartsize"), settings->getCVar("body_maxbodypartsize") ); bp->y = randgen->Instance()->get( settings->getCVar("body_minbodypartsize"), settings->getCVar("body_maxbodypartsize") ); bp->z = randgen->Instance()->get( settings->getCVar("body_minbodypartsize"), settings->getCVar("body_maxbodypartsize") ); // Get it connected somehow unsigned int connID1 = randgen->Instance()->get( 0, archBodyparts.size()-1 ); unsigned int connID2 = archBodyparts.size()-1; while ( connID1 == connID2 ) connID1 = randgen->Instance()->get( 0, archBodyparts.size()-1 ); addRandomConstraint(connID1, connID2, false); } void BodyArch::addRandomConstraint(unsigned int connID1, unsigned int connID2, bool isMouth) { archConstraints.push_back( archConstraint() ); archConstraint *co = &archConstraints[archConstraints.size()-1]; co->isMouthConstraint = isMouth; // first initialize constraint id's co->constraint_id1 = 0; co->constraint_id2 = 0; co->constraint_id1 = getUniqueConstraintID(); co->constraint_id2 = getUniqueConstraintID(); co->id_1 = archBodyparts[ connID1 ].id; if ( isMouth ) co->id_2 = archMouths[ connID2 ].id; else co->id_2 = archBodyparts[ connID2 ].id; co->rot_x_1 = ((float)randgen->Instance()->get( 0, 1571 ) - 0) / 1000; co->rot_y_1 = ((float)randgen->Instance()->get( 0, 1571 ) - 0) / 1000; co->rot_z_1 = ((float)randgen->Instance()->get( 0, 1571 ) - 0) / 1000; co->rot_x_2 = ((float)randgen->Instance()->get( 0, 1571 ) - 0) / 1000; co->rot_y_2 = ((float)randgen->Instance()->get( 0, 1571 ) - 0) / 1000; co->rot_z_2 = ((float)randgen->Instance()->get( 0, 1571 ) - 0) / 1000; randomConstraintPosition(co, 1, connID1); randomConstraintPosition(co, 2, connID2); co->limit_1 = (float)randgen->Instance()->get( 0, 7853 ) / -10000; co->limit_2 = -1.0f * co->limit_1; } void BodyArch::randomConstraintPosition(archConstraint* co, unsigned int OneOrTwo, unsigned int connID) { if ( OneOrTwo == 1 ) { co->XYZ = randgen->Instance()->get( 0, 2 ); co->sign = randgen->Instance()->get( 0, 1 ); if ( co->sign == 0 ) co->sign = -1; // now we know the plane to connect to, determine positions if ( co->XYZ == 0 ) // X { // ((x / 1000.0f) / 2) * 1.5f * co->sign = co->pos_x_1 = (archBodyparts[connID].x / 2000.0f) * co->sign * bodypartspacer; co->pos_y_1 = ((float)randgen->Instance()->get( 0, (archBodyparts[connID].y)*2) - archBodyparts[connID].y) / 1000; co->pos_z_1 = ((float)randgen->Instance()->get( 0, (archBodyparts[connID].z)*2) - archBodyparts[connID].z) / 1000; } else if ( co->XYZ == 1 ) // Y { co->pos_x_1 = ((float)randgen->Instance()->get( 0, (archBodyparts[connID].x)*2) - archBodyparts[connID].x) / 1000; co->pos_y_1 = (archBodyparts[connID].y / 2000.0f) * co->sign * bodypartspacer; co->pos_z_1 = ((float)randgen->Instance()->get( 0, (archBodyparts[connID].z)*2) - archBodyparts[connID].z) / 1000; } else // Z { co->pos_x_1 = ((float)randgen->Instance()->get( 0, (archBodyparts[connID].x)*2) - archBodyparts[connID].x) / 1000; co->pos_y_1 = ((float)randgen->Instance()->get( 0, (archBodyparts[connID].y)*2) - archBodyparts[connID].y) / 1000; co->pos_z_1 = (archBodyparts[connID].z / 2000.0f) * co->sign * bodypartspacer; } } else { int othersign = -1 * co->sign; if ( !co->isMouthConstraint ) { if ( co->XYZ == 0 ) // X { co->pos_x_2 = (archBodyparts[connID].x / 2000.0f) * othersign * bodypartspacer; co->pos_y_2 = ((float)randgen->Instance()->get( 0, (archBodyparts[connID].y)*2) - archBodyparts[connID].y) / 1000; co->pos_z_2 = ((float)randgen->Instance()->get( 0, (archBodyparts[connID].z)*2) - archBodyparts[connID].z) / 1000; } else if ( co->XYZ == 1 ) // Y { co->pos_x_2 = ((float)randgen->Instance()->get( 0, (archBodyparts[connID].x)*2) - archBodyparts[connID].x) / 1000; co->pos_y_2 = (archBodyparts[connID].y / 2000.0f) * othersign * bodypartspacer; co->pos_z_2 = ((float)randgen->Instance()->get( 0, (archBodyparts[connID].z)*2) - archBodyparts[connID].z) / 1000; } else // Z { co->pos_x_2 = ((float)randgen->Instance()->get( 0, (archBodyparts[connID].x)*2) - archBodyparts[connID].x) / 1000; co->pos_y_2 = ((float)randgen->Instance()->get( 0, (archBodyparts[connID].y)*2) - archBodyparts[connID].y) / 1000; co->pos_z_2 = (archBodyparts[connID].z / 2000.0f) * othersign * bodypartspacer; } } else { if ( co->XYZ == 0 ) // X { co->pos_x_2 = (archMouths[connID].x / 2000.0f) * othersign * bodypartspacer; co->pos_y_2 = ((float)randgen->Instance()->get( 0, (archMouths[connID].y)*2) - archMouths[connID].y) / 1000; co->pos_z_2 = ((float)randgen->Instance()->get( 0, (archMouths[connID].z)*2) - archMouths[connID].z) / 1000; } else if ( co->XYZ == 1 ) // Y { co->pos_x_2 = ((float)randgen->Instance()->get( 0, (archMouths[connID].x)*2) - archMouths[connID].x) / 1000; co->pos_y_2 = (archMouths[connID].y / 2000.0f) * othersign * bodypartspacer; co->pos_z_2 = ((float)randgen->Instance()->get( 0, (archMouths[connID].z)*2) - archMouths[connID].z) / 1000; } else // Z { co->pos_x_2 = ((float)randgen->Instance()->get( 0, (archMouths[connID].x)*2) - archMouths[connID].x) / 1000; co->pos_y_2 = ((float)randgen->Instance()->get( 0, (archMouths[connID].y)*2) - archMouths[connID].y) / 1000; co->pos_z_2 = (archMouths[connID].z / 2000.0f) * othersign * bodypartspacer; } } } } void BodyArch::mutate(unsigned int runs) { for ( unsigned int i=0; i < runs; i++ ) { unsigned int tsum = settings->getCVar("body_percentmutateeffectchangecolor") + settings->getCVar("body_percentmutateeffectchangecolor_slightly") + settings->getCVar("body_percentmutateeffectaddbodypart") + settings->getCVar("body_percentmutateeffectremovebodypart") + settings->getCVar("body_percentmutateeffectresizebodypart") + settings->getCVar("body_percentmutateeffectresizebodypart_slightly") + settings->getCVar("body_percentmutateeffectresizehead") + settings->getCVar("body_percentmutateeffectresizehead_slightly") + settings->getCVar("body_percentmutateeffectchangeconstraintlimits") + settings->getCVar("body_percentmutateeffectchangeconstraintlimits_slightly") + settings->getCVar("body_percentmutateeffectchangeconstraintangles") + settings->getCVar("body_percentmutateeffectchangeconstraintangles_slightly") + settings->getCVar("body_percentmutateeffectchangeconstraintposition") + settings->getCVar("body_percentmutateeffectchangeconstraintposition_slightly") + settings->getCVar("body_percentmutateeffectrepositionhead") ; unsigned int mode = randgen->Instance()->get(1,tsum); // CHANGE COLOR unsigned int modesum = settings->getCVar("body_percentmutateeffectchangecolor"); if ( mode <= modesum ) { // mutate color unsigned int ncolor = randgen->Instance()->get(0,2); if ( ncolor == 0 ) color.r = (float)RandGen::Instance()->get(0,100)/100.0f; else if ( ncolor == 1 ) color.g = (float)RandGen::Instance()->get(0,100)/100.0f; else if ( ncolor == 2 ) color.b = (float)RandGen::Instance()->get(0,100)/100.0f; continue; } // CHANGE COLOR SLIGHTLY modesum += settings->getCVar("body_percentmutateeffectchangecolor_slightly"); if ( mode <= modesum ) { // mutate color unsigned int ncolor = randgen->Instance()->get(0,2); unsigned int nweight = randgen->Instance()->get(1,10); float amount = 0.01 * nweight; if ( randgen->Instance()->get(0,1) == 0 ) amount *= -1; if ( ncolor == 0 ) color.r += amount; else if ( ncolor == 1 ) color.g += amount; else if ( ncolor == 2 ) color.b += amount; if ( color.r < 0.1f ) { float diff = 0.1f - color.r; color.r += diff; color.g += diff; color.b += diff; color.a += diff; } if ( color.g < 0.1f ) { float diff = 0.1f - color.g; color.r += diff; color.g += diff; color.b += diff; color.a += diff; } if ( color.b < 0.1f ) { float diff = 0.1f - color.b; color.r += diff; color.g += diff; color.b += diff; color.a += diff; } if ( color.r > 1.0f && color.g > 1.0f && color.b > 1.0f ) color.normalize(); continue; } // ADD BODYPART modesum += settings->getCVar("body_percentmutateeffectaddbodypart"); if ( mode <= modesum ) { if ( archBodyparts.size() < settings->getCVar("body_maxbodyparts") ) { // cerr << "adding bodypart" << endl; addRandomBodypart(); // cerr << "done adding bodypart" << endl; } else runs++; continue; } // REMOVE BODYPART modesum += settings->getCVar("body_percentmutateeffectremovebodypart"); if ( mode <= modesum ) { if ( archBodyparts.size() > 2 ) { // pick a random bodypart unsigned int bid = randgen->Instance()->get( 0, archBodyparts.size()-1 ); // if not main body, remove it if ( archBodyparts[bid].id != 1000 ) { // cerr << "removing bodypart " << bid << " id " << archBodyparts[bid].id << endl; removeBodypart( archBodyparts[bid].id ); // cerr << "removing obsolete constraints, expected errors:" << endl; for ( int i = 0; i < (int)archConstraints.size(); i++ ) { archConstraint* c = &archConstraints[i]; if ( findBodypart( c->id_1 ) == -1 ) { archConstraints.erase(archConstraints.begin()+i); i--; } else if ( c->isMouthConstraint && findMouth( c->id_2 ) == -1 ) { archConstraints.erase(archConstraints.begin()+i); i--; } else if ( !c->isMouthConstraint && findBodypart( c->id_2 ) == -1 ) { archConstraints.erase(archConstraints.begin()+i); i--; } } // cerr << "done removing obsolete constraints" << endl << endl; // cerr << "done removing bodypart" << endl; // re add mouth if needed if ( archMouths.size() == 0 ) addRandomMouth(); } else runs++; } else runs++; continue; } // RESIZE BODYPART modesum += settings->getCVar("body_percentmutateeffectresizebodypart"); if ( mode <= modesum ) { // cerr << "resize bodypart" << endl; // pick a random bodypart unsigned int bid = randgen->Instance()->get( 0, archBodyparts.size()-1 ); archBodypart *bp = &archBodyparts[bid]; unsigned int axismode = randgen->Instance()->get(0,2); if ( axismode == 0 ) bp->x = randgen->Instance()->get( settings->getCVar("body_minbodypartsize"), settings->getCVar("body_maxbodypartsize") ); else if ( axismode == 1 ) bp->y = randgen->Instance()->get( settings->getCVar("body_minbodypartsize"), settings->getCVar("body_maxbodypartsize") ); else bp->z = randgen->Instance()->get( settings->getCVar("body_minbodypartsize"), settings->getCVar("body_maxbodypartsize") ); // reposition the constraints back to the resized bodypart repositiontoConstraints(bp); // cerr << "done resize bodypart" << endl; continue; } // RESIZE BODYPART SLIGHTLY modesum += settings->getCVar("body_percentmutateeffectresizebodypart_slightly"); if ( mode <= modesum ) { // cerr << "resize bodypart slightly" << endl; // pick a random bodypart unsigned int bid = randgen->Instance()->get( 0, archBodyparts.size()-1 ); archBodypart* bp = &archBodyparts[bid]; unsigned int axismode = randgen->Instance()->get(0,2); unsigned int direction = randgen->Instance()->get(0,1); if ( axismode == 0 ) { if ( direction == 0 ) bp->x += randgen->Instance()->get( 1, settings->getCVar("body_maxbodypartsize") / 10 ); else bp->x -= randgen->Instance()->get( 1, settings->getCVar("body_maxbodypartsize") / 10 ); } else if ( axismode == 1 ) { if ( direction == 0 ) bp->y += randgen->Instance()->get( 1, settings->getCVar("body_maxbodypartsize") / 10 ); else bp->y -= randgen->Instance()->get( 1, settings->getCVar("body_maxbodypartsize") / 10 ); } else { if ( direction == 0 ) bp->z += randgen->Instance()->get( 1, settings->getCVar("body_maxbodypartsize") / 10 ); else bp->z -= randgen->Instance()->get( 1, settings->getCVar("body_maxbodypartsize") / 10 ); } // see that they didn't go over their limits if ( bp->x < settings->getCVar("body_minbodypartsize") ) bp->x = settings->getCVar("body_minbodypartsize"); else if ( bp->x > settings->getCVar("body_maxbodypartsize") ) bp->x = settings->getCVar("body_minbodypartsize"); if ( bp->y < settings->getCVar("body_minbodypartsize") ) bp->y = settings->getCVar("body_minbodypartsize"); else if ( bp->y > settings->getCVar("body_maxbodypartsize") ) bp->y = settings->getCVar("body_minbodypartsize"); if ( bp->z < settings->getCVar("body_minbodypartsize") ) bp->z = settings->getCVar("body_minbodypartsize"); else if ( bp->z > settings->getCVar("body_maxbodypartsize") ) bp->z = settings->getCVar("body_minbodypartsize"); // reposition the constraints back to the resized bodypart repositiontoConstraints(bp); // cerr << "done resize bodypart" << endl; continue; } // RESIZE HEAD modesum += settings->getCVar("body_percentmutateeffectresizehead"); if ( mode <= modesum ) { // cerr << "resize mouth" << endl; // pick a random head unsigned int mid = randgen->Instance()->get( 0, archMouths.size()-1 ); archMouth* head = &archMouths[mid]; unsigned int axismode = randgen->Instance()->get(0,2); if ( axismode == 0 ) head->x = randgen->Instance()->get( settings->getCVar("body_minheadsize"), settings->getCVar("body_maxheadsize") ); else if ( axismode == 1 ) head->y = randgen->Instance()->get( settings->getCVar("body_minheadsize"), settings->getCVar("body_maxheadsize") ); else head->z = randgen->Instance()->get( settings->getCVar("body_minheadsize"), settings->getCVar("body_maxheadsize") ); // reposition the constraints back to the resized bodypart repositiontoConstraints(head); // cerr << "done resize head" << endl; continue; } // RESIZE HEAD SLIGHTLY modesum += settings->getCVar("body_percentmutateeffectresizehead_slightly"); if ( mode <= modesum ) { // cerr << "resize head slightly" << endl; // pick a random head unsigned int mid = randgen->Instance()->get( 0, archMouths.size()-1 ); archMouth* head = &archMouths[mid]; unsigned int axismode = randgen->Instance()->get(0,2); unsigned int direction = randgen->Instance()->get(0,1); if ( axismode == 0 ) { if ( direction == 0 ) head->x += randgen->Instance()->get( 1, settings->getCVar("body_maxheadsize") / 10 ); else head->x -= randgen->Instance()->get( 1, settings->getCVar("body_maxheadsize") / 10 ); } else if ( axismode == 1 ) { if ( direction == 0 ) head->y += randgen->Instance()->get( 1, settings->getCVar("body_maxheadsize") / 10 ); else head->y -= randgen->Instance()->get( 1, settings->getCVar("body_maxheadsize") / 10 ); } else { if ( direction == 0 ) head->z += randgen->Instance()->get( 1, settings->getCVar("body_maxheadsize") / 10 ); else head->z -= randgen->Instance()->get( 1, settings->getCVar("body_maxheadsize") / 10 ); } // see that they didn't go over their limits if ( head->x < settings->getCVar("body_minheadsize") ) head->x = settings->getCVar("body_minheadsize"); else if ( head->x > settings->getCVar("body_maxheadsize") ) head->x = settings->getCVar("body_minheadsize"); if ( head->y < settings->getCVar("body_minheadsize") ) head->y = settings->getCVar("body_minheadsize"); else if ( head->y > settings->getCVar("body_maxheadsize") ) head->y = settings->getCVar("body_minheadsize"); if ( head->z < settings->getCVar("body_minheadsize") ) head->z = settings->getCVar("body_minheadsize"); else if ( head->z > settings->getCVar("body_maxheadsize") ) head->z = settings->getCVar("body_minheadsize"); // reposition the constraints back to the resized bodypart repositiontoConstraints(head); // cerr << "done resize head" << endl; continue; } // CHANGE CONSTRAINT LIMITS modesum += settings->getCVar("body_percentmutateeffectchangeconstraintlimits"); if ( mode <= modesum ) { // cerr << "changing constraint limits" << endl; unsigned int cid = randgen->Instance()->get( 0, archConstraints.size()-1 ); archConstraint* co = &archConstraints[cid]; co->limit_1 = (float)randgen->Instance()->get( 0, 7853 ) / -10000; co->limit_2 = -1.0f * co->limit_1; // cerr << "done changing constraint limits" << endl; continue; } // CHANGE CONSTRAINT LIMITS SLIGHTLY modesum += settings->getCVar("body_percentmutateeffectchangeconstraintlimits_slightly"); if ( mode <= modesum ) { // cerr << "changing constraint limits" << endl; unsigned int cid = randgen->Instance()->get( 0, archConstraints.size()-1 ); archConstraint* co = &archConstraints[cid]; unsigned int direction = randgen->Instance()->get(0,1); if ( direction == 0 ) co->limit_1 += 0.01f; else co->limit_1 -= 0.01f; // check limits limits, ya if ( co->limit_1 > 0.0f ) co->limit_1 = 0.0f; if ( co->limit_1 < -0.7853f ) co->limit_1 = -0.7853f; co->limit_2 = -1.0f * co->limit_1; // cerr << "done changing constraint limits" << endl; continue; } // CHANGE CONSTRAINT ANGLES modesum += settings->getCVar("body_percentmutateeffectchangeconstraintangles"); if ( mode <= modesum ) { // cerr << "changing constraint angles" << endl; unsigned int cid = randgen->Instance()->get( 0, archConstraints.size()-1 ); archConstraint* co = &archConstraints[cid]; co->rot_x_1 = ((float)randgen->Instance()->get( 0, 3141 ) - 1571) / 1000; co->rot_z_1 = ((float)randgen->Instance()->get( 0, 3141 ) - 1571) / 1000; co->rot_y_1 = ((float)randgen->Instance()->get( 0, 3141 ) - 1571) / 1000; co->rot_x_2 = ((float)randgen->Instance()->get( 0, 3141 ) - 1571) / 1000; co->rot_y_2 = ((float)randgen->Instance()->get( 0, 3141 ) - 1571) / 1000; co->rot_z_2 = ((float)randgen->Instance()->get( 0, 3141 ) - 1571) / 1000; // cerr << "done changing constraint angles" << endl; continue; } // CHANGE CONSTRAINT ANGLES SLIGHTLY modesum += settings->getCVar("body_percentmutateeffectchangeconstraintangles_slightly"); if ( mode <= modesum ) { // cerr << "changing constraint angles" << endl; unsigned int cid = randgen->Instance()->get( 0, archConstraints.size()-1 ); archConstraint* co = &archConstraints[cid]; unsigned int XYZ = randgen->Instance()->get(0,2); unsigned int direction = randgen->Instance()->get(0,1); if ( direction == 0 ) { if ( XYZ == 0 ) co->rot_x_1 += 0.01f; else if ( XYZ == 1 ) co->rot_y_1 += 0.01f; else co->rot_z_1 += 0.01f; } else { if ( XYZ == 0 ) co->rot_x_1 -= 0.01f; else if ( XYZ == 1 ) co->rot_y_1 -= 0.01f; else co->rot_z_1 -= 0.01f; } XYZ = randgen->Instance()->get(0,2); direction = randgen->Instance()->get(0,1); if ( direction == 0 ) { if ( XYZ == 0 ) co->rot_x_2 += 0.01f; else if ( XYZ == 1 ) co->rot_y_2 += 0.01f; else co->rot_z_2 += 0.01f; } else { if ( XYZ == 0 ) co->rot_x_2 -= 0.01f; else if ( XYZ == 1 ) co->rot_y_2 -= 0.01f; else co->rot_z_2 -= 0.01f; } if ( co->rot_x_1 < -0.1571f ) co->rot_x_1 = -0.1571f; if ( co->rot_x_1 > 0.1571f ) co->rot_x_1 = 0.1571f; if ( co->rot_y_1 < -0.1571f ) co->rot_y_1 = -0.1571f; if ( co->rot_y_1 > 0.1571f ) co->rot_y_1 = 0.1571f; if ( co->rot_z_1 < -0.1571f ) co->rot_z_1 = -0.1571f; if ( co->rot_z_1 > 0.1571f ) co->rot_z_1 = 0.1571f; if ( co->rot_x_2 < -0.1571f ) co->rot_x_2 = -0.1571f; if ( co->rot_x_2 > 0.1571f ) co->rot_x_2 = 0.1571f; if ( co->rot_y_2 < -0.1571f ) co->rot_y_2 = -0.1571f; if ( co->rot_y_2 > 0.1571f ) co->rot_y_2 = 0.1571f; if ( co->rot_z_2 < -0.1571f ) co->rot_z_2 = -0.1571f; if ( co->rot_z_2 > 0.1571f ) co->rot_z_2 = 0.1571f; // cerr << "done changing constraint angles" << endl; continue; } // REPOSITION A CONSTRAINT modesum += settings->getCVar("body_percentmutateeffectchangeconstraintposition"); if ( mode <= modesum ) { // cerr << "changing constraint position" << endl; unsigned int cid = randgen->Instance()->get( 0, archConstraints.size()-1 ); archConstraint* co = &archConstraints[cid]; int connID1 = findBodypart(co->id_1); int connID2; if ( co->isMouthConstraint ) connID2 = findMouth(co->id_2); else connID2 = findBodypart(co->id_2); // pick one of 2 bodies to reconnect unsigned int body1or2 = randgen->Instance()->get( 1, 2 ); if ( body1or2 == 1 ) randomConstraintPosition(co, 1, connID1); else randomConstraintPosition(co, 2, connID2); // cerr << "done changing constraint position" << endl; continue; } // REPOSITION A CONSTRAINT SLIGHTLY modesum += settings->getCVar("body_percentmutateeffectchangeconstraintposition_slightly"); if ( mode <= modesum ) { // cerr << "changing constraint position" << endl; unsigned int cid = randgen->Instance()->get( 0, archConstraints.size()-1 ); archConstraint* co = &archConstraints[cid]; int connID1 = findBodypart(co->id_1); int connID2; if ( co->isMouthConstraint ) connID2 = findMouth(co->id_2); else connID2 = findBodypart(co->id_2); // pick one of 2 bodies to reconnect unsigned int body1or2 = randgen->Instance()->get( 1, 2 ); unsigned int direction = randgen->Instance()->get( 0, 1 ); unsigned int axis1or2 = randgen->Instance()->get( 0, 1 ); if ( body1or2 == 1 ) { // now we know the plane to connect to, determine positions if ( co->XYZ == 0 ) { // X if ( direction == 0 ) { if ( axis1or2 == 0 ) co->pos_y_1 += archBodyparts[connID1].y / 100000; else co->pos_z_1 += archBodyparts[connID1].z / 100000; } else { if ( axis1or2 == 0 ) co->pos_y_1 -= archBodyparts[connID1].y / 100000; else co->pos_z_1 -= archBodyparts[connID1].z / 100000; } } else if ( co->XYZ == 1 ) { // Y if ( direction == 0 ) { if ( axis1or2 == 0 ) co->pos_x_1 += archBodyparts[connID1].x / 100000; else co->pos_z_1 += archBodyparts[connID1].z / 100000; } else { if ( axis1or2 == 0 ) co->pos_x_1 -= archBodyparts[connID1].x / 100000; else co->pos_z_1 -= archBodyparts[connID1].z / 100000; } } else { // Z if ( direction == 0 ) { if ( axis1or2 == 0 ) co->pos_x_1 += archBodyparts[connID1].x / 100000; else co->pos_y_1 += archBodyparts[connID1].y / 100000; } else { if ( axis1or2 == 0 ) co->pos_x_1 -= archBodyparts[connID1].x / 100000; else co->pos_y_1 -= archBodyparts[connID1].y / 100000; } } if ( co->pos_x_1 < archBodyparts[connID1].x/-2000 ) co->pos_x_1 = archBodyparts[connID1].x/-2000; if ( co->pos_x_1 > archBodyparts[connID1].x/2000 ) co->pos_x_1 = archBodyparts[connID1].x/2000; if ( co->pos_y_1 < archBodyparts[connID1].y/-2000 ) co->pos_y_1 = archBodyparts[connID1].y/-2000; if ( co->pos_y_1 > archBodyparts[connID1].y/2000 ) co->pos_y_1 = archBodyparts[connID1].y/2000; if ( co->pos_z_1 < archBodyparts[connID1].z/-2000 ) co->pos_z_1 = archBodyparts[connID1].z/-2000; if ( co->pos_z_1 > archBodyparts[connID1].z/2000 ) co->pos_z_1 = archBodyparts[connID1].z/2000; } else { if ( !co->isMouthConstraint ) { // now we know the plane to connect to, determine positions if ( co->XYZ == 0 ) { // X if ( direction == 0 ) { if ( axis1or2 == 0 ) co->pos_y_2 += archBodyparts[connID2].y / 100000; else co->pos_z_2 += archBodyparts[connID2].z / 100000; } else { if ( axis1or2 == 0 ) co->pos_y_2 -= archBodyparts[connID2].y / 100000; else co->pos_z_2 -= archBodyparts[connID2].z / 100000; } } else if ( co->XYZ == 1 ) { // Y if ( direction == 0 ) { if ( axis1or2 == 0 ) co->pos_x_2 += archBodyparts[connID2].x / 100000; else co->pos_z_2 += archBodyparts[connID2].z / 100000; } else { if ( axis1or2 == 0 ) co->pos_x_2 -= archBodyparts[connID2].x / 100000; else co->pos_z_2 -= archBodyparts[connID2].z / 100000; } } else { // Z if ( direction == 0 ) { if ( axis1or2 == 0 ) co->pos_x_2 += archBodyparts[connID2].x / 100000; else co->pos_y_2 += archBodyparts[connID2].y / 100000; } else { if ( axis1or2 == 0 ) co->pos_x_2 -= archBodyparts[connID2].x / 100000; else co->pos_y_2 -= archBodyparts[connID2].y / 100000; } } if ( co->pos_x_2 < archBodyparts[connID2].x/-2000 ) co->pos_x_2 = archBodyparts[connID2].x/-2000; if ( co->pos_x_2 > archBodyparts[connID2].x/2000 ) co->pos_x_2 = archBodyparts[connID2].x/2000; if ( co->pos_y_2 < archBodyparts[connID2].y/-2000 ) co->pos_y_2 = archBodyparts[connID2].y/-2000; if ( co->pos_y_2 > archBodyparts[connID2].y/2000 ) co->pos_y_2 = archBodyparts[connID2].y/2000; if ( co->pos_z_2 < archBodyparts[connID2].z/-2000 ) co->pos_z_2 = archBodyparts[connID2].z/-2000; if ( co->pos_z_2 > archBodyparts[connID2].z/2000 ) co->pos_z_2 = archBodyparts[connID2].z/2000; } else { if ( co->XYZ == 0 ) { // X if ( direction == 0 ) { if ( axis1or2 == 0 ) co->pos_y_2 += archMouths[connID2].y / 100000; else co->pos_z_2 += archMouths[connID2].z / 100000; } else { if ( axis1or2 == 0 ) co->pos_y_2 -= archMouths[connID2].y / 100000; else co->pos_z_2 -= archMouths[connID2].z / 100000; } } else if ( co->XYZ == 1 ) { // Y if ( direction == 0 ) { if ( axis1or2 == 0 ) co->pos_x_2 += archMouths[connID2].x / 100000; else co->pos_z_2 += archMouths[connID2].z / 100000; } else { if ( axis1or2 == 0 ) co->pos_x_2 -= archMouths[connID2].x / 100000; else co->pos_z_2 -= archMouths[connID2].z / 100000; } } else { // Z if ( direction == 0 ) { if ( axis1or2 == 0 ) co->pos_x_2 += archMouths[connID2].x / 100000; else co->pos_y_2 += archMouths[connID2].y / 100000; } else { if ( axis1or2 == 0 ) co->pos_x_2 -= archMouths[connID2].x / 100000; else co->pos_y_2 -= archMouths[connID2].y / 100000; } } if ( co->pos_x_2 < archMouths[connID2].x/-2000 ) co->pos_x_2 = archMouths[connID2].x/-2000; if ( co->pos_x_2 > archMouths[connID2].x/2000 ) co->pos_x_2 = archMouths[connID2].x/2000; if ( co->pos_y_2 < archMouths[connID2].y/-2000 ) co->pos_y_2 = archMouths[connID2].y/-2000; if ( co->pos_y_2 > archMouths[connID2].y/2000 ) co->pos_y_2 = archMouths[connID2].y/2000; if ( co->pos_z_2 < archMouths[connID2].z/-2000 ) co->pos_z_2 = archMouths[connID2].z/-2000; if ( co->pos_z_2 > archMouths[connID2].z/2000 ) co->pos_z_2 = archMouths[connID2].z/2000; } } // randomConstraintPosition(co, 2, connID2); // cerr << "done changing constraint position" << endl; continue; } // REMOVE AND ADD MOUTH modesum += settings->getCVar("body_percentmutateeffectrepositionhead"); if ( mode <= modesum ) { // cerr << "remove and add mouth" << endl; for ( int i = 0; i < (int)archConstraints.size(); i++ ) { archConstraint* c = &archConstraints[i]; if ( c->isMouthConstraint && c->id_2 == archMouths[0].id ) { archConstraints.erase(archConstraints.begin()+i); i--; } } removeMouth(0); addRandomMouth(); // cerr << "done remove and add mouth" << endl; continue; } // if we reach here, none were processed, decrease runs by 1 to make sure we get a hit if ( modesum > 0 ) runs++; } } void BodyArch::repositiontoConstraints( archBodypart* bp ) { // reposition the constraints back to the resized bodypart / mouth for ( int i = 0; i < (int)archConstraints.size(); i++ ) { archConstraint* co = &archConstraints[i]; if ( findBodypart( co->id_1 ) == (int)bp->id ) { if ( co->XYZ == 0 ) // X co->pos_x_1 = (bp->x / 2000.0f) * co->sign * bodypartspacer; else if ( co->XYZ == 1 ) // Y co->pos_y_1 = (bp->y / 2000.0f) * co->sign * bodypartspacer; else if ( co->XYZ == 2 ) // Z co->pos_z_1 = (bp->z / 2000.0f) * co->sign * bodypartspacer; } else if ( !co->isMouthConstraint && findBodypart( co->id_2 ) == (int)bp->id ) { int othersign = -1 * co->sign; if ( co->XYZ == 0 ) // X co->pos_x_2 = (bp->x / 2000.0f) * othersign * bodypartspacer; else if ( co->XYZ == 1 ) // Y co->pos_y_2 = (bp->y / 2000.0f) * othersign * bodypartspacer; else if ( co->XYZ == 2 ) // Z co->pos_z_2 = (bp->z / 2000.0f) * othersign * bodypartspacer; } } } void BodyArch::repositiontoConstraints( archMouth* bp ) { // reposition the constraints back to the resized bodypart / mouth for ( int i = 0; i < (int)archConstraints.size(); i++ ) { archConstraint* co = &archConstraints[i]; if ( co->isMouthConstraint && findBodypart( co->id_2 ) == (int)bp->id ) { int othersign = -1 * co->sign; if ( co->XYZ == 0 ) // X co->pos_x_2 = (bp->x / 2000.0f) * othersign * bodypartspacer; else if ( co->XYZ == 1 ) // Y co->pos_y_2 = (bp->y / 2000.0f) * othersign * bodypartspacer; else if ( co->XYZ == 2 ) // Z co->pos_z_2 = (bp->z / 2000.0f) * othersign * bodypartspacer; } } } int BodyArch::findBodypart( unsigned int id ) { for ( unsigned int i=0; i < archBodyparts.size(); i++ ) { if ( archBodyparts[i].id == id ) { return i; } } // cerr << " NOT GOOD: cannot find a bodypart for the id " << id << endl; return -1; } int BodyArch::findMouth( unsigned int id ) { for ( unsigned int i=0; i < archMouths.size(); i++ ) { if ( archMouths[i].id == id ) { return i; } } // cerr << " NOT GOOD " << endl; // cerr << " NOT GOOD: cannot find a mouth for the id " << id << endl; return -1; } unsigned int BodyArch::getUniqueBodypartID() { unsigned int id = 1000; bool found = true; while ( found ) { found = false; for ( unsigned int i = 0; i < archBodyparts.size() && !found; i++ ) if ( archBodyparts[i].id == id ) { found = true; id++; } } return id; } unsigned int BodyArch::getUniqueConstraintID() { unsigned int id = 1000; bool found = true; while ( found ) { found = false; for ( unsigned int i = 0; i < archConstraints.size() && !found; i++ ) { if ( archConstraints[i].constraint_id1 == id || archConstraints[i].constraint_id2 == id ) { found = true; id++; } } } return id; } void BodyArch::copyFrom(const BodyArch* otherBody) { color = otherBody->color; retinasize = otherBody->retinasize; for ( unsigned int i=0; i < otherBody->archBodyparts.size(); i++ ) { const archBodypart *obp = &otherBody->archBodyparts[i]; archBodyparts.push_back( archBodypart() ); archBodypart *bp = &archBodyparts[archBodyparts.size()-1]; bp->id = obp->id; bp->type = obp->type; bp->materialID = obp->materialID; bp->x = obp->x; bp->y = obp->y; bp->z = obp->z; } for ( unsigned int i=0; i < otherBody->archMouths.size(); i++ ) { const archMouth *omo = &otherBody->archMouths[i]; archMouths.push_back( archMouth() ); archMouth *mo = &archMouths[archMouths.size()-1]; mo->id = omo->id; mo->x = omo->x; mo->y = omo->y; mo->z = omo->z; } for ( unsigned int i=0; i < otherBody->archConstraints.size(); i++ ) { const archConstraint *oco = &otherBody->archConstraints[i]; archConstraints.push_back( archConstraint() ); archConstraint *co = &archConstraints[archConstraints.size()-1]; co->isMouthConstraint = oco->isMouthConstraint; co->constraint_id1 = oco->constraint_id1; co->constraint_id2 = oco->constraint_id2; co->XYZ = oco->XYZ; co->sign = oco->sign; co->id_1 = oco->id_1; co->id_2 = oco->id_2; co->rot_x_1 = oco->rot_x_1; co->rot_x_2 = oco->rot_x_2; co->rot_y_1 = oco->rot_y_1; co->rot_y_2 = oco->rot_y_2; co->rot_z_1 = oco->rot_z_1; co->rot_z_2 = oco->rot_z_2; co->pos_x_1 = oco->pos_x_1; co->pos_x_2 = oco->pos_x_2; co->pos_y_1 = oco->pos_y_1; co->pos_y_2 = oco->pos_y_2; co->pos_z_1 = oco->pos_z_1; co->pos_z_2 = oco->pos_z_2; co->limit_1 = oco->limit_1; co->limit_2 = oco->limit_2; } } void BodyArch::setArch(string* content) { // cerr << *content << endl; string contentCopy = *content; string line = parseH->Instance()->returnUntillStrip( "\n", contentCopy ); while ( !line.empty() ) { if ( Parser::Instance()->beginMatchesStrip( "color=", line ) ) { string R = Parser::Instance()->returnUntillStrip( ",", line ); string G = Parser::Instance()->returnUntillStrip( ",", line ); string B = Parser::Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(R.c_str(), "%f", &color.r)) cerr << "ERROR INSERTING CRITTER (colorR)" << endl; if(EOF == sscanf(G.c_str(), "%f", &color.g)) cerr << "ERROR INSERTING CRITTER (colorG)" << endl; if(EOF == sscanf(B.c_str(), "%f", &color.b)) cerr << "ERROR INSERTING CRITTER (colorB)" << endl; color.a = 0.0f; } else if ( Parser::Instance()->beginMatchesStrip( "retinasize=", line ) ) { string RES = Parser::Instance()->returnUntillStrip( ";", line ); //cerr << "RES: " << RES << endl; if(EOF == sscanf(RES.c_str(), "%d", &retinasize)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "b ", line ) ) { // b 99999 box 0 75 75 200 // cerr << "bodypart" << endl; archBodyparts.push_back( archBodypart() ); archBodypart *bp = &archBodyparts[archBodyparts.size()-1]; string bodypartID = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(bodypartID.c_str(), "%d", &bp->id)) cerr << "error in parsing body" << endl; string bodypartShape = Parser::Instance()->returnUntillStrip( " ", line ); if ( bodypartShape == "box" ) { // type = box bp->type = 0; // materialID string materialID = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(materialID.c_str(), "%d", &bp->materialID)) cerr << "error in parsing body" << endl; // dimesions X Y Z string X = Parser::Instance()->returnUntillStrip( " ", line ); string Y = Parser::Instance()->returnUntillStrip( " ", line ); string Z = line; if(EOF == sscanf(X.c_str(), "%f", &bp->x)) cerr << "error in parsing body" << endl; if(EOF == sscanf(Y.c_str(), "%f", &bp->y)) cerr << "error in parsing body" << endl; if(EOF == sscanf(Z.c_str(), "%f", &bp->z)) cerr << "error in parsing body" << endl; /* cerr << endl << " id " << bp->id << endl; cerr << " type " << bp->type << endl; cerr << " material " << bp->materialID << endl; cerr << " x " << bp->x << endl; cerr << " y " << bp->y << endl; cerr << " z " << bp->z << endl;*/ } } else if ( parseH->Instance()->beginMatchesStrip( "c ", line ) ) { // c 99999 1.5707963 0 0 0 0 -0.25 99998 1.5707963 0 0 0 0 0.25 // cm 0 1 1000 1001 1000 1.115 -0.752 -0.102 0.258 0.089 -0.133 -0.1103 1000 -1.4 -1.007 -1.287 -0.258 0.039 0.137 0.1103 // cerr << "constraint" << endl; archConstraint CO; archConstraints.push_back( CO ); archConstraint *co = &archConstraints[archConstraints.size()-1]; // XYZ & sign string XYZ = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(XYZ.c_str(), "%d", &co->XYZ)) cerr << "error in parsing body" << endl; string SIGN = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(SIGN.c_str(), "%d", &co->sign)) cerr << "error in parsing body" << endl; // CONSTRAINT IDS string ID = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ID.c_str(), "%d", &co->constraint_id1)) cerr << "error in parsing body" << endl; ID = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ID.c_str(), "%d", &co->constraint_id2)) cerr << "error in parsing body" << endl; // CONNECTION TO BODYPART 1 string ID_1 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ID_1.c_str(), "%d", &co->id_1)) cerr << "error in parsing body" << endl; // ROTATION string ROT_X_1 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ROT_X_1.c_str(), "%f", &co->rot_x_1)) cerr << "error in parsing body" << endl; string ROT_Y_1 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ROT_Y_1.c_str(), "%f", &co->rot_y_1)) cerr << "error in parsing body" << endl; string ROT_Z_1 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ROT_Z_1.c_str(), "%f", &co->rot_z_1)) cerr << "error in parsing body" << endl; // POSITION string POS_X_1 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(POS_X_1.c_str(), "%f", &co->pos_x_1)) cerr << "error in parsing body" << endl; string POS_Y_1 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(POS_Y_1.c_str(), "%f", &co->pos_y_1)) cerr << "error in parsing body" << endl; string POS_Z_1 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(POS_Z_1.c_str(), "%f", &co->pos_z_1)) cerr << "error in parsing body" << endl; // LIMIT string LIMIT_1 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(LIMIT_1.c_str(), "%f", &co->limit_1)) cerr << "error in parsing body" << endl; // CONNECTION TO BODYPART 2 string ID_2 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ID_2.c_str(), "%d", &co->id_2)) cerr << "error in parsing body" << endl; // ROTATION string ROT_X_2 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ROT_X_2.c_str(), "%f", &co->rot_x_2)) cerr << "error in parsing body" << endl; string ROT_Y_2 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ROT_Y_2.c_str(), "%f", &co->rot_y_2)) cerr << "error in parsing body" << endl; string ROT_Z_2 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ROT_Z_2.c_str(), "%f", &co->rot_z_2)) cerr << "error in parsing body" << endl; // POSITION string POS_X_2 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(POS_X_2.c_str(), "%f", &co->pos_x_2)) cerr << "error in parsing body" << endl; string POS_Y_2 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(POS_Y_2.c_str(), "%f", &co->pos_y_2)) cerr << "error in parsing body" << endl; string POS_Z_2 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(POS_Z_2.c_str(), "%f", &co->pos_z_2)) cerr << "error in parsing body" << endl; // LIMIT string LIMIT_2 = line; if(EOF == sscanf(LIMIT_2.c_str(), "%f", &co->limit_2)) cerr << "error in parsing body" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "cm ", line ) ) { // cm 99999 1.5707963 0 0 0 0 -0.25 99998 1.5707963 0 0 0 0 0.25 // cerr << "constraint" << endl; archConstraint CO; archConstraints.push_back( CO ); archConstraint *co = &archConstraints[archConstraints.size()-1]; co->isMouthConstraint = true; // XYZ & sign string XYZ = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(XYZ.c_str(), "%d", &co->XYZ)) cerr << "error in parsing body" << endl; string SIGN = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(SIGN.c_str(), "%d", &co->sign)) cerr << "error in parsing body" << endl; // CONSTRAINT IDS string ID = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ID.c_str(), "%d", &co->constraint_id1)) cerr << "error in parsing body" << endl; ID = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ID.c_str(), "%d", &co->constraint_id2)) cerr << "error in parsing body" << endl; // CONNECTION TO BODYPART 1 string ID_1 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ID_1.c_str(), "%d", &co->id_1)) cerr << "error in parsing body" << endl; // ROTATION string ROT_X_1 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ROT_X_1.c_str(), "%f", &co->rot_x_1)) cerr << "error in parsing body" << endl; string ROT_Y_1 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ROT_Y_1.c_str(), "%f", &co->rot_y_1)) cerr << "error in parsing body" << endl; string ROT_Z_1 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ROT_Z_1.c_str(), "%f", &co->rot_z_1)) cerr << "error in parsing body" << endl; // POSITION string POS_X_1 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(POS_X_1.c_str(), "%f", &co->pos_x_1)) cerr << "error in parsing body" << endl; string POS_Y_1 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(POS_Y_1.c_str(), "%f", &co->pos_y_1)) cerr << "error in parsing body" << endl; string POS_Z_1 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(POS_Z_1.c_str(), "%f", &co->pos_z_1)) cerr << "error in parsing body" << endl; // LIMIT string LIMIT_1 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(LIMIT_1.c_str(), "%f", &co->limit_1)) cerr << "error in parsing body" << endl; // CONNECTION TO BODYPART 2 string ID_2 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ID_2.c_str(), "%d", &co->id_2)) cerr << "error in parsing body" << endl; // ROTATION string ROT_X_2 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ROT_X_2.c_str(), "%f", &co->rot_x_2)) cerr << "error in parsing body" << endl; string ROT_Y_2 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ROT_Y_2.c_str(), "%f", &co->rot_y_2)) cerr << "error in parsing body" << endl; string ROT_Z_2 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ROT_Z_2.c_str(), "%f", &co->rot_z_2)) cerr << "error in parsing body" << endl; // POSITION string POS_X_2 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(POS_X_2.c_str(), "%f", &co->pos_x_2)) cerr << "error in parsing body" << endl; string POS_Y_2 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(POS_Y_2.c_str(), "%f", &co->pos_y_2)) cerr << "error in parsing body" << endl; string POS_Z_2 = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(POS_Z_2.c_str(), "%f", &co->pos_z_2)) cerr << "error in parsing body" << endl; // LIMIT string LIMIT_2 = line; if(EOF == sscanf(LIMIT_2.c_str(), "%f", &co->limit_2)) cerr << "error in parsing body" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "m ", line ) ) { // m 99999 50, 50, 100 // cerr << "constraint" << endl; archMouth MO; archMouths.push_back( MO ); archMouth *mo = &archMouths[archMouths.size()-1]; string ID = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(ID.c_str(), "%d", &mo->id)) cerr << "error in parsing body" << endl; string X = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(X.c_str(), "%f", &mo->x)) cerr << "error in parsing body" << endl; string Y = Parser::Instance()->returnUntillStrip( " ", line ); if(EOF == sscanf(Y.c_str(), "%f", &mo->y)) cerr << "error in parsing body" << endl; string Z = line; if(EOF == sscanf(Z.c_str(), "%f", &mo->z)) cerr << "error in parsing body" << endl; } line = parseH->Instance()->returnUntillStrip( "\n", contentCopy ); } } string* BodyArch::getArch() { stringstream buf; // neuron info buf << "color=" << color.r << "," << color.g << "," << color.b << ";\n"; buf << "retinasize=" << retinasize << ";\n"; for ( unsigned int i=0; i < archBodyparts.size(); i++ ) { archBodypart *bp = &archBodyparts[i]; buf << "b" << " " << bp->id << " " << "box" << " " << bp->materialID << " " << bp->x << " " << bp->y << " " << bp->z << "\n"; } for ( unsigned int i=0; i < archMouths.size(); i++ ) { archMouth *mo = &archMouths[i]; buf << "m" << " " << mo->id << " " << mo->x << " " << mo->y << " " << mo->z << "\n"; } for ( unsigned int i=0; i < archConstraints.size(); i++ ) { archConstraint *co = &archConstraints[i]; if ( co->isMouthConstraint ) buf << "cm"; else buf << "c"; buf << " " << co->XYZ << " " << co->sign; buf << " " << co->constraint_id1 << " " << co->constraint_id2 << " "; buf << co->id_1 << " " << co->rot_x_1 << " " << co->rot_y_1 << " " << co->rot_z_1 << " " << co->pos_x_1 << " " << co->pos_y_1 << " " << co->pos_z_1 << " " << co->limit_1 << " "; buf << co->id_2 << " " << co->rot_x_2 << " " << co->rot_y_2 << " " << co->rot_z_2 << " " << co->pos_x_2 << " " << co->pos_y_2 << " " << co->pos_z_2 << " " << co->limit_2; buf << "\n"; } archBuffer = buf.str(); return &archBuffer; } BodyArch::~BodyArch() { } critterding-beta12.1/src/scenes/entities/entity.cpp0000644000175000017500000000022211340265263021446 0ustar bobkebobke#include "entity.h" Entity::Entity() { type = 0; color.r = 0.0f; color.g = 0.0f; color.b = 0.0f; color.a = 0.0f; } Entity::~Entity() { } critterding-beta12.1/src/scenes/entities/bodypart.h0000644000175000017500000000070111334110375021421 0ustar bobkebobke#ifndef BODYPART_H #define BODYPART_H #include #include "btBulletDynamicsCommon.h" using namespace std; class Bodypart { public: Bodypart(btDynamicsWorld* ownerWorld, void* owner, const btVector3& dimensions, float weight, btTransform& offset, btTransform& transform); ~Bodypart(); btRigidBody* body; btCollisionShape* shape; btDefaultMotionState* myMotionState; private: btDynamicsWorld* m_ownerWorld; }; #endif critterding-beta12.1/src/scenes/entities/food.h0000644000175000017500000000127011343530351020526 0ustar bobkebobke#ifndef FOOD_H #define FOOD_H #include "btBulletDynamicsCommon.h" #include "GL/gl.h" #include "../../utils/settings.h" #include "../../utils/displaylists.h" #include "entity.h" #include "body.h" using namespace std; class Food : public Entity { public: Food(); ~Food(); Body body; void createBody(btDynamicsWorld* m_dynamicsWorld, const btVector3& startOffset); void draw(); btScalar position[16]; // float color[3]; unsigned int lifetime; float energyLevel; unsigned int totalFrames; btDefaultMotionState* myMotionState; private: Settings *settings; btBoxShape* boxShape; btVector3 halfExtent; const unsigned int* food_size; }; #endif critterding-beta12.1/src/scenes/entities/genotypes.h0000644000175000017500000000124111343530351021612 0ustar bobkebobke#ifndef GENOTYPES_H #define GENOTYPES_H #include "genotype.h" #include "../../utils/color.h" #include "../../utils/settings.h" #include #include using std::cerr; using std::endl; class Genotypes { public: static Genotypes* Instance(); Genotype* newg(Settings* settings); void add(Genotype* gt); Genotype* copy(Genotype* gt, bool brainmutant, unsigned int brruns, bool bodymutant, unsigned int boruns); Genotype* loadGenotype(string& content); string saveGenotype(); void remove(Genotype* gt); Color colorH; vector list; protected: Genotypes(); ~Genotypes(); private: static Genotypes* _instance; }; #endif critterding-beta12.1/src/scenes/entities/entity.h0000644000175000017500000000042511340265263021120 0ustar bobkebobke#ifndef ENTITY_H #define ENTITY_H #include "btBulletDynamicsCommon.h" #include "../../utils/color.h" using namespace std; class Entity { public: Entity(); ~Entity(); unsigned int type; // float color[4]; Color color; bool isPicked; private: }; #endif critterding-beta12.1/src/scenes/entities/worldb.h0000644000175000017500000001473011345336346021107 0ustar bobkebobke#ifndef WORLDB_H #define WORLDB_H #include "btBulletDynamicsCommon.h" // #include "BulletMultiThreaded/SpuCollisionTaskProcess.h" // #include "BulletMultiThreaded/SpuCollisionTaskProcess.h" // #include "BulletMultiThreaded/PosixThreadSupport.h" // #include "BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h" // #include "BulletMultiThreaded/SpuGatheringCollisionDispatcher.h" // #include "BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuMinkowskiPenetrationDepthSolver.h" // #include "LinearMath/btIDebugDraw.h" // #include "../../gl/gldebugdrawer.h" // #include #include #include // #include // #include // #include #include "../../utils/timer.h" #include "../../utils/dir.h" #include "../../utils/file.h" #include "../../utils/parser.h" #include "../../utils/settings.h" #include "../../utils/raycast.h" #include "../../utils/mousepicker.h" #include "../../utils/statsbuffer.h" #include "../../utils/critterselection.h" #include "../../utils/logbuffer.h" #include "../../utils/dirlayout.h" #include "../../utils/randgen.h" #include "../gui/textverbosemessage.h" #include "food.h" #include "wall.h" #include "critterb.h" #include "camera.h" using namespace std; class WorldB { class btThreadSupportInterface* m_threadSupportCollision; class btThreadSupportInterface* m_threadSupportSolver; public: WorldB(); virtual ~WorldB(); virtual void init(); virtual void process(); virtual btVector3 findPosition(); virtual void makeFloor(); float insertHight; void getGeneralStats(); void killHalf(); void expireFood(); void expireCritters(); void autoinsertFood(); void autosaveCritters(); void autoexchangeCritters(); void autoinsertCritters(); void eat( CritterB* c ); void procreate( CritterB* c ); void makeDefaultFloor(); Settings* settings; Critterselection *critterselection; Statsbuffer* statsBuffer; RandGen* randgen; Mousepicker* mousepicker; Dirlayout* dirlayout; Camera camera; void resetCamera(); //SpuGatheringCollisionDispatcher* m_dispatcher; btCollisionDispatcher* m_dispatcher; btBroadphaseInterface* m_broadphase; btDefaultCollisionConfiguration* m_collisionConfiguration; btDynamicsWorld* m_dynamicsWorld; btConstraintSolver* m_solver; // SpuMinkowskiPenetrationDepthSolver* m_solver; btAlignedObjectArray m_collisionShapes; vector critters; vector food; vector walls; unsigned long currentCritterID; float freeEnergy; //float freeEnergyInfo; virtual void drawWithGrid(); virtual void drawWithoutFaces(); void drawWithinCritterSight(CritterB *c); void drawWithinCritterSight(unsigned int cid); virtual void drawfloor(); virtual void childPositionOffset(btVector3* v); void startfoodamount(unsigned int amount); void insertRandomFood(int amount, float energy); virtual void insertCritter(); // void positionCritterB(unsigned int cid); void saveAllCritters(); virtual void loadAllCritters(); virtual void loadAllLastSavedCritters(); void removeSelectedCritter(); void removeAllSelectedCritters(); void duplicateCritter(unsigned int cid, bool brainmutant, bool bodymutant); void duplicateSelectedCritter(); void spawnBrainMutantSelectedCritter(); void spawnBodyMutantSelectedCritter(); void spawnBrainBodyMutantSelectedCritter(); void feedSelectedCritter(); void resetageSelectedCritter(); void duplicateAllSelectedCritters(); void spawnBrainMutantAllSelectedCritters(); void spawnBodyMutantAllSelectedCritters(); void spawnBrainBodyMutantAllSelectedCritters(); void killHalfOfCritters(); void pickBody(const int& x, const int& y); void selectBody(const int& x, const int& y); void castMouseRay(); void movePickedBodyTo(); void movePickedBodyFrom(); float autosaveCounter; float autoexchangeCounter; // vision unsigned char *retina; unsigned int items; const unsigned int* retinasperrow; const unsigned int* critter_raycastvision; const unsigned int* critter_retinasize; const unsigned int* critter_maxenergy; const unsigned int* worldsizeX; const unsigned int* worldsizeY; const unsigned int* headless; const unsigned int* threads; void checkCollisions( CritterB* c ); void grabVision(); void renderVision(); void calcMouseDirection(); void moveInMouseDirection(bool towards); Dir dirH; Parser* parseH; File fileH; bool mouseRayHit; Entity* mouseRayHitEntity; // camera operations (needed for commands) void camera_moveup(); void camera_movedown(); void camera_moveforward(); void camera_movebackward(); void camera_moveleft(); void camera_moveright(); void camera_lookup(); void camera_lookdown(); void camera_lookleft(); void camera_lookright(); void camera_rollleft(); void camera_rollright(); // pointers to parents (evolution) mousepos int* mousex; int* mousey; // threading omp_lock_t my_lock1; // omp_lock_t my_lock2; private: Raycast* raycast; castResult mouseRay; btVector3 mouseRayTo; void drawShadow(btScalar* m,const btVector3& extrusion,const btCollisionShape* shape,const btVector3& worldBoundsMin,const btVector3& worldBoundsMax); unsigned int insertCritterCounter; // GLDebugDrawer debugDrawer; // methods inline void removeCritter(unsigned int cid); // inline void createDirs(); // Settings pointers.. performance const unsigned int* critter_maxlifetime; const unsigned int* critter_autosaveinterval; const unsigned int* critter_autoexchangeinterval; const unsigned int* critter_killhalfat; const unsigned int* critter_sightrange; const unsigned int* critter_enableomnivores; const unsigned int* brain_mutationrate; const unsigned int* body_mutationrate; const unsigned int* killhalf_decrenergypct; const unsigned int* killhalf_incrworldsizeX; const unsigned int* killhalf_incrworldsizeY; const unsigned int* killhalf_decrmaxlifetimepct; const unsigned int* food_maxlifetime; const unsigned int* food_maxenergy; const unsigned int* energy; const unsigned int* mincritters; const unsigned int* insertcritterevery; const unsigned int* critter_startenergy; // vision opts unsigned int picwidth; btScalar drawposition[16]; btManifoldArray manifoldArray; int findSelectedCritterID(); int findCritterID(unsigned int cid); }; #endif critterding-beta12.1/src/scenes/entities/camera.cpp0000644000175000017500000001470611302776100021371 0ustar bobkebobke #include "camera.h" #include using namespace std; Camera::Camera() { settings = Settings::Instance(); camerasensitivity = settings->getCVarPtr("camerasensitivity"); // position = btVector3( 0.0f, 0.0f, 0.0f); // rotation = Vector3f( 90.0f, 0.0f, 0.0f); position.setIdentity(); // position.setOrigin( btVector3(-5.0f, 10.0f, 0.0f) ); // position.getBasis().setEulerZYX( 75.0f*.18f, 0.0f, 0.0f ); // position.setOrigin( btVector3(0.0f, 0.0f, 0.0f) ); } void Camera::place() { glViewport(0,0,*settings->winWidth,*settings->winHeight); glMatrixMode(GL_PROJECTION); glLoadIdentity(); float nheight = 0.05f * ((float)(*settings->winHeight) / *settings->winWidth); glFrustum(-0.05f,0.05f,-nheight,nheight,0.1f,10000.0f); // glRotatef(rotation.x, 1.0f, 0.0f, 0.0f); // glRotatef(rotation.y, 0.0f, 1.0f, 0.0f); // glRotatef(rotation.z, 0.0f, 0.0f, 1.0f); // glTranslatef(position.getOrigin().getX(), position.getOrigin().getY(), position.getOrigin().getZ()); btScalar positionr[16]; position.inverse().getOpenGLMatrix(positionr); glMultMatrixf(positionr); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void Camera::follow(btDefaultMotionState* myMotionState) const { glViewport( *settings->winWidth - *settings->winWidth/8, 0, *settings->winWidth/8, *settings->winHeight/8 ); glMatrixMode(GL_PROJECTION); glLoadIdentity(); float nheight = 0.05f * ((float)(*settings->winHeight) / *settings->winWidth); glFrustum( -0.05f, 0.05f,-nheight,nheight, 0.1f, 10000.0f); btScalar position[16]; myMotionState->m_graphicsWorldTrans.inverse().getOpenGLMatrix(position); glMultMatrixf(position); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } // Moving void Camera::moveForward(const float& factor) { // position.getOrigin() += position.getBasis()[2] * factor; btTransform tr; tr.setIdentity(); tr.setOrigin( btVector3(0.0f, 0.0f, -factor * *camerasensitivity) ); // 1.5707f (float)settings->getCVar("energy")/10 position *= tr; } void Camera::moveBackward(const float& factor) { // position.getOrigin() -= position.getBasis()[2] * factor; btTransform tr; tr.setIdentity(); tr.setOrigin( btVector3(0.0f, 0.0f, factor * *camerasensitivity) ); // 1.5707f (float)settings->getCVar("energy")/10 position *= tr; } void Camera::moveRight(const float& factor) { // position.getOrigin() += position.getBasis()[0] * factor; btTransform tr; tr.setIdentity(); tr.setOrigin( btVector3(factor * *camerasensitivity, 0.0f, 0.0f) ); // 1.5707f (float)settings->getCVar("energy")/10 position *= tr; } void Camera::moveLeft(const float& factor) { // position.getOrigin() -= position.getBasis()[0] * factor; btTransform tr; tr.setIdentity(); tr.setOrigin( btVector3(-factor * *camerasensitivity, 0.0f, 0.0f) ); // 1.5707f (float)settings->getCVar("energy")/10 position *= tr; } void Camera::moveUp(const float& factor) { // position.getOrigin() -= position.getBasis()[1] * factor; btTransform tr; tr.setIdentity(); tr.setOrigin( btVector3(0.0f, factor * *camerasensitivity, 0.0f) ); // 1.5707f (float)settings->getCVar("energy")/10 position *= tr; } void Camera::moveDown(const float& factor) { // position.getOrigin() += position.getBasis()[1] * factor; btTransform tr; tr.setIdentity(); tr.setOrigin( btVector3(0.0f, -factor * *camerasensitivity, 0.0f) ); // 1.5707f (float)settings->getCVar("energy")/10 position *= tr; } void Camera::rollLeft(const float& factor) { // rotation.z += factor * *camerasensitivity; btTransform tr; tr.setIdentity(); tr.setOrigin(btVector3(0,0,0)); tr.getBasis().setEulerZYX( 0.0f, 0.0f, factor * *camerasensitivity ); // 1.5707f (float)settings->getCVar("energy")/10 position.getBasis() *= tr.getBasis(); } void Camera::rollRight(const float& factor) { // rotation.z -= factor * *camerasensitivity; btTransform tr; tr.setIdentity(); tr.setOrigin(btVector3(0,0,0)); tr.getBasis().setEulerZYX( 0.0f, 0.0f, -factor * *camerasensitivity ); // 1.5707f (float)settings->getCVar("energy")/10 position.getBasis() *= tr.getBasis(); } // Looking void Camera::lookRight(const float& factor) { // rotation.y += factor * *camerasensitivity; // if ( rotation.y > 360.0f ) rotation.y -= 360.0f; btTransform tr; tr.setIdentity(); tr.setOrigin(btVector3(0,0,0)); tr.getBasis().setEulerZYX( 0.0f, -factor * *camerasensitivity, 0.0f ); // 1.5707f (float)settings->getCVar("energy")/10 position.getBasis() *= tr.getBasis(); } void Camera::lookLeft(const float& factor) { // rotation.y -= factor * *camerasensitivity; // if ( rotation.y < 0.0f ) rotation.y += 360.0f; btTransform tr; tr.setIdentity(); tr.setOrigin(btVector3(0,0,0)); tr.getBasis().setEulerZYX( 0.0f, factor * *camerasensitivity, 0.0f ); // 1.5707f (float)settings->getCVar("energy")/10 position *= tr; } void Camera::lookUp(const float& factor) { // rotation.x -= factor * *camerasensitivity; // if ( rotation.x < 0.0f ) rotation.x += 360.0f; btTransform tr; tr.setIdentity(); tr.setOrigin(btVector3(0,0,0)); tr.getBasis().setEulerZYX( factor * *camerasensitivity, 0.0f, 0.0f ); // 1.5707f (float)settings->getCVar("energy")/10 position *= tr; } void Camera::lookDown(const float& factor) { // rotation.x += factor * *camerasensitivity; // if ( rotation.x > 360.0f ) rotation.x -= 360.0f; btTransform tr; tr.setIdentity(); tr.setOrigin(btVector3(0,0,0)); tr.getBasis().setEulerZYX( -factor * *camerasensitivity, 0.0f, 0.0f ); // 1.5707f (float)settings->getCVar("energy")/10 position *= tr; } void Camera::moveTowards(const btVector3& direction) { position.setOrigin( position.getOrigin() + direction ); } void Camera::moveAwayFrom(const btVector3& direction) { position.setOrigin( position.getOrigin() - direction ); } btVector3 Camera::getScreenDirection(const int& x, const int& y) { float directionlength = 1000000.f; btVector3 forwardRay( -position.getBasis()[0][2], -position.getBasis()[1][2], -position.getBasis()[2][2]); forwardRay *= directionlength; btVector3 upRay( position.getBasis()[0][1], position.getBasis()[1][1], position.getBasis()[2][1]); btVector3 hor = forwardRay.cross(upRay); hor.normalize(); hor *= directionlength; upRay = hor.cross(forwardRay); upRay.normalize(); upRay *= directionlength * ((float)*settings->winHeight / *settings->winWidth); btVector3 rayTo = (position.getOrigin() + forwardRay) - (0.5f * hor) + (0.5f * upRay); rayTo += x * (hor * (1.0f/((float)*settings->winWidth))); rayTo -= y * (upRay * (1.0f/((float)*settings->winHeight))); return rayTo; } Camera::~Camera() { } critterding-beta12.1/src/scenes/entities/wall.cpp0000644000175000017500000000234211340265263021076 0ustar bobkebobke#include "wall.h" Wall::Wall(float X, float Y, float Z, btVector3 position, btDynamicsWorld* m_dynamicsWorld) { m_ownerWorld = m_dynamicsWorld; halfX = X/2; halfY = Y/2; halfZ = Z/2; color.r = 0.0f; color.g = 0.0f; color.b = 0.5f; color.a = 0.0f; groundShape = new btBoxShape( btVector3( halfX ,halfY, halfZ ) ); groundTransform.setIdentity(); groundTransform.setOrigin( position ); fixedGround = new btCollisionObject(); fixedGround->setUserPointer(this); fixedGround->setCollisionShape(groundShape); fixedGround->setWorldTransform(groundTransform); m_ownerWorld->addCollisionObject(fixedGround); fixedGround->getWorldTransform().getOpenGLMatrix(nposition); type = 2; isPicked = false; } void Wall::draw() { // fixedGround->getWorldTransform().getOpenGLMatrix(m); glPushMatrix(); glMultMatrixf(nposition); glColor4f( color.r, color.g, color.b, color.a ); /* const btBoxShape* boxShape = static_cast(groundShape); btVector3 halfExtent = boxShape->getHalfExtentsWithMargin();*/ glScaled(halfX, halfY, halfZ); Displaylists::Instance()->call(1); glPopMatrix(); } Wall::~Wall() { m_ownerWorld->removeCollisionObject(fixedGround); delete groundShape; delete fixedGround; } critterding-beta12.1/src/scenes/entities/archbodypart.cpp0000644000175000017500000000023611240640066022616 0ustar bobkebobke#include "archbodypart.h" archBodypart::archBodypart() { type = 0; id = 0; x = 0; y = 0; z = 0; materialID = 0; } archBodypart::~archBodypart() { } critterding-beta12.1/src/scenes/entities/mouth.h0000644000175000017500000000113211334110375020730 0ustar bobkebobke#ifndef MOUTH_H #define MOUTH_H #include #include "btBulletDynamicsCommon.h" #include using namespace std; class Mouth { public: Mouth(btDynamicsWorld* ownerWorld, void* owner, const btVector3& dimensions, float weight, btTransform& offset, btTransform& transform); ~Mouth(); btPairCachingGhostObject* ghostObject; btRigidBody* body; btCollisionShape* shape; void updateGhostObjectPosition(); void connectMouthAndBody(); btDefaultMotionState* myMotionState; private: btDynamicsWorld* m_ownerWorld; }; #endif critterding-beta12.1/src/scenes/entities/archconstraint.h0000644000175000017500000000112711242636417022632 0ustar bobkebobke#ifndef ARCHCONSTRAINT_H #define ARCHCONSTRAINT_H using namespace std; class archConstraint { public: archConstraint(); ~archConstraint(); unsigned int type; unsigned int constraint_id1; unsigned int constraint_id2; bool isMouthConstraint; unsigned int XYZ; int sign; unsigned int id_1; unsigned int id_2; float rot_x_1; float rot_x_2; float rot_y_1; float rot_y_2; float rot_z_1; float rot_z_2; float pos_x_1; float pos_x_2; float pos_y_1; float pos_y_2; float pos_z_1; float pos_z_2; float limit_1; float limit_2; private: }; #endif critterding-beta12.1/src/scenes/entities/archconstraint.cpp0000644000175000017500000000020711240640066023154 0ustar bobkebobke#include "archconstraint.h" archConstraint::archConstraint() { isMouthConstraint = false; } archConstraint::~archConstraint() { } critterding-beta12.1/src/scenes/entities/archmouth.h0000644000175000017500000000032411240640066021571 0ustar bobkebobke#ifndef ARCHMOUTH_H #define ARCHMOUTH_H using namespace std; class archMouth { public: archMouth(); ~archMouth(); unsigned int id; // dimension float x; float y; float z; private: }; #endif critterding-beta12.1/src/scenes/entities/critterb.cpp0000644000175000017500000003542511343530351021761 0ustar bobkebobke#include "critterb.h" void CritterB::initConst() { // settings and pointers settings = Settings::Instance(); genotypes = Genotypes::Instance(); retinasperrow = settings->getCVarPtr("retinasperrow"); colormode = settings->getCVarPtr("colormode"); critter_maxlifetime = settings->getCVarPtr("critter_maxlifetime"); critter_maxenergy = settings->getCVarPtr("critter_maxenergy"); critter_sightrange = settings->getCVarPtr("critter_sightrange"); critter_procinterval = settings->getCVarPtr("critter_procinterval"); critter_minenergyproc = settings->getCVarPtr("critter_minenergyproc"); critter_raycastvision = settings->getCVarPtr("critter_raycastvision"); brain_costhavingneuron = settings->getCVarPtr("brain_costhavingneuron"); brain_costfiringneuron = settings->getCVarPtr("brain_costfiringneuron"); brain_costfiringmotorneuron = settings->getCVarPtr("brain_costfiringmotorneuron"); brain_costhavingsynapse = settings->getCVarPtr("brain_costhavingsynapse"); type = 0; isPicked = false; totalFrames = 0; procreateTimeCount = 0; // sightrange = settings->critter_sightrange; // colorTrim = 0.15f; eat = false; procreate = false; // raycast raycast = new Raycast(btDynWorld); } CritterB::CritterB(btDynamicsWorld* btWorld, long unsigned int id, const btVector3& startPos, unsigned char* retinap) { loadError = false; // first things first btDynWorld = btWorld; retina = retinap; critterID = id; initConst(); energyLevel = settings->getCVar("critter_startenergy"); // lifetime = settings->critter_maxlifetime; genotype = genotypes->newg( settings ); // BODY // genotype->bodyArch->buildArch(); body.wireArch( genotype->bodyArch, (void*)this, btDynWorld, startPos ); // LINK registerBrainInputOutputs(); // BRAIN // genotype->brainzArch->buildArch(); brain.wireArch( genotype->brainzArch ); } CritterB::CritterB(CritterB& other, long unsigned int id, const btVector3& startPos, bool brainmutant, bool bodymutant) { loadError = false; // first things first btDynWorld = other.btDynWorld; retina = other.retina; critterID = id; initConst(); // lifetime = other.lifetime; genotype = genotypes->copy(other.genotype, brainmutant, RandGen::Instance()->get(1, settings->getCVar("brain_maxmutations")), bodymutant, RandGen::Instance()->get(1, settings->getCVar("body_maxmutations"))); body.wireArch( genotype->bodyArch, (void*)this, btDynWorld, startPos ); // LINK registerBrainInputOutputs(); brain.wireArch( genotype->brainzArch ); } CritterB::CritterB(string &critterstring, btDynamicsWorld* btWorld, const btVector3& startPos, unsigned char* retinap) { loadError = false; // critterID is arranged in world, definite critter insertion is not determined yet // first things first btDynWorld = btWorld; retina = retinap; initConst(); energyLevel = settings->getCVar("critter_startenergy"); genotype = genotypes->loadGenotype(critterstring); if ( genotype->bodyArch->retinasize != settings->getCVar("critter_retinasize")) { stringstream buf; buf << "ERROR: critter retinasize (" << genotype->bodyArch->retinasize << ") doesn't fit world retinasize (" << settings->getCVar("critter_retinasize") << ")"; Logbuffer::Instance()->add(buf); cerr << "!ERROR: critter retinasize (" << genotype->bodyArch->retinasize << ") doesn't fit world retinasize (" << settings->getCVar("critter_retinasize") << ")" << endl; loadError = true; } else { // BODY body.wireArch( genotype->bodyArch, (void*)this, btDynWorld, startPos ); // LINK registerBrainInputOutputs(); // BRAIN brain.wireArch( genotype->brainzArch ); } } void CritterB::registerBrainInputOutputs() { // cerr << "attaching INPUTS" << endl; for ( unsigned int i=0; i < genotype->brainzArch->InputIDs.size(); i++ ) { brain.registerInput( genotype->brainzArch->InputIDs[i] ); } // cerr << "attaching OUTPUTS" << endl; for ( unsigned int i=0; i < body.constraints.size(); i++ ) { for ( unsigned int j=0; j < body.constraints[i]->Inputs.size(); j++ ) { brain.registerOutput( body.constraints[i]->Inputs[j], genotype->brainzArch->OutputIDs[ (i*2)+j ] ); } } // eat brain.registerOutput( &eat, 100000 ); // procreate brain.registerOutput( &procreate, 100001 ); // debug check if ( brain.Outputs.size() != genotype->brainzArch->OutputIDs.size() ) cerr << "WARNING: brain.Outputs.size() != genotype->brainzArch->OutputIDs.size()" << endl; } void CritterB::draw(bool drawFaces) { for( unsigned int j=0; j < body.bodyparts.size(); j++) { body.bodyparts[j]->myMotionState->m_graphicsWorldTrans.getOpenGLMatrix(position); glPushMatrix(); glMultMatrixf(position); if ( *colormode == 1 ) glColor4f( genotype->speciescolor.r, genotype->speciescolor.g, genotype->speciescolor.b, genotype->speciescolor.a ); else glColor4f( genotype->bodyArch->color.r, genotype->bodyArch->color.g, genotype->bodyArch->color.b, genotype->bodyArch->color.a ); const btBoxShape* boxShape = static_cast(body.bodyparts[j]->shape); btVector3 halfExtent = boxShape->getHalfExtentsWithMargin(); glScaled(halfExtent[0], halfExtent[1], halfExtent[2]); Displaylists::Instance()->call(1); glPopMatrix(); } if ( drawFaces ) { for( unsigned int j=0; j < body.mouths.size(); j++) { body.mouths[j]->ghostObject->getWorldTransform().getOpenGLMatrix(position); glPushMatrix(); glMultMatrixf(position); glColor4f( 1.0f, 0.0f, 0.0f, 0.0f ); const btBoxShape* boxShape = static_cast(body.mouths[j]->shape); btVector3 halfExtent = boxShape->getHalfExtentsWithMargin(); glScaled(halfExtent[0], halfExtent[1], halfExtent[2]); Displaylists::Instance()->call(1); glPopMatrix(); } } } void CritterB::process() { // increase counters totalFrames++; procreateTimeCount++; eaten = false; // reset motor bools movementsmade = 0; // eat = false; // procreate = false; // carrydrop = false; // SENSORS procInputNeurons(); // INTERS brain.process(); // MOTORS // procOutputNeurons(); // calc used energy, energyUsed is used in world aswell, don't remove // energyUsed = ( (float)brain.totalNeurons + (float)brain.neuronsFired + (2.0f*(float)motorneuronsfired) + ((float)brain.totalSynapses/10.0f) ) / 200.0f; energyUsed = brain.totalNeurons * *brain_costhavingneuron; energyUsed += brain.neuronsFired * *brain_costfiringneuron; energyUsed += brain.motorneuronsFired * *brain_costfiringmotorneuron; energyUsed += brain.totalSynapses * *brain_costhavingsynapse; energyUsed = energyUsed / 100000; // cerr << energyUsed << endl; // apply energy usage energyLevel -= energyUsed; // move // motorate all constraints for ( unsigned int i=0; i < body.constraints.size(); i++ ) body.constraints[i]->motorate(); // move ghostobject to mouth object position for ( unsigned int i=0; i < body.mouths.size(); i++ ) body.mouths[i]->updateGhostObjectPosition(); } void CritterB::procInputNeurons() { // clear all inputs brain.clearInputs(); unsigned int overstep = 0; // touching food if ( touchingFood ) brain.Inputs[overstep++].output = 1; else brain.Inputs[overstep++].output = 0; // touching critter if ( touchingCritter ) brain.Inputs[overstep++].output = 1; else brain.Inputs[overstep++].output = 0; // can procreate sensor neuron canProcreate = false; if ( procreateTimeCount > *critter_procinterval && energyLevel > *critter_minenergyproc ) { brain.Inputs[overstep++].output = 1; canProcreate = true; } else brain.Inputs[overstep++].output = 0; // energy neurons unsigned int NeuronToFire = (int)((energyLevel / (*critter_maxenergy+1)) * 10) + overstep; unsigned int count = 10 + overstep; while ( overstep < count ) { if ( overstep <= NeuronToFire ) brain.Inputs[overstep++].output = 1; // !!! <= else brain.Inputs[overstep++].output = 0; } // age neurons NeuronToFire = (int)(((float)totalFrames / (*critter_maxlifetime+1)) * 10) + overstep; count = 10 + overstep; while ( overstep < count ) { if ( overstep <= NeuronToFire ) brain.Inputs[overstep++].output = 1; // !!! <= else brain.Inputs[overstep++].output = 0; } // Vision // unsigned int vstart = overstep; if ( *critter_raycastvision ) for ( int y = genotype->bodyArch->retinasize-1; y >= 0; y-- ) for ( unsigned int x = 0; x < genotype->bodyArch->retinasize; x++ ) { // cerr << "starting" << endl; mouseRay = raycast->cast( body.mouths[0]->ghostObject->getWorldTransform().getOrigin(), getScreenDirection(x+1, y) ); // cerr << "e1" << endl; if ( mouseRay.hit ) { Entity* e = static_cast(mouseRay.hitBody->getUserPointer()); if ( e->type == 0 ) { CritterB* c = static_cast(e); brain.Inputs[overstep++].output = c->genotype->bodyArch->color.r; brain.Inputs[overstep++].output = c->genotype->bodyArch->color.g; brain.Inputs[overstep++].output = c->genotype->bodyArch->color.b; brain.Inputs[overstep++].output = c->genotype->bodyArch->color.a; } else { brain.Inputs[overstep++].output = e->color.r; brain.Inputs[overstep++].output = e->color.g; brain.Inputs[overstep++].output = e->color.b; brain.Inputs[overstep++].output = e->color.a; } } else { brain.Inputs[overstep++].output = 0.0f; brain.Inputs[overstep++].output = 0.0f; brain.Inputs[overstep++].output = 0.0f; brain.Inputs[overstep++].output = 0.0f; } // cerr << "e2" << endl; } else for ( unsigned int h=retinaRowStart; h < retinaRowStart+(genotype->bodyArch->retinasize*retinaRowLength); h += retinaRowLength ) for ( unsigned int w=h+retinaColumnStart; w < h+retinaColumnStart+((genotype->bodyArch->retinasize)*4); w++ ) brain.Inputs[overstep++].output = (float)retina[w] / 256.0f; // for ( unsigned int x = 0; x < retinasize; x++ ) // { // for ( unsigned int y = vstart+(retinasize*4*x); y < vstart+(retinasize*4*x)+(retinasize*4); y+=4 ) // { // // cerr << " now = " << y << endl; // if ( brain.Inputs[y].output ) cerr << "\033[1;34mB\033[0m"; // else cerr << "."; // if ( brain.Inputs[y+1].output ) cerr << "\033[1;32mG\033[0m"; // else cerr << "."; // if ( brain.Inputs[y+2].output ) cerr << "\033[1;31mR\033[0m"; // else cerr << "."; // if ( brain.Inputs[y+3].output ) cerr << "\033[1;35mA\033[0m"; // else cerr << "."; // } // cerr << endl; // } // cerr << endl; // // for ( unsigned int h=retinaRowStart; h < retinaRowStart+(retinasize*retinaRowLength); h += retinaRowLength ) // { // for ( unsigned int w=h+retinaColumnStart; w < h+retinaColumnStart+((retinasize)*4); w+=4 ) // { // if ( (int)retina[w] ) cerr << "\033[1;34mB\033[0m"; // else cerr << "."; // if ( (int)retina[w+1] ) cerr << "\033[1;32mG\033[0m"; // else cerr << "."; // if ( (int)retina[w+2] ) cerr << "\033[1;31mR\033[0m"; // else cerr << "."; // if ( (int)retina[w+3] ) cerr << "\033[1;35mA\033[0m"; // else cerr << "."; // } // cerr << endl; // } // cerr << endl; // constraint angle neurons for ( unsigned int i=0; i < body.constraints.size(); i++ ) brain.Inputs[overstep++].output = body.constraints[i]->getAngle(); // debugging check if ( overstep-1 != brain.numberOfInputs-1 ) { cerr << overstep << " does not equal " << brain.Inputs.size()-1 << endl; exit(0); } } btVector3 CritterB::getScreenDirection(const int& x, const int& y) { float directionlength = 1000000.f; btTransform tr = body.mouths[0]->ghostObject->getWorldTransform(); btVector3 forwardRay( -tr.getBasis()[0][2], -tr.getBasis()[1][2], -tr.getBasis()[2][2]); forwardRay *= directionlength; btVector3 upRay( tr.getBasis()[0][1], tr.getBasis()[1][1], tr.getBasis()[2][1]); btVector3 hor = forwardRay.cross(upRay); hor.normalize(); hor *= directionlength; upRay = hor.cross(forwardRay); upRay.normalize(); upRay *= directionlength; btVector3 rayTo = (tr.getOrigin() + forwardRay) - (0.5f * hor) + (0.5f * upRay); rayTo += x * (hor * (1.0f/(genotype->bodyArch->retinasize))); rayTo -= y * (upRay * (1.0f/(genotype->bodyArch->retinasize))); return rayTo; } void CritterB::mutateBrain() // FIXME PUSH THIS TO BODYARCH MUTATE FUNCTION { // // mutate color // unsigned int mode = RandGen::Instance()->get(1,2); // unsigned int ncolor = RandGen::Instance()->get(0,2); // // // nasty correction // if ( ncolor == 1 ) // ncolor = 0; // if ( mode == 1 ) // { // color[ncolor] += (float)RandGen::Instance()->get(1,10)/100.0f; // if ( color[ncolor] > 1.0f ) color[ncolor] = 1.0f; // } // else // { // color[ncolor] -= (float)RandGen::Instance()->get(1,10)/100.0f; // if ( color[ncolor] < colorTrim ) color[ncolor] = colorTrim; // } } // Vision Stuff void CritterB::place() { glViewport(framePosX, framePosY, genotype->bodyArch->retinasize, genotype->bodyArch->retinasize); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum( -0.05f, 0.05f, -0.05, 0.05, 0.1f, (float)*critter_sightrange/10); body.mouths[0]->ghostObject->getWorldTransform().inverse().getOpenGLMatrix(position); glMultMatrixf(position); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } void CritterB::calcFramePos(unsigned int pos) { visionPosition = pos; // Calc 2D cartesian vectors X & Y for frame positioning of retina framePosY = 0; while ( pos >= *retinasperrow ) { pos -= *retinasperrow; framePosY += genotype->bodyArch->retinasize; } framePosX = (pos * genotype->bodyArch->retinasize) + pos; // Calculate where in the Great Retina this critter shold start (column & row) unsigned int target = visionPosition; retinaRowStart = 0; // determine on which row of the retina to start for this critter retinaRowLength = *retinasperrow * (genotype->bodyArch->retinasize+1) * 4; // determine on which column to start while ( target >= *retinasperrow ) { retinaRowStart += genotype->bodyArch->retinasize * retinaRowLength; target -= *retinasperrow; } retinaColumnStart = target * (genotype->bodyArch->retinasize+1) * 4; // cerr << framePosX << " : " << framePosY << endl; // usleep (1000); } void CritterB::printVision() { for ( unsigned int h=retinaRowStart; h < retinaRowStart+(genotype->bodyArch->retinasize*retinaRowLength); h += retinaRowLength ) { for ( unsigned int w=h+retinaColumnStart; w < h+retinaColumnStart+((genotype->bodyArch->retinasize)*4); w+=4 ) { if ( (int)retina[w+2] ) cerr << "\033[1;31mR\033[0m"; else cerr << "."; if ( (int)retina[w+1] ) cerr << "\033[1;32mG\033[0m"; else cerr << "."; if ( (int)retina[w] ) cerr << "\033[1;34mB\033[0m"; else cerr << "."; if ( (int)retina[w+3] ) cerr << "\033[1;35mA\033[0m"; else cerr << "."; } cerr << "" << endl; } cerr << "" << endl; } CritterB::~CritterB() { genotypes->remove(genotype); delete raycast; } critterding-beta12.1/src/scenes/entities/genotype.h0000644000175000017500000000064011340265263021435 0ustar bobkebobke#ifndef GENOTYPE_H #define GENOTYPE_H #include "bodyarch.h" #include "../../brainz/brainzarch.h" #include "../../utils/color.h" using namespace std; class Genotype { public: Genotype(); ~Genotype(); unsigned int adamdist; Color speciescolor; BodyArch* bodyArch; BrainzArch* brainzArch; unsigned int count; void registerBrainInputOutputs(); string saveGenotype(); private: }; #endif critterding-beta12.1/src/scenes/entities/critterb.h0000644000175000017500000000551011343530351021416 0ustar bobkebobke#ifndef CRITTERB_H #define CRITTERB_H #include "btBulletDynamicsCommon.h" #include "GL/gl.h" #include "../../utils/parser.h" #include "../../brainz/brainz.h" #include "../../utils/settings.h" #include "../../utils/displaylists.h" #include "../../utils/raycast.h" #include "../../utils/color.h" #include "genotypes.h" #include "entity.h" #include "body.h" using namespace std; class CritterB : public Entity { public: CritterB(btDynamicsWorld* btWorld, long unsigned int id, const btVector3& startPos, unsigned char* retinap); CritterB(CritterB& , long unsigned int id, const btVector3& startPos, bool brainmutant, bool bodymutant); CritterB(string &critterstring, btDynamicsWorld* btWorld, const btVector3& startPos, unsigned char* retinap); ~CritterB(); Brainz brain; Body body; Genotype* genotype; inline void registerBrainInputOutputs(); void draw(bool drawFaces); void move(); bool eaten; unsigned long critterID; // unsigned int adamdist; btScalar position[16]; // float speciescolor[3]; // float colorTrim; bool loadError; float energyLevel; float energyUsed; unsigned int totalFrames; // Inputs bool canProcreate; bool touchingFood; bool touchingCritter; Entity* touchedEntity; // Motor Func bool eat; bool procreate; unsigned int procreateTimeCount; unsigned int procreateTimeTrigger; void process(); // Vision // unsigned int components; float straal; unsigned char *retina; unsigned int items; void place(); void calcFramePos(unsigned int pos); void printVision(); float fitness_index; vector crittersWithinRange; private: Settings* settings; Genotypes* genotypes; Raycast* raycast; castResult mouseRay; unsigned int movementsmade; btDynamicsWorld* btDynWorld; btVector3 getScreenDirection(const int& x, const int& y); inline void initConst(); inline void procInputNeurons(); inline void createInputOutputNeurons(); inline void mutateBody(); inline void mutateBrain(); // Vision unsigned int framePosX; unsigned int framePosY; unsigned int retinaColumnStart; unsigned int retinaRowStart; unsigned int retinaRowLength; unsigned int visionPosition; // Settings pointers.. performance const unsigned int* retinasperrow; const unsigned int* critter_maxlifetime; const unsigned int* critter_maxenergy; const unsigned int* critter_sightrange; const unsigned int* critter_procinterval; const unsigned int* critter_minenergyproc; const unsigned int* critter_raycastvision; const unsigned int* brain_costhavingneuron; const unsigned int* brain_costfiringneuron; const unsigned int* brain_costfiringmotorneuron; const unsigned int* brain_costhavingsynapse; const unsigned int* colormode; }; #endif critterding-beta12.1/src/scenes/entities/constraint.h0000644000175000017500000000117011240640066021763 0ustar bobkebobke#ifndef CONSTRAINT_H #define CONSTRAINT_H #include #include #include "btBulletDynamicsCommon.h" using namespace std; class Constraint { public: Constraint(btDynamicsWorld* ownerWorld, btRigidBody& bodyA, btRigidBody& bodyB, btTransform& localA, btTransform& localB, double limitA, double limitB); ~Constraint(); void motorate(); float getAngle(); vector Inputs; // btTypedConstraint* hinge; btHingeConstraint* hinge; float fullRange; float diffFromZero; private: btDynamicsWorld* m_ownerWorld; bool input1; bool input2; // float limitA; // float limitB; }; #endif critterding-beta12.1/src/scenes/entities/archmouth.cpp0000644000175000017500000000012211240640066022120 0ustar bobkebobke#include "archmouth.h" archMouth::archMouth() { } archMouth::~archMouth() { } critterding-beta12.1/src/scenes/entities/body.cpp0000644000175000017500000001115611337071441021076 0ustar bobkebobke#include "body.h" Body::Body() { totalWeight = 0.0f; } // void Body::addBodyPart_Capsule(void* owner, float width, float height, float weight, btTransform& offset, btTransform& transform) // { // Bodypart *b = new Bodypart(m_ownerWorld); // bodyparts.push_back( b ); // // b->shape = new btCapsuleShape(width, height); // // btVector3 localInertia(0,0,0); // if (weight != 0.f) // weight of non zero = dynamic // b->shape->calculateLocalInertia(weight,localInertia); // // btDefaultMotionState* myMotionState = new btDefaultMotionState(offset*transform); // // btRigidBody::btRigidBodyConstructionInfo rbInfo(weight,myMotionState,b->shape,localInertia); // b->body = new btRigidBody(rbInfo); // // m_ownerWorld->addRigidBody(b->body); // // b->body->setUserPointer(owner); // b->body->setDamping(0.05, 0.85); // b->body->setDeactivationTime(0.001); // b->body->setSleepingThresholds(1.6, 2.5); // } void Body::addBodyPart_Box(void* owner, float x, float y, float z, float weight, btTransform& offset, btTransform& transform) { totalWeight += weight; Bodypart *b = new Bodypart( m_ownerWorld, owner, btVector3( x, y, z ), weight, offset, transform ); bodyparts.push_back( b ); } void Body::addMouth(void* owner, float x, float y, float z, float weight, btTransform& offset, btTransform& transform) { totalWeight += weight; Mouth *m = new Mouth( m_ownerWorld, owner, btVector3( x, y, z ), weight, offset, transform ); mouths.push_back( m ); // connect mouth and body, for some reason this segfaults in the constructor m->connectMouthAndBody(); } void Body::addConstraint(unsigned int bodypartID1, unsigned int bodypartID2, btTransform& localA, btTransform& localB, double limitA, double limitB) { Constraint *c = new Constraint( m_ownerWorld, *bodyparts[bodypartID1]->body, *bodyparts[bodypartID2]->body, localA, localB, limitA, limitB ); constraints.push_back( c ); } void Body::addMouthConstraint(unsigned int bodypartID, unsigned int mouthID, btTransform& localA, btTransform& localB, double limitA, double limitB) { Constraint *c = new Constraint(m_ownerWorld, *bodyparts[bodypartID]->body, *mouths[mouthID]->body, localA, localB, limitA, limitB ); constraints.push_back( c ); } void Body::wireArch(BodyArch* bodyArch, void* owner, btDynamicsWorld* ownerWorld, const btVector3& startOffset) { m_ownerWorld = ownerWorld; btTransform offset; offset.setIdentity(); offset.setOrigin(startOffset); btTransform transform; transform.setIdentity(); transform.setOrigin( btVector3( 0.0f, 0.0f, 0.0f ) ); for ( unsigned int i=0; i < bodyArch->archBodyparts.size(); i++ ) { archBodypart *bp = &bodyArch->archBodyparts[i]; // BOX if ( bp->type ==0 ) { // calculate weight float weight = ((bp->x*bp->y*bp->z)/1000) * 0.001f; // FIXME 0.001 is density of material totalWeight += weight; Bodypart *b = new Bodypart(m_ownerWorld, owner, btVector3( bp->x/1000, bp->y/1000, bp->z/1000 ), weight, offset, transform); bodyparts.push_back( b ); } } // 5 MOUTH-HEAD for ( unsigned int i=0; i < bodyArch->archMouths.size(); i++ ) { archMouth *mo = &bodyArch->archMouths[i]; // calculate weight float weight = ((mo->x*mo->y*mo->z)/1000) * 0.00025f; // FIXME 0.001 is density of material totalWeight += weight; addMouth(owner, mo->x/1000, mo->y/1000, mo->z/1000, weight, offset, transform); } btTransform localA; btTransform localB; for ( unsigned int i=0; i < bodyArch->archConstraints.size(); i++ ) { archConstraint *co = &bodyArch->archConstraints[i]; localA.setIdentity(); localA.getBasis().setEulerZYX( co->rot_x_1, co->rot_y_1, co->rot_z_1 ); localA.setOrigin( btVector3(co->pos_x_1, co->pos_y_1, co->pos_z_1) ); localB.setIdentity(); localB.getBasis().setEulerZYX( co->rot_x_2, co->rot_y_2, co->rot_z_2 ); localB.setOrigin( btVector3(co->pos_x_2, co->pos_y_2, co->pos_z_2) ); // find the ID's to connect int bpID_1 = bodyArch->findBodypart( co->id_1 ); if ( co->isMouthConstraint ) { int bpID_2 = bodyArch->findMouth( co->id_2 ); if ( bpID_1 > -1 && bpID_2 > -1 ) addMouthConstraint( (unsigned int)bpID_1, (unsigned int)bpID_2, localA, localB, co->limit_1, co->limit_2 ); } else { int bpID_2 = bodyArch->findBodypart( co->id_2 ); if ( bpID_1 > -1 && bpID_2 > -1 ) addConstraint( (unsigned int)bpID_1, (unsigned int)bpID_2, localA, localB, co->limit_1, co->limit_2 ); } } } Body::~Body() { for ( unsigned int i=0; i < constraints.size(); i++ ) delete constraints[i]; for ( unsigned int i=0; i < bodyparts.size(); i++ ) delete bodyparts[i]; for ( unsigned int i=0; i < mouths.size(); i++ ) delete mouths[i]; } critterding-beta12.1/src/scenes/entities/archbodypart.h0000644000175000017500000000040311240640066022257 0ustar bobkebobke#ifndef ARCHBODYPART_H #define ARCHBODYPART_H using namespace std; class archBodypart { public: archBodypart(); ~archBodypart(); unsigned int type; unsigned int id; float x; float y; float z; unsigned int materialID; private: }; #endif critterding-beta12.1/src/scenes/entities/mouth.cpp0000644000175000017500000000335011334110375021267 0ustar bobkebobke#include "mouth.h" Mouth::Mouth(btDynamicsWorld* ownerWorld, void* owner, const btVector3& dimensions, float weight, btTransform& offset, btTransform& transform) { m_ownerWorld = ownerWorld; // Add a box body shape = new btBoxShape( dimensions ); btVector3 localInertia(0,0,0); if (weight != 0.f) // weight of non zero = dynamic shape->calculateLocalInertia(weight,localInertia); myMotionState = new btDefaultMotionState(offset*transform); btRigidBody::btRigidBodyConstructionInfo rbInfo(weight,myMotionState,shape,localInertia); body = new btRigidBody(rbInfo); body->setUserPointer(owner); body->setDamping(0.05, 0.85); body->setDeactivationTime(0.001); body->setSleepingThresholds(1.6, 2.5); m_ownerWorld->addRigidBody(body); // Mouth piece ghostObject = new btPairCachingGhostObject(); ghostObject->setCollisionShape( new btBoxShape( btVector3( dimensions.getX()+0.01f, dimensions.getY()+0.01f, dimensions.getZ()+0.01f ) ) ); ghostObject->setCollisionFlags( btCollisionObject::CF_KINEMATIC_OBJECT | btCollisionObject::CF_NO_CONTACT_RESPONSE ); ghostObject->setWorldTransform(offset*transform); ghostObject->setUserPointer(owner); m_ownerWorld->addCollisionObject(ghostObject); // create a pointer to the body's motionstate } void Mouth::connectMouthAndBody() { myMotionState = (btDefaultMotionState*)body->getMotionState(); } void Mouth::updateGhostObjectPosition() { ghostObject->setWorldTransform(myMotionState->m_graphicsWorldTrans); } Mouth::~Mouth() { // Remove all bodies and shapes m_ownerWorld->removeRigidBody(body); delete body->getMotionState(); delete body; delete shape; m_ownerWorld->removeCollisionObject(ghostObject); delete ghostObject->getCollisionShape(); delete ghostObject; } critterding-beta12.1/src/scenes/entities/camera.h0000644000175000017500000000226311302776100021031 0ustar bobkebobke#ifndef CAMERA_H #define CAMERA_H #include "../../utils/settings.h" #include "../../math/vector3f.h" #include "GL/gl.h" #include "../../utils/bullet/btBulletDynamicsCommon.h" class Camera{ public: Camera(); ~Camera(); // Position // btVector3 position; btTransform position; // Controls Vector3f rotation; void place(); void follow(btDefaultMotionState* myMotionState) const; void lookRight(const float& factor); void lookLeft(const float& factor); void lookUp(const float& factor); void lookDown(const float& factor); void lookRollRight(const float& factor); void lookRollLeft(const float& factor); void moveForward(const float& factor); void moveBackward(const float& factor); void moveRight(const float& factor); void moveLeft(const float& factor); void moveUp(const float& factor); void moveDown(const float& factor); void moveRollLeft(const float& factor); void rollRight(const float& factor); void rollLeft(const float& factor); void moveTowards(const btVector3& direction); void moveAwayFrom(const btVector3& direction); btVector3 getScreenDirection(const int& x, const int& y); private: Settings *settings; const unsigned int* camerasensitivity; }; #endif critterding-beta12.1/src/scenes/entities/wall.h0000644000175000017500000000127211276347255020556 0ustar bobkebobke#ifndef WALL_H #define WALL_H #include "btBulletDynamicsCommon.h" #include "GL/gl.h" #include "../../utils/displaylists.h" #include #include "entity.h" using namespace std; class Wall : public Entity { public: Wall(float X, float Y, float Z, btVector3 position, btDynamicsWorld* m_dynamicsWorld); ~Wall(); void draw(); void create(float X, float Y, float Z, btVector3 position, btDynamicsWorld* m_dynamicsWorld); // float color[4]; btTransform groundTransform; private: btDynamicsWorld* m_ownerWorld; float halfX; float halfY; float halfZ; btCollisionShape* groundShape; btScalar nposition[16]; btCollisionObject* fixedGround; }; #endif critterding-beta12.1/src/scenes/entities/worldb.cpp0000644000175000017500000012167211345021566021441 0ustar bobkebobke/*#ifdef _WIN32 #include #include #endif*/ #include "worldb.h" WorldB::WorldB() { // settings and pointers settings = Settings::Instance(); retinasperrow = settings->getCVarPtr("retinasperrow"); critter_maxlifetime = settings->getCVarPtr("critter_maxlifetime"); critter_maxenergy = settings->getCVarPtr("critter_maxenergy"); critter_autosaveinterval = settings->getCVarPtr("critter_autosaveinterval"); critter_autoexchangeinterval = settings->getCVarPtr("critter_autoexchangeinterval"); critter_killhalfat = settings->getCVarPtr("critter_killhalfat"); critter_retinasize = settings->getCVarPtr("critter_retinasize"); critter_sightrange = settings->getCVarPtr("critter_sightrange"); critter_raycastvision = settings->getCVarPtr("critter_raycastvision"); critter_enableomnivores = settings->getCVarPtr("critter_enableomnivores"); critter_startenergy = settings->getCVarPtr("critter_startenergy"); killhalf_decrenergypct = settings->getCVarPtr("killhalf_decrenergypct"); killhalf_incrworldsizeX = settings->getCVarPtr("killhalf_incrworldsizeX"); killhalf_incrworldsizeY = settings->getCVarPtr("killhalf_incrworldsizeY"); killhalf_decrmaxlifetimepct = settings->getCVarPtr("killhalf_decrmaxlifetimepct"); brain_mutationrate = settings->getCVarPtr("brain_mutationrate"); body_mutationrate = settings->getCVarPtr("body_mutationrate"); food_maxlifetime = settings->getCVarPtr("food_maxlifetime"); food_maxenergy = settings->getCVarPtr("food_maxenergy"); energy = settings->getCVarPtr("energy"); headless = settings->getCVarPtr("headless"); threads = settings->getCVarPtr("threads"); mincritters = settings->getCVarPtr("mincritters"); insertcritterevery = settings->getCVarPtr("critter_insertevery"); worldsizeX = settings->getCVarPtr("worldsizeX"); worldsizeY = settings->getCVarPtr("worldsizeY"); statsBuffer = Statsbuffer::Instance(); critterselection = Critterselection::Instance(); // home & program directory dirlayout = Dirlayout::Instance(); freeEnergy = *food_maxenergy * *energy; currentCritterID = 1; insertCritterCounter = 0; autosaveCounter = 0.0f; autoexchangeCounter = 0.0f; insertHight = 1.0f; // vision retina allocation items = 4 * 800 * 600; retina = (unsigned char*)malloc(items); memset(retina, 0, items); // THREADED BULLET /* int maxNumOutstandingTasks = 4; m_collisionConfiguration = new btDefaultCollisionConfiguration(); PosixThreadSupport::ThreadConstructionInfo constructionInfo("collision", processCollisionTask, createCollisionLocalStoreMemory, maxNumOutstandingTasks); m_threadSupportCollision = new PosixThreadSupport(constructionInfo); m_dispatcher = new SpuGatheringCollisionDispatcher(m_threadSupportCollision,maxNumOutstandingTasks,m_collisionConfiguration); btVector3 worldAabbMin(-10000,-10000,-10000); btVector3 worldAabbMax(10000,10000,10000); m_broadphase = new btAxisSweep3 (worldAabbMin, worldAabbMax); m_broadphase->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback()); m_solver = new btSequentialImpulseConstraintSolver; // m_solver = new SpuMinkowskiPenetrationDepthSolver(); m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration); m_dynamicsWorld->getSolverInfo().m_numIterations = 10; m_dynamicsWorld->getSolverInfo().m_solverMode = SOLVER_SIMD+SOLVER_USE_WARMSTARTING; m_dynamicsWorld->getDispatchInfo().m_enableSPU = true;*/ // stop threaded bullet // NOT THREADED m_collisionConfiguration = new btDefaultCollisionConfiguration(); m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); btVector3 worldAabbMin(-10000,-10000,-10000); btVector3 worldAabbMax(10000,10000,10000); m_broadphase = new btAxisSweep3 (worldAabbMin, worldAabbMax); m_broadphase->getOverlappingPairCache()->setInternalGhostPairCallback(new btGhostPairCallback()); m_solver = new btSequentialImpulseConstraintSolver; m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration); // END NOT THREADED // btVector3 v = m_dynamicsWorld->getGravity(); // cerr << v.y() << endl; // m_dynamicsWorld->setGravity( btVector3(0.0f, -50.0f, 0.0f) ); m_dynamicsWorld->getSolverInfo().m_solverMode = SOLVER_USE_WARMSTARTING + SOLVER_SIMD; m_dynamicsWorld->getSolverInfo().m_numIterations = 8; // raycast raycast = new Raycast(m_dynamicsWorld); // mousepicker mousepicker = new Mousepicker(m_dynamicsWorld); // determine vision width picwidth = *retinasperrow * (*critter_retinasize+1); // reset cam resetCamera(); // debugDrawer.setDebugMode(btIDebugDraw::DBG_DrawWireframe|btIDebugDraw::DBG_DrawConstraints+btIDebugDraw::DBG_DrawConstraintLimits); // debugDrawer.setDebugMode(btIDebugDraw::DBG_DrawConstraints+btIDebugDraw::DBG_DrawConstraintLimits); // debugDrawer.setDebugMode(btIDebugDraw::DBG_DrawConstraints); // debugDrawer.setDebugMode(btIDebugDraw::DBG_DrawConstraintLimits); // m_dynamicsWorld->setDebugDrawer(&debugDrawer); // threading locks omp_init_lock(&my_lock1); // omp_init_lock(&my_lock2); } void WorldB::init() { makeFloor(); if ( settings->getCVar("autoload") ) loadAllCritters(); if ( settings->getCVar("autoloadlastsaved") ) loadAllLastSavedCritters(); } void WorldB::castMouseRay() { // cerr << "casting" << endl; mouseRay = raycast->cast( camera.position.getOrigin(), mouseRayTo ); mouseRayHit = false; if ( mouseRay.hit ) { // if ( !( mouseRay.hitBody->isStaticObject() || mouseRay.hitBody->isKinematicObject() ) ) // { Entity* e = static_cast(mouseRay.hitBody->getUserPointer()); if ( e->type == 1 || e->type == 0 ) { mouseRayHit = true; mouseRayHitEntity = e; } // } } } void WorldB::calcMouseDirection() { // cerr << "updating mouserayto" << endl; mouseRayTo = camera.getScreenDirection(*mousex, *mousey); } void WorldB::moveInMouseDirection(bool towards) { // cerr << "updating mouserayto" << endl; if ( towards ) camera.moveTowards(mouseRayTo.normalized()); else camera.moveAwayFrom(mouseRayTo.normalized()); } void WorldB::pickBody(const int& x, const int& y) { if ( mouseRayHit ) { if ( mouseRayHitEntity->type == 0 || mouseRayHitEntity->type == 1 ) { btRigidBody* b = static_cast(mouseRay.hitBody); // if critter, and it's the head's ghostobject we touch, overwrite with head's body if ( mouseRayHitEntity->type == 0 ) { btCollisionObject* co = static_cast(mouseRay.hitBody); CritterB* c = static_cast(mouseRayHitEntity); if ( co == c->body.mouths[0]->ghostObject ) b = c->body.mouths[0]->body; } mousepicker->attach( b, mouseRay.hitPosition, camera.position.getOrigin(), mouseRayTo ); mousepicker->pickedBool = &mouseRayHitEntity->isPicked; *mousepicker->pickedBool = true; } } } void WorldB::selectBody(const int& x, const int& y) { if ( mouseRayHit ) if ( mouseRayHitEntity->type == 0 ) critterselection->registerCritter(static_cast(mouseRayHitEntity)); } void WorldB::movePickedBodyTo() { if ( mousepicker->active ) mousepicker->moveTo( camera.position.getOrigin(), mouseRayTo ); } void WorldB::movePickedBodyFrom() { if ( mousepicker->active ) mousepicker->moveFrom( camera.position.getOrigin() ); } void WorldB::process() { // kill half? killHalf(); // Remove food expireFood(); // Autoinsert Food autoinsertFood(); // remove all dead critters expireCritters(); // Autosave Critters? autosaveCritters(); // Autoexchange Critters? autoexchangeCritters(); // Autoinsert Critters? autoinsertCritters(); if ( *critter_raycastvision == 0 ) { renderVision(); grabVision(); } // do a bullet step m_dynamicsWorld->stepSimulation(0.016667f, 0, 0.016667f); // m_dynamicsWorld->stepSimulation(0.016667f); // m_dynamicsWorld->stepSimulation(Timer::Instance()->bullet_ms / 1000.f); // cerr << Timer::Instance()->bullet_ms << " : " << Timer::Instance()->bullet_ms / 1000.f << endl; // process all critters int lmax = (int)critters.size(); // int i; CritterB* c; float freeEnergyc = 0.0f; omp_set_num_threads( *threads ); #pragma omp parallel for ordered shared(freeEnergyc, lmax) private(c) // ordered for( int i=0; i < lmax; i++) { // omp_set_lock(&my_lock1); c = critters[i]; // omp_unset_lock(&my_lock1); omp_set_lock(&my_lock1); // #pragma omp critical checkCollisions( c ); omp_unset_lock(&my_lock1); // process // omp_set_lock(&my_lock1); c->process(); // omp_unset_lock(&my_lock1); // record critter used energy // omp_set_lock(&my_lock1); freeEnergyc += c->energyUsed; // omp_unset_lock(&my_lock1); // process Output Neurons // omp_set_lock(&my_lock1); eat(c); // omp_unset_lock(&my_lock1); // procreation if procreation energy trigger is hit omp_set_lock(&my_lock1); // #pragma omp critical procreate(c); omp_unset_lock(&my_lock1); // } } freeEnergy += freeEnergyc; } void WorldB::childPositionOffset(btVector3* v) { v->setY(insertHight); } void WorldB::procreate( CritterB* c ) { if ( c->procreate && c->canProcreate ) { bool brainmutant = false; bool bodymutant = false; if ( randgen->Instance()->get(1,100) <= *brain_mutationrate ) brainmutant = true; if ( randgen->Instance()->get(1,100) <= *body_mutationrate ) bodymutant = true; btVector3 np = c->body.bodyparts[0]->myMotionState->m_graphicsWorldTrans.getOrigin(); // position offset childPositionOffset(&np); // np.setY(insertHight); // if ( np.getX() > *worldsizeX/2 ) // np.setX(np.getX()-1.0f); // else // np.setX(np.getX()+1.0f); CritterB *nc = new CritterB(*c, currentCritterID++, np, brainmutant, bodymutant); //CritterB *nc = new CritterB(*c, currentCritterID++, findPosition(), mutant); // display message of birth stringstream buf; buf << setw(4) << c->critterID << " : " << setw(4) << nc->critterID; buf << " ad: " << setw(4) << nc->genotype->adamdist; buf << " n: " << setw(4) << nc->brain.totalNeurons << " s: " << setw(5) << nc->brain.totalSynapses; if ( brainmutant || bodymutant ) { buf << " "; if ( brainmutant ) buf << "brain"; if ( brainmutant && bodymutant ) buf << "+"; if ( bodymutant ) buf << "body"; buf << " mutant"; } Textverbosemessage::Instance()->addBirth(buf); if (*headless) cerr << buf.str()<< endl; // split energies in half nc->energyLevel = c->energyLevel/2.0f; c->energyLevel -= nc->energyLevel; // reset procreation energy count critters.push_back( nc ); nc->calcFramePos(critters.size()-1); } } void WorldB::eat( CritterB* c ) { if ( c->eat ) { if ( c->touchingFood ) { Food* f = static_cast(c->touchedEntity); float eaten = *critter_maxenergy / 100.0f; if ( c->energyLevel + eaten > *critter_maxenergy ) eaten -= (c->energyLevel + eaten) - *critter_maxenergy; if ( f->energyLevel - eaten < 0 ) eaten = f->energyLevel; c->energyLevel += eaten; f->energyLevel -= eaten; } else if ( c->touchingCritter && *critter_enableomnivores ) { CritterB* ct = static_cast(c->touchedEntity); float eaten = *critter_maxenergy / 100.0f; if ( c->energyLevel + eaten > *critter_maxenergy ) eaten -= (c->energyLevel + eaten) - *critter_maxenergy; if ( ct->energyLevel - eaten < 0 ) eaten = ct->energyLevel; c->energyLevel += eaten; ct->energyLevel -= eaten; ct->eaten = true; } } } void WorldB::killHalf() { if ( critters.size() >= *critter_killhalfat ) { killHalfOfCritters(); // reduce energy if ( *killhalf_decrenergypct > 0 ) { float dec_amount = ((*food_maxenergy * *energy) - *food_maxenergy) / *food_maxenergy; if ( dec_amount >= 0.0f ) { int dec = (dec_amount / 100) * *killhalf_decrenergypct; settings->setCVar("energy", *energy-dec ); //*energy -= dec; freeEnergy -= dec * *food_maxenergy; } } // increase worldsizes if ( *killhalf_incrworldsizeX > 0 ) { settings->increaseCVar("worldsizeX", *killhalf_incrworldsizeX); makeFloor(); } if ( *killhalf_incrworldsizeY > 0 ) { settings->increaseCVar("worldsizeY", *killhalf_incrworldsizeY); makeFloor(); } // decrease critter_maxlifetime if ( *killhalf_decrmaxlifetimepct > 0 ) { int dec = (*critter_maxlifetime / 100) * *killhalf_decrmaxlifetimepct; settings->setCVar("critter_maxlifetime", *critter_maxlifetime-dec ); } } } void WorldB::autoinsertCritters() { // insert critter if < minimum if ( critters.size() < *mincritters ) insertCritter(); // insert critter if insertcritterevery is reached if ( *insertcritterevery > 0 ) { if ( insertCritterCounter >= *insertcritterevery ) { insertCritter(); insertCritterCounter = 0; } else { insertCritterCounter++; } } } void WorldB::autosaveCritters() { if ( *critter_autosaveinterval > 0 ) { autosaveCounter += ((float)Timer::Instance()->elapsed/1000); if ( autosaveCounter > *critter_autosaveinterval ) { autosaveCounter = 0.0f; saveAllCritters(); } } } void WorldB::autoexchangeCritters() { if ( *critter_autoexchangeinterval > 0 ) { autoexchangeCounter += ((float)Timer::Instance()->elapsed/1000); if ( autoexchangeCounter > *critter_autoexchangeinterval ) { autoexchangeCounter = 0.0f; // determine exchange directory stringstream buf; buf << dirlayout->savedir << "/exchange"; string exchangedir = buf.str(); // save or load? :) unsigned int mode = randgen->Instance()->get( 0, 1 ); // always load if critters == 0 if ( critters.size() == 0 || mode ) { vector files; dirH.listContentsFull(exchangedir, files); // FIXME same routine as load all critters for ( unsigned int i = 0; i < files.size(); i++ ) { if ( parseH->Instance()->endMatches( ".cr", files[i] ) ) { stringstream buf; buf << "loading " << files[i]; if ( !*headless ) { Logbuffer::Instance()->add(buf); } string content; fileH.open( files[i], content ); fileH.rm( files[i] ); CritterB *c = new CritterB(content, m_dynamicsWorld, findPosition(), retina); if ( !c->loadError) { critters.push_back( c ); c->critterID = currentCritterID++; c->calcFramePos(critters.size()-1); // start energy freeEnergy -= c->energyLevel; } else delete c; } } stringstream buf; buf << "Loaded critters from " << exchangedir; if ( !*headless ) { Logbuffer::Instance()->add(buf); } else cerr << buf.str()<< endl; } else { // pick one to save unsigned int savec = randgen->Instance()->get( 0, critters.size()-1 ); buf << "/" << time(0) << ".cr"; string filename = buf.str(); // makde dirs if ( !dirH.exists(dirlayout->savedir) ) dirH.make(dirlayout->savedir); if ( !dirH.exists(exchangedir) ) dirH.make(exchangedir); // save critter fileH.save(filename, critters[savec]->genotype->saveGenotype()); //cerr << endl << "Saved critters to " << subsavedir << endl << endl; stringstream buf2; buf2 << "Autoexchange: Saved critter to " << filename; if ( !*headless ) Logbuffer::Instance()->add(buf2); else cerr << buf2.str()<< endl; } } } } void WorldB::autoinsertFood() { if ( freeEnergy >= *food_maxenergy ) { insertRandomFood(1, *food_maxenergy); freeEnergy -= *food_maxenergy; //cerr << "food: " << food.size() << endl; } } void WorldB::expireCritters() { for( unsigned int i=0; i < critters.size(); i++) { // see if energy level isn't below 0 -> die, or die of old age if ( critters[i]->energyLevel <= 0.0f ) { stringstream buf; if ( critters[i]->eaten ) buf << setw(4) << critters[i]->critterID << " got eaten"; else buf << setw(4) << critters[i]->critterID << " starved"; Textverbosemessage::Instance()->addDeath(buf); if (*headless) cerr << buf.str()<< endl; removeCritter(i); i--; } // die of old age else if ( critters[i]->totalFrames > *critter_maxlifetime ) { stringstream buf; buf << setw(4) << critters[i]->critterID << " died of age"; Textverbosemessage::Instance()->addDeath(buf); if (*headless) cerr << buf.str()<< endl; removeCritter(i); i--; } // die if y < 100 else { btVector3 pos = critters[i]->body.bodyparts[0]->myMotionState->m_graphicsWorldTrans.getOrigin(); if ( pos.getY() < -100.0f ) { stringstream buf; buf << setw(4) << critters[i]->critterID << " fell in the pit"; Textverbosemessage::Instance()->addDeath(buf); if (*headless) cerr << buf.str()<< endl; removeCritter(i); i--; } } } } void WorldB::expireFood() { for( unsigned int i=0; i < food.size(); i++) { // food was eaten if ( food[i]->energyLevel <= 0 ) { freeEnergy += food[i]->energyLevel; if ( food[i]->isPicked ) mousepicker->detach(); delete food[i]; food.erase(food.begin()+i); i--; } // old food, this should remove stuff from corners else if ( ++food[i]->totalFrames >= *food_maxlifetime ) { freeEnergy += food[i]->energyLevel; if ( food[i]->isPicked ) mousepicker->detach(); delete food[i]; food.erase(food.begin()+i); i--; } /* // die if y < 100 else { btVector3 pos = food[i]->body.bodyparts[0]->myMotionState->m_graphicsWorldTrans.getOrigin(); if ( pos.getY() < -100.0f ) { freeEnergy += food[i]->energyLevel; if ( food[i]->isPicked ) mousepicker->detach(); delete food[i]; food.erase(food.begin()+i); i--; } }*/ } } void WorldB::getGeneralStats() { // settings->info_totalNeurons = 0; // settings->info_totalSynapses = 0; // settings->info_totalAdamDistance = 0; // settings->info_totalBodyparts = 0; // settings->info_totalWeight = 0; // settings->info_critters = critters.size(); // settings->info_food = food.size(); // int info_totalNeurons = 0; // int info_totalSynapses = 0; // int info_totalAdamDistance = 0; // int info_totalBodyparts = 0; // int info_totalWeight = 0; // CritterB* c; // #pragma omp parallel for shared (info_totalNeurons, info_totalSynapses, info_totalAdamDistance, info_totalBodyparts, info_totalWeight, crittersize) private(i, c) // for( unsigned int i=0; i < critters.size(); i++ ) // { // c = critters[i]; // info_totalNeurons += c->brain.totalNeurons; // info_totalSynapses += c->brain.totalSynapses; // info_totalAdamDistance += c->genotype->adamdist; // info_totalBodyparts += c->body.bodyparts.size(); // info_totalWeight += c->body.totalWeight; // } // // settings->info_totalNeurons += info_totalNeurons; // settings->info_totalSynapses += info_totalSynapses; // settings->info_totalAdamDistance += info_totalAdamDistance; // settings->info_totalBodyparts += info_totalBodyparts; // settings->info_totalWeight += info_totalWeight; statsBuffer->add( critters, food ); } void WorldB::checkCollisions( CritterB* c ) { // set inputs to false and recheck c->touchingFood = false; c->touchingCritter = false; if ( c->body.mouths.size() > 0 ) { btBroadphasePairArray& pairArray = c->body.mouths[0]->ghostObject->getOverlappingPairCache()->getOverlappingPairArray(); int numPairs = pairArray.size(); for ( int i=0; i < numPairs; i++ ) { manifoldArray.clear(); const btBroadphasePair& pair = pairArray[i]; //unless we manually perform collision detection on this pair, the contacts are in the dynamics world paircache: btBroadphasePair* collisionPair = m_dynamicsWorld->getPairCache()->findPair(pair.m_pProxy0,pair.m_pProxy1); if (!collisionPair) continue; if (collisionPair->m_algorithm) collisionPair->m_algorithm->getAllContactManifolds(manifoldArray); for ( int j = 0; j < manifoldArray.size(); j++ ) { btPersistentManifold* manifold = manifoldArray[j]; btCollisionObject* object1 = static_cast(manifold->getBody0()); btCollisionObject* object2 = static_cast(manifold->getBody1()); if ( object1->getUserPointer() == c && object2->getUserPointer() == c ) continue; for ( int p = 0; p < manifold->getNumContacts(); p++ ) { const btManifoldPoint &pt = manifold->getContactPoint(p); if ( pt.getDistance() < 0.0f ) { void* Collidingobject; if ( object1->getUserPointer() != c && object1->getUserPointer() != 0 ) Collidingobject = object1->getUserPointer(); else if ( object2->getUserPointer() != c && object2->getUserPointer() != 0 ) Collidingobject = object2->getUserPointer(); else continue; // Touching Food Entity* e = static_cast(Collidingobject); if ( e->type == 1 ) { // cerr << "touches food" << endl; c->touchingFood = true; c->touchedEntity = e; return; } // Touching Critter else if ( e->type == 0 ) { // cerr << "touches critter" << endl; c->touchingCritter = true; c->touchedEntity = e; return; } /* // Touching Food Food* f = static_cast(Collidingobject); if ( f ) { if ( f->type == 1 ) { stop = true; c->touchingFood = true; c->touchedFoodID = f; } else { // Touching Critter CritterB* b = static_cast(Collidingobject); if ( b->type == 0 ) { stop = true; c->touchingCritter = true; c->touchedCritterID = b; } } }*/ } } } } } } void WorldB::insertRandomFood(int amount, float energy) { for ( int i=0; i < amount; i++ ) { Food *f = new Food(); f->energyLevel = energy; //f->resize(); f->createBody( m_dynamicsWorld, findPosition() ); food.push_back( f ); } } void WorldB::insertCritter() { CritterB *c = new CritterB(m_dynamicsWorld, currentCritterID++, findPosition(), retina); critters.push_back( c ); c->calcFramePos(critters.size()-1); // start energy freeEnergy -= c->energyLevel; } btVector3 WorldB::findPosition() { return btVector3( (float)randgen->Instance()->get( 0, 100**worldsizeX ) / 100, insertHight, (float)randgen->Instance()->get( 0, 100**worldsizeY ) / 100 ); } void WorldB::removeCritter(unsigned int cid) { freeEnergy += critters[cid]->energyLevel; if ( critters[cid]->isPicked ) mousepicker->detach(); critterselection->unregisterCritterID(critters[cid]->critterID); critterselection->deselectCritter(critters[cid]->critterID); delete critters[cid]; critters.erase(critters.begin()+cid); // update higher retina frame positions int c; omp_set_num_threads( *threads ); // #pragma omp parallel for private(c) for ( c = cid; c < (int)critters.size(); c++ ) critters[c]->calcFramePos(c); } void WorldB::killHalfOfCritters() { for ( unsigned int c = 0; c < critters.size(); c++ ) removeCritter(c); /* // kill oldest if ( critters.size() > 0 ) { unsigned int half = (critters.size()+1)/2; for ( unsigned int c = 0; c < half; c++ ) removeCritter(0); }*/ } void WorldB::renderVision() { // render critter vision if ( !*critter_raycastvision ) for( unsigned int i=0; i < critters.size(); i++) if ( critters[i]->body.mouths.size() > 0 ) { critters[i]->place(); // drawWithinCritterSight(critters[i]); drawWithinCritterSight( i ); } } void WorldB::grabVision() { // Read pixels into retina if ( !*critter_raycastvision && critters.size() > 0 ) { // determine height unsigned int picheight = *critter_retinasize; unsigned int rows = critters.size(); while ( rows > *retinasperrow ) { picheight += *critter_retinasize; rows -= *retinasperrow; } glReadBuffer(GL_BACK); glPixelStorei( GL_UNPACK_ALIGNMENT, 1 ); glReadPixels(0, 0, picwidth, picheight, GL_RGBA, GL_UNSIGNED_BYTE, retina); } } void WorldB::drawWithoutFaces() { drawfloor(); for( unsigned int i=0; i < critters.size(); i++) critters[i]->draw(false); for( unsigned int i=0; i < food.size(); i++) food[i]->draw(); } void WorldB::drawWithGrid() { drawfloor(); for( unsigned int i=0; i < critters.size(); i++) critters[i]->draw(true); for( unsigned int i=0; i < food.size(); i++) food[i]->draw(); // m_dynamicsWorld->debugDrawWorld(); } void WorldB::drawfloor() { for( unsigned int i=0; i < walls.size(); i++) walls[i]->draw(); } void WorldB::drawShadow(btScalar* m,const btVector3& extrusion,const btCollisionShape* shape,const btVector3& worldBoundsMin,const btVector3& worldBoundsMax) { glPushMatrix(); glMultMatrixf(m); if(shape->getShapeType() == UNIFORM_SCALING_SHAPE_PROXYTYPE) { const btUniformScalingShape* scalingShape = static_cast(shape); const btConvexShape* convexShape = scalingShape->getChildShape(); float scalingFactor = (float)scalingShape->getUniformScalingFactor(); btScalar tmpScaling[4][4]={ {scalingFactor,0,0,0}, {0,scalingFactor,0,0}, {0,0,scalingFactor,0}, {0,0,0,1}}; drawShadow((btScalar*)tmpScaling,extrusion,convexShape,worldBoundsMin,worldBoundsMax); glPopMatrix(); return; } else if(shape->getShapeType()==COMPOUND_SHAPE_PROXYTYPE) { const btCompoundShape* compoundShape = static_cast(shape); for (int i=compoundShape->getNumChildShapes()-1;i>=0;i--) { btTransform childTrans = compoundShape->getChildTransform(i); const btCollisionShape* colShape = compoundShape->getChildShape(i); btScalar childMat[16]; childTrans.getOpenGLMatrix(childMat); drawShadow(childMat,extrusion*childTrans.getBasis(),colShape,worldBoundsMin,worldBoundsMax); } } glPopMatrix(); } void WorldB::drawWithinCritterSight(CritterB *c) { if ( c->body.mouths.size() > 0 ) { btVector3 cposi = c->body.mouths[0]->myMotionState->m_graphicsWorldTrans.getOrigin(); // draw everything in it's sight float sightrange = (float)*critter_sightrange/10; drawfloor(); for( unsigned int i=0; i < food.size(); i++) { Food *f = food[i]; if ( cposi.distance( f->myMotionState->m_graphicsWorldTrans.getOrigin() ) < sightrange ) f->draw(); } for( unsigned int j=0; j < critters.size(); j++) { CritterB *f = critters[j]; for( unsigned int b=0; b < f->body.bodyparts.size(); b++) { if ( cposi.distance( f->body.bodyparts[b]->myMotionState->m_graphicsWorldTrans.getOrigin() ) < sightrange ) { f->body.bodyparts[b]->myMotionState->m_graphicsWorldTrans.getOpenGLMatrix(drawposition); glPushMatrix(); glMultMatrixf(drawposition); glColor4f( f->genotype->bodyArch->color.r, f->genotype->bodyArch->color.g, f->genotype->bodyArch->color.b, f->genotype->bodyArch->color.a ); btVector3 halfExtent = static_cast(f->body.bodyparts[b]->shape)->getHalfExtentsWithMargin(); glScaled(halfExtent[0], halfExtent[1], halfExtent[2]); Displaylists::Instance()->call(0); glPopMatrix(); } } if ( c->critterID != f->critterID ) { for( unsigned int b=0; b < f->body.mouths.size(); b++) { if ( cposi.distance( f->body.mouths[b]->ghostObject->getWorldTransform().getOrigin() ) < sightrange ) { f->body.mouths[b]->ghostObject->getWorldTransform().getOpenGLMatrix(drawposition); glPushMatrix(); glMultMatrixf(drawposition); glColor4f( 1.0f, 0.0f, 0.0f, 0.0f ); btVector3 halfExtent = static_cast(f->body.mouths[b]->shape)->getHalfExtentsWithMargin(); glScaled(halfExtent[0], halfExtent[1], halfExtent[2]); Displaylists::Instance()->call(1); glPopMatrix(); } } } } } } // same as before, but with exponential optimisation void WorldB::drawWithinCritterSight(unsigned int cid) { CritterB *c = critters[cid]; if ( c->body.mouths.size() > 0 ) { // cerr << endl << "run " << cid << endl; btVector3 cposi = c->body.mouths[0]->myMotionState->m_graphicsWorldTrans.getOrigin(); // draw everything in it's sight float sightrange = (float)*critter_sightrange/10; drawfloor(); for( unsigned int i=0; i < food.size(); i++) { Food *f = food[i]; if ( cposi.distance( f->myMotionState->m_graphicsWorldTrans.getOrigin() ) < sightrange ) f->draw(); } // cerr << "prerecorded " << c->crittersWithinRange.size() << endl; // first process prechecked crittersWithinRange vector for( unsigned int p=0; p < c->crittersWithinRange.size(); p++) { // cerr << " drawing " << c->crittersWithinRange[p] << endl; CritterB *f = critters[ c->crittersWithinRange[p] ]; for( unsigned int b=0; b < f->body.bodyparts.size(); b++) { f->body.bodyparts[b]->myMotionState->m_graphicsWorldTrans.getOpenGLMatrix(drawposition); glPushMatrix(); glMultMatrixf(drawposition); glColor4f( f->genotype->bodyArch->color.r, f->genotype->bodyArch->color.g, f->genotype->bodyArch->color.b, f->genotype->bodyArch->color.a ); btVector3 halfExtent = static_cast(f->body.bodyparts[b]->shape)->getHalfExtentsWithMargin(); glScaled(halfExtent[0], halfExtent[1], halfExtent[2]); Displaylists::Instance()->call(0); glPopMatrix(); } for( unsigned int j=0; j < f->body.mouths.size(); j++) { f->body.mouths[j]->ghostObject->getWorldTransform().getOpenGLMatrix(drawposition); glPushMatrix(); glMultMatrixf(drawposition); glColor4f( 1.0f, 0.0f, 0.0f, 0.0f ); btVector3 halfExtent = static_cast(f->body.mouths[j]->shape)->getHalfExtentsWithMargin(); glScaled(halfExtent[0], halfExtent[1], halfExtent[2]); Displaylists::Instance()->call(1); glPopMatrix(); } } // clear crittersWithinRange vector c->crittersWithinRange.clear(); // cerr << "not recorded " << endl; // now start from current critter to last, record new checks for later critters for( unsigned int j=cid; j < critters.size(); j++) { // cerr << " checking distance of " << j << endl; CritterB *f = critters[j]; // if the first head is within range, draw critters bodyparts and if not same critter, draw head. if ( c->critterID == f->critterID || cposi.distance( f->body.mouths[0]->ghostObject->getWorldTransform().getOrigin() ) < sightrange ) { //draw bodies if within range for( unsigned int b=0; b < f->body.bodyparts.size(); b++) { f->body.bodyparts[b]->myMotionState->m_graphicsWorldTrans.getOpenGLMatrix(drawposition); glPushMatrix(); glMultMatrixf(drawposition); glColor4f( f->genotype->bodyArch->color.r, f->genotype->bodyArch->color.g, f->genotype->bodyArch->color.b, f->genotype->bodyArch->color.a ); btVector3 halfExtent = static_cast(f->body.bodyparts[b]->shape)->getHalfExtentsWithMargin(); glScaled(halfExtent[0], halfExtent[1], halfExtent[2]); Displaylists::Instance()->call(0); glPopMatrix(); } //draw heads if within range, and not itself if ( c->critterID != f->critterID ) { // record for future distance checks f->crittersWithinRange.push_back(cid); // cerr << "recording " << cid << " in " << j << endl; for( unsigned int b=0; b < f->body.mouths.size(); b++) { f->body.mouths[b]->ghostObject->getWorldTransform().getOpenGLMatrix(drawposition); glPushMatrix(); glMultMatrixf(drawposition); glColor4f( 1.0f, 0.0f, 0.0f, 0.0f ); btVector3 halfExtent = static_cast(f->body.mouths[b]->shape)->getHalfExtentsWithMargin(); glScaled(halfExtent[0], halfExtent[1], halfExtent[2]); Displaylists::Instance()->call(1); glPopMatrix(); } } } } } } void WorldB::loadAllCritters() { vector files; dirH.listContentsFull(dirlayout->loaddir, files); for ( unsigned int i = 0; i < files.size(); i++ ) { if ( parseH->Instance()->endMatches( ".cr", files[i] ) ) { stringstream buf; buf << "loading " << files[i]; Logbuffer::Instance()->add(buf); string content; fileH.open( files[i], content ); CritterB *c = new CritterB(content, m_dynamicsWorld, findPosition(), retina); if ( !c->loadError) { critters.push_back( c ); c->critterID = currentCritterID++; c->calcFramePos(critters.size()-1); // start energy freeEnergy -= c->energyLevel; } else delete c; } } stringstream buf; buf << "Loaded critters from " << dirlayout->loaddir; Logbuffer::Instance()->add(buf); //cerr << endl << "Loaded critters from " << loaddir << endl << endl; } void WorldB::loadAllLastSavedCritters() // FIXME overlap with previous function { cerr << "loading" << endl; vector files; string filen = dirlayout->progdir; filen.append("/lastsaved"); if ( fileH.exists(filen) ) { string lastsaveddir; fileH.open( filen, lastsaveddir ); lastsaveddir = lastsaveddir.substr(0, lastsaveddir.length() - 1); // lastsaveddir.append("/"); cerr << lastsaveddir << endl; dirH.listContentsFull(lastsaveddir, files); cerr << "found file: " << files.size() << endl; for ( unsigned int i = 0; i < files.size(); i++ ) { if ( parseH->Instance()->endMatches( ".cr", files[i] ) ) { stringstream buf; buf << "loading " << files[i]; Logbuffer::Instance()->add(buf); string content; fileH.open( files[i], content ); CritterB *c = new CritterB(content, m_dynamicsWorld, findPosition(), retina); if ( !c->loadError) { critters.push_back( c ); c->critterID = currentCritterID++; c->calcFramePos(critters.size()-1); // start energy freeEnergy -= c->energyLevel; } else delete c; } } stringstream buf; buf << "Loaded critters from " << lastsaveddir; Logbuffer::Instance()->add(buf); //cerr << endl << "Loaded critters from " << loaddir << endl << endl; } } void WorldB::saveAllCritters() { // determine save directory stringstream buf; buf << dirlayout->savedir << "/" << settings->profileName; string subprofiledir = buf.str(); buf << "/" << time(0); string subsavedir = buf.str(); // make dirs if ( !dirH.exists(dirlayout->savedir) ) dirH.make(dirlayout->savedir); if ( !dirH.exists(subprofiledir) ) dirH.make(subprofiledir); if ( !dirH.exists(subsavedir) ) dirH.make(subsavedir); for ( unsigned int i = 0; i < critters.size(); i++ ) { // determine filename stringstream filename; filename << subsavedir << "/" << "critter" << i << ".cr"; // save critters fileH.save(filename.str(), critters[i]->genotype->saveGenotype()); } // save lastsaved file stringstream lastsaved; lastsaved << dirlayout->progdir << "/" << "lastsaved"; fileH.save( lastsaved.str(), subsavedir ); cerr << "saved " << lastsaved.str() << " with " << subsavedir << endl; //cerr << endl << "Saved critters to " << subsavedir << endl << endl; stringstream buf2; buf2 << "Saved critters to " << subsavedir; Logbuffer::Instance()->add(buf2); } void WorldB::resetCamera() { unsigned int biggest = *worldsizeX; if ( *worldsizeY > biggest ) biggest = 1.4f**worldsizeY; camera.position.setOrigin( btVector3( 0.5f**worldsizeX, 1.3f*biggest, 0.5f**worldsizeY) ); // camera.position.setRotation(btQuaternion(btVector3(1, 0, 0), btScalar(90))); camera.position.getBasis().setEulerZYX( -1.5707f, 0.0f, 0.0f ); // 1.5707f (float)*energy/10 // camera.position = btVector3( -0.5f**worldsizeX, -1.3f*biggest, -0.5f**worldsizeY); // camera.rotation = Vector3f( 90.0f, 0.0f, 0.0f); } // selected critter actions int WorldB::findSelectedCritterID() { for ( unsigned int i=0; i < critters.size(); i++ ) if ( critters[i]->critterID == critterselection->selectedCritter->critterID ) return i; return -1; } int WorldB::findCritterID(unsigned int cid) { for ( unsigned int i=0; i < critters.size(); i++ ) if ( critters[i]->critterID == cid ) return i; return -1; } void WorldB::removeSelectedCritter() { removeCritter(findSelectedCritterID()); } void WorldB::removeAllSelectedCritters() { while ( critterselection->clist.size() > 0 ) removeCritter( findCritterID(critterselection->clist[0]->critterID) ); } void WorldB::duplicateCritter(unsigned int cid, bool brainmutant, bool bodymutant) { btVector3 np = critters[cid]->body.bodyparts[0]->myMotionState->m_graphicsWorldTrans.getOrigin(); // position offset childPositionOffset(&np); CritterB *nc = new CritterB(*critters[cid], currentCritterID++, np, brainmutant, bodymutant); // duplicate energy levels nc->energyLevel = *critter_startenergy; freeEnergy -= nc->energyLevel; critters.push_back( nc ); nc->calcFramePos(critters.size()-1); } void WorldB::duplicateSelectedCritter() { duplicateCritter( findSelectedCritterID(), false, false ); } void WorldB::spawnBrainMutantSelectedCritter() { duplicateCritter( findSelectedCritterID(), true, false ); } void WorldB::spawnBodyMutantSelectedCritter() { duplicateCritter( findSelectedCritterID(), false, true ); } void WorldB::spawnBrainBodyMutantSelectedCritter() { duplicateCritter( findSelectedCritterID(), true, true ); } void WorldB::feedSelectedCritter() { CritterB* c = critters[findSelectedCritterID()]; if ( c->energyLevel < *critter_startenergy ) { float max_currentDiff = (float)*critter_startenergy - c->energyLevel; c->energyLevel += max_currentDiff; freeEnergy -= max_currentDiff; } } void WorldB::resetageSelectedCritter() { critters[findSelectedCritterID()]->totalFrames = 0; } void WorldB::duplicateAllSelectedCritters() { for ( unsigned int i=0; i < critterselection->clist.size(); i ++ ) duplicateCritter( findCritterID(critterselection->clist[i]->critterID), false, false ); } void WorldB::spawnBrainMutantAllSelectedCritters() { for ( unsigned int i=0; i < critterselection->clist.size(); i ++ ) duplicateCritter( findCritterID(critterselection->clist[i]->critterID), true, false ); } void WorldB::spawnBodyMutantAllSelectedCritters() { for ( unsigned int i=0; i < critterselection->clist.size(); i ++ ) duplicateCritter( findCritterID(critterselection->clist[i]->critterID), false, true ); } void WorldB::spawnBrainBodyMutantAllSelectedCritters() { for ( unsigned int i=0; i < critterselection->clist.size(); i ++ ) duplicateCritter( findCritterID(critterselection->clist[i]->critterID), true, true ); } void WorldB::makeFloor() { makeDefaultFloor(); } void WorldB::makeDefaultFloor() { for ( unsigned int i=0; i < walls.size(); i++ ) delete walls[i]; walls.clear(); // Wall Constants float WallWidth = 0.5f; float WallHalfWidth = WallWidth/2.0f; float WallHeight = 2.0f; float WallHalfHeight = WallHeight/2.0f; // Ground Floor btVector3 position( *worldsizeX/2.0f, -WallHalfWidth, *worldsizeY/2.0f ); Wall* w = new Wall( *worldsizeX, WallWidth, *worldsizeY, position, m_dynamicsWorld ); w->color.r = 0.30f; w->color.g = 0.20f; w->color.b = 0.10f; walls.push_back(w); if ( settings->getCVar("worldwalls") ) { // Left Wall position = btVector3 ( 0.0f-WallHalfWidth, WallHalfHeight-WallWidth, *worldsizeY/2.0f ); w = new Wall( WallWidth, WallHeight, *worldsizeY, position, m_dynamicsWorld ); w->color.r = 0.34f; w->color.g = 0.25f; w->color.b = 0.11f; walls.push_back(w); // Right Wall position = btVector3 ( *worldsizeX+WallHalfWidth, WallHalfHeight-WallWidth, *worldsizeY/2.0f ); w = new Wall( WallWidth, WallHeight, *worldsizeY, position, m_dynamicsWorld ); w->color.r = 0.34f; w->color.g = 0.25f; w->color.b = 0.11f; walls.push_back(w); // Top Wall position = btVector3 ( *worldsizeX/2.0f, WallHalfHeight-WallWidth, 0.0f-WallHalfWidth ); w = new Wall( *worldsizeX+(WallWidth*2), WallHeight, WallWidth, position, m_dynamicsWorld ); w->color.r = 0.34f; w->color.g = 0.25f; w->color.b = 0.11f; walls.push_back(w); // Bottom Wall position = btVector3 ( *worldsizeX/2.0f, WallHalfHeight-WallWidth, *worldsizeY+WallHalfWidth ); w = new Wall( *worldsizeX+(WallWidth*2), WallHeight, WallWidth, position, m_dynamicsWorld ); w->color.r = 0.34f; w->color.g = 0.25f; w->color.b = 0.11f; walls.push_back(w); } } // camera ops void WorldB::camera_moveup() { camera.moveUp(0.01f); movePickedBodyFrom(); } void WorldB::camera_movedown() { camera.moveDown(0.01f); movePickedBodyFrom(); } void WorldB::camera_moveforward() { camera.moveForward(0.01f); movePickedBodyFrom(); } void WorldB::camera_movebackward() { camera.moveBackward(0.01f); movePickedBodyFrom(); } void WorldB::camera_moveleft() { camera.moveLeft(0.01f); movePickedBodyFrom(); } void WorldB::camera_moveright() { camera.moveRight(0.01f); movePickedBodyFrom(); } void WorldB::camera_lookup() { camera.lookUp(0.001f); calcMouseDirection(); movePickedBodyTo(); } void WorldB::camera_lookdown() { camera.lookDown(0.001f); calcMouseDirection(); movePickedBodyTo(); } void WorldB::camera_lookleft() { camera.lookLeft(0.001f); calcMouseDirection(); movePickedBodyTo(); } void WorldB::camera_lookright() { camera.lookRight(0.001f); calcMouseDirection(); movePickedBodyTo(); } void WorldB::camera_rollleft() { camera.rollLeft(0.001f); calcMouseDirection(); movePickedBodyTo(); } void WorldB::camera_rollright() { camera.rollRight(0.001f); calcMouseDirection(); movePickedBodyTo(); } WorldB::~WorldB() { for ( unsigned int i=0; i < food.size(); i++ ) delete food[i]; for ( unsigned int i=0; i < critters.size(); i++ ) delete critters[i]; for ( unsigned int i=0; i < walls.size(); i++ ) delete walls[i]; free(retina); delete m_collisionConfiguration; delete m_dispatcher; delete m_broadphase; delete m_solver; delete m_dynamicsWorld; delete raycast; delete mousepicker; omp_destroy_lock(&my_lock1); // omp_destroy_lock(&my_lock2); } critterding-beta12.1/src/scenes/entities/genotype.cpp0000644000175000017500000000351211340265263021771 0ustar bobkebobke#include "genotype.h" Genotype::Genotype() { bodyArch = new BodyArch(); brainzArch = new BrainzArch(); count = 0; adamdist = 0; } void Genotype::registerBrainInputOutputs() { // BRAIN INPUTS // touching food brainzArch->registerInput( 10000 ); // touching critter brainzArch->registerInput( 10001 ); // canprocreate brainzArch->registerInput( 20000 ); // energy state for ( unsigned int i=0; i < 10; i++ ) brainzArch->registerInput( 30000+i ); // age state for ( unsigned int i=0; i < 10; i++ ) brainzArch->registerInput( 40000+i ); // vision retina number of items unsigned int items = bodyArch->retinasize * bodyArch->retinasize * 4; for ( unsigned int i=0; i < items; i++ ) brainzArch->registerInput( 50000+i ); // register constraint angles outputs as brain inputs, take constraint_id1 for ease for ( unsigned int i=0; i < bodyArch->archConstraints.size(); i++ ) brainzArch->registerInput( bodyArch->archConstraints[i].constraint_id1 ); // BRAIN OUTPUTS // register constraints's inputs as brain outputs for ( unsigned int i=0; i < bodyArch->archConstraints.size(); i++ ) { brainzArch->registerOutput( bodyArch->archConstraints[i].constraint_id1 ); brainzArch->registerOutput( bodyArch->archConstraints[i].constraint_id2 ); } // eat brainzArch->registerOutput( 100000 ); // procreate brainzArch->registerOutput( 100001 ); } string Genotype::saveGenotype() { stringstream buf; // buf << "color=" << color[0] << "," << color[1] << "," << color[2] << ";\n"; buf << "adamdist=" << adamdist << ";\n"; // buf << "retinasize=" << retinasize << ";\n"; string* bodyarch = bodyArch->getArch(); string* brainarch = brainzArch->getArch(); buf << *bodyarch; buf << *brainarch; //cout << *arch << endl; return buf.str(); } Genotype::~Genotype() { delete bodyArch; delete brainzArch; } critterding-beta12.1/src/scenes/entities/constraint.cpp0000644000175000017500000000345711253543540022333 0ustar bobkebobke#include "constraint.h" Constraint::Constraint(btDynamicsWorld* ownerWorld, btRigidBody& bodyA, btRigidBody& bodyB, btTransform& localA, btTransform& localB, double limitA, double limitB) { input1 = false; input2 = false; // init constraint inputs Inputs.push_back(&input1); // 0: direction + Inputs.push_back(&input2); // 1: direction - m_ownerWorld = ownerWorld; // btTypedConstraint* c_hinge = new btHingeConstraint( bodyA, bodyB, localA, localB ); // c_hinge->m_limitSoftness = 0.9f; // c_hinge->m_solveLimit = false; // hinge = static_cast(c_hinge); hinge = new btHingeConstraint( bodyA, bodyB, localA, localB ); // hinge->m_setting.m_impulseClamp = 30.f; // hinge->m_setting.m_tau = 0.1f; hinge->setLimit( limitA, limitB, 0.9f, 0.3f, 1.0f ); m_ownerWorld->addConstraint( hinge, true ); // Calculate full and half range of hinge, HACK could be more efficient float smallestLimit = limitA; if ( limitB < limitA ) smallestLimit = limitB; diffFromZero = 0.0f - smallestLimit ; //cerr << "diff" << diffFromZero << endl; fullRange = 0.0f; if ( limitA > 0.0f ) fullRange += limitA; else fullRange += (limitA * -1.0f); if ( limitB > 0.0f ) fullRange += limitB; else fullRange += (limitB * -1.0f); hinge->setDbgDrawSize(5.0f); } float Constraint::getAngle() { float percentAngle = (hinge->getHingeAngle() + diffFromZero) / fullRange; if ( percentAngle > 1.0f ) percentAngle = 1.0f; if ( percentAngle < 0.0f ) percentAngle = 0.0f; return percentAngle; } void Constraint::motorate() { float direction = 0.0f; if ( input1 ) direction +=10.0f; if ( input2 ) direction -=10.0f; if ( direction != 0.0f ) { hinge->enableAngularMotor(true, direction, 5000.0f); } } Constraint::~Constraint() { m_ownerWorld->removeConstraint( hinge ); delete hinge; } critterding-beta12.1/src/scenes/entities/genotypes.cpp0000644000175000017500000001713711343530351022160 0ustar bobkebobke#include "genotypes.h" Genotypes* Genotypes::Instance () { static Genotypes t; return &t; } Genotypes::Genotypes() { } Genotype* Genotypes::newg( Settings* settings ) { // cerr << " gentotype start" << endl; Genotype* gt = new Genotype(); gt->bodyArch->retinasize = settings->getCVar("critter_retinasize"); gt->bodyArch->color = colorH.randomColorRGB(); gt->bodyArch->buildArch(); gt->registerBrainInputOutputs(); gt->brainzArch->maxNeurons = settings->getCVar("brain_maxneurons"); gt->brainzArch->minSynapses = settings->getCVar("brain_minsynapses"); gt->brainzArch->maxSynapses = settings->getCVar("brain_maxsynapses"); gt->brainzArch->minNeuronsAtBuildtime = settings->getCVar("brain_minneuronsatbuildtime"); gt->brainzArch->maxNeuronsAtBuildtime = settings->getCVar("brain_maxneuronsatbuildtime"); gt->brainzArch->minSynapsesAtBuildtime = settings->getCVar("brain_minsynapsesatbuildtime"); // brain.mutate_minSynapsesAtBuildtime = settings->getCVar("brain_mutate_minsynapsesatbuildtime"); gt->brainzArch->maxSynapsesAtBuildtime = settings->getCVar("brain_maxsynapsesatbuildtime"); // brain.mutate_maxSynapsesAtBuildtime = settings->getCVar("brain_mutate_maxsynapsesatbuildtime"); gt->brainzArch->percentChanceInhibitoryNeuron = settings->getCVar("brain_percentchanceinhibitoryneuron"); gt->brainzArch->mutate_percentChanceInhibitoryNeuron = settings->getCVar("brain_mutate_percentchanceinhibitoryneuron"); gt->brainzArch->percentChanceMotorNeuron = settings->getCVar("brain_percentchancemotorneuron"); gt->brainzArch->mutate_percentChanceMotorNeuron = settings->getCVar("brain_mutate_percentchancemotorneuron"); gt->brainzArch->percentChancePlasticNeuron = settings->getCVar("brain_percentchanceplasticneuron"); gt->brainzArch->mutate_percentChancePlasticNeuron = settings->getCVar("brain_mutate_percentchanceplasticneuron"); gt->brainzArch->minPlasticityStrengthen = settings->getCVar("brain_minplasticitystrengthen"); gt->brainzArch->maxPlasticityStrengthen = settings->getCVar("brain_maxplasticitystrengthen"); gt->brainzArch->minPlasticityWeaken = settings->getCVar("brain_minplasticityweaken"); gt->brainzArch->maxPlasticityWeaken = settings->getCVar("brain_maxplasticityweaken"); gt->brainzArch->mutate_PlasticityFactors = settings->getCVar("brain_mutate_plasticityfactors"); gt->brainzArch->minFiringThreshold = settings->getCVar("brain_minfiringthreshold"); gt->brainzArch->mutate_minFiringThreshold = settings->getCVar("brain_mutate_minfiringthreshold"); gt->brainzArch->maxFiringThreshold = settings->getCVar("brain_maxfiringthreshold"); gt->brainzArch->mutate_maxFiringThreshold = settings->getCVar("brain_mutate_maxfiringthreshold"); gt->brainzArch->maxDendridicBranches = settings->getCVar("brain_maxdendridicbranches"); gt->brainzArch->mutate_maxDendridicBranches = settings->getCVar("brain_mutate_maxdendridicbranches"); gt->brainzArch->percentChanceConsistentSynapses = settings->getCVar("brain_percentchanceconsistentsynapses"); gt->brainzArch->mutate_percentChanceConsistentSynapses = settings->getCVar("brain_mutate_percentchanceconsistentsynapses"); gt->brainzArch->percentChanceInhibitorySynapses = settings->getCVar("brain_percentchanceinhibitorysynapses"); gt->brainzArch->mutate_percentChanceInhibitorySynapses = settings->getCVar("brain_mutate_percentchanceinhibitorysynapses"); gt->brainzArch->percentChanceSensorySynapse = settings->getCVar("brain_percentchancesensorysynapse"); gt->brainzArch->mutate_percentChanceSensorySynapse = settings->getCVar("brain_mutate_percentchancesensorysynapse"); gt->brainzArch->percentMutateEffectAddNeuron = settings->getCVar("brain_percentmutateeffectaddneuron"); gt->brainzArch->percentMutateEffectRemoveNeuron = settings->getCVar("brain_percentmutateeffectremoveneuron"); gt->brainzArch->percentMutateEffectAlterNeuron = settings->getCVar("brain_percentmutateeffectalterneuron"); gt->brainzArch->percentMutateEffectAddSynapse = settings->getCVar("brain_percentmutateeffectaddsynapse"); gt->brainzArch->percentMutateEffectRemoveSynapse = settings->getCVar("brain_percentmutateeffectremovesynapse"); gt->brainzArch->mutate_MutateEffects = settings->getCVar("brain_mutate_mutateeffects"); gt->brainzArch->buildArch(); gt->count=1; gt->adamdist=0; gt->speciescolor = colorH.randomColorRGB().getNormalized(); list.push_back(gt); // cerr << " new genotype " << list.size() << endl; return gt; } void Genotypes::add(Genotype* gt) { gt->count++; // cerr << " added genotype " << list.size() << endl; } Genotype* Genotypes::copy(Genotype* gt, bool brainmutant, unsigned int brruns, bool bodymutant, unsigned int boruns) { // cerr << " gentotype copy start" << endl; if ( bodymutant || brainmutant ) { Genotype* newgt = new Genotype(); newgt->bodyArch->copyFrom(gt->bodyArch); if ( bodymutant ) { unsigned int runs = RandGen::Instance()->get(1, boruns); newgt->bodyArch->mutate( runs ); } newgt->registerBrainInputOutputs(); newgt->brainzArch->copyFrom(gt->brainzArch); if ( bodymutant ) newgt->brainzArch->removeObsoleteMotorsAndSensors(); if ( brainmutant ) { unsigned int runs = RandGen::Instance()->get(1, brruns); newgt->brainzArch->mutate( runs ); } newgt->count=1; newgt->adamdist = gt->adamdist+1; newgt->speciescolor = colorH.randomColorRGB().getNormalized(); list.push_back(newgt); // cerr << " gentotype copy end" << endl; return newgt; } else { add(gt); // cerr << " gentotype copy end" << endl; return gt; } // cerr << " copied genotype " << list.size() << endl; } void Genotypes::remove(Genotype* gt) { // cerr << gt->count << endl; if ( gt->count > 1 ) gt->count--; else { for ( unsigned int i=0; i < list.size(); i++ ) if ( list[i] == gt ) { delete gt; list.erase(list.begin()+i); // cerr << " removing genotype " << list.size() << endl; return; } } } Genotype* Genotypes::loadGenotype(string& content) { // cerr << "loading genotype start" << endl; Genotype* gt = new Genotype(); string passToBody; string passToBrain; string line = Parser::Instance()->returnUntillStrip( "\n", content ); while ( !line.empty() ) { // adamdist=690; if ( Parser::Instance()->beginMatchesStrip( "adamdist=", line ) ) { string AD = Parser::Instance()->returnUntillStrip( ";", line ); //cerr << "AD: " << AD << endl; if(EOF == sscanf(AD.c_str(), "%d", >->adamdist)) cerr << "ERROR INSERTING CRITTER" << endl; } // the rest goes to the body or brain else { if ( Parser::Instance()->beginMatches( "color=", line ) || Parser::Instance()->beginMatches( "retinasize=", line ) || Parser::Instance()->beginMatches( "b ", line ) || Parser::Instance()->beginMatches( "m ", line ) || Parser::Instance()->beginMatches( "c ", line ) || Parser::Instance()->beginMatches( "cm ", line ) ) { passToBody.append(line); passToBody.append("\n"); } else { passToBrain.append(line); passToBrain.append("\n"); } } line = Parser::Instance()->returnUntillStrip( "\n", content ); } gt->bodyArch->setArch(&passToBody); gt->registerBrainInputOutputs(); gt->brainzArch->setArch(&passToBrain); gt->count=1; gt->speciescolor = colorH.randomColorRGB().getNormalized(); list.push_back(gt); // genotype = genotypes->newg(passToBody, passToBrain, retinasize); // FIXME, with a speciesID // genotype->bodyArch->setArch(&passToBody); // genotype->brainzArch->setArch(&passToBrain); // cerr << "loading genotype end" << endl; return gt; } Genotypes::~Genotypes() { for (unsigned int i=0; igetCVarPtr("food_size"); totalFrames = 0; lifetime = 0; energyLevel = 0; color.r = 0.0f; color.g = 0.5f; color.b = 0.0f; color.a = 1.0f; type = 1; isPicked = false; } void Food::draw() { myMotionState->m_graphicsWorldTrans.getOpenGLMatrix(position); /* btVector3 pos = myMotionState->m_graphicsWorldTrans.getOrigin(); cerr << pos.getY() */ glPushMatrix(); glMultMatrixf(position); glColor4f( color.r, color.g, color.b, color.a ); glScaled(halfExtent[0], halfExtent[1], halfExtent[2]); Displaylists::Instance()->call(1); glPopMatrix(); } void Food::createBody(btDynamicsWorld* m_dynamicsWorld, const btVector3& startOffset) { body.m_ownerWorld = m_dynamicsWorld; btTransform offset; offset.setIdentity(); offset.setOrigin(startOffset); btTransform transform; transform.setIdentity(); transform.setOrigin( btVector3(0.0f, 0.10f, 0.0f) ); body.addBodyPart_Box((void*)this, (float)*food_size/1000, (float)*food_size/1000, (float)*food_size/1000, 1.0f, offset, transform); myMotionState = (btDefaultMotionState*)body.bodyparts[0]->body->getMotionState(); boxShape = static_cast(body.bodyparts[0]->shape); halfExtent = boxShape->getHalfExtentsWithMargin(); } Food::~Food() { } critterding-beta12.1/src/scenes/gui/0000755000175000017500000000000011347266042016375 5ustar bobkebobkecritterding-beta12.1/src/scenes/gui/maincanvas.cpp0000644000175000017500000001012511344301105021203 0ustar bobkebobke#include "maincanvas.h" Maincanvas::Maincanvas() { active = true; // mouse focus mouseFocus = false; focussedwidget = 0; // movable widget picking hasPickedwidget = false; pickedwidget = 0; if ( settings->getCVar("headless") == 0 ) { // register subwidgets of maincanvas addWidgetPanel( "helpinfo", new Helpinfo() ); addWidgetPanel( "textmessage", new Textmessage() ); addWidgetPanel( "statsgraph", new Statsgraph() ); addWidgetPanel( "infobar", new Infobar() ); addWidgetPanel( "infostats", new Infostats() ); addWidgetPanel( "textverbosemessage", Textverbosemessage::Instance() ); addWidgetPanel( "exitpanel", new Exitpanel() ); addWidgetPanel( "mutationpanel", new Mutationpanel() ); addWidgetPanel( "globalsettingspanel", new Globalsettingspanel() ); addWidgetPanel( "settingsbrainpanel", new Settingsbrainpanel() ); addWidgetPanel( "settingsbodypanel", new Settingsbodypanel() ); addWidgetPanel( "critterview", new Critterview() ); addWidgetPanel( "brainview", new Brainview() ); addWidgetPanel( "hud", new Hud() ); addWidgetPanel( "speciesview", new Speciesview() ); } // set default z axises to panels unsigned int panelc = 0; for( childit = children.begin(); childit != children.end(); childit++ ) { static_cast(childit->second)->zaxis = panelc; // update sorted drawing/clicking vector sortedindices.push_back(childit->first); panelc++; } // point the widget width/height pointers to the window's width/height v_widthP = settings->winWidth; v_heightP = settings->winHeight; // set parent pointer to 0 parent = 0; } void Maincanvas::moveMouse(unsigned int x, unsigned int y) { if ( hasPickedwidget && pickedwidget->isMovable ) { pickedwidget->translate( (int)x-oldx, (int)y-oldy ); } else { mouseFocus = false; if ( mouseOverChild( &focussedwidget, x, y ) ) mouseFocus = true; } oldx = x; oldy = y; } void Maincanvas::buttonPress(const unsigned int& button) { if ( mouseFocus ) { pickedwidget = focussedwidget; pickedwidget->click(button); hasPickedwidget = true; // raise panel? raisePanel(pickedwidget); } } void Maincanvas::buttonRelease(const unsigned int& button) { if ( hasPickedwidget ) { pickedwidget->release(button); hasPickedwidget = false; } } void Maincanvas::raisePanel(Widget* w) { Panel* rp = static_cast(w); if ( rp->zaxis > 0 ) { // the other lower zaxis values get ++ for( childit = children.begin(); childit != children.end(); childit++ ) { Panel* p = static_cast(childit->second); if ( p->zaxis < rp->zaxis ) p->zaxis++; } // this zaxis goes to 0 rp->zaxis = 0; // resort sortedindices for ( int i = sortedindices.size(); i>0; i-- ) for ( int j = 0; j < i-1; j++ ) if ( static_cast(children[sortedindices[j]])->zaxis < static_cast(children[sortedindices[j+1]])->zaxis ) { string keepS = sortedindices[j]; sortedindices[j] = sortedindices[j+1]; sortedindices[j+1] = keepS; } } } void Maincanvas::draw() { if ( active ) drawChildren(); } void Maincanvas::drawChildren() { for( unsigned int i=0; i < sortedindices.size(); i++ ) children[sortedindices[i]]->draw(); } bool Maincanvas::mouseOverChild(Widget** fWidget, int x, int y) { for ( int i = sortedindices.size()-1; i >= 0; i-- ) { Widget* w = children[sortedindices[i]]; if ( (w->isTouchable && w->active && w->mouseOver(x, y)) || !w->isTouchable ) { // RECURSIVE INTO CONTAINERS if ( w->isContainer ) { Container* c = static_cast(w); if ( c->mouseOverChild( fWidget, x, y ) ) { return true; } else if ( w->isTouchable ) { *fWidget = w; return true; } } else if ( w->isTouchable ) { *fWidget = w; return true; } } } return false; } void Maincanvas::swapChild(const string& child) { // cerr << "swapping child" << endl; children[child]->swap(); if ( children[child]->active ) raisePanel(children[child]); if ( children[child]->isMovable ) { if ( children[child] == pickedwidget ) hasPickedwidget = false; } moveMouse(oldx, oldy); } Maincanvas::~Maincanvas() { } critterding-beta12.1/src/scenes/gui/textmessage.h0000644000175000017500000000043411320212237021064 0ustar bobkebobke#ifndef TEXTMESSAGE_H #define TEXTMESSAGE_H #include "../../utils/logbuffer.h" #include "../../gui/panel.h" using namespace std; class Textmessage : public Panel { public: Textmessage(); ~Textmessage(); void draw(); private: int vpadding; int hpadding; }; #endif critterding-beta12.1/src/scenes/gui/textverbosemessage.h0000644000175000017500000000135511342625205022464 0ustar bobkebobke#ifndef TEXTVERBOSEMESSAGE_H #define TEXTVERBOSEMESSAGE_H #include "../../utils/timer.h" // FIXME howso this is here? #include "../../gui/panel.h" using namespace std; struct vmsg { string str; unsigned int appeartime; }; class Textverbosemessage : public Panel { public: static Textverbosemessage* Instance(); void draw(); void addBirth(stringstream& streamptr); void addDeath(stringstream& streamptr); unsigned int maxMessages; unsigned int msgLifetime; void swap(); protected: Textverbosemessage(); private: static Textverbosemessage* _instance; vector births; vector deaths; // float longestLength; void getLongestMsg(); void deleteExpiredMsg(); unsigned int col2; }; #endif critterding-beta12.1/src/scenes/gui/globalsettingspanel.h0000644000175000017500000000037611340630500022600 0ustar bobkebobke#ifndef GLOBALSETTINGSPANEL_H #define GLOBALSETTINGSPANEL_H #include "../../gui/settingspanel.h" using namespace std; class Globalsettingspanel : public Settingspanel { public: Globalsettingspanel(); ~Globalsettingspanel(); private: }; #endif critterding-beta12.1/src/scenes/gui/mutationpanel.cpp0000644000175000017500000000103411331352461021751 0ustar bobkebobke#include "mutationpanel.h" Mutationpanel::Mutationpanel() { v_width = 340; v_height = 85; isMovable = true; position.x = 50; position.y = 35; unsigned int vint = 12; hspace = 10; vspace = vint; addSettingmutator("body_maxmutations", hspace, vspace); vspace += vint; addSettingmutator("body_mutationrate", hspace, vspace); vspace += vint; vspace += vint; addSettingmutator("brain_maxmutations", hspace, vspace); vspace += vint; addSettingmutator("brain_mutationrate", hspace, vspace); } Mutationpanel::~Mutationpanel() { } critterding-beta12.1/src/scenes/gui/speciesview.h0000644000175000017500000000133111343055377021075 0ustar bobkebobke#ifndef SPECIESVIEW_H #define SPECIESVIEW_H #include "../../gui/panel.h" #include "../entities/genotypes.h" #include "../../math/vector2f.h" # include using namespace std; class Speciesview : public Panel { public: Speciesview(); ~Speciesview(); void draw(); private: Genotypes* genotypes; int titlebar; int v_space; int rowspacer; int qwidth; int qheight; string titlePos; string titleColor; string titleNum; string titleAd; string titleNeurons; string titleSynapses; string titleBodyparts; int titlePosW; int titleColorW; int titleNumW; int titleAdW; int titleNeuronsW; int titleSynapsesW; int titleBodypartsW; const unsigned int* colormode; }; #endif critterding-beta12.1/src/scenes/gui/Makefile.am0000644000175000017500000000164511340334147020432 0ustar bobkebobkeINCLUDES = $(all_includes) -I../../utils/bullet -fopenmp METASOURCES = AUTO noinst_LTLIBRARIES = libcdgui.la noinst_HEADERS = critterview.h \ brainview.h \ exitpanel.h \ helpinfo.h \ infostats.h \ infobar.h \ textmessage.h \ textverbosemessage.h \ statsgraph.h \ globalsettingspanel.h \ mutationpanel.h \ settingsbodypanel.h \ settingsbrainpanel.h \ hud.h \ speciesview.h \ maincanvas.h libcdgui_la_SOURCES = critterview.cpp \ brainview.cpp \ exitpanel.cpp \ helpinfo.cpp \ infostats.cpp \ infobar.cpp \ textmessage.cpp \ textverbosemessage.cpp \ statsgraph.cpp \ globalsettingspanel.cpp \ mutationpanel.cpp \ settingsbodypanel.cpp \ settingsbrainpanel.cpp \ hud.cpp \ speciesview.cpp \ maincanvas.cpp libcdgui_la_LIBADD = $(top_builddir)/src/gui/libgui.la \ $(top_builddir)/src/utils/libutils.la \ $(top_builddir)/src/math/libmath.la critterding-beta12.1/src/scenes/gui/settingsbodypanel.h0000644000175000017500000000036411340630500022272 0ustar bobkebobke#ifndef SETTINGSBODYPANEL_H #define SETTINGSBODYPANEL_H #include "../../gui/settingspanel.h" using namespace std; class Settingsbodypanel : public Settingspanel { public: Settingsbodypanel(); ~Settingsbodypanel(); private: }; #endif critterding-beta12.1/src/scenes/gui/textmessage.cpp0000644000175000017500000000175311320212237021424 0ustar bobkebobke#include "textmessage.h" Textmessage::Textmessage() { isMovable = true; vpadding = 10; hpadding = 10; position.x = 10; position.y = 50; // v_width = 300; // v_width = 200 + ( hpadding*2 ); // v_height = (15 * (messages.size()-1)) + 20 + ( vpadding*2 ); } void Textmessage::draw() { Logbuffer::Instance()->deleteExpiredMsg(); if ( !Logbuffer::Instance()->messages.empty() ) { active = true; unsigned int height = 5; v_width = Logbuffer::Instance()->longestLength + ( hpadding*2 ); v_height = (15 * (Logbuffer::Instance()->messages.size()-1)) + height + ( vpadding*2 ); // draw background box and border drawBackground(); drawBorders(); // render text glColor3f(1.0f, 1.0f, 1.0f); for ( unsigned int i = 0; i < Logbuffer::Instance()->messages.size(); i++ ) Textprinter::Instance()->print(position.x + hpadding, position.y + height + (i*15.0f) + vpadding, Logbuffer::Instance()->messages[i]->str); } else active = false; } Textmessage::~Textmessage() { }critterding-beta12.1/src/scenes/gui/speciesview.cpp0000644000175000017500000001531211343055377021434 0ustar bobkebobke#include "speciesview.h" Speciesview::Speciesview() { genotypes = Genotypes::Instance(); colormode = Settings::Instance()->getCVarPtr("colormode"); v_width = 200; v_height = 300; active = false; isMovable = true; titlebar = 25; v_space = -10 + titlebar; rowspacer = 4; qwidth = 25; qheight = 10; titlePos = "#"; titleColor = "Color"; titleNum = "Population"; titleAd = "Adam Distance"; titleNeurons = "Neurons"; titleSynapses = "Synapses"; titleBodyparts = "Bodyparts"; titlePosW = textprinter->getWidth( titlePos ); titleColorW = textprinter->getWidth( titleColor ); titleNumW = textprinter->getWidth( titleNum ); titleAdW = textprinter->getWidth( titleAd ); titleNeuronsW = textprinter->getWidth( titleNeurons ); titleSynapsesW = textprinter->getWidth( titleSynapses ); titleBodypartsW = textprinter->getWidth( titleBodyparts ); } void Speciesview::draw() { if (active) { unsigned int highestCount = 0; unsigned int highestAD = 0; unsigned int highestNeurons = 0; unsigned int highestSynapses = 0; unsigned int highestBodyparts = 0; // initialize sort indices // at the same time find the highest Counts for all columns vector indices ( genotypes->list.size(), 0 ); for ( unsigned int i = 0; i < genotypes->list.size(); i++ ) { indices[i] = i; if ( genotypes->list[i]->count > highestCount ) highestCount = genotypes->list[i]->count; if ( genotypes->list[i]->adamdist > highestAD ) highestAD = genotypes->list[i]->adamdist; if ( genotypes->list[i]->brainzArch->ArchNeurons.size() > highestNeurons ) highestNeurons = genotypes->list[i]->brainzArch->ArchNeurons.size(); // calc total syns unsigned int totalSyns = 0; for ( unsigned int j = 0; j < genotypes->list[i]->brainzArch->ArchNeurons.size(); j++ ) totalSyns += genotypes->list[i]->brainzArch->ArchNeurons[j].ArchSynapses.size(); if ( totalSyns > highestSynapses ) highestSynapses = totalSyns; if ( genotypes->list[i]->bodyArch->archBodyparts.size() > highestNeurons ) highestNeurons = genotypes->list[i]->bodyArch->archBodyparts.size(); } // sort results for ( int i = genotypes->list.size(); i>0; i-- ) for ( int j = 0; j < i-1; j++ ) if ( genotypes->list[indices[j]]->count < genotypes->list[indices[j+1]]->count ) { unsigned keepI = indices[j]; indices[j] = indices[j+1]; indices[j+1] = keepI; } int titleNumWH = textprinter->getWidth( highestCount ); int titleColorWH = qwidth; int titlePosWH = textprinter->getWidth( genotypes->list.size() ); int titleAdWH = textprinter->getWidth( highestAD ); int titleNeuronsWH = textprinter->getWidth( highestNeurons ); int titleSynapsesWH = textprinter->getWidth( highestSynapses ); int titleBodypartsWH = textprinter->getWidth( highestBodyparts ); int colw1 = titlePosW; if ( colw1 < titlePosWH ) colw1 = titlePosWH; int colw2 = titleColorW; if ( colw2 < titleColorWH ) colw2 = titleColorWH; int colw3 = titleNumW; if ( colw3 < titleNumWH ) colw3 = titleNumWH; int colw4 = titleAdW; if ( colw4 < titleAdWH ) colw4 = titleAdWH; int colw5 = titleNeuronsW; if ( colw5 < titleNeuronsWH ) colw5 = titleNeuronsWH; int colw6 = titleSynapsesW; if ( colw6 < titleSynapsesWH ) colw6 = titleSynapsesWH; int colw7 = titleBodypartsW; if ( colw7 < titleBodypartsWH ) colw7 = titleBodypartsWH; int colspacer = 15; int col1 = colspacer; int col2 = col1+colspacer + colw1; int col3 = col2+colspacer + colw2; int col4 = col3+colspacer + colw3; int col5 = col4+colspacer + colw4; int col6 = col5+colspacer + colw5; int col7 = col6+colspacer + colw6; int col8 = col7+colspacer + colw7; v_space = -10 + titlebar; v_height = (genotypes->list.size() * (qheight+rowspacer)) + rowspacer + titlebar; v_width = col8; drawBackground(); drawBorders(); drawChildren(); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); textprinter->print( absPosition.x+col1, absPosition.y+19, titlePos ); textprinter->print( absPosition.x+col2, absPosition.y+19, titleColor ); textprinter->print( absPosition.x+col3, absPosition.y+19, titleNum ); textprinter->print( absPosition.x+col4, absPosition.y+19, titleAd ); textprinter->print( absPosition.x+col5, absPosition.y+19, titleNeurons ); textprinter->print( absPosition.x+col6, absPosition.y+19, titleSynapses ); textprinter->print( absPosition.x+col7, absPosition.y+19, titleBodyparts ); for ( unsigned int i=0; i < genotypes->list.size(); i++ ) { v_space += qheight + rowspacer; glColor4f(1.0f, 1.0f, 1.0f, 1.0f); textprinter->print( absPosition.x+col1, absPosition.y+v_space+9, i+1 ); textprinter->print( absPosition.x+col3, absPosition.y+v_space+9, genotypes->list[indices[i]]->count ); textprinter->print( absPosition.x+col4, absPosition.y+v_space+9, genotypes->list[indices[i]]->adamdist ); textprinter->print( absPosition.x+col5, absPosition.y+v_space+9, genotypes->list[i]->brainzArch->ArchNeurons.size() ); // total syns unsigned int totalSyns = 0; for ( unsigned int j = 0; j < genotypes->list[i]->brainzArch->ArchNeurons.size(); j++ ) totalSyns += genotypes->list[i]->brainzArch->ArchNeurons[j].ArchSynapses.size(); textprinter->print( absPosition.x+col6, absPosition.y+v_space+9, totalSyns ); textprinter->print( absPosition.x+col7, absPosition.y+v_space+9, genotypes->list[i]->bodyArch->archBodyparts.size() ); if ( *colormode ) glColor4f(genotypes->list[indices[i]]->speciescolor.r, genotypes->list[indices[i]]->speciescolor.g, genotypes->list[indices[i]]->speciescolor.b, genotypes->list[indices[i]]->speciescolor.a); else glColor4f(genotypes->list[indices[i]]->bodyArch->color.r, genotypes->list[indices[i]]->bodyArch->color.g, genotypes->list[indices[i]]->bodyArch->color.b, genotypes->list[indices[i]]->bodyArch->color.a); glBegin(GL_QUADS); glVertex2f(absPosition.x+col2, absPosition.y+v_space+qheight); glVertex2f(absPosition.x+col2, absPosition.y+v_space); glVertex2f(absPosition.x+col2+qwidth, absPosition.y+v_space); glVertex2f(absPosition.x+col2+qwidth, absPosition.y+v_space+qheight); glEnd(); glColor4f(1.0f, 1.0f, 1.0f, 0.0f); glBegin(GL_LINES); glVertex2f(absPosition.x+col2, absPosition.y+v_space+qheight); glVertex2f(absPosition.x+col2, absPosition.y+v_space); glVertex2f(absPosition.x+col2, absPosition.y+v_space); glVertex2f(absPosition.x+col2+qwidth, absPosition.y+v_space); glVertex2f(absPosition.x+col2+qwidth, absPosition.y+v_space); glVertex2f(absPosition.x+col2+qwidth, absPosition.y+v_space+qheight); glVertex2f(absPosition.x+col2+qwidth, absPosition.y+v_space+qheight); glVertex2f(absPosition.x+col2, absPosition.y+v_space+qheight); glEnd(); } } } Speciesview::~Speciesview() { } critterding-beta12.1/src/scenes/gui/exitpanel.h0000644000175000017500000000027311320212237020525 0ustar bobkebobke#ifndef EXITPANEL_H #define EXITPANEL_H #include "../../gui/panel.h" using namespace std; class Exitpanel : public Panel { public: Exitpanel(); ~Exitpanel(); private: }; #endif critterding-beta12.1/src/scenes/gui/infobar.cpp0000644000175000017500000000540011343530351020511 0ustar bobkebobke#include "infobar.h" Infobar::Infobar() { statsBuffer = Statsbuffer::Instance(); energy = settings->getCVarPtr("energy"); active = true; isMovable = true; position.x = 10; position.y = 10; v_width = 400; v_height = 20; hsp = 10; vsp = 13; } void Infobar::draw() { if (active) { fps.mark(); drawBackground(); drawBorders(); float col1 = (v_width/3); float col2 = col1 * 2.0f; float col3 = col1 * 3.0f; // float col4 = col1 * 4.0f; float linespacer = 0.0f; glBegin(GL_LINES); // glVertex2f(0.0f, v_height); // glVertex2f(v_width, v_height); glVertex2f(position.x+col1, position.y+linespacer); glVertex2f(position.x+col1, position.y+v_height - linespacer); glVertex2f(position.x+col2, position.y+linespacer); glVertex2f(position.x+col2, position.y+v_height - linespacer); /* glVertex2f(position.x+col3, position.y+linespacer); glVertex2f(position.x+col3, position.y+v_height - linespacer);*/ glEnd(); glColor3f(1.0f, 1.0f, 1.0f); // glEnable(GL_TEXTURE_2D); // Row 1 Textprinter::Instance()->print(position.x+hsp, position.y+vsp, "fps:"); Textprinter::Instance()->printR(position.x+col1-hsp, position.y+vsp, "%1.1f", fps.currentfps); Textprinter::Instance()->print(position.x+col1+hsp, position.y+vsp, "critters:"); // Textprinter::Instance()->printR(position.x+col2-hsp, position.y+vsp, "%1u", settings->info_critters); Textprinter::Instance()->printR(position.x+col2-hsp, position.y+vsp, "%1u", statsBuffer->current.critters); Textprinter::Instance()->print(position.x+col2+hsp, position.y+vsp, "food:"); // Textprinter::Instance()->printR(position.x+col3-hsp, position.y+vsp, "%1u/%1u", settings->info_food, settings->getCVar("energy")); Textprinter::Instance()->printR(position.x+col3-hsp, position.y+vsp, "%1u/%1u", statsBuffer->current.food, *energy); // Textprinter::Instance()->print(col3+hsp, vsp, "corpses:"); // Textprinter::Instance()->printR(col4-hsp, vsp, "%1u", Settings::Instance()->info_corpses); // Row 2 // Textprinter::Instance()->print(hsp, vsp*2, "neu/cri:"); // Textprinter::Instance()->printR(col1-hsp, vsp*2, "%1.2f", (float)totalneurons / Settings::Instance()->info_critters); // // Textprinter::Instance()->print(col1+hsp, vsp*2, "syn/cri:"); // Textprinter::Instance()->printR(col2-hsp, vsp*2, "%1.2f", (float)totalsynapses / Settings::Instance()->info_critters); // // Textprinter::Instance()->print(col2+hsp, vsp*2, "syn/neu:"); // Textprinter::Instance()->printR(col3-hsp, vsp*2, "%1.2f", (float)totalsynapses / totalneurons); // // Textprinter::Instance()->print(col3+hsp, vsp*2, "bullets:"); // Textprinter::Instance()->printR(col4-hsp, vsp*2, "%1u", Settings::Instance()->info_bullets); // glDisable(GL_TEXTURE_2D); } } Infobar::~Infobar() { } critterding-beta12.1/src/scenes/gui/helpinfo.cpp0000644000175000017500000001224411344004551020700 0ustar bobkebobke#include "helpinfo.h" Helpinfo::Helpinfo() { isMovable = true; position.x = 50; position.y = 35; v_width = 420; v_height = 520; halfboxwidth = 210; halfboxheight = 260; } void Helpinfo::draw() { if (active) { drawBackground(); drawBorders(); // print text // glEnable(GL_TEXTURE_2D); int widthpos1 = position.x + 20; int widthpos2 = position.x + 100; int heightpos = position.y; int vspace = 13; glColor3f(1.0f, 1.0f, 1.0f); heightpos += vspace + 3; printInfoLine(heightpos, widthpos1, widthpos2, "World / Engine operations", ""); glColor3f(0.7f, 0.7f, 0.7f); heightpos += vspace + 3; printInfoLine(heightpos, widthpos1, widthpos2, "esc", "exit"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "tab", "toggle species panel"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "F1", "toggle this help panel"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "F2", "toggle small infobar"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "F3", "toggle critter statistics"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "F4", "toggle birth and death events panel"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "F5", "toggle critters vs food graph"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "F6", "toggle main settings panel"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "F7", "toggle brain settings panel"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "F8", "toggle hud"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "F9/F10", "dec/inc body mutation rate (%)"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "F11/F12", "dec/inc brain mutation rate (%)"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "+/-", "dec/inc energy in the system by 1 food unit"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "c", "switch critter color mode"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "f", "toggle fullscreen"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "h", "toggle render gui"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "i", "insert adam"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "l", "toggle fps limiter"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "m", "toggle mouse mode"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "p", "pause"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "r", "toggle render scene"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "s", "save profile to \"~/.critterding/save/profile/(profile).pro\""); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "k", "kill half of critters"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "pageup", "load all critters from \"~/.critterding/load\""); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "pagedown", "save all critters into \"~/.critterding/save/profile/(time)\""); glColor3f(1.0f, 1.0f, 1.0f); heightpos += vspace + 3; printInfoLine(heightpos, widthpos1, widthpos2, "Camera Operations", ""); glColor3f(0.7f, 0.7f, 0.7f); heightpos += vspace + 3; printInfoLine(heightpos, widthpos1, widthpos2, "/", "dec camera sensitivity"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "*", "inc camera sensitivity"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "backspace", "reset camera"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "arrow up", "move camera forward"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "arrow down", "move camera backwards"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "arrow left", "strafe left"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "arrow right", "strafe right"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "home/end", "move up / down"); // heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "End", "move down"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "numpad 2/8", "look up / down"); // heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "NumKey 8", "look down"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "numpad 4/6", "look left / right"); // heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "NumKey 6", "look right"); heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "numpad 1/3", "roll left / right"); // heightpos += vspace; printInfoLine(heightpos, widthpos1, widthpos2, "NumKey 3", "roll right"); // glDisable(GL_TEXTURE_2D); } } void Helpinfo::printInfoLine(float heightpos, float widthpos1, float widthpos2, const char* key, const char* expl) { Textprinter::Instance()->print(widthpos1, heightpos, key); Textprinter::Instance()->print(widthpos2, heightpos, expl); } Helpinfo::~Helpinfo() { } critterding-beta12.1/src/scenes/gui/helpinfo.h0000644000175000017500000000055611320212237020344 0ustar bobkebobke#ifndef HELPINFO_H #define HELPINFO_H #include "../../gui/panel.h" using namespace std; class Helpinfo : public Panel { public: Helpinfo(); ~Helpinfo(); void draw(); private: unsigned int halfboxwidth; unsigned int halfboxheight; void printInfoLine(float heightpos, float widthpos1, float widthpos2, const char* key, const char* expl); }; #endif critterding-beta12.1/src/scenes/gui/infostats.h0000644000175000017500000000054111340630500020543 0ustar bobkebobke#ifndef INFOSTATS_H #define INFOSTATS_H #include "../../gui/panel.h" #include "../../utils/statsbuffer.h" using namespace std; class Infostats : public Panel { public: Infostats(); ~Infostats(); void draw(); private: Statsbuffer* statsBuffer; // horizontal/vertical spacers (padding) unsigned int hsp; unsigned int vsp; }; #endif critterding-beta12.1/src/scenes/gui/statsgraph.cpp0000644000175000017500000000377711320212237021263 0ustar bobkebobke#include "statsgraph.h" Statsgraph::Statsgraph() { active = false; isMovable = true; statsBuffer = Statsbuffer::Instance(); v_width = 300; v_height = 100; position.x = 10; position.y = 50; } void Statsgraph::draw() { if (active) { // hack v_width = *parent->v_widthP - 20; // updateAbsPosition(); drawBackground(); drawBorders(); int number = statsBuffer->snapshots.size(); if ( number > 0 ) { int start = 0; if ( number > (int)v_width ) start = number - v_width; // find the highest value in the stats vector unsigned int highest = 0; for ( int i=start; i < number; i++ ) { /* unsigned int sum = statsBuffer->snapshots[i].food + statsBuffer->snapshots[i].critters; if ( sum > highest ) highest = sum;*/ // unsigned int sum = statsBuffer->snapshots[i].food + statsBuffer->snapshots[i].critters; if ( statsBuffer->snapshots[i].food > highest ) highest = statsBuffer->snapshots[i].food; if ( statsBuffer->snapshots[i].critters > highest ) highest = statsBuffer->snapshots[i].critters; } // cerr << highest << endl; if ( highest > 0 ) { // so, highest ~ v_height // and, number ~ boxwidth float heightratio = ((float)v_height/highest); // draw the number of critters graph glColor3f(0.0f, 1.0f, 0.0f); glBegin(GL_LINES); for ( int i=start; i < number-1; i++ ) { glVertex2f( position.x+i-start, position.y+v_height-(heightratio*statsBuffer->snapshots[i].food) ); glVertex2f( position.x+i+1-start, position.y+v_height-(heightratio*statsBuffer->snapshots[i+1].food) ); } // glEnd(); glColor3f(1.0f, 0.0f, 0.0f); // glBegin(GL_LINES); for ( int i=start; i < number-1; i++ ) { glVertex2f( position.x+i-start, position.y+v_height-(heightratio*statsBuffer->snapshots[i].critters) ); glVertex2f( position.x+i+1-start, position.y+v_height-(heightratio*statsBuffer->snapshots[i+1].critters) ); } glEnd(); } } } } Statsgraph::~Statsgraph() { } critterding-beta12.1/src/scenes/gui/settingsbrainpanel.cpp0000644000175000017500000000745411342625205023002 0ustar bobkebobke#include "settingsbrainpanel.h" Settingsbrainpanel::Settingsbrainpanel() { v_width = 490; v_height = 510; isMovable = true; position.x = 50; position.y = 35; mutatorcol2 = 350; mutatorcol3 = 430; unsigned int vint = 12; unsigned int vspace; unsigned int hspace = 10; vspace = 7; addSettingmutator("brain_maxneurons", hspace, vspace); vspace += vint; addSettingmutator("brain_minsynapses", hspace, vspace); vspace += vint; addSettingmutator("brain_maxsynapses", hspace, vspace); vspace += vint; addSettingmutator("brain_minneuronsatbuildtime", hspace, vspace); vspace += vint; addSettingmutator("brain_maxneuronsatbuildtime", hspace, vspace); vspace += vint; addSettingmutator("brain_minsynapsesatbuildtime", hspace, vspace); vspace += vint; addSettingmutator("brain_maxsynapsesatbuildtime", hspace, vspace); vspace += vint; addSettingmutator("brain_percentchanceinhibitoryneuron", hspace, vspace); vspace += vint; addSettingmutator("brain_mutate_percentchanceinhibitoryneuron", hspace, vspace); vspace += vint; addSettingmutator("brain_percentchancemotorneuron", hspace, vspace); vspace += vint; addSettingmutator("brain_mutate_percentchancemotorneuron", hspace, vspace); vspace += vint; addSettingmutator("brain_percentchanceplasticneuron", hspace, vspace); vspace += vint; addSettingmutator("brain_mutate_percentchanceplasticneuron", hspace, vspace); vspace += vint; addSettingmutator("brain_minplasticitystrengthen", hspace, vspace); vspace += vint; addSettingmutator("brain_maxplasticitystrengthen", hspace, vspace); vspace += vint; addSettingmutator("brain_minplasticityweaken", hspace, vspace); vspace += vint; addSettingmutator("brain_maxplasticityweaken", hspace, vspace); vspace += vint; addSettingmutator("brain_mutate_plasticityfactors", hspace, vspace); vspace += vint; addSettingmutator("brain_minfiringthreshold", hspace, vspace); vspace += vint; addSettingmutator("brain_mutate_minfiringthreshold", hspace, vspace); vspace += vint; addSettingmutator("brain_maxfiringthreshold", hspace, vspace); vspace += vint; addSettingmutator("brain_mutate_maxfiringthreshold", hspace, vspace); vspace += vint; addSettingmutator("brain_maxdendridicbranches", hspace, vspace); vspace += vint; addSettingmutator("brain_mutate_maxdendridicbranches", hspace, vspace); vspace += vint; addSettingmutator("brain_percentchanceconsistentsynapses", hspace, vspace); vspace += vint; addSettingmutator("brain_mutate_percentchanceconsistentsynapses", hspace, vspace); vspace += vint; addSettingmutator("brain_percentchanceinhibitorysynapses", hspace, vspace); vspace += vint; addSettingmutator("brain_mutate_percentchanceinhibitorysynapses", hspace, vspace); vspace += vint; addSettingmutator("brain_percentchancesensorysynapse", hspace, vspace); vspace += vint; addSettingmutator("brain_mutate_percentchancesensorysynapse", hspace, vspace); vspace += vint; addSettingmutator("brain_percentmutateeffectaddneuron", hspace, vspace); vspace += vint; addSettingmutator("brain_percentmutateeffectremoveneuron", hspace, vspace); vspace += vint; addSettingmutator("brain_percentmutateeffectalterneuron", hspace, vspace); vspace += vint; addSettingmutator("brain_percentmutateeffectaddsynapse", hspace, vspace); vspace += vint; addSettingmutator("brain_percentmutateeffectremovesynapse", hspace, vspace); vspace += vint; addSettingmutator("brain_mutate_mutateeffects", hspace, vspace); vspace += vint; addSettingmutator("brain_percentmutateeffectaltermutable", hspace, vspace); vspace += vint; addSettingmutator("brain_costhavingneuron", hspace, vspace); vspace += vint; addSettingmutator("brain_costfiringneuron", hspace, vspace); vspace += vint; addSettingmutator("brain_costfiringmotorneuron", hspace, vspace); vspace += vint; addSettingmutator("brain_costhavingsynapse", hspace, vspace); } Settingsbrainpanel::~Settingsbrainpanel() { } critterding-beta12.1/src/scenes/gui/settingsbrainpanel.h0000644000175000017500000000037111340630500022426 0ustar bobkebobke#ifndef SETTINGSBRAINPANEL_H #define SETTINGSBRAINPANEL_H #include "../../gui/settingspanel.h" using namespace std; class Settingsbrainpanel : public Settingspanel { public: Settingsbrainpanel(); ~Settingsbrainpanel(); private: }; #endif critterding-beta12.1/src/scenes/gui/settingsbodypanel.cpp0000644000175000017500000000434211342625205022635 0ustar bobkebobke#include "settingsbodypanel.h" Settingsbodypanel::Settingsbodypanel() { v_width = 490; v_height = 265; isMovable = true; position.x = 50; position.y = 35; mutatorcol2 = 350; mutatorcol3 = 430; unsigned int vint = 12; unsigned int vspace; unsigned int hspace = 10; vspace = 7; addSettingmutator("body_maxbodyparts", hspace, vspace); vspace += vint; addSettingmutator("body_maxbodypartsatbuildtime", hspace, vspace); vspace += vint; addSettingmutator("body_minbodypartsize", hspace, vspace); vspace += vint; addSettingmutator("body_maxbodypartsize", hspace, vspace); vspace += vint; addSettingmutator("body_minheadsize", hspace, vspace); vspace += vint; addSettingmutator("body_maxheadsize", hspace, vspace); vspace += vint; addSettingmutator("body_percentmutateeffectchangecolor", hspace, vspace); vspace += vint; addSettingmutator("body_percentmutateeffectchangecolor_slightly", hspace, vspace); vspace += vint; addSettingmutator("body_percentmutateeffectaddbodypart", hspace, vspace); vspace += vint; addSettingmutator("body_percentmutateeffectremovebodypart", hspace, vspace); vspace += vint; addSettingmutator("body_percentmutateeffectresizebodypart", hspace, vspace); vspace += vint; addSettingmutator("body_percentmutateeffectresizebodypart_slightly", hspace, vspace); vspace += vint; addSettingmutator("body_percentmutateeffectchangeconstraintlimits", hspace, vspace); vspace += vint; addSettingmutator("body_percentmutateeffectchangeconstraintlimits_slightly", hspace, vspace); vspace += vint; addSettingmutator("body_percentmutateeffectchangeconstraintangles", hspace, vspace); vspace += vint; addSettingmutator("body_percentmutateeffectchangeconstraintangles_slightly", hspace, vspace); vspace += vint; addSettingmutator("body_percentmutateeffectchangeconstraintposition", hspace, vspace); vspace += vint; addSettingmutator("body_percentmutateeffectchangeconstraintposition_slightly", hspace, vspace); vspace += vint; addSettingmutator("body_percentmutateeffectresizehead", hspace, vspace); vspace += vint; addSettingmutator("body_percentmutateeffectresizehead_slightly", hspace, vspace); vspace += vint; addSettingmutator("body_percentmutateeffectrepositionhead", hspace, vspace); } Settingsbodypanel::~Settingsbodypanel() { } critterding-beta12.1/src/scenes/gui/statsgraph.h0000644000175000017500000000042211320212237020710 0ustar bobkebobke#ifndef STATSGRAPH_H #define STATSGRAPH_H #include "../../gui/panel.h" #include "../../utils/statsbuffer.h" using namespace std; class Statsgraph : public Panel { public: Statsgraph(); ~Statsgraph(); void draw(); private: Statsbuffer* statsBuffer; }; #endif critterding-beta12.1/src/scenes/gui/globalsettingspanel.cpp0000644000175000017500000000541011343774652023151 0ustar bobkebobke#include "globalsettingspanel.h" Globalsettingspanel::Globalsettingspanel() { v_width = 340; v_height = 388; isMovable = true; position.x = 50; position.y = 35; // FIXME camera sensitivity is missing unsigned int vint = 12; unsigned int vspace; unsigned int hspace = 10; // hspace = 10; vspace = 7; addSettingmutator("mincritters", hspace, vspace); vspace += vint; addMutator("energy", cmd.gen("decreaseenergy"), cmd.gen("increaseenergy"), hspace, vspace); vspace += vint; addMutator("worldsizeX", cmd.gen("dec_worldsizex"), cmd.gen("inc_worldsizex"), hspace, vspace); vspace += vint; addMutator("worldsizeY", cmd.gen("dec_worldsizey"), cmd.gen("inc_worldsizey"), hspace, vspace); // vspace += vint; vspace += vint; addSettingmutator("fsX", hspace, vspace); vspace += vint; addSettingmutator("fsY", hspace, vspace); vspace += vint; addSettingmutator("fullscreen", hspace, vspace); vspace += vint; addSettingmutator("colormode", hspace, vspace); vspace += vint; addSettingmutator("exit_if_empty", hspace, vspace); vspace += vint; addSettingmutator("fpslimit", hspace, vspace); vspace += vint; addSettingmutator("threads", hspace, vspace); vspace += vint; addSettingmutator("drawscene", hspace, vspace); // vspace += vint; vspace += vint; addSettingmutator("critter_insertevery", hspace, vspace); vspace += vint; addSettingmutator("critter_maxlifetime", hspace, vspace); vspace += vint; addSettingmutator("critter_maxenergy", hspace, vspace); vspace += vint; addSettingmutator("critter_startenergy", hspace, vspace); vspace += vint; addSettingmutator("critter_procinterval", hspace, vspace); vspace += vint; addSettingmutator("critter_minenergyproc", hspace, vspace); vspace += vint; addSettingmutator("critter_sightrange", hspace, vspace); vspace += vint; addSettingmutator("critter_autosaveinterval", hspace, vspace); vspace += vint; addSettingmutator("critter_autoexchangeinterval", hspace, vspace); vspace += vint; addSettingmutator("critter_enableomnivores", hspace, vspace); vspace += vint; addSettingmutator("critter_raycastvision", hspace, vspace); vspace += vint; addSettingmutator("critter_killhalfat", hspace, vspace); vspace += vint; addSettingmutator("killhalf_decrenergypct", hspace, vspace); vspace += vint; addSettingmutator("killhalf_incrworldsizeX", hspace, vspace); vspace += vint; addSettingmutator("killhalf_incrworldsizeY", hspace, vspace); vspace += vint; addSettingmutator("killhalf_decrmaxlifetimepct", hspace, vspace); // vspace += vint; vspace += vint; addSettingmutator("food_maxlifetime", hspace, vspace); vspace += vint; addMutator("food_maxenergy", cmd.gen("dec_foodmaxenergy"), cmd.gen("inc_foodmaxenergy"), hspace, vspace); vspace += vint; addSettingmutator("food_size", hspace, vspace); } Globalsettingspanel::~Globalsettingspanel() { } critterding-beta12.1/src/scenes/gui/maincanvas.h0000644000175000017500000000206411340334147020663 0ustar bobkebobke#ifndef MAINCANVAS_H #define MAINCANVAS_H #include "../../gui/container.h" #include "helpinfo.h" #include "textmessage.h" #include "statsgraph.h" #include "infobar.h" #include "infostats.h" #include "textverbosemessage.h" #include "exitpanel.h" #include "mutationpanel.h" #include "globalsettingspanel.h" #include "settingsbrainpanel.h" #include "settingsbodypanel.h" #include "hud.h" #include "critterview.h" #include "brainview.h" #include "speciesview.h" using namespace std; class Maincanvas : public Container { public: Maincanvas(); ~Maincanvas(); void draw(); void moveMouse(unsigned int x, unsigned int y); bool mouseFocus; void buttonPress(const unsigned int& button); void buttonRelease(const unsigned int& button); void swapChild(const string& child); private: unsigned int oldx; unsigned int oldy; bool hasPickedwidget; Widget* pickedwidget; Widget* focussedwidget; vector sortedindices; void drawChildren(); bool mouseOverChild( Widget** fWidget, int x, int y ); void raisePanel(Widget* w); }; #endif critterding-beta12.1/src/scenes/gui/critterview.h0000644000175000017500000000121111331157113021077 0ustar bobkebobke#ifndef CRITTERVIEW_H #define CRITTERVIEW_H #include "../entities/worldb.h" #include "../../gui/panel.h" #include "../../utils/critterselection.h" #include "../../math/vector2f.h" #include "../entities/critterb.h" using namespace std; class Critterview : public Panel { public: Critterview(); ~Critterview(); void draw(); WorldB* world; private: Critterselection* critterselection; Widget* viewbutton; btScalar viewposition[16]; CritterB* currentCritter; // drawing helpers int v_spacer; int v_space; // int v_radius; // int v_diam; // int spacing; // int column; // int row; // int rowlength; }; #endif critterding-beta12.1/src/scenes/gui/hud.cpp0000644000175000017500000001400511340334147017654 0ustar bobkebobke#include "hud.h" #include "../../gui/button.h" Hud::Hud() { active = true; v_height = 62; v_width = 800; position.x = 0; position.y = *settings->winHeight - v_height; critterselection = Critterselection::Instance(); unsigned int bwidth = 60; unsigned int bheight = 18; unsigned int bspacing = 2; unsigned int c_width = bspacing; unsigned int c_height = bspacing; addWidgetButton( "hud_exit", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "exit", cmd.gen("gui_togglepanel", "exitpanel"), 0, 0, 0 ); c_height += bspacing + bheight; addWidgetButton( "hud_graph", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "graph", cmd.gen("gui_togglepanel", "statsgraph"), 0, 0, 0 ); c_height += bspacing + bheight; addWidgetButton( "hud_stats", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "stats", cmd.gen("gui_togglepanel", "infostats"), 0, 0, 0 ); c_width += bspacing + bwidth; c_height = bspacing; addWidgetButton( "hud_events", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "events", cmd.gen("gui_togglepanel", "textverbosemessage"), 0, 0, 0 ); c_height += bspacing + bheight; addWidgetButton( "hud_settings", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "settings", cmd.gen("gui_togglepanel", "globalsettingspanel"), 0, 0, 0 ); c_height += bspacing + bheight; addWidgetButton( "hud_mutationpanel", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "mutation", cmd.gen("gui_togglepanel", "mutationpanel"), 0, 0, 0 ); c_width += bspacing + bwidth; c_height = bspacing; addWidgetButton( "hud_brainpanel", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "brain", cmd.gen("gui_togglepanel", "settingsbrainpanel"), 0, 0, 0 ); c_height += bspacing + bheight; addWidgetButton( "hud_bodypanel", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "body", cmd.gen("gui_togglepanel", "settingsbodypanel"), 0, 0, 0 ); c_height += bspacing + bheight; addWidgetButton( "hud_speciesview", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "species", cmd.gen("gui_togglepanel", "speciesview"), 0, 0, 0 ); // init critter selection buttons c_width += bspacing + bwidth; bheight = 28; bwidth = 28; c_height = bspacing; unsigned int tok = 0; stringstream s; s << "hud_cv1"; for ( unsigned int i=0; i < 20; i++ ) { s << i; cbuttons.push_back( addWidgetButton( s.str(), Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "", Vector2i(16, 13), cmd.gen("cs_select", i), 0, 0, 0 ) ); s << "2"; static_cast(cbuttons[i])->genEvent(3, s.str(), cmd.gen("cs_unregister", i), 0, 0, 0); cbuttons[i]->swap(); if ( ++tok == 2 ) { tok = 0; c_width += bspacing + bwidth; c_height = bspacing; } else c_height += bspacing + bheight; } bwidth = 90; bheight = 18; c_height = bspacing; addWidgetButton( "hud__cs_selectall", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "select all", cmd.gen("cs_selectall"), 0, 0, 0 ); c_height += bspacing + bheight; addWidgetButton( "hud__cs_clear", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "clear", cmd.gen("cs_clear"), 0, 0, 0 ); c_height += bspacing + bheight; addWidgetButton( "hud__cs_kill", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "kill", cmd.gen("cs_killall"), 0, 0, 0 ); c_width += bspacing + bwidth; c_height = bspacing; addWidgetButton( "hud__cs_duplicateall", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "duplicate", cmd.gen("cs_duplicateall"), 0, 0, 0 ); c_height += bspacing + bheight; addWidgetButton( "hud_cs_spawnbrainmutantall", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "brain mutants", cmd.gen("cs_spawnbrainmutantall"), 0, 0, 0 ); c_height += bspacing + bheight; addWidgetButton( "cs_spawnbodymutantall", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "body mutants", cmd.gen("cs_spawnbodymutantall"), 0, 0, 0 ); c_width += bspacing + bwidth; c_height = bspacing; addWidgetButton( "cs_spawnbrainbodymutantall", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "brain+body m", cmd.gen("cs_spawnbrainbodymutantall"), 0, 0, 0 ); c_height += bspacing + bheight; // addWidgetButton( "cs_feed", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "feed", cmd.gen("cs_spawnbodymutantall"), 0, 0, 0 ); } void Hud::draw() { if (active) { position.y = *settings->winHeight - v_height; updateAbsPosition(); drawBackground(); drawBorders(); drawChildren(); // activate the proper buttons before drawing children for (unsigned int i = 0; i < cbuttons.size(); i++ ) if ( i < critterselection->clist.size() ) cbuttons[i]->active = true; else cbuttons[i]->active = false; unsigned int bwidth = 28; unsigned int bheight = 28; for (unsigned int i=0; i < critterselection->clist.size() && i < 20; i++ ) { glViewport(cbuttons[i]->absPosition. x+1, *settings->winHeight-bheight-(cbuttons[i]->absPosition.y-1), bwidth-1, bheight-1); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum( -0.05f, 0.05f,-0.05f,0.05f, 0.1f, 10000.0f); critterselection->clist[i]->body.mouths[0]->ghostObject->getWorldTransform().inverse().getOpenGLMatrix(viewposition); glMultMatrixf(viewposition); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); world->drawWithinCritterSight(critterselection->clist[i]); } world->camera.place(); // switch back to 2d glPushMatrix(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, *settings->winWidth, *settings->winHeight, 0, 0, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } } void Hud::drawBorders() { glColor3f(0.5f, 0.5f, 0.5f); glBegin(GL_LINES); glVertex2f(absPosition.x, absPosition.y+v_height); glVertex2f(absPosition.x, absPosition.y); glVertex2f(absPosition.x, absPosition.y); glVertex2f(absPosition.x+v_width, absPosition.y); glVertex2f(absPosition.x+v_width, absPosition.y); glVertex2f(absPosition.x+v_width, absPosition.y+v_height); glVertex2f(absPosition.x+v_width, absPosition.y+v_height); glVertex2f(absPosition.x, absPosition.y+v_height); glEnd(); } Hud::~Hud() { } critterding-beta12.1/src/scenes/gui/brainview.h0000644000175000017500000000210211340630500020512 0ustar bobkebobke#ifndef BRAINVIEW_H #define BRAINVIEW_H #include "../../gui/settingspanel.h" #include "../entities/worldb.h" #include "../../utils/critterselection.h" #include "../../math/vector2f.h" #include "../entities/critterb.h" using namespace std; class Brainview : public Settingspanel { struct neuron { NeuronInterz* nPointer; Vector2f position; Vector2f newposition; }; struct sensor { sensorNeuron* sPointer; Vector2f position; }; public: Brainview(); ~Brainview(); void draw(); WorldB* world; private: Critterselection* critterselection; Widget* viewbutton; Widget* brainview; btScalar viewposition[16]; CritterB* currentCritter; // drawing helpers int v_spacer; int v_space; float v_radius; float v_diam; int spacing; int column; int row; int rowlength; // shortcuts to settings const unsigned int* attractor1; const unsigned int* attractor2; const unsigned int* attractor3; const unsigned int* attractor4; const unsigned int* brain_maxfiringthreshold; vector neurons; vector sensors; }; #endif critterding-beta12.1/src/scenes/gui/infobar.h0000644000175000017500000000063611343530351020164 0ustar bobkebobke#ifndef INFOBAR_H #define INFOBAR_H #include "../../utils/fps.h" #include "../../utils/statsbuffer.h" #include "../../gui/panel.h" using namespace std; class Infobar : public Panel { public: Infobar(); ~Infobar(); void draw(); private: Fps fps; Statsbuffer* statsBuffer; // horizontal/vertical spacers (padding) unsigned int hsp; unsigned int vsp; const unsigned int* energy; }; #endif critterding-beta12.1/src/scenes/gui/textverbosemessage.cpp0000644000175000017500000000455611342625205023025 0ustar bobkebobke#include "textverbosemessage.h" Textverbosemessage* Textverbosemessage::Instance () { static Textverbosemessage t; return &t; // _instance isn't needed in this case } Textverbosemessage::Textverbosemessage() { position.x = 10; position.y = 50; v_width = 520; v_height = 75; col2 = (unsigned int)(((float)v_width/16)*11); // active = false; isMovable = true; maxMessages = 5; msgLifetime = 0; // longestLength = 0; } void Textverbosemessage::addBirth(stringstream& streamptr) { vmsg *Msg = new vmsg; Msg->str = streamptr.str(); Msg->appeartime = Timer::Instance()->sdl_lasttime; births.push_back(Msg); // to prevent overfilling: deleteExpiredMsg(); } void Textverbosemessage::addDeath(stringstream& streamptr) { vmsg *Msg = new vmsg; Msg->str = streamptr.str(); Msg->appeartime = Timer::Instance()->sdl_lasttime; deaths.push_back(Msg); // to prevent overfilling: deleteExpiredMsg(); } void Textverbosemessage::deleteExpiredMsg() { if ( !births.empty() ) { if ( births.size() > maxMessages || ( msgLifetime > 0 && Timer::Instance()->sdl_lasttime - births[0]->appeartime > msgLifetime ) ) { delete births[0]; births.erase(births.begin()+0); } } if ( !deaths.empty() ) { if ( deaths.size() > maxMessages || ( msgLifetime > 0 && Timer::Instance()->sdl_lasttime - deaths[0]->appeartime > msgLifetime ) ) { delete deaths[0]; deaths.erase(deaths.begin()+0); } } } void Textverbosemessage::draw() { if ( active ) { // updateAbsPosition(); deleteExpiredMsg(); drawBackground(); drawBorders(); glColor3f(0.7f, 0.7f, 0.7f); glBegin(GL_LINES); glVertex2f(position.x+col2, position.y); glVertex2f(position.x+col2, position.y+v_height); glEnd(); if ( !births.empty() ) { // render text // glEnable(GL_TEXTURE_2D); glColor3f(1.0f, 1.0f, 1.0f); for ( unsigned int i = 0; i < births.size(); i++ ) Textprinter::Instance()->print(position.x+10, position.y + 13 + 1 + (i*13), births[i]->str); // glDisable(GL_TEXTURE_2D); } if ( !deaths.empty() ) { // render text // glEnable(GL_TEXTURE_2D); glColor3f(1.0f, 1.0f, 1.0f); for ( unsigned int i = 0; i < deaths.size(); i++ ) Textprinter::Instance()->print(position.x + col2 + 10, (position.y + 13) + 1 + (i*13), deaths[i]->str); // glDisable(GL_TEXTURE_2D); } } } void Textverbosemessage::swap() { active = !active; } critterding-beta12.1/src/scenes/gui/exitpanel.cpp0000644000175000017500000000075511320212237021065 0ustar bobkebobke#include "exitpanel.h" Exitpanel::Exitpanel() { isMovable = true; position.x = 200; position.y = 257; v_width = 400; v_height = 86; addWidgetText( "askexit", 10, 20, "Are you sure you want to exit?" ); addWidgetButton( "yes", Vector2i(100, 40), Vector2i(50, 30), "Yes", Vector2i(15, 19), cmd.gen("quit"), 0, 0, 0 ); addWidgetButton( "no", Vector2i(200, 40), Vector2i(50, 30), "No", Vector2i(18, 19), cmd.gen("gui_togglepanel", "exitpanel"), 0, 0, 0 ); } Exitpanel::~Exitpanel() { } critterding-beta12.1/src/scenes/gui/hud.h0000644000175000017500000000062511345336346017334 0ustar bobkebobke#ifndef HUD_H #define HUD_H #include #include "../../gui/panel.h" #include "../entities/worldb.h" #include "../../utils/critterselection.h" using namespace std; class Hud : public Panel { public: Hud(); ~Hud(); void draw(); WorldB* world; private: void drawBorders(); Critterselection *critterselection; vector cbuttons; btScalar viewposition[16]; }; #endif critterding-beta12.1/src/scenes/gui/critterview.cpp0000644000175000017500000001255711340265263021457 0ustar bobkebobke#include "critterview.h" Critterview::Critterview() { critterselection = Critterselection::Instance(); active = false; isMovable = true; // action button settings unsigned int bwidth = 90; unsigned int bheight = 18; unsigned int bspacing = 2; unsigned int totalbuttonheight = (2*bheight) + bspacing; v_width = 386; v_height = 150; int buttons_starty = v_height - totalbuttonheight-10; position.x = 10; position.y = 50; currentCritter = 0; // text widgets v_spacer = 14; v_space = 3; v_space += v_spacer; addWidgetText( "cv_cid", 10, v_space, "Critter" ); v_space += v_spacer; addWidgetText( "cv_ad", 10, v_space, "Adam Distance" ); v_space += v_spacer; addWidgetText( "cv_age", 10, v_space, "Age" ); addWidgetText( "cv_age_/", 200, v_space, "/" ); addWidgetText( "cv_age_max", 210, v_space, settings->getCVarPtr("critter_maxlifetime") ); v_space += v_spacer; addWidgetText( "cv_energy", 10, v_space, "Energy" ); addWidgetText( "cv_energy_/", 200, v_space, "/" ); addWidgetText( "cv_energy_max", 210, v_space, settings->getCVarPtr("critter_maxenergy") ); v_space += v_spacer; addWidgetText( "cv_neurons", 10, v_space, "Neurons" ); v_space += v_spacer; addWidgetText( "cv_synapses", 10, v_space, "Synapses" ); // view widgets viewbutton = addWidgetButton( "cv_view", Vector2i(0+v_width-60, 35), Vector2i(50, 50), "", Vector2i(0, 0), cmd.gen(""), 0, 0, 0 ); // close button addWidgetButton( "cv_close", Vector2i(v_width-25, 10), Vector2i(15, 15), "x", cmd.gen("gui_togglepanel", "critterview"), 0, 0, 0 ); // action buttons unsigned int c_width = 10; unsigned int c_height = buttons_starty; addWidgetButton( "cv_action_kill", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "kill", cmd.gen("cs_kill"), 0, 0, 0 ); c_height += bspacing + bheight; addWidgetButton( "cv_action_brainview", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "brainview", cmd.gen("gui_togglepanel", "brainview"), 0, 0, 0 ); c_width += bwidth + bspacing; c_height = buttons_starty; addWidgetButton( "cv_action_duplicate", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "duplicate", cmd.gen("cs_duplicate"), 0, 0, 0 ); c_height += bspacing + bheight; addWidgetButton( "cv_action_spawnbrainmutant", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "brain mutant", cmd.gen("cs_spawnbrainmutant"), 0, 0, 0 ); c_width += bwidth + bspacing; c_height = buttons_starty; addWidgetButton( "cv_action_spawnbodymutant", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "body mutant", cmd.gen("cs_spawnbodymutant"), 0, 0, 0 ); c_height += bspacing + bheight; addWidgetButton( "cv_action_spawnbrainbodymutant", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "brain+body m", cmd.gen("cs_spawnbrainbodymutant"), 0, 0, 0 ); c_width += bwidth + bspacing; c_height = buttons_starty; addWidgetButton( "cv_action_feed", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "feed", cmd.gen("cs_feed"), 0, 0, 0 ); c_height += bspacing + bheight; addWidgetButton( "cv_action_resetage", Vector2i(c_width, c_height), Vector2i(bwidth, bheight), "reset age", cmd.gen("cs_resetage"), 0, 0, 0 ); } void Critterview::draw() { if ( critterselection->cv_activate ) { active = true; critterselection->cv_activate = false; } if ( critterselection->selectedCritter == 0 ) { active = false; currentCritter = 0; } if (active) { if ( critterselection->selectedCritter != currentCritter ) currentCritter = critterselection->selectedCritter; drawBackground(); drawBorders(); // draw the rest drawChildren(); // draw values of critter v_space = 0; v_space += v_spacer; textprinter->print( absPosition.x+110, absPosition.y+v_space, critterselection->selectedCritter->critterID ); v_space += v_spacer; textprinter->print( absPosition.x+110, absPosition.y+v_space, critterselection->selectedCritter->genotype->adamdist ); v_space += v_spacer; textprinter->print( absPosition.x+110, absPosition.y+v_space, critterselection->selectedCritter->totalFrames ); v_space += v_spacer; textprinter->print( absPosition.x+110, absPosition.y+v_space, "%1.1f", critterselection->selectedCritter->energyLevel ); v_space += v_spacer; textprinter->print( absPosition.x+110, absPosition.y+v_space, critterselection->selectedCritter->brain.totalNeurons ); v_space += v_spacer; textprinter->print( absPosition.x+110, absPosition.y+v_space, critterselection->selectedCritter->brain.totalSynapses ); textprinter->print( absPosition.x+200, absPosition.y+v_space, "%5.2f avg", (float)critterselection->selectedCritter->brain.totalSynapses / critterselection->selectedCritter->brain.totalNeurons ); // draw gl view glViewport(viewbutton->absPosition.x, *settings->winHeight-50-viewbutton->absPosition.y, 50, 50); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glFrustum( -0.05f, 0.05f,-0.05f,0.05f, 0.1f, 10000.0f); critterselection->selectedCritter->body.mouths[0]->ghostObject->getWorldTransform().inverse().getOpenGLMatrix(viewposition); glMultMatrixf(viewposition); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); world->drawWithinCritterSight(critterselection->selectedCritter); // switch back to 2d world->camera.place(); glPushMatrix(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0, *settings->winWidth, *settings->winHeight, 0, 0, 1); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); } } Critterview::~Critterview() { } critterding-beta12.1/src/scenes/gui/brainview.cpp0000644000175000017500000003470411341607306021073 0ustar bobkebobke#include #include "brainview.h" Brainview::Brainview() { critterselection = Critterselection::Instance(); brain_maxfiringthreshold = settings->getCVarPtr("brain_maxfiringthreshold"); active = false; isMovable = true; rowlength = 37; v_radius = 2; v_diam = 2*v_radius; spacing = 3; int brainview_width = 20 + ((v_diam+spacing) * settings->getCVar("critter_retinasize") * 4); if ( brainview_width < 400 ) brainview_width = 400; int brainview_height = 20 + ((v_diam+spacing) * 40); if ( brainview_height < 400 ) brainview_height = 400; v_width = 20 + brainview_width; v_height = 80 + brainview_height; int buttons_starty = v_height - brainview_height - 10; int brainview_starty = buttons_starty; position.x = 10; position.y = 50; currentCritter = 0; // view widgets // viewbutton = addWidgetButton( "bv_view", Vector2i(0+v_width-60, 35), Vector2i(50, 50), "", Vector2i(0, 0), cmd.gen(""), 0, 0, 0 ); brainview = addWidgetButton( "bv_bview", Vector2i(10, brainview_starty), Vector2i(brainview_width, brainview_height), "", Vector2i(0, 0), cmd.gen(""), 0, 0, 0 ); children["bv_bview"]->isTransparant = false; addWidgetButton( "bv_close", Vector2i(v_width-25, 10), Vector2i(15, 15), "x", cmd.gen("gui_togglepanel", "brainview"), 0, 0, 0 ); settings->registerLocalCVar("attract neurons", 100, 0, 1000000, false, "attract neurons"); addSettingmutator("attract neurons", 10, 10); settings->registerLocalCVar("repel neurons", 100, 0, 1000000, false, "repel neurons"); addSettingmutator("repel neurons", 10, 22); settings->registerLocalCVar("attract neuron inputs", 100, 0, 1000000, false, "attract neuron<>inputs"); addSettingmutator("attract neuron inputs", 10, 36); settings->registerLocalCVar("repel neuron inputs", 100, 0, 1000000, false, "repel neuron<>inputs"); addSettingmutator("repel neuron inputs", 10, 48); attractor1 = settings->getCVarPtr("attract neurons"); attractor2 = settings->getCVarPtr("attract neuron inputs"); attractor3 = settings->getCVarPtr("repel neurons"); attractor4 = settings->getCVarPtr("repel neuron inputs"); } void Brainview::draw() { column = 0; row = 0; if ( critterselection->selectedCritter == 0 ) { active = false; currentCritter = 0; } if (active) { if ( critterselection->selectedCritter != currentCritter ) { currentCritter = critterselection->selectedCritter; sensors.clear(); int sverticalpos = 0; int constraintcount = 0; for ( unsigned int i=0; i < currentCritter->brain.numberOfInputs; i++ ) { if ( currentCritter->brain.Inputs[i].id == 10000 ) { sensor s; s.sPointer = ¤tCritter->brain.Inputs[i]; s.position = Vector2f(brainview->position.x, 10); sensors.push_back(s); } else if ( currentCritter->brain.Inputs[i].id == 10001 ) { sverticalpos = 2; sensor s; s.sPointer = ¤tCritter->brain.Inputs[i]; s.position = Vector2f(brainview->position.x, 10+(spacing+v_diam)*sverticalpos); sensors.push_back(s); } else if ( currentCritter->brain.Inputs[i].id == 20000 ) { sverticalpos = 4; sensor s; s.sPointer = ¤tCritter->brain.Inputs[i]; s.position = Vector2f(brainview->position.x, 10+(spacing+v_diam)*sverticalpos); sensors.push_back(s); } else if ( currentCritter->brain.Inputs[i].id >= 30000 && currentCritter->brain.Inputs[i].id < 40000 ) { sverticalpos = 6; sensor s; s.sPointer = ¤tCritter->brain.Inputs[i]; s.position = Vector2f(brainview->position.x, 10+(spacing+v_diam)*sverticalpos +((spacing+v_diam)*(currentCritter->brain.Inputs[i].id-30000))); sensors.push_back(s); } else if ( currentCritter->brain.Inputs[i].id >= 40000 && currentCritter->brain.Inputs[i].id < 50000 ) { sverticalpos = 17; sensor s; s.sPointer = ¤tCritter->brain.Inputs[i]; s.position = Vector2f(brainview->position.x, 10+(spacing+v_diam)*sverticalpos +((spacing+v_diam)*(currentCritter->brain.Inputs[i].id-40000))); sensors.push_back(s); } else if ( currentCritter->brain.Inputs[i].id < 10000 ) { sverticalpos = 28; sensor s; s.sPointer = ¤tCritter->brain.Inputs[i]; s.position = Vector2f(brainview->position.x, 10+(spacing+v_diam)*sverticalpos +((spacing+v_diam)*(constraintcount))); sensors.push_back(s); constraintcount++; } else if ( currentCritter->brain.Inputs[i].id >= 50000 && currentCritter->brain.Inputs[i].id < 60000 ) { int vinput = currentCritter->brain.Inputs[i].id-50000; int vcolmax = currentCritter->genotype->bodyArch->retinasize * 4; int row = vinput / vcolmax; int col = vinput - (row * vcolmax); row = currentCritter->genotype->bodyArch->retinasize - row - 1; sensor s; s.sPointer = ¤tCritter->brain.Inputs[i]; s.position = Vector2f(brainview->position.x+((spacing+v_diam)*col)+10, 10+((spacing+v_diam)*row)); sensors.push_back(s); } else { cerr << "critterview: inputs don't add up" << endl; exit(0); } } // for ( unsigned int i=0; i < currentCritter->brain.numberOfInputs; i++ ) // { // sensor s; // s.sPointer = ¤tCritter->brain.Inputs[i]; // int woffset, hoffset; // if ( s.sPointer->id == 10000 ) // woffset = 100; hoffset = 50; // else // { // // woffset = v_radius+((spacing+v_diam)*column); // // hoffset = v_radius+((spacing+v_diam)*row); // woffset = 20; hoffset = 20; // } // s.position = Vector2f(woffset, hoffset); // sensors.push_back(s); // // if ( ++column == rowlength ) { column = 0; row++; } // } row = (currentCritter->brain.numberOfInputs/rowlength) + 1; neurons.clear(); for ( unsigned int i=0; i < currentCritter->brain.totalNeurons; i++ ) { neuron n; n.nPointer = ¤tCritter->brain.Neurons[i]; int woffset = v_radius+((spacing+v_diam)*column); int hoffset = 30+v_radius+((spacing+v_diam)*row*3); n.position = Vector2f(woffset, hoffset); neurons.push_back(n); if ( ++column == rowlength ) { column = 0; row++; } } } drawBackground(); drawBorders(); // draw the rest drawChildren(); // drift // neuron vs neuron unsigned int i, j, k, nrlinks; float xD, yD, dist, oneoverdistance, oneoverdistancesquared; ArchSynapse* as; // reset newpositions for ( i=0; i < neurons.size(); i++ ) { neurons[i].newposition.x = 0; neurons[i].newposition.y = 0; } // #pragma omp parallel for private(i, j, k, nrlinks, xD, yD, dist, oneoverdistancesquared, as) for ( i=0; i < neurons.size()-1; i++ ) for ( j=i+1; j < neurons.size(); j++ ) { // how many connections do they have underling nrlinks = 0; for ( k=0; k < currentCritter->genotype->brainzArch->ArchNeurons[i].ArchSynapses.size(); k++ ) { as = ¤tCritter->genotype->brainzArch->ArchNeurons[i].ArchSynapses[k]; if ( !as->isSensorNeuron && as->neuronID == j ) nrlinks++; } for ( k=0; k < currentCritter->genotype->brainzArch->ArchNeurons[j].ArchSynapses.size(); k++ ) { as = ¤tCritter->genotype->brainzArch->ArchNeurons[j].ArchSynapses[k]; if ( !as->isSensorNeuron && as->neuronID == i ) nrlinks++; } xD=neurons[j].position.x - neurons[i].position.x; yD=neurons[j].position.y - neurons[i].position.y; dist = sqrt((xD*xD)+(yD*yD)); oneoverdistance = 1.0f/dist; oneoverdistancesquared = oneoverdistance * oneoverdistance; // if ( oneoverdistancesquared < 0.00001f ) // oneoverdistancesquared = 0.00001f; if ( oneoverdistancesquared > 0.001f ) oneoverdistancesquared = 0.001f; if ( nrlinks > 0 ) { neurons[i].newposition.x += xD * oneoverdistancesquared * *attractor1 * nrlinks / 10.0f; neurons[i].newposition.y += yD * oneoverdistancesquared * *attractor1 * nrlinks / 10.0f; neurons[j].newposition.x -= xD * oneoverdistancesquared * *attractor1 * nrlinks / 10.0f; neurons[j].newposition.y -= yD * oneoverdistancesquared * *attractor1 * nrlinks / 10.0f; } // general antigravity neurons[i].newposition.x -= xD * oneoverdistancesquared * oneoverdistancesquared * *attractor3 * 100; neurons[i].newposition.y -= yD * oneoverdistancesquared * oneoverdistancesquared * *attractor3 * 100; neurons[j].newposition.x += xD * oneoverdistancesquared * oneoverdistancesquared * *attractor3 * 100; neurons[j].newposition.y += yD * oneoverdistancesquared * oneoverdistancesquared * *attractor3 * 100; } // neuron vs sensor for ( unsigned int i=0; i < neurons.size(); i++ ) for ( unsigned int j=0; j < sensors.size(); j++ ) { // how many connections do they have underling unsigned int nrlinks = 0; for ( unsigned int k=0; k < currentCritter->genotype->brainzArch->ArchNeurons[i].ArchSynapses.size(); k++ ) { ArchSynapse* as = ¤tCritter->genotype->brainzArch->ArchNeurons[i].ArchSynapses[k]; if ( as->isSensorNeuron && as->realneuronID == j ) nrlinks++; } float xD=sensors[j].position.x - neurons[i].position.x; float yD=sensors[j].position.y - neurons[i].position.y; float dist = sqrt((xD*xD)+(yD*yD)); float oneoverdistancesquared = 1.0f/(dist*dist*dist); /* if ( oneoverdistancesquared > 1.0f ) oneoverdistancesquared = 1.0f;*/ if ( oneoverdistancesquared > 0.001f ) oneoverdistancesquared = 0.001f; if ( nrlinks > 0 ) { neurons[i].newposition.x += xD * oneoverdistancesquared * *attractor2 * nrlinks * 10.0f; neurons[i].newposition.y += yD * oneoverdistancesquared * *attractor2 * nrlinks * 10.0f; } // general antigravity neurons[i].newposition.x -= xD * oneoverdistancesquared * oneoverdistancesquared * *attractor4 * 100000; neurons[i].newposition.y -= yD * oneoverdistancesquared * oneoverdistancesquared * *attractor4 * 100000; } // apply newpositions & check boundaries for ( i=0; i < neurons.size(); i++ ) { neurons[i].position.x += neurons[i].newposition.x; neurons[i].position.y += neurons[i].newposition.y; float miny = (v_radius*2)+((spacing+v_diam) * ((sensors.size()/rowlength)+1) ); float leftborder = 20.0f; if ( neurons[i].position.x+v_radius > *brainview->v_widthP ) neurons[i].position.x = *brainview->v_widthP-v_radius; if ( neurons[i].position.x < v_radius+leftborder ) neurons[i].position.x = v_radius+leftborder; if ( neurons[i].position.y+v_radius > *brainview->v_heightP ) neurons[i].position.y = *brainview->v_heightP-v_radius; if ( neurons[i].position.y < miny ) neurons[i].position.y = miny; } // draw brain // connections glBegin(GL_LINES); float dimmed = 0.20f; // glColor4f(1.0f, 1.0f, 1.0f, 1.0f); for ( unsigned int i=0; i < neurons.size(); i++ ) { // if ( neurons[i].nPointer->output ) // { // if ( neurons[i].nPointer->isMotor ) // glColor4f(0.0f, 0.0f, 0.5f, 1.0f); // else if ( neurons[i].nPointer->isInhibitory ) // glColor4f(0.5f, 0.0f, 0.0f, 1.0f); // else // glColor4f(0.0f, 0.5f, 0.0f, 1.0f); // } // else // { // if ( neurons[i].nPointer->isMotor ) // glColor4f(0.0f, 0.0f, dimmed, 1.0f); // else if ( neurons[i].nPointer->isInhibitory ) // glColor4f(dimmed, 0.0f, 0.0f, 1.0f); // else // glColor4f(0.0f, dimmed, 0.0f, 1.0f); // } for ( unsigned int j=0; j < currentCritter->genotype->brainzArch->ArchNeurons[i].ArchSynapses.size(); j++ ) { ArchSynapse* as = ¤tCritter->genotype->brainzArch->ArchNeurons[i].ArchSynapses[j]; if ( !as->isSensorNeuron && currentCritter->brain.Neurons[as->neuronID].output || as->isSensorNeuron && currentCritter->brain.Inputs[as->realneuronID].output ) { if ( as->isSensorNeuron ) glColor4f(0.0f, dimmed, 0.0f, 1.0f); else if ( !neurons[as->neuronID].nPointer->isInhibitory ) glColor4f(0.0f, dimmed, 0.0f, 1.0f); else glColor4f(dimmed, 0.0f, 0.0f, 1.0f); glVertex2f(neurons[i].position.x+brainview->absPosition.x, neurons[i].position.y+brainview->absPosition.y); if ( as->isSensorNeuron ) { glVertex2f(brainview->absPosition.x+sensors[as->realneuronID].position.x, brainview->absPosition.y+sensors[as->realneuronID].position.y); } else { glVertex2f(brainview->absPosition.x+neurons[as->neuronID].position.x, brainview->absPosition.y+neurons[as->neuronID].position.y); } } } // } } glEnd(); glBegin(GL_QUADS); // inputs for ( unsigned int i=0; i < sensors.size(); i++ ) { if ( sensors[i].sPointer->output ) glColor4f(0.0f, 1.0f, 0.0f, 1.0f); else glColor4f(0.0f, dimmed, 0.0f, 1.0f); // glScaled(sensors[i].sPointer->output, sensors[i].sPointer->output, sensors[i].sPointer->output); // cerr << sensors[i].sPointer->output << endl; // float nv_radius = sensors[i].sPointer->output * v_radius; float nv_radius = v_radius; glVertex2f(sensors[i].position.x+brainview->absPosition.x-nv_radius, sensors[i].position.y+brainview->absPosition.y+nv_radius); glVertex2f(sensors[i].position.x+brainview->absPosition.x-nv_radius, sensors[i].position.y+brainview->absPosition.y-nv_radius); glVertex2f(sensors[i].position.x+brainview->absPosition.x+nv_radius, sensors[i].position.y+brainview->absPosition.y-nv_radius); glVertex2f(sensors[i].position.x+brainview->absPosition.x+nv_radius, sensors[i].position.y+brainview->absPosition.y+nv_radius); } // neurons for ( unsigned int i=0; i < neurons.size(); i++ ) { // if ( neurons[i].nPointer->output ) // { if ( neurons[i].nPointer->isMotor ) glColor4f(0.3f, 0.3f, 1.0f, 1.0f); else if ( neurons[i].nPointer->isInhibitory ) glColor4f(1.0f, 0.0f, 0.0f, 1.0f); else glColor4f(0.0f, 1.0f, 0.0f, 1.0f); float nv_radius = abs(neurons[i].nPointer->potential * (v_diam / *brain_maxfiringthreshold)); // show minimum if ( nv_radius < 0.5f ) nv_radius = 0.5f; glVertex2f(neurons[i].position.x+brainview->absPosition.x-nv_radius, neurons[i].position.y+brainview->absPosition.y+nv_radius); glVertex2f(neurons[i].position.x+brainview->absPosition.x-nv_radius, neurons[i].position.y+brainview->absPosition.y-nv_radius); glVertex2f(neurons[i].position.x+brainview->absPosition.x+nv_radius, neurons[i].position.y+brainview->absPosition.y-nv_radius); glVertex2f(neurons[i].position.x+brainview->absPosition.x+nv_radius, neurons[i].position.y+brainview->absPosition.y+nv_radius); } glEnd(); } } Brainview::~Brainview() { } critterding-beta12.1/src/scenes/gui/mutationpanel.h0000644000175000017500000000041611331157113021416 0ustar bobkebobke#ifndef MUTATIONPANEL_H #define MUTATIONPANEL_H #include "../../gui/settingspanel.h" using namespace std; class Mutationpanel : public Settingspanel { public: Mutationpanel(); ~Mutationpanel(); private: unsigned int vspace; unsigned int hspace; }; #endif critterding-beta12.1/src/scenes/gui/infostats.cpp0000644000175000017500000000653711340630500021111 0ustar bobkebobke#include "infostats.h" Infostats::Infostats() { statsBuffer = Statsbuffer::Instance(); hsp = 10; vsp = 13; // active = true; isMovable = true; position.x = 10; position.y = 50; v_width = 480; v_height = 75; } void Infostats::draw() { if (active) { // updateAbsPosition(); drawBackground(); drawBorders(); unsigned int colWidth = (position.x+v_width-position.x) / 4; unsigned int col1 = position.x + colWidth; unsigned int col2 = col1 + colWidth; unsigned int col3 = col2 + colWidth; unsigned int col4 = col3 + colWidth; float linespacer = 0.0f; glColor3f(0.7f, 0.7f, 0.7f); glBegin(GL_LINES); glVertex2f(col2, position.y + linespacer); glVertex2f(col2, (position.y+v_height) - linespacer); glEnd(); glColor3f(1.0f, 1.0f, 1.0f); // glEnable(GL_TEXTURE_2D); // row counter unsigned int rc=1; // statsSnapshot* ss = &statsBuffer->snapshots[statsBuffer->snapshots.size()-1]; // HEADING // COLUMN 1 Textprinter::Instance()->print(position.x+hsp, position.y+vsp*rc, "brain"); rc++; Textprinter::Instance()->print(position.x+hsp, position.y+vsp*rc, "avg neurons:"); if ( statsBuffer->current.critters > 0 ) Textprinter::Instance()->printR(col2-hsp, position.y+vsp*rc, "%1.2f", (float)statsBuffer->current.neurons / statsBuffer->current.critters); else Textprinter::Instance()->printR(col2-hsp, position.y+vsp*rc, "%1.2f", 0.0f); rc++; Textprinter::Instance()->print(position.x+hsp, position.y+vsp*rc, "avg synapses:"); if ( statsBuffer->current.critters > 0 ) Textprinter::Instance()->printR(col2-hsp, position.y+vsp*rc, "%1.2f", (float)statsBuffer->current.synapses / statsBuffer->current.critters); else Textprinter::Instance()->printR(col2-hsp, position.y+vsp*rc, "%1.2f", 0.0f); rc++; Textprinter::Instance()->print(position.x+hsp, position.y+vsp*rc, "avg synapses/neuron:"); if ( statsBuffer->current.neurons > 0 ) Textprinter::Instance()->printR(col2-hsp, position.y+vsp*rc, "%1.2f", (float)statsBuffer->current.synapses / statsBuffer->current.neurons); else Textprinter::Instance()->printR(col2-hsp, position.y+vsp*rc, "%1.2f", 0.0f); rc++; Textprinter::Instance()->print(position.x+hsp, position.y+vsp*rc, "avg adam distance:"); if ( statsBuffer->current.critters > 0 ) Textprinter::Instance()->printR(col2-hsp, position.y+vsp*rc, "%1.2f", (float)statsBuffer->current.adamdistance / statsBuffer->current.critters); else Textprinter::Instance()->printR(col2-hsp, position.y+vsp*rc, "%1.2f", 0.0f); // COLUMN 2 rc = 1; Textprinter::Instance()->print(col2+hsp, position.y+vsp*rc, "body"); rc++; Textprinter::Instance()->print(col2+hsp, position.y+vsp*rc, "avg body parts:"); if ( statsBuffer->current.critters > 0 ) Textprinter::Instance()->printR(col4-hsp, position.y+vsp*rc, "%1.2f", (float)statsBuffer->current.bodyparts / statsBuffer->current.critters); else Textprinter::Instance()->printR(col4-hsp, position.y+vsp*rc, "%1.2f", 0.0f); rc++; Textprinter::Instance()->print(col2+hsp, position.y+vsp*rc, "avg weight:"); if ( statsBuffer->current.critters > 0 ) Textprinter::Instance()->printR(col4-hsp, position.y+vsp*rc, "%1.2f", (float)statsBuffer->current.weight / statsBuffer->current.critters); else Textprinter::Instance()->printR(col4-hsp, position.y+vsp*rc, "%1.2f", 0.0f); // glDisable(GL_TEXTURE_2D); } } Infostats::~Infostats() { } critterding-beta12.1/src/utils/0000755000175000017500000000000011347266042015471 5ustar bobkebobkecritterding-beta12.1/src/utils/sleeper.cpp0000644000175000017500000000175511346046106017640 0ustar bobkebobke/*#ifdef _WIN32 #include #endif*/ #include "sleeper.h" Sleeper::Sleeper() { settings = Settings::Instance(); t = Timer::Instance(); active = false; optimal = Settings::Instance()->getCVarPtr("fpslimit"); stepsize = 100; sleeptime = 0; cps = *optimal; timeSinceLastRender = 1.0f; } void Sleeper::mark() { if ( active ) { if ( t->elapsed == 0 ) cps = 0; else cps = t->bullet_ms; if ( cps > *optimal ) sleeptime += stepsize; else if ( cps < *optimal ) { if ( sleeptime >= stepsize ) sleeptime -= stepsize; else sleeptime = 0; } // if (sleeptime > 0 ) usleep(sleeptime); if (sleeptime > 0 ) SDL_Delay(sleeptime*0.01f); } } bool Sleeper::isRenderTime() { if ( active ) return true; timeSinceLastRender += t->elapsed; if ( timeSinceLastRender >= (1.0f / *optimal ) ) { timeSinceLastRender = 0.0f; return true; } // cerr << "returning false" << endl; return false; } void Sleeper::swap() { active =! active; } Sleeper::~Sleeper() { } critterding-beta12.1/src/utils/Makefile.am0000644000175000017500000000216711345336346017536 0ustar bobkebobkeINCLUDES = $(all_includes) -I./bullet METASOURCES = AUTO noinst_LTLIBRARIES = libutils.la noinst_HEADERS = dir.h \ file.h \ parser.h \ randgen.h \ timer.h \ fps.h \ sleeper.h \ settings.h \ displaylists.h \ events.h \ raycast.h \ mousepicker.h \ statsbuffer.h \ commands.h \ execcmd.h \ logbuffer.h \ critterselection.h \ headless.h \ color.h \ dirlayout.h libutils_la_SOURCES = dir.cpp \ file.cpp \ parser.cpp \ randgen.cpp \ timer.cpp \ fps.cpp \ sleeper.cpp \ settings.cpp \ displaylists.cpp \ events.cpp \ raycast.cpp \ mousepicker.cpp \ statsbuffer.cpp \ commands.cpp \ execcmd.cpp \ logbuffer.cpp \ critterselection.cpp \ headless.cpp \ color.cpp \ dirlayout.cpp libutils_la_LIBADD = @FTGL_LA@ $(top_builddir)/src/utils/bullet/libbulletmath.la \ $(top_builddir)/src/utils/bullet/libbulletcollision.la \ $(top_builddir)/src/utils/bullet/libbulletdynamics.la # $(top_builddir)/src/utils/bullet/libbulletmultithreaded.la libutils_la_LDFLAGS = -avoid-version -no-undefined SUBDIRS = @FTGL_LOCALDIR@ bullet critterding-beta12.1/src/utils/headless.h0000644000175000017500000000054711301117413017423 0ustar bobkebobke#ifndef HEADLESS_H #define HEADLESS_H #include "../utils/settings.h" #include "../gl/glscene.h" class Headless { public: Headless(); ~Headless(); // create the XFree86 window, with a GLX context. void create(); // Main loop for the program. void runGLScene(GLScene* glscene); private: int w_width; int w_height; }; #endif // GLWINDOW_H critterding-beta12.1/src/utils/parser.cpp0000644000175000017500000000234711344073457017502 0ustar bobkebobke#include "parser.h" Parser* Parser::Instance() { static Parser t; return &t; // _instance isn't needed in this case } Parser::Parser() { } string Parser::returnUntill(string stop, string &line) { string result; size_t pos = line.find_first_of( stop, 0 ); if ( pos != string::npos ) result = line.substr( 0, pos ); return result; } string Parser::returnUntillStrip(string stop, string &line) { string result; size_t pos = line.find_first_of( stop, 0 ); if ( pos != string::npos ) result = line.substr( 0, pos ); // strip result from line line = line.substr( pos+1, line.size() ); return result; } bool Parser::beginMatchesStrip(string stop, string &line) { if ( line.substr( 0, stop.size() ) == stop ) { line = line.substr( stop.size(), line.size() ); return true; } else return false; } bool Parser::beginMatches(string stop, string &line) { if ( line.substr( 0, stop.size() ) == stop ) return true; return false; } bool Parser::endMatches(string stop, string &line) { if ( line.substr( line.size()-stop.size(), stop.size() ) == stop ) return true; return false; } bool Parser::contains(string stop, string &line) { size_t pos = line.find_first_of( stop, 0 ); if ( pos != 0 ) return true; return false; } critterding-beta12.1/src/utils/critterselection.cpp0000644000175000017500000000275111331142230021545 0ustar bobkebobke#include "critterselection.h" Critterselection* Critterselection::Instance () { static Critterselection t; return &t; } Critterselection::Critterselection() { cv_activate = false; } void Critterselection::unregisterCritterID(const unsigned long& critterID) { for ( unsigned int i = 0; i < clist.size(); i++ ) if ( clist[i]->critterID == critterID ) { clist.erase(clist.begin()+i); return; } } void Critterselection::clear() { while ( clist.size() > 0 ) clist.erase(clist.begin()); } void Critterselection::unregisterCritterVID(const unsigned int& vectorID) { if ( vectorID < clist.size() ) clist.erase(clist.begin()+vectorID); } void Critterselection::registerCritter(CritterB* critter) { // selectCritter(critter); // skip if already registered; for ( unsigned int i = 0; i < clist.size(); i++ ) if ( clist[i]->critterID == critter->critterID ) return; clist.push_back(critter); } void Critterselection::deselectCritter(CritterB* critter) { if ( selectedCritter && selectedCritter == critter ) selectedCritter = 0; } void Critterselection::deselectCritter(const unsigned long& critterID) { if ( selectedCritter && selectedCritter->critterID == critterID ) selectedCritter = 0; } void Critterselection::selectCritter(CritterB* critter) { cv_activate = true; selectedCritter = critter; } void Critterselection::selectCritterVID(const unsigned int& vectorID) { cv_activate = true; selectedCritter = clist[vectorID]; } Critterselection::~Critterselection() { } critterding-beta12.1/src/utils/logbuffer.h0000644000175000017500000000113511342625205017610 0ustar bobkebobke#ifndef LOGBUFFER_H #define LOGBUFFER_H #include #include #include "timer.h" #include "../gui/textprinter.h" using namespace std; struct msg { string str; unsigned int len; unsigned int appeartime; // struct timeval appeartime; }; class Logbuffer { public: static Logbuffer* Instance(); void add(const stringstream& streamptr); unsigned int maxMessages; unsigned int msgLifetime; unsigned int longestLength; vector messages; void deleteExpiredMsg(); protected: Logbuffer(); private: static Logbuffer* _instance; void getLongest(); }; #endif critterding-beta12.1/src/utils/randgen.cpp0000644000175000017500000000352711345336346017625 0ustar bobkebobke#ifdef _WIN32 #include #endif #include "randgen.h" // good rng seeds for benchmark: // 1063523561 RandGen* RandGen::Instance () { static RandGen t; return &t; } RandGen::RandGen() { // random seed unsigned int startseed; if ( Settings::Instance()->getCVar("startseed") == 0 ) { Timer::Instance()->mark(); unsigned int n1 = Timer::Instance()->sdl_now; srand( n1 ); unsigned int r1 = get( 2000, 20000 ); for ( unsigned int i=0; imark(); unsigned int n2 = Timer::Instance()->sdl_now; srand( n2 ); unsigned int r2 = get( 2000, 20000 ); for ( unsigned int i=0; imark(); unsigned int n3 = Timer::Instance()->sdl_now; srand( n3 ); unsigned int r3 = get( 2000, 20000 ); for ( unsigned int i=0; imark(); startseed = (n1*n2*n3*Timer::Instance()->sdl_now)+r1+r2+r3+Timer::Instance()->sdl_now; } else { // custom seed startseed = Settings::Instance()->getCVar("startseed"); // 420041141; } cerr << "start seed: " << startseed << endl; srand( startseed ); count = 0; } unsigned int RandGen::get(unsigned int minimum, unsigned int maximum) { // cerr << "requested betweed " << minimum << " and " << maximum << " got "; if ( maximum > minimum ) { // commented out for benchmark, no reseeding /* if (++count > 1000) { unsigned int newseed = Timer::Instance()->sdl_lasttime; if ( newseed > 0 ) srand( newseed + (rand() % (maximum-minimum+1)) + minimum ); count = 0; }*/ return ((rand() % (maximum-minimum+1)) + minimum); } else { return minimum; } } critterding-beta12.1/src/utils/randgen.h0000644000175000017500000000100111345336346017253 0ustar bobkebobke#ifndef RANDGEN_H #define RANDGEN_H #include #include "timer.h" #include "settings.h" using namespace std; class RandGen { public: static RandGen* Instance(); unsigned int get(unsigned int minimum, unsigned int maximum); protected: RandGen(); private: static RandGen* _instance; unsigned int count; /* unsigned int rand1(unsigned int lim); unsigned int rand2(unsigned int lim); unsigned int rand3(unsigned int lim); unsigned int seed; unsigned int startseed;*/ }; #endif critterding-beta12.1/src/utils/dir.cpp0000644000175000017500000000241711343530351016750 0ustar bobkebobke#include "dir.h" Dir::Dir() { } bool Dir::exists(string &directory) { DIR *pdir; pdir = opendir(directory.c_str()); if (pdir) { closedir(pdir); return true; } else return false; } void Dir::make(string &directory) { // [02:44:27] #ifdef CD_PLATFORM_LINUX // [02:44:36] #ifdef CD_PLATFORM_MINGW // [02:44:40] #else // [02:44:42] #endif // [02:44:44] #endif // [02:44:50] alright :) #ifndef _WIN32 mkdir( directory.c_str(), 0755 ); #else mkdir( directory.c_str() ); #endif } void Dir::listContents(string dir, vector &files) { DIR *dp; struct dirent *dirp; if((dp = opendir(dir.c_str())) != NULL) { while ((dirp = readdir(dp)) != NULL) { if ( string(dirp->d_name) != "." && string(dirp->d_name) != ".." ) { files.push_back(string(dirp->d_name)); } } closedir(dp); } } void Dir::listContentsFull(string dir, vector &files) { DIR *dp; struct dirent *dirp; if((dp = opendir(dir.c_str())) != NULL) { while ((dirp = readdir(dp)) != NULL) { if ( string(dirp->d_name) != "." && string(dirp->d_name) != ".." ) { string fulldir = dir; fulldir.append("/"); fulldir.append(dirp->d_name); files.push_back(fulldir); } } closedir(dp); } } Dir::~Dir() { } critterding-beta12.1/src/utils/parser.h0000644000175000017500000000102011344065077017131 0ustar bobkebobke#ifndef PARSER_H #define PARSER_H #include #include using namespace std; class Parser { public: static Parser* Instance(); string returnUntillStrip(string stop, string &line); string returnUntill(string stop, string &line); bool beginMatches(string stop, string &line); bool beginMatchesStrip(string stop, string &line); bool endMatches(string stop, string &line); bool contains(string stop, string &line); protected: Parser(); private: static Parser* _instance; }; #endif critterding-beta12.1/src/utils/raycast.cpp0000644000175000017500000000130211276347255017646 0ustar bobkebobke#include "raycast.h" Raycast::Raycast(btDynamicsWorld* btWorld) { btDynWorld = btWorld; } castResult Raycast::cast(const btVector3& rayFrom, const btVector3& rayTo) { result.hit = false; btCollisionWorld::ClosestRayResultCallback resultCallback(rayFrom,rayTo); btDynWorld->rayTest(rayFrom,rayTo,resultCallback); if (resultCallback.hasHit()) { // cerr << "1 true" << endl; result.hitBody = resultCallback.m_collisionObject; result.hit = true; result.hitPosition = resultCallback.m_hitPointWorld; /* if ( result.hitBody ) { cerr << "2 true" << endl; result.hit = true; result.hitPosition = resultCallback.m_hitPointWorld; }*/ } return result; } Raycast::~Raycast() { } critterding-beta12.1/src/utils/critterselection.h0000644000175000017500000000163411331142230021211 0ustar bobkebobke#ifndef CRITTERSELECTION_H #define CRITTERSELECTION_H #include #include "../scenes/entities/critterb.h" using namespace std; class Critterselection { public: static Critterselection* Instance(); ~Critterselection(); void registerCritter(CritterB* critter); void unregisterCritterID(const unsigned long& critterID); void unregisterCritterVID(const unsigned int& vectorID); void selectCritter(CritterB* critter); void selectCritterVID(const unsigned int& vectorID); void deselectCritter(CritterB* critter); void deselectCritter(const unsigned long& critterID); void clear(); vector clist; CritterB* selectedCritter; bool cv_activate; protected: Critterselection(); private: static Critterselection* _instance; /* map clist; typedef map ::const_iterator clist_iterator; clist_iterator cit;*/ }; #endif critterding-beta12.1/src/utils/file.cpp0000644000175000017500000000262411301116254017105 0ustar bobkebobke#include "file.h" File::File() { } bool File::exists(string &file) { return exists( file.c_str() ); } bool File::exists(const char* file) { fstream file_op(file,ios::in); if (file_op.is_open()) { file_op.close(); return true; } else return false; } void File::rm(const string &filename) { if( remove( filename.c_str() ) != 0 ) cerr << "Error deleting file" << endl; // else // cerr << "file succesfully deleted" << endl; } void File::save(const string &filename, const string& content) { fstream file_op(filename.c_str(),ios::out); file_op << content; file_op.close(); } void File::save(const string &filename, string* content) { fstream file_op(filename.c_str(),ios::out); file_op << *content; file_op.close(); } bool File::open(const string &filename, string &content) { content.clear(); char str[2000]; // string str; fstream file_op(filename.c_str(),ios::in); if (file_op) { while ( !file_op.eof() ) { file_op.getline(str,2000); content.append(str); content.append("\n"); } file_op.close(); return true; } else return false; } bool File::open(const char* filename, string &content) { content.clear(); char str[2000]; fstream file_op(filename,ios::in); if (file_op) { while ( !file_op.eof() ) { file_op.getline(str,2000); content.append(str); content.append("\n"); } file_op.close(); return true; } else return false; } File::~File() { } critterding-beta12.1/src/utils/commands.h0000644000175000017500000000376011343530351017442 0ustar bobkebobke#ifndef COMMANDS_H #define COMMANDS_H #include #include #include "execcmd.h" #include "logbuffer.h" #include "../scenes/entities/worldb.h" #include "settings.h" #include "critterselection.h" #include "../scenes/gui/maincanvas.h" using namespace std; class Commands { struct cmd { cmdtype commandtype; cmdargtype argtype; void (WorldB::*worldMember)(); void (Commands::*commandsMember)(); void (Maincanvas::*canvasMember)(); void (Maincanvas::*canvasMember_string)(const string&); void (Settings::*settingsMember_string)(const string&); void (Critterselection::*critterselectionMember)(); void (Critterselection::*critterselectionMember_uint)(const unsigned int&); void (*member)(int); }; public: static Commands* Instance(); ~Commands(); WorldB* world; Maincanvas* canvas; void execCmd(const cmdsettings& cmds); void quit(); protected: Commands(); private: static Commands* _instance; Settings* settings; Critterselection* critterselection; void execCmd(const string& name); void execCmd(const string& name, const string& str); void execCmd(const string& name, const unsigned int& ui); void registerCmd(string name, void (Commands::*pt2Func)()); void registerCmd(string name, void (WorldB::*pt2Func)()); void registerCmd(string name, void (Maincanvas::*pt2Func)()); void registerCmd(string name, void (Maincanvas::*pt2Func)(const string&)); void registerCmd(string name, void (Settings::*pt2Func)(const string&)); void registerCmd(string name, void (Critterselection::*pt2Func)()); void registerCmd(string name, void (Critterselection::*pt2Func)(const unsigned int&)); void decreaseenergy(); void increaseenergy(); void decreasefoodmaxenergy(); void increasefoodmaxenergy(); void dec_worldsizex(); void inc_worldsizex(); void dec_worldsizey(); void inc_worldsizey(); void selectCritterAll(); map cmdlist; typedef map ::const_iterator cmdlist_iterator; cmdlist_iterator cmdit; }; #endif critterding-beta12.1/src/utils/timer.h0000644000175000017500000000100511344543245016756 0ustar bobkebobke#ifndef TIMER_H #define TIMER_H #include // #include #include using std::cerr; using std::endl; class Timer { public: static Timer* Instance(); unsigned int elapsed; void mark(); int sdl_now; int sdl_lasttime; int sdl_firsttime; // struct timeval lasttime; // float timediff(const struct timeval& now, const struct timeval& lasttime); float bullet_ms; protected: Timer(); private: static Timer* _instance; // struct timezone timer_tz; }; #endif critterding-beta12.1/src/utils/fps.h0000644000175000017500000000042111346046106016423 0ustar bobkebobke#ifndef FPS_H #define FPS_H #include "timer.h" #include using std::cerr; using std::endl; class Fps { public: Fps(); ~Fps(); void mark(); float currentfps; private: Timer* t; int dispcounter; int dispevery; float dispsum; }; #endif critterding-beta12.1/src/utils/dirlayout.cpp0000644000175000017500000000174311334504050020204 0ustar bobkebobke#ifdef _WIN32 #include #include #endif #include "dirlayout.h" Dirlayout* Dirlayout::Instance () { static Dirlayout t; return &t; // _instance isn't needed in this case } Dirlayout::Dirlayout() { createDirs(); } void Dirlayout::createDirs() { #ifndef _WIN32 homedir = getenv("HOME"); if ( homedir.empty() ) { cout << "environment variable HOME not defined/detected" << endl; exit(0); } progdir = homedir; progdir.append("/.critterding"); savedir = progdir; savedir.append("/save"); loaddir = progdir; loaddir.append("/load"); #else char mydoc[256]; memset(mydoc, 0, sizeof(mydoc)); SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, 0, mydoc); homedir.assign(mydoc); progdir = homedir; progdir.append("\\critterding"); savedir = progdir; savedir.append("\\save"); loaddir = progdir; loaddir.append("\\load"); #endif // cerr << progdir << endl; if ( !dirH.exists(progdir) ) dirH.make(progdir); if ( !dirH.exists(loaddir) ) dirH.make(loaddir); } critterding-beta12.1/src/utils/displaylists.cpp0000644000175000017500000000624311266367046020734 0ustar bobkebobke#include "displaylists.h" Displaylists* Displaylists::Instance() { static Displaylists t; return &t; } Displaylists::Displaylists() { generateList(); } void Displaylists::call(unsigned int index) { glCallList(displayLists+index); } void Displaylists::generateList() { // cerr << "generating displaylists" << endl; glDeleteLists(displayLists, 2); displayLists = glGenLists(2); // 0 = cube with the bottom missing glNewList(displayLists,GL_COMPILE); glBegin(GL_QUADS); //Quad 1 glVertex3f( 1.0f, 1.0f, 1.0f); //V2 glVertex3f( 1.0f,-1.0f, 1.0f); //V1 glVertex3f( 1.0f,-1.0f,-1.0f); //V3 glVertex3f( 1.0f, 1.0f,-1.0f); //V4 //Quad 2 glVertex3f( 1.0f, 1.0f,-1.0f); //V4 glVertex3f( 1.0f,-1.0f,-1.0f); //V3 glVertex3f(-1.0f,-1.0f,-1.0f); //V5 glVertex3f(-1.0f, 1.0f,-1.0f); //V6 //Quad 3 glVertex3f(-1.0f, 1.0f,-1.0f); //V6 glVertex3f(-1.0f,-1.0f,-1.0f); //V5 glVertex3f(-1.0f,-1.0f, 1.0f); //V7 glVertex3f(-1.0f, 1.0f, 1.0f); //V8 //Quad 4 glVertex3f(-1.0f, 1.0f, 1.0f); //V8 glVertex3f(-1.0f,-1.0f, 1.0f); //V7 glVertex3f( 1.0f,-1.0f, 1.0f); //V1 glVertex3f( 1.0f, 1.0f, 1.0f); //V2 //Quad 5 glVertex3f(-1.0f, 1.0f,-1.0f); //V6 glVertex3f(-1.0f, 1.0f, 1.0f); //V8 glVertex3f( 1.0f, 1.0f, 1.0f); //V2 glVertex3f( 1.0f, 1.0f,-1.0f); //V4 //Quad 6 glVertex3f( 1.0f,-1.0f,-1.0f); //V4 glVertex3f( 1.0f,-1.0f, 1.0f); //V2 glVertex3f(-1.0f,-1.0f, 1.0f); //V8 glVertex3f(-1.0f,-1.0f,-1.0f); //V6 glEnd(); glEndList(); // 0 = cube with the bottom missing glNewList(displayLists+1,GL_COMPILE); glBegin(GL_QUADS); //Quad 1 glNormal3f( 1.0f, 0.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 1.0f); //V2 glVertex3f( 1.0f,-1.0f, 1.0f); //V1 glVertex3f( 1.0f,-1.0f,-1.0f); //V3 glVertex3f( 1.0f, 1.0f,-1.0f); //V4 //Quad 2 glNormal3f( 0.0f, 0.0f,-1.0f); glVertex3f( 1.0f, 1.0f,-1.0f); //V4 glVertex3f( 1.0f,-1.0f,-1.0f); //V3 glVertex3f(-1.0f,-1.0f,-1.0f); //V5 glVertex3f(-1.0f, 1.0f,-1.0f); //V6 //Quad 3 glNormal3f(-1.0f, 0.0f, 0.0f); glVertex3f(-1.0f, 1.0f,-1.0f); //V6 glVertex3f(-1.0f,-1.0f,-1.0f); //V5 glVertex3f(-1.0f,-1.0f, 1.0f); //V7 glVertex3f(-1.0f, 1.0f, 1.0f); //V8 //Quad 4 glNormal3f( 0.0f, 0.0f, 1.0f); glVertex3f(-1.0f, 1.0f, 1.0f); //V8 glVertex3f(-1.0f,-1.0f, 1.0f); //V7 glVertex3f( 1.0f,-1.0f, 1.0f); //V1 glVertex3f( 1.0f, 1.0f, 1.0f); //V2 //Quad 5 glNormal3f( 0.0f, 1.0f, 0.0f); glVertex3f(-1.0f, 1.0f,-1.0f); //V6 glVertex3f(-1.0f, 1.0f, 1.0f); //V8 glVertex3f( 1.0f, 1.0f, 1.0f); //V2 glVertex3f( 1.0f, 1.0f,-1.0f); //V4 //Quad 6 glNormal3f(0.0f, -1.0f, 0.0f); glVertex3f( 1.0f,-1.0f,-1.0f); //V4 glVertex3f( 1.0f,-1.0f, 1.0f); //V2 glVertex3f(-1.0f,-1.0f, 1.0f); //V8 glVertex3f(-1.0f,-1.0f,-1.0f); //V6 glEnd(); glEndList(); /* // 1 = floor glNewList(displayLists+2,GL_COMPILE); glColor4f( 0.0f, 0.0f, 1.0f, 0.0f ); glBegin(GL_QUADS); glVertex3f( 0.0f, 0.0f, 0.0f); glVertex3f( 0.0f, 0.0f, 1.0f); glVertex3f( 1.0f, 0.0f, 1.0f); glVertex3f( 1.0f, 0.0f, 0.0f); glEnd(); glEndList();*/ } critterding-beta12.1/src/utils/displaylists.h0000644000175000017500000000101111254221376020355 0ustar bobkebobke#ifndef DISPLAYLISTS_H #define DISPLAYLISTS_H #include "bullet/btBulletDynamicsCommon.h" // #include "BulletCollision/CollisionShapes/btShapeHull.h" #include #include #include #include "file.h" #include "parser.h" #include using namespace std; class Displaylists { public: static Displaylists* Instance(); int displayLists; void generateList(); void call(unsigned int index); protected: Displaylists(); private: static Displaylists* _instance; }; #endif critterding-beta12.1/src/utils/settings.h0000644000175000017500000000406211344065077017506 0ustar bobkebobke#ifndef SETTINGS_H #define SETTINGS_H #include #include #include #include #include #include "file.h" #include "parser.h" #include "logbuffer.h" #include "dirlayout.h" // #include using namespace std; enum cvartype { T_INT = 1, T_FLOAT, T_BOOL, T_STRING, }; struct cvar { // string name; string comment; cvartype type; unsigned int int_val; unsigned int int_min; unsigned int int_max; bool loop; bool local; }; class Settings { public: static Settings* Instance(); ~Settings(); void registerCVar(const string& name, const unsigned int& defaultvalue, const unsigned int& min_val, const unsigned int& max_val, const string& comment); void registerCVar(const string& name, const unsigned int& defaultvalue, const unsigned int& min_val, const unsigned int& max_val, bool loop, const string& comment); void registerLocalCVar(const string& name, const unsigned int& defaultvalue, const unsigned int& min_val, const unsigned int& max_val, bool loop, const string& comment); void unregisterCVar(const string& name); bool isCVar(const string& name); unsigned int getCVar(const string& name); const unsigned int* getCVarPtr(const string& name); bool setCVar(const string& name, const unsigned int& value); void decreaseCVar(const string& name, const unsigned int& value); void increaseCVar(const string& name, const unsigned int& value); void decreaseCVar(const string& name); void increaseCVar(const string& name); string profileName; int *winWidth; int *winHeight; // other vars // float freeEnergyInfo; void doCommandLineOptions(int argc, char *argv[]); void loadProfile(char* filename); void saveProfile(); string binarypath; protected: Settings(); private: static Settings* _instance; File fileH; Dir dirH; Parser* parseH; Dirlayout* dirlayout; map cvarlist; typedef map ::const_iterator cvarlist_iterator; cvarlist_iterator cvarit; stringstream helpinfo; void createHelpInfo(); }; #endif critterding-beta12.1/src/utils/ftgl/0000755000175000017500000000000011347266042016425 5ustar bobkebobkecritterding-beta12.1/src/utils/ftgl/FTCharmap.cpp0000644000175000017500000000527311147116040020733 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include "FTFace.h" #include "FTCharmap.h" FTCharmap::FTCharmap(FTFace* face) : ftFace(*(face->Face())), err(0) { if(!ftFace->charmap) { if(!ftFace->num_charmaps) { // This face doesn't even have one charmap! err = 0x96; // Invalid_CharMap_Format return; } err = FT_Set_Charmap(ftFace, ftFace->charmaps[0]); } ftEncoding = ftFace->charmap->encoding; for(unsigned int i = 0; i < FTCharmap::MAX_PRECOMPUTED; i++) { charIndexCache[i] = FT_Get_Char_Index(ftFace, i); } } FTCharmap::~FTCharmap() { charMap.clear(); } bool FTCharmap::CharMap(FT_Encoding encoding) { if(ftEncoding == encoding) { err = 0; return true; } err = FT_Select_Charmap(ftFace, encoding); if(!err) { ftEncoding = encoding; charMap.clear(); } return !err; } unsigned int FTCharmap::GlyphListIndex(const unsigned int characterCode) { return charMap.find(characterCode); } unsigned int FTCharmap::FontIndex(const unsigned int characterCode) { if(characterCode < FTCharmap::MAX_PRECOMPUTED) { return charIndexCache[characterCode]; } return FT_Get_Char_Index(ftFace, characterCode); } void FTCharmap::InsertIndex(const unsigned int characterCode, const size_t containerIndex) { charMap.insert(characterCode, static_cast(containerIndex)); } critterding-beta12.1/src/utils/ftgl/FTCharmap.h0000644000175000017500000001220311147116040020367 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * 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. */ #ifndef __FTCharmap__ #define __FTCharmap__ #include #include FT_FREETYPE_H #include FT_GLYPH_H #include "FTGL/ftgl.h" #include "FTCharToGlyphIndexMap.h" /** * FTCharmap takes care of specifying the encoding for a font and mapping * character codes to glyph indices. * * It doesn't preprocess all indices, only on an as needed basis. This may * seem like a performance penalty but it is quicker than using the 'raw' * freetype calls and will save significant amounts of memory when dealing * with unicode encoding * * @see "Freetype 2 Documentation" * */ class FTFace; class FTCharmap { public: /** * Constructor */ FTCharmap(FTFace* face); /** * Destructor */ virtual ~FTCharmap(); /** * Queries for the current character map code. * * @return The current character map code. */ FT_Encoding Encoding() const { return ftEncoding; } /** * Sets the character map for the face. If an error occurs the object is not modified. * Valid encodings as at Freetype 2.0.4 * ft_encoding_none * ft_encoding_symbol * ft_encoding_unicode * ft_encoding_latin_2 * ft_encoding_sjis * ft_encoding_gb2312 * ft_encoding_big5 * ft_encoding_wansung * ft_encoding_johab * ft_encoding_adobe_standard * ft_encoding_adobe_expert * ft_encoding_adobe_custom * ft_encoding_apple_roman * * @param encoding the Freetype encoding symbol. See above. * @return true if charmap was valid and set * correctly. */ bool CharMap(FT_Encoding encoding); /** * Get the FTGlyphContainer index of the input character. * * @param characterCode The character code of the requested glyph in * the current encoding eg apple roman. * @return The FTGlyphContainer index for the character or zero * if it wasn't found */ unsigned int GlyphListIndex(const unsigned int characterCode); /** * Get the font glyph index of the input character. * * @param characterCode The character code of the requested glyph in * the current encoding eg apple roman. * @return The glyph index for the character. */ unsigned int FontIndex(const unsigned int characterCode); /** * Set the FTGlyphContainer index of the character code. * * @param characterCode The character code of the requested glyph in * the current encoding eg apple roman. * @param containerIndex The index into the FTGlyphContainer of the * character code. */ void InsertIndex(const unsigned int characterCode, const size_t containerIndex); /** * Queries for errors. * * @return The current error code. Zero means no error. */ FT_Error Error() const { return err; } private: /** * Current character map code. */ FT_Encoding ftEncoding; /** * The current Freetype face. */ const FT_Face ftFace; /** * A structure that maps glyph indices to character codes * * < character code, face glyph index> */ typedef FTCharToGlyphIndexMap CharacterMap; CharacterMap charMap; /** * Precomputed font indices. */ static const unsigned int MAX_PRECOMPUTED = 128; unsigned int charIndexCache[MAX_PRECOMPUTED]; /** * Current error code. */ FT_Error err; }; #endif // __FTCharmap__ critterding-beta12.1/src/utils/ftgl/Makefile.am0000644000175000017500000000522511336076205020463 0ustar bobkebobkeINCLUDES = $(all_includes) METASOURCES = AUTO noinst_LTLIBRARIES = libftgl.la noinst_HEADERS = $(ftgl_headers) libftgl_la_CPPFLAGS = -IFTGlyph -IFTFont -IFTLayout libftgl_la_LDFLAGS = -avoid-version -no-undefined #libftgl_la_LIBADD = -l libftgl_la_SOURCES = \ FTBuffer.cpp \ FTCharmap.cpp \ FTCharmap.h \ FTCharToGlyphIndexMap.h \ FTContour.cpp \ FTContour.h \ FTFace.cpp \ FTFace.h \ FTGlyphContainer.cpp \ FTGlyphContainer.h \ FTInternals.h \ FTLibrary.cpp \ FTLibrary.h \ FTList.h \ FTPoint.cpp \ FTSize.cpp \ FTSize.h \ FTVector.h \ FTVectoriser.cpp \ FTVectoriser.h \ FTUnicode.h \ $(ftglyph_sources) \ $(ftfont_sources) \ $(ftlayout_sources) \ $(ftgl_headers) \ $(NULL) ftgl_headers = \ FTGL/ftgl.h \ FTGL/FTBBox.h \ FTGL/FTBuffer.h \ FTGL/FTPoint.h \ FTGL/FTGlyph.h \ FTGL/FTBitmapGlyph.h \ FTGL/FTBufferGlyph.h \ FTGL/FTExtrdGlyph.h \ FTGL/FTOutlineGlyph.h \ FTGL/FTPixmapGlyph.h \ FTGL/FTPolyGlyph.h \ FTGL/FTTextureGlyph.h \ FTGL/FTFont.h \ FTGL/FTGLBitmapFont.h \ FTGL/FTBufferFont.h \ FTGL/FTGLExtrdFont.h \ FTGL/FTGLOutlineFont.h \ FTGL/FTGLPixmapFont.h \ FTGL/FTGLPolygonFont.h \ FTGL/FTGLTextureFont.h \ FTGL/FTLayout.h \ FTGL/FTSimpleLayout.h \ ${NULL} ftglyph_sources = \ FTGlyph/FTGlyph.cpp \ FTGlyph/FTGlyphImpl.h \ FTGlyph/FTGlyphGlue.cpp \ FTGlyph/FTBitmapGlyph.cpp \ FTGlyph/FTBitmapGlyphImpl.h \ FTGlyph/FTBufferGlyph.cpp \ FTGlyph/FTBufferGlyphImpl.h \ FTGlyph/FTExtrudeGlyph.cpp \ FTGlyph/FTExtrudeGlyphImpl.h \ FTGlyph/FTOutlineGlyph.cpp \ FTGlyph/FTOutlineGlyphImpl.h \ FTGlyph/FTPixmapGlyph.cpp \ FTGlyph/FTPixmapGlyphImpl.h \ FTGlyph/FTPolygonGlyph.cpp \ FTGlyph/FTPolygonGlyphImpl.h \ FTGlyph/FTTextureGlyph.cpp \ FTGlyph/FTTextureGlyphImpl.h \ $(NULL) ftfont_sources = \ FTFont/FTFont.cpp \ FTFont/FTFontImpl.h \ FTFont/FTFontGlue.cpp \ FTFont/FTBitmapFont.cpp \ FTFont/FTBitmapFontImpl.h \ FTFont/FTBufferFont.cpp \ FTFont/FTBufferFontImpl.h \ FTFont/FTExtrudeFont.cpp \ FTFont/FTExtrudeFontImpl.h \ FTFont/FTOutlineFont.cpp \ FTFont/FTOutlineFontImpl.h \ FTFont/FTPixmapFont.cpp \ FTFont/FTPixmapFontImpl.h \ FTFont/FTPolygonFont.cpp \ FTFont/FTPolygonFontImpl.h \ FTFont/FTTextureFont.cpp \ FTFont/FTTextureFontImpl.h \ $(NULL) ftlayout_sources = \ FTLayout/FTLayout.cpp \ FTLayout/FTLayoutImpl.h \ FTLayout/FTLayoutGlue.cpp \ FTLayout/FTSimpleLayout.cpp \ FTLayout/FTSimpleLayoutImpl.h \ $(NULL) NULL =critterding-beta12.1/src/utils/ftgl/FTSize.h0000644000175000017500000001126711147116040017737 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * 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. */ #ifndef __FTSize__ #define __FTSize__ #include #include FT_FREETYPE_H #include "FTGL/ftgl.h" /** * FTSize class provides an abstraction layer for the Freetype Size. * * @see "Freetype 2 Documentation" * */ class FTSize { public: /** * Default Constructor */ FTSize(); /** * Destructor */ virtual ~FTSize(); /** * Sets the char size for the current face. * * This doesn't guarantee that the size was set correctly. Clients * should check errors. If an error does occur the size object isn't modified. * * @param face Parent face for this size object * @param point_size the face size in points (1/72 inch) * @param x_resolution the horizontal resolution of the target device. * @param y_resolution the vertical resolution of the target device. * @return true if the size has been set. Clients should check Error() for more information if this function returns false() */ bool CharSize(FT_Face* face, unsigned int point_size, unsigned int x_resolution, unsigned int y_resolution); /** * get the char size for the current face. * * @return The char size in points */ unsigned int CharSize() const; /** * Gets the global ascender height for the face in pixels. * * @return Ascender height */ float Ascender() const; /** * Gets the global descender height for the face in pixels. * * @return Ascender height */ float Descender() const; /** * Gets the global face height for the face. * * If the face is scalable this returns the height of the global * bounding box which ensures that any glyph will be less than or * equal to this height. If the font isn't scalable there is no * guarantee that glyphs will not be taller than this value. * * @return height in pixels. */ float Height() const; /** * Gets the global face width for the face. * * If the face is scalable this returns the width of the global * bounding box which ensures that any glyph will be less than or * equal to this width. If the font isn't scalable this value is * the max_advance for the face. * * @return width in pixels. */ float Width() const; /** * Gets the underline position for the face. * * @return underline position in pixels */ float Underline() const; /** * Queries for errors. * * @return The current error code. */ FT_Error Error() const { return err; } private: /** * The current Freetype face that this FTSize object relates to. */ FT_Face* ftFace; /** * The Freetype size. */ FT_Size ftSize; /** * The size in points. */ unsigned int size; /** * The horizontal resolution. */ unsigned int xResolution; /** * The vertical resolution. */ unsigned int yResolution; /** * Current error code. Zero means no error. */ FT_Error err; }; #endif // __FTSize__ critterding-beta12.1/src/utils/ftgl/FTVector.h0000644000175000017500000001163711147116040020270 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * 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. */ #ifndef __FTVector__ #define __FTVector__ #include "FTGL/ftgl.h" /** * Provides a non-STL alternative to the STL vector */ template class FTVector { public: typedef FT_VECTOR_ITEM_TYPE value_type; typedef value_type& reference; typedef const value_type& const_reference; typedef value_type* iterator; typedef const value_type* const_iterator; typedef size_t size_type; FTVector() { Capacity = Size = 0; Items = 0; } virtual ~FTVector() { clear(); } FTVector& operator =(const FTVector& v) { reserve(v.capacity()); iterator ptr = begin(); const_iterator vbegin = v.begin(); const_iterator vend = v.end(); while(vbegin != vend) { *ptr++ = *vbegin++; } Size = v.size(); return *this; } size_type size() const { return Size; } size_type capacity() const { return Capacity; } iterator begin() { return Items; } const_iterator begin() const { return Items; } iterator end() { return begin() + size(); } const_iterator end() const { return begin() + size(); } bool empty() const { return size() == 0; } reference operator [](size_type pos) { return(*(begin() + pos)); } const_reference operator [](size_type pos) const { return *(begin() + pos); } void clear() { if(Capacity) { delete [] Items; Capacity = Size = 0; Items = 0; } } void reserve(size_type n) { if(capacity() < n) { expand(n); } } void push_back(const value_type& x) { if(size() == capacity()) { expand(); } (*this)[size()] = x; ++Size; } void resize(size_type n, value_type x) { if(n == size()) { return; } reserve(n); iterator ibegin, iend; if(n >= Size) { ibegin = this->end(); iend = this->begin() + n; } else { ibegin = this->begin() + n; iend = this->end(); } while(ibegin != iend) { *ibegin++ = x; } Size = n; } private: void expand(size_type capacity_hint = 0) { size_type new_capacity = (capacity() == 0) ? 256 : capacity() * 2; if(capacity_hint) { while(new_capacity < capacity_hint) { new_capacity *= 2; } } value_type *new_items = new value_type[new_capacity]; iterator ibegin = this->begin(); iterator iend = this->end(); value_type *ptr = new_items; while(ibegin != iend) { *ptr++ = *ibegin++; } if(Capacity) { delete [] Items; } Items = new_items; Capacity = new_capacity; } size_type Capacity; size_type Size; value_type* Items; }; #endif // __FTVector__ critterding-beta12.1/src/utils/ftgl/FTInternals.h0000644000175000017500000000661011147116040020760 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTINTERNALS_H__ #define __FTINTERNALS_H__ #include "FTGL/ftgl.h" #include #include // Fixes for deprecated identifiers in 2.1.5 #ifndef FT_OPEN_MEMORY #define FT_OPEN_MEMORY (FT_Open_Flags)1 #endif #ifndef FT_RENDER_MODE_MONO #define FT_RENDER_MODE_MONO ft_render_mode_mono #endif #ifndef FT_RENDER_MODE_NORMAL #define FT_RENDER_MODE_NORMAL ft_render_mode_normal #endif #ifdef WIN32 // Under windows avoid including is overrated. // Sure, it can be avoided and "name space pollution" can be // avoided, but why? It really doesn't make that much difference // these days. #define WIN32_LEAN_AND_MEAN #include #ifndef __gl_h_ #include #include #endif #else // Non windows platforms - don't require nonsense as seen above :-) #ifndef __gl_h_ #ifdef SDL_main #include "SDL_opengl.h" #elif __APPLE_CC__ #include #include #else #include #if defined (__sun__) && !defined (__sparc__) #include #else #include #endif #endif #endif // Required for compatibility with glext.h style function definitions of // OpenGL extensions, such as in src/osg/Point.cpp. #ifndef APIENTRY #define APIENTRY #endif #endif FTGL_BEGIN_C_DECLS typedef enum { GLYPH_CUSTOM, GLYPH_BITMAP, GLYPH_BUFFER, GLYPH_PIXMAP, GLYPH_OUTLINE, GLYPH_POLYGON, GLYPH_EXTRUDE, GLYPH_TEXTURE, } GlyphType; struct _FTGLglyph { FTGlyph *ptr; FTGL::GlyphType type; }; typedef enum { FONT_CUSTOM, FONT_BITMAP, FONT_BUFFER, FONT_PIXMAP, FONT_OUTLINE, FONT_POLYGON, FONT_EXTRUDE, FONT_TEXTURE, } FontType; struct _FTGLfont { FTFont *ptr; FTGL::FontType type; }; typedef enum { LAYOUT_SIMPLE, } LayoutType; struct _FTGLlayout { FTLayout *ptr; FTGLfont *font; FTGL::LayoutType type; }; FTGL_END_C_DECLS #endif //__FTINTERNALS_H__ critterding-beta12.1/src/utils/ftgl/FTGL/0000755000175000017500000000000011347266042017161 5ustar bobkebobkecritterding-beta12.1/src/utils/ftgl/FTGL/FTGlyph.h0000644000175000017500000001414111147116040020636 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTGlyph__ #define __FTGlyph__ #ifdef __cplusplus class FTGlyphImpl; /** * FTGlyph is the base class for FTGL glyphs. * * It provides the interface between Freetype glyphs and their openGL * renderable counterparts. This is an abstract class and derived classes * must implement the Render function. * * @see FTBBox * @see FTPoint */ class FTGL_EXPORT FTGlyph { protected: /** * Create a glyph. * * @param glyph The Freetype glyph to be processed */ FTGlyph(FT_GlyphSlot glyph); private: /** * Internal FTGL FTGlyph constructor. For private use only. * * @param pImpl Internal implementation object. Will be destroyed * upon FTGlyph deletion. */ FTGlyph(FTGlyphImpl *pImpl); /* Allow our internal subclasses to access the private constructor */ friend class FTBitmapGlyph; friend class FTBufferGlyph; friend class FTExtrudeGlyph; friend class FTOutlineGlyph; friend class FTPixmapGlyph; friend class FTPolygonGlyph; friend class FTTextureGlyph; public: /** * Destructor */ virtual ~FTGlyph(); /** * Renders this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode) = 0; /** * Return the advance width for this glyph. * * @return advance width. */ virtual float Advance() const; /** * Return the bounding box for this glyph. * * @return bounding box. */ virtual const FTBBox& BBox() const; /** * Queries for errors. * * @return The current error code. */ virtual FT_Error Error() const; private: /** * Internal FTGL FTGlyph implementation object. For private use only. */ FTGlyphImpl *impl; }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * FTGLglyph is the base class for FTGL glyphs. * * It provides the interface between Freetype glyphs and their openGL * renderable counterparts. This is an abstract class and derived classes * must implement the ftglRenderGlyph() function. */ struct _FTGLGlyph; typedef struct _FTGLglyph FTGLglyph; /** * Create a custom FTGL glyph object. * FIXME: maybe get rid of "base" and have advanceCallback etc. functions * * @param base The base FTGLglyph* to subclass. * @param data A pointer to private data that will be passed to callbacks. * @param renderCallback A rendering callback function. * @param destroyCallback A callback function to be called upon destruction. * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreateCustomGlyph(FTGLglyph *base, void *data, void (*renderCallback) (FTGLglyph *, void *, FTGL_DOUBLE, FTGL_DOUBLE, int, FTGL_DOUBLE *, FTGL_DOUBLE *), void (*destroyCallback) (FTGLglyph *, void *)); /** * Destroy an FTGL glyph object. * * @param glyph An FTGLglyph* object. */ FTGL_EXPORT void ftglDestroyGlyph(FTGLglyph *glyph); /** * Render a glyph at the current pen position and compute the corresponding * advance. * * @param glyph An FTGLglyph* object. * @param penx The current pen's X position. * @param peny The current pen's Y position. * @param renderMode Render mode to display * @param advancex A pointer to an FTGL_DOUBLE where to write the advance's X * component. * @param advancey A pointer to an FTGL_DOUBLE where to write the advance's Y * component. */ FTGL_EXPORT void ftglRenderGlyph(FTGLglyph *glyph, FTGL_DOUBLE penx, FTGL_DOUBLE peny, int renderMode, FTGL_DOUBLE *advancex, FTGL_DOUBLE *advancey); /** * Return the advance for a glyph. * * @param glyph An FTGLglyph* object. * @return The advance's X component. */ FTGL_EXPORT float ftglGetGlyphAdvance(FTGLglyph *glyph); /** * Return the bounding box for a glyph. * * @param glyph An FTGLglyph* object. * @param bounds An array of 6 float values where the bounding box's lower * left near and upper right far 3D coordinates will be stored. */ FTGL_EXPORT void ftglGetGlyphBBox(FTGLglyph *glyph, float bounds[6]); /** * Query a glyph for errors. * * @param glyph An FTGLglyph* object. * @return The current error code. */ FTGL_EXPORT FT_Error ftglGetGlyphError(FTGLglyph* glyph); FTGL_END_C_DECLS #endif // __FTGlyph__ critterding-beta12.1/src/utils/ftgl/FTGL/FTGLTextureFont.h0000644000175000017500000000612611147116040022271 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTTextureFont__ #define __FTTextureFont__ #ifdef __cplusplus /** * FTTextureFont is a specialisation of the FTFont class for handling * Texture mapped fonts * * @see FTFont */ class FTGL_EXPORT FTTextureFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTTextureFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTTextureFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ virtual ~FTTextureFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #define FTGLTextureFont FTTextureFont #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling texture-mapped fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont */ FTGL_EXPORT FTGLfont *ftglCreateTextureFont(const char *file); FTGL_END_C_DECLS #endif // __FTTextureFont__ critterding-beta12.1/src/utils/ftgl/FTGL/FTExtrdGlyph.h0000644000175000017500000000727511147116040021657 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTExtrudeGlyph__ #define __FTExtrudeGlyph__ #ifdef __cplusplus /** * FTExtrudeGlyph is a specialisation of FTGlyph for creating tessellated * extruded polygon glyphs. */ class FTGL_EXPORT FTExtrudeGlyph : public FTGlyph { public: /** * Constructor. Sets the Error to Invalid_Outline if the glyph isn't * an outline. * * @param glyph The Freetype glyph to be processed * @param depth The distance along the z axis to extrude the glyph * @param frontOutset outset contour size * @param backOutset outset contour size * @param useDisplayList Enable or disable the use of Display Lists * for this glyph * true turns ON display lists. * false turns OFF display lists. */ FTExtrudeGlyph(FT_GlyphSlot glyph, float depth, float frontOutset, float backOutset, bool useDisplayList); /** * Destructor */ virtual ~FTExtrudeGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #define FTExtrdGlyph FTExtrudeGlyph #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialisation of FTGLglyph for creating tessellated * extruded polygon glyphs. * * @param glyph The Freetype glyph to be processed * @param depth The distance along the z axis to extrude the glyph * @param frontOutset outset contour size * @param backOutset outset contour size * @param useDisplayList Enable or disable the use of Display Lists * for this glyph * true turns ON display lists. * false turns OFF display lists. * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreateExtrudeGlyph(FT_GlyphSlot glyph, float depth, float frontOutset, float backOutset, int useDisplayList); FTGL_END_C_DECLS #endif // __FTExtrudeGlyph__ critterding-beta12.1/src/utils/ftgl/FTGL/FTGLPixmapFont.h0000644000175000017500000000611611147116040022066 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTPixmapFont__ #define __FTPixmapFont__ #ifdef __cplusplus /** * FTPixmapFont is a specialisation of the FTFont class for handling * Pixmap (Grey Scale) fonts * * @see FTFont */ class FTGL_EXPORT FTPixmapFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTPixmapFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTPixmapFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ ~FTPixmapFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #define FTGLPixmapFont FTPixmapFont #endif // __cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling pixmap (grey scale) fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont */ FTGL_EXPORT FTGLfont *ftglCreatePixmapFont(const char *file); FTGL_END_C_DECLS #endif // __FTPixmapFont__ critterding-beta12.1/src/utils/ftgl/FTGL/FTOutlineGlyph.h0000644000175000017500000000635111147116040022202 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTOutlineGlyph__ #define __FTOutlineGlyph__ #ifdef __cplusplus /** * FTOutlineGlyph is a specialisation of FTGlyph for creating outlines. */ class FTGL_EXPORT FTOutlineGlyph : public FTGlyph { public: /** * Constructor. Sets the Error to Invalid_Outline if the glyphs isn't * an outline. * * @param glyph The Freetype glyph to be processed * @param outset outset distance * @param useDisplayList Enable or disable the use of Display Lists * for this glyph * true turns ON display lists. * false turns OFF display lists. */ FTOutlineGlyph(FT_GlyphSlot glyph, float outset, bool useDisplayList); /** * Destructor */ virtual ~FTOutlineGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialisation of FTGLglyph for creating outlines. * * @param glyph The Freetype glyph to be processed * @param outset outset contour size * @param useDisplayList Enable or disable the use of Display Lists * for this glyph * true turns ON display lists. * false turns OFF display lists. * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreateOutlineGlyph(FT_GlyphSlot glyph, float outset, int useDisplayList); FTGL_END_C_DECLS #endif // __FTOutlineGlyph__ critterding-beta12.1/src/utils/ftgl/FTGL/FTSimpleLayout.h0000644000175000017500000001472011147116040022205 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTSimpleLayout__ #define __FTSimpleLayout__ #ifdef __cplusplus class FTFont; /** * FTSimpleLayout is a specialisation of FTLayout for simple text boxes. * * This class has basic support for text wrapping, left, right and centered * alignment, and text justification. * * @see FTLayout */ class FTGL_EXPORT FTSimpleLayout : public FTLayout { public: /** * Initializes line spacing to 1.0, alignment to * ALIGN_LEFT and wrap to 100.0 */ FTSimpleLayout(); /** * Destructor */ ~FTSimpleLayout(); /** * Get the bounding box for a formatted string. * * @param string A char string. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @return The corresponding bounding box. */ virtual FTBBox BBox(const char* string, const int len = -1, FTPoint position = FTPoint()); /** * Get the bounding box for a formatted string. * * @param string A wchar_t string. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @return The corresponding bounding box. */ virtual FTBBox BBox(const wchar_t* string, const int len = -1, FTPoint position = FTPoint()); /** * Render a string of characters. * * @param string 'C' style string to be output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param renderMode Render mode to display (optional) */ virtual void Render(const char *string, const int len = -1, FTPoint position = FTPoint(), int renderMode = FTGL::RENDER_ALL); /** * Render a string of characters. * * @param string wchar_t string to be output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param renderMode Render mode to display (optional) */ virtual void Render(const wchar_t *string, const int len = -1, FTPoint position = FTPoint(), int renderMode = FTGL::RENDER_ALL); /** * Set the font to use for rendering the text. * * @param fontInit A pointer to the new font. The font is * referenced by this but will not be * disposed of when this is deleted. */ void SetFont(FTFont *fontInit); /** * @return The current font. */ FTFont *GetFont(); /** * The maximum line length for formatting text. * * @param LineLength The new line length. */ void SetLineLength(const float LineLength); /** * @return The current line length. */ float GetLineLength() const; /** * The text alignment mode used to distribute * space within a line or rendered text. * * @param Alignment The new alignment mode. */ void SetAlignment(const FTGL::TextAlignment Alignment); /** * @return The text alignment mode. */ FTGL::TextAlignment GetAlignment() const; /** * Sets the line height. * * @param LineSpacing The height of each line of text expressed as * a percentage of the current fonts line height. */ void SetLineSpacing(const float LineSpacing); /** * @return The line spacing. */ float GetLineSpacing() const; }; #endif //__cplusplus FTGL_BEGIN_C_DECLS FTGL_EXPORT FTGLlayout *ftglCreateSimpleLayout(void); FTGL_EXPORT void ftglSetLayoutFont(FTGLlayout *, FTGLfont*); FTGL_EXPORT FTGLfont *ftglGetLayoutFont(FTGLlayout *); FTGL_EXPORT void ftglSetLayoutLineLength(FTGLlayout *, const float); FTGL_EXPORT float ftglGetLayoutLineLength(FTGLlayout *); FTGL_EXPORT void ftglSetLayoutAlignment(FTGLlayout *, const int); FTGL_EXPORT int ftglGetLayoutAlignement(FTGLlayout *); FTGL_EXPORT void ftglSetLayoutLineSpacing(FTGLlayout *, const float); FTGL_EXPORT float ftglGetLayoutLineSpacing(FTGLlayout *); FTGL_END_C_DECLS #endif /* __FTSimpleLayout__ */ critterding-beta12.1/src/utils/ftgl/FTGL/FTLayout.h0000644000175000017500000001454511147116040021040 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTLayout__ #define __FTLayout__ #ifdef __cplusplus class FTLayoutImpl; /** * FTLayout is the interface for layout managers that render text. * * Specific layout manager classes are derived from this class. This class * is abstract and deriving classes must implement the protected * Render methods to render formatted text and * BBox methods to determine the bounding box of output text. * * @see FTFont * @see FTBBox */ class FTGL_EXPORT FTLayout { protected: FTLayout(); private: /** * Internal FTGL FTLayout constructor. For private use only. * * @param pImpl Internal implementation object. Will be destroyed * upon FTLayout deletion. */ FTLayout(FTLayoutImpl *pImpl); /* Allow our internal subclasses to access the private constructor */ friend class FTSimpleLayout; public: /** * Destructor */ virtual ~FTLayout(); /** * Get the bounding box for a formatted string. * * @param string A char string. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @return The corresponding bounding box. */ virtual FTBBox BBox(const char* string, const int len = -1, FTPoint position = FTPoint()) = 0; /** * Get the bounding box for a formatted string. * * @param string A wchar_t string. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @return The corresponding bounding box. */ virtual FTBBox BBox(const wchar_t* string, const int len = -1, FTPoint position = FTPoint()) = 0; /** * Render a string of characters. * * @param string 'C' style string to be output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param renderMode Render mode to display (optional) */ virtual void Render(const char *string, const int len = -1, FTPoint position = FTPoint(), int renderMode = FTGL::RENDER_ALL) = 0; /** * Render a string of characters. * * @param string wchar_t string to be output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param renderMode Render mode to display (optional) */ virtual void Render(const wchar_t *string, const int len = -1, FTPoint position = FTPoint(), int renderMode = FTGL::RENDER_ALL) = 0; /** * Queries the Layout for errors. * * @return The current error code. */ virtual FT_Error Error() const; private: /** * Internal FTGL FTLayout implementation object. For private use only. */ FTLayoutImpl *impl; }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * FTGLlayout is the interface for layout managers that render text. */ struct _FTGLlayout; typedef struct _FTGLlayout FTGLlayout; /** * Destroy an FTGL layout object. * * @param layout An FTGLlayout* object. */ FTGL_EXPORT void ftglDestroyLayout(FTGLlayout* layout); /** * Get the bounding box for a string. * * @param layout An FTGLlayout* object. * @param string A char buffer * @param bounds An array of 6 float values where the bounding box's lower * left near and upper right far 3D coordinates will be stored. */ FTGL_EXPORT void ftglGetLayoutBBox(FTGLlayout *layout, const char* string, float bounds[6]); /** * Render a string of characters. * * @param layout An FTGLlayout* object. * @param string Char string to be output. * @param mode Render mode to display. */ FTGL_EXPORT void ftglRenderLayout(FTGLlayout *layout, const char *string, int mode); /** * Query a layout for errors. * * @param layout An FTGLlayout* object. * @return The current error code. */ FTGL_EXPORT FT_Error ftglGetLayoutError(FTGLlayout* layout); FTGL_END_C_DECLS #endif /* __FTLayout__ */ critterding-beta12.1/src/utils/ftgl/FTGL/FTPoint.h0000644000175000017500000001702411147116040020647 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTPoint__ #define __FTPoint__ #ifdef __cplusplus /** * FTPoint class is a basic 3-dimensional point or vector. */ class FTGL_EXPORT FTPoint { public: /** * Default constructor. Point is set to zero. */ inline FTPoint() { values[0] = 0; values[1] = 0; values[2] = 0; } /** * Constructor. Z coordinate is set to zero if unspecified. * * @param x First component * @param y Second component * @param z Third component */ inline FTPoint(const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z = 0) { values[0] = x; values[1] = y; values[2] = z; } /** * Constructor. This converts an FT_Vector to an FTPoint * * @param ft_vector A freetype vector */ inline FTPoint(const FT_Vector& ft_vector) { values[0] = ft_vector.x; values[1] = ft_vector.y; values[2] = 0; } /** * Normalise a point's coordinates. If the coordinates are zero, * the point is left untouched. * * @return A vector of norm one. */ FTPoint Normalise(); /** * Operator += In Place Addition. * * @param point * @return this plus point. */ inline FTPoint& operator += (const FTPoint& point) { values[0] += point.values[0]; values[1] += point.values[1]; values[2] += point.values[2]; return *this; } /** * Operator + * * @param point * @return this plus point. */ inline FTPoint operator + (const FTPoint& point) const { FTPoint temp; temp.values[0] = values[0] + point.values[0]; temp.values[1] = values[1] + point.values[1]; temp.values[2] = values[2] + point.values[2]; return temp; } /** * Operator -= In Place Substraction. * * @param point * @return this minus point. */ inline FTPoint& operator -= (const FTPoint& point) { values[0] -= point.values[0]; values[1] -= point.values[1]; values[2] -= point.values[2]; return *this; } /** * Operator - * * @param point * @return this minus point. */ inline FTPoint operator - (const FTPoint& point) const { FTPoint temp; temp.values[0] = values[0] - point.values[0]; temp.values[1] = values[1] - point.values[1]; temp.values[2] = values[2] - point.values[2]; return temp; } /** * Operator * Scalar multiplication * * @param multiplier * @return this multiplied by multiplier. */ inline FTPoint operator * (double multiplier) const { FTPoint temp; temp.values[0] = values[0] * multiplier; temp.values[1] = values[1] * multiplier; temp.values[2] = values[2] * multiplier; return temp; } /** * Operator * Scalar multiplication * * @param point * @param multiplier * @return multiplier multiplied by point. */ inline friend FTPoint operator * (double multiplier, FTPoint& point) { return point * multiplier; } /** * Operator * Scalar product * * @param a First vector. * @param b Second vector. * @return a.b scalar product. */ inline friend double operator * (FTPoint &a, FTPoint& b) { return a.values[0] * b.values[0] + a.values[1] * b.values[1] + a.values[2] * b.values[2]; } /** * Operator ^ Vector product * * @param point Second point * @return this vector point. */ inline FTPoint operator ^ (const FTPoint& point) { FTPoint temp; temp.values[0] = values[1] * point.values[2] - values[2] * point.values[1]; temp.values[1] = values[2] * point.values[0] - values[0] * point.values[2]; temp.values[2] = values[0] * point.values[1] - values[1] * point.values[0]; return temp; } /** * Operator == Tests for equality * * @param a * @param b * @return true if a & b are equal */ friend bool operator == (const FTPoint &a, const FTPoint &b); /** * Operator != Tests for non equality * * @param a * @param b * @return true if a & b are not equal */ friend bool operator != (const FTPoint &a, const FTPoint &b); /** * Cast to FTGL_DOUBLE* */ inline operator const FTGL_DOUBLE*() const { return values; } /** * Setters */ inline void X(FTGL_DOUBLE x) { values[0] = x; }; inline void Y(FTGL_DOUBLE y) { values[1] = y; }; inline void Z(FTGL_DOUBLE z) { values[2] = z; }; /** * Getters */ inline FTGL_DOUBLE X() const { return values[0]; }; inline FTGL_DOUBLE Y() const { return values[1]; }; inline FTGL_DOUBLE Z() const { return values[2]; }; inline FTGL_FLOAT Xf() const { return static_cast(values[0]); }; inline FTGL_FLOAT Yf() const { return static_cast(values[1]); }; inline FTGL_FLOAT Zf() const { return static_cast(values[2]); }; private: /** * The point data */ FTGL_DOUBLE values[3]; }; #endif //__cplusplus #endif // __FTPoint__ critterding-beta12.1/src/utils/ftgl/FTGL/FTGLPolygonFont.h0000644000175000017500000000614411147116040022260 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTPolygonFont__ #define __FTPolygonFont__ #ifdef __cplusplus /** * FTPolygonFont is a specialisation of the FTFont class for handling * tesselated Polygon Mesh fonts * * @see FTFont */ class FTGL_EXPORT FTPolygonFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTPolygonFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTPolygonFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ ~FTPolygonFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #define FTGLPolygonFont FTPolygonFont #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling tesselated polygon * mesh fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont */ FTGL_EXPORT FTGLfont *ftglCreatePolygonFont(const char *file); FTGL_END_C_DECLS #endif // __FTPolygonFont__ critterding-beta12.1/src/utils/ftgl/FTGL/FTGLExtrdFont.h0000644000175000017500000000617711147116040021725 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTExtrudeFont__ #define __FTExtrudeFont__ #ifdef __cplusplus /** * FTExtrudeFont is a specialisation of the FTFont class for handling * extruded Polygon fonts * * @see FTFont * @see FTPolygonFont */ class FTGL_EXPORT FTExtrudeFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTExtrudeFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTExtrudeFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ ~FTExtrudeFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #define FTGLExtrdFont FTExtrudeFont #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling extruded poygon fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont * @see ftglCreatePolygonFont */ FTGL_EXPORT FTGLfont *ftglCreateExtrudeFont(const char *file); FTGL_END_C_DECLS #endif // __FTExtrudeFont__ critterding-beta12.1/src/utils/ftgl/FTGL/FTBufferGlyph.h0000644000175000017500000000426211147116040021773 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __ftgl__ # warning Please use instead of . # include #endif #ifndef __FTBufferGlyph__ #define __FTBufferGlyph__ #ifdef __cplusplus /** * FTBufferGlyph is a specialisation of FTGlyph for memory buffer rendering. */ class FTGL_EXPORT FTBufferGlyph : public FTGlyph { public: /** * Constructor * * @param glyph The Freetype glyph to be processed * @param buffer An FTBuffer object in which to render the glyph. */ FTBufferGlyph(FT_GlyphSlot glyph, FTBuffer *buffer); /** * Destructor */ virtual ~FTBufferGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #endif //__cplusplus #endif // __FTBufferGlyph__ critterding-beta12.1/src/utils/ftgl/FTGL/FTGLBitmapFont.h0000644000175000017500000000606311147116040022045 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTBitmapFont__ #define __FTBitmapFont__ #ifdef __cplusplus /** * FTBitmapFont is a specialisation of the FTFont class for handling * Bitmap fonts * * @see FTFont */ class FTGL_EXPORT FTBitmapFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTBitmapFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTBitmapFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ ~FTBitmapFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #define FTGLBitmapFont FTBitmapFont #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling bitmap fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont */ FTGL_EXPORT FTGLfont *ftglCreateBitmapFont(const char *file); FTGL_END_C_DECLS #endif // __FTBitmapFont__ critterding-beta12.1/src/utils/ftgl/FTGL/FTFont.h0000644000175000017500000004730311147116040020467 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTFont__ #define __FTFont__ #ifdef __cplusplus class FTFontImpl; /** * FTFont is the public interface for the FTGL library. * * Specific font classes are derived from this class. It uses the helper * classes FTFace and FTSize to access the Freetype library. This class * is abstract and deriving classes must implement the protected * MakeGlyph function to create glyphs of the * appropriate type. * * It is good practice after using these functions to test the error * code returned. FT_Error Error(). Check the freetype file * fterrdef.h for error definitions. * * @see FTFace * @see FTSize */ class FTGL_EXPORT FTFont { protected: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTFont(char const *fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); private: /* Allow our internal subclasses to access the private constructor */ friend class FTBitmapFont; friend class FTBufferFont; friend class FTExtrudeFont; friend class FTOutlineFont; friend class FTPixmapFont; friend class FTPolygonFont; friend class FTTextureFont; /** * Internal FTGL FTFont constructor. For private use only. * * @param pImpl Internal implementation object. Will be destroyed * upon FTFont deletion. */ FTFont(FTFontImpl *pImpl); public: virtual ~FTFont(); /** * Attach auxilliary file to font e.g font metrics. * * Note: not all font formats implement this function. * * @param fontFilePath auxilliary font file path. * @return true if file has been attached * successfully. */ virtual bool Attach(const char* fontFilePath); /** * Attach auxilliary data to font e.g font metrics, from memory. * * Note: not all font formats implement this function. * * @param pBufferBytes the in-memory buffer. * @param bufferSizeInBytes the length of the buffer in bytes. * @return true if file has been attached * successfully. */ virtual bool Attach(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Set the glyph loading flags. By default, fonts use the most * sensible flags when loading a font's glyph using FT_Load_Glyph(). * This function allows to override the default flags. * * @param flags The glyph loading flags. */ virtual void GlyphLoadFlags(FT_Int flags); /** * Set the character map for the face. * * @param encoding Freetype enumerate for char map code. * @return true if charmap was valid and * set correctly. */ virtual bool CharMap(FT_Encoding encoding); /** * Get the number of character maps in this face. * * @return character map count. */ virtual unsigned int CharMapCount() const; /** * Get a list of character maps in this face. * * @return pointer to the first encoding. */ virtual FT_Encoding* CharMapList(); /** * Set the char size for the current face. * * @param size the face size in points (1/72 inch) * @param res the resolution of the target device. * @return true if size was set correctly */ virtual bool FaceSize(const unsigned int size, const unsigned int res = 72); /** * Get the current face size in points (1/72 inch). * * @return face size */ virtual unsigned int FaceSize() const; /** * Set the extrusion distance for the font. Only implemented by * FTExtrudeFont * * @param depth The extrusion distance. */ virtual void Depth(float depth); /** * Set the outset distance for the font. Only implemented by * FTOutlineFont, FTPolygonFont and FTExtrudeFont * * @param outset The outset distance. */ virtual void Outset(float outset); /** * Set the front and back outset distances for the font. Only * implemented by FTExtrudeFont * * @param front The front outset distance. * @param back The back outset distance. */ virtual void Outset(float front, float back); /** * Enable or disable the use of Display Lists inside FTGL * * @param useList true turns ON display lists. * false turns OFF display lists. */ virtual void UseDisplayList(bool useList); /** * Get the global ascender height for the face. * * @return Ascender height */ virtual float Ascender() const; /** * Gets the global descender height for the face. * * @return Descender height */ virtual float Descender() const; /** * Gets the line spacing for the font. * * @return Line height */ virtual float LineHeight() const; /** * Get the bounding box for a string. * * @param string A char buffer. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param spacing A displacement vector to add after each character * has been checked (optional). * @return The corresponding bounding box. */ virtual FTBBox BBox(const char *string, const int len = -1, FTPoint position = FTPoint(), FTPoint spacing = FTPoint()); /** * Get the bounding box for a string (deprecated). * * @param string A char buffer. * @param llx Lower left near x coordinate. * @param lly Lower left near y coordinate. * @param llz Lower left near z coordinate. * @param urx Upper right far x coordinate. * @param ury Upper right far y coordinate. * @param urz Upper right far z coordinate. */ void BBox(const char* string, float& llx, float& lly, float& llz, float& urx, float& ury, float& urz) { FTBBox b = BBox(string); llx = b.Lower().Xf(); lly = b.Lower().Yf(); llz = b.Lower().Zf(); urx = b.Upper().Xf(); ury = b.Upper().Yf(); urz = b.Upper().Zf(); } /** * Get the bounding box for a string. * * @param string A wchar_t buffer. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param spacing A displacement vector to add after each character * has been checked (optional). * @return The corresponding bounding box. */ virtual FTBBox BBox(const wchar_t *string, const int len = -1, FTPoint position = FTPoint(), FTPoint spacing = FTPoint()); /** * Get the bounding box for a string (deprecated). * * @param string A wchar_t buffer. * @param llx Lower left near x coordinate. * @param lly Lower left near y coordinate. * @param llz Lower left near z coordinate. * @param urx Upper right far x coordinate. * @param ury Upper right far y coordinate. * @param urz Upper right far z coordinate. */ void BBox(const wchar_t* string, float& llx, float& lly, float& llz, float& urx, float& ury, float& urz) { FTBBox b = BBox(string); llx = b.Lower().Xf(); lly = b.Lower().Yf(); llz = b.Lower().Zf(); urx = b.Upper().Xf(); ury = b.Upper().Yf(); urz = b.Upper().Zf(); } /** * Get the advance for a string. * * @param string 'C' style string to be checked. * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param spacing A displacement vector to add after each character * has been checked (optional). * @return The string's advance width. */ virtual float Advance(const char* string, const int len = -1, FTPoint spacing = FTPoint()); /** * Get the advance for a string. * * @param string A wchar_t string * @param len The length of the string. If < 0 then all characters * will be checked until a null character is encountered * (optional). * @param spacing A displacement vector to add after each character * has been checked (optional). * @return The string's advance width. */ virtual float Advance(const wchar_t* string, const int len = -1, FTPoint spacing = FTPoint()); /** * Render a string of characters. * * @param string 'C' style string to be output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param spacing A displacement vector to add after each character * has been displayed (optional). * @param renderMode Render mode to use for display (optional). * @return The new pen position after the last character was output. */ virtual FTPoint Render(const char* string, const int len = -1, FTPoint position = FTPoint(), FTPoint spacing = FTPoint(), int renderMode = FTGL::RENDER_ALL); /** * Render a string of characters * * @param string wchar_t string to be output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered * (optional). * @param position The pen position of the first character (optional). * @param spacing A displacement vector to add after each character * has been displayed (optional). * @param renderMode Render mode to use for display (optional). * @return The new pen position after the last character was output. */ virtual FTPoint Render(const wchar_t *string, const int len = -1, FTPoint position = FTPoint(), FTPoint spacing = FTPoint(), int renderMode = FTGL::RENDER_ALL); /** * Queries the Font for errors. * * @return The current error code. */ virtual FT_Error Error() const; protected: /* Allow impl to access MakeGlyph */ friend class FTFontImpl; /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot) = 0; private: /** * Internal FTGL FTFont implementation object. For private use only. */ FTFontImpl *impl; }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * FTGLfont is the public interface for the FTGL library. * * It is good practice after using these functions to test the error * code returned. FT_Error Error(). Check the freetype file * fterrdef.h for error definitions. */ struct _FTGLFont; typedef struct _FTGLfont FTGLfont; /** * Create a custom FTGL font object. * * @param fontFilePath The font file name. * @param data A pointer to private data that will be passed to callbacks. * @param makeglyphCallback A glyph-making callback function. * @return An FTGLfont* object. */ FTGL_EXPORT FTGLfont *ftglCreateCustomFont(char const *fontFilePath, void *data, FTGLglyph * (*makeglyphCallback) (FT_GlyphSlot, void *)); /** * Destroy an FTGL font object. * * @param font An FTGLfont* object. */ FTGL_EXPORT void ftglDestroyFont(FTGLfont* font); /** * Attach auxilliary file to font e.g. font metrics. * * Note: not all font formats implement this function. * * @param font An FTGLfont* object. * @param path Auxilliary font file path. * @return 1 if file has been attached successfully. */ FTGL_EXPORT int ftglAttachFile(FTGLfont* font, const char* path); /** * Attach auxilliary data to font, e.g. font metrics, from memory. * * Note: not all font formats implement this function. * * @param font An FTGLfont* object. * @param data The in-memory buffer. * @param size The length of the buffer in bytes. * @return 1 if file has been attached successfully. */ FTGL_EXPORT int ftglAttachData(FTGLfont* font, const unsigned char * data, size_t size); /** * Set the character map for the face. * * @param font An FTGLfont* object. * @param encoding Freetype enumerate for char map code. * @return 1 if charmap was valid and set correctly. */ FTGL_EXPORT int ftglSetFontCharMap(FTGLfont* font, FT_Encoding encoding); /** * Get the number of character maps in this face. * * @param font An FTGLfont* object. * @return character map count. */ FTGL_EXPORT unsigned int ftglGetFontCharMapCount(FTGLfont* font); /** * Get a list of character maps in this face. * * @param font An FTGLfont* object. * @return pointer to the first encoding. */ FTGL_EXPORT FT_Encoding* ftglGetFontCharMapList(FTGLfont* font); /** * Set the char size for the current face. * * @param font An FTGLfont* object. * @param size The face size in points (1/72 inch). * @param res The resolution of the target device, or 0 to use the default * value of 72. * @return 1 if size was set correctly. */ FTGL_EXPORT int ftglSetFontFaceSize(FTGLfont* font, unsigned int size, unsigned int res); /** * Get the current face size in points (1/72 inch). * * @param font An FTGLfont* object. * @return face size */ FTGL_EXPORT unsigned int ftglGetFontFaceSize(FTGLfont* font); /** * Set the extrusion distance for the font. Only implemented by * FTExtrudeFont. * * @param font An FTGLfont* object. * @param depth The extrusion distance. */ FTGL_EXPORT void ftglSetFontDepth(FTGLfont* font, float depth); /** * Set the outset distance for the font. Only FTOutlineFont, FTPolygonFont * and FTExtrudeFont implement front outset. Only FTExtrudeFont implements * back outset. * * @param font An FTGLfont* object. * @param front The front outset distance. * @param back The back outset distance. */ FTGL_EXPORT void ftglSetFontOutset(FTGLfont* font, float front, float back); /** * Enable or disable the use of Display Lists inside FTGL. * * @param font An FTGLfont* object. * @param useList 1 turns ON display lists. * 0 turns OFF display lists. */ FTGL_EXPORT void ftglSetFontDisplayList(FTGLfont* font, int useList); /** * Get the global ascender height for the face. * * @param font An FTGLfont* object. * @return Ascender height */ FTGL_EXPORT float ftglGetFontAscender(FTGLfont* font); /** * Gets the global descender height for the face. * * @param font An FTGLfont* object. * @return Descender height */ FTGL_EXPORT float ftglGetFontDescender(FTGLfont* font); /** * Gets the line spacing for the font. * * @param font An FTGLfont* object. * @return Line height */ FTGL_EXPORT float ftglGetFontLineHeight(FTGLfont* font); /** * Get the bounding box for a string. * * @param font An FTGLfont* object. * @param string A char buffer * @param len The length of the string. If < 0 then all characters will be * checked until a null character is encountered (optional). * @param bounds An array of 6 float values where the bounding box's lower * left near and upper right far 3D coordinates will be stored. */ FTGL_EXPORT void ftglGetFontBBox(FTGLfont* font, const char *string, int len, float bounds[6]); /** * Get the advance width for a string. * * @param font An FTGLfont* object. * @param string A char string. * @return Advance width */ FTGL_EXPORT float ftglGetFontAdvance(FTGLfont* font, const char *string); /** * Render a string of characters. * * @param font An FTGLfont* object. * @param string Char string to be output. * @param mode Render mode to display. */ FTGL_EXPORT void ftglRenderFont(FTGLfont* font, const char *string, int mode); /** * Query a font for errors. * * @param font An FTGLfont* object. * @return The current error code. */ FTGL_EXPORT FT_Error ftglGetFontError(FTGLfont* font); FTGL_END_C_DECLS #endif // __FTFont__ critterding-beta12.1/src/utils/ftgl/FTGL/FTGLOutlineFont.h0000644000175000017500000000611511147116040022246 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTOutlineFont__ #define __FTOutlineFont__ #ifdef __cplusplus /** * FTOutlineFont is a specialisation of the FTFont class for handling * Vector Outline fonts * * @see FTFont */ class FTGL_EXPORT FTOutlineFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTOutlineFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTOutlineFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ ~FTOutlineFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #define FTGLOutlineFont FTOutlineFont #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling vector outline fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont */ FTGL_EXPORT FTGLfont *ftglCreateOutlineFont(const char *file); FTGL_END_C_DECLS #endif // __FTOutlineFont__ critterding-beta12.1/src/utils/ftgl/FTGL/FTBuffer.h0000644000175000017500000000637311147116040020774 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __ftgl__ # warning Please use instead of . # include #endif #ifndef __FTBuffer__ #define __FTBuffer__ #ifdef __cplusplus /** * FTBuffer is a helper class for pixel buffers. * * It provides the interface between FTBufferFont and FTBufferGlyph to * optimise rendering operations. * * @see FTBufferGlyph * @see FTBufferFont */ class FTGL_EXPORT FTBuffer { public: /** * Default constructor. */ FTBuffer(); /** * Destructor */ ~FTBuffer(); /** * Get the pen's position in the buffer. * * @return The pen's position as an FTPoint object. */ inline FTPoint Pos() const { return pos; } /** * Set the pen's position in the buffer. * * @param arg An FTPoint object with the desired pen's position. */ inline void Pos(FTPoint arg) { pos = arg; } /** * Set the buffer's size. * * @param w The buffer's desired width, in pixels. * @param h The buffer's desired height, in pixels. */ void Size(int w, int h); /** * Get the buffer's width. * * @return The buffer's width, in pixels. */ inline int Width() const { return width; } /** * Get the buffer's height. * * @return The buffer's height, in pixels. */ inline int Height() const { return height; } /** * Get the buffer's direct pixel buffer. * * @return A read-write pointer to the buffer's pixels. */ inline unsigned char *Pixels() const { return pixels; } private: /** * Buffer's width and height. */ int width, height; /** * Buffer's pixel buffer. */ unsigned char *pixels; /** * Buffer's internal pen position. */ FTPoint pos; }; #endif //__cplusplus #endif // __FTBuffer__ critterding-beta12.1/src/utils/ftgl/FTGL/FTPixmapGlyph.h0000644000175000017500000000472611147116040022025 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTPixmapGlyph__ #define __FTPixmapGlyph__ #ifdef __cplusplus /** * FTPixmapGlyph is a specialisation of FTGlyph for creating pixmaps. */ class FTGL_EXPORT FTPixmapGlyph : public FTGlyph { public: /** * Constructor * * @param glyph The Freetype glyph to be processed */ FTPixmapGlyph(FT_GlyphSlot glyph); /** * Destructor */ virtual ~FTPixmapGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialisation of FTGLglyph for creating pixmaps. * * @param glyph The Freetype glyph to be processed * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreatePixmapGlyph(FT_GlyphSlot glyph); FTGL_END_C_DECLS #endif // __FTPixmapGlyph__ critterding-beta12.1/src/utils/ftgl/FTGL/FTBitmapGlyph.h0000644000175000017500000000472511147116040022002 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTBitmapGlyph__ #define __FTBitmapGlyph__ #ifdef __cplusplus /** * FTBitmapGlyph is a specialisation of FTGlyph for creating bitmaps. */ class FTGL_EXPORT FTBitmapGlyph : public FTGlyph { public: /** * Constructor * * @param glyph The Freetype glyph to be processed */ FTBitmapGlyph(FT_GlyphSlot glyph); /** * Destructor */ virtual ~FTBitmapGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialisation of FTGLglyph for creating bitmaps. * * @param glyph The Freetype glyph to be processed * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreateBitmapGlyph(FT_GlyphSlot glyph); FTGL_END_C_DECLS #endif // __FTBitmapGlyph__ critterding-beta12.1/src/utils/ftgl/FTGL/ftgl.h0000644000175000017500000001002611147116040020253 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ #define __ftgl__ /* We need the Freetype headers */ #include #include FT_FREETYPE_H #include FT_GLYPH_H #include FT_OUTLINE_H /* Floating point types used by the library */ typedef double FTGL_DOUBLE; typedef float FTGL_FLOAT; /* Macros used to declare C-linkage types and symbols */ #ifdef __cplusplus # define FTGL_BEGIN_C_DECLS extern "C" { namespace FTGL { # define FTGL_END_C_DECLS } } #else # define FTGL_BEGIN_C_DECLS # define FTGL_END_C_DECLS #endif #ifdef __cplusplus namespace FTGL { typedef enum { RENDER_FRONT = 0x0001, RENDER_BACK = 0x0002, RENDER_SIDE = 0x0004, RENDER_ALL = 0xffff } RenderMode; typedef enum { ALIGN_LEFT = 0, ALIGN_CENTER = 1, ALIGN_RIGHT = 2, ALIGN_JUSTIFY = 3 } TextAlignment; } #else # define FTGL_RENDER_FRONT 0x0001 # define FTGL_RENDER_BACK 0x0002 # define FTGL_RENDER_SIDE 0x0004 # define FTGL_RENDER_ALL 0xffff # define FTGL_ALIGN_LEFT 0 # define FTGL_ALIGN_CENTER 1 # define FTGL_ALIGN_RIGHT 2 # define FTGL_ALIGN_JUSTIFY 3 #endif // Compiler-specific conditional compilation #ifdef _MSC_VER // MS Visual C++ // Disable various warning. // 4786: template name too long #pragma warning(disable : 4251) #pragma warning(disable : 4275) #pragma warning(disable : 4786) // The following definitions control how symbols are exported. // If the target is a static library ensure that FTGL_LIBRARY_STATIC // is defined. If building a dynamic library (ie DLL) ensure the // FTGL_LIBRARY macro is defined, as it will mark symbols for // export. If compiling a project to _use_ the _dynamic_ library // version of the library, no definition is required. #ifdef FTGL_LIBRARY_STATIC // static lib - no special export required # define FTGL_EXPORT #elif FTGL_LIBRARY // dynamic lib - must export/import symbols appropriately. # define FTGL_EXPORT __declspec(dllexport) #else # define FTGL_EXPORT __declspec(dllimport) #endif #else // Compiler that is not MS Visual C++. // Ensure that the export symbol is defined (and blank) #define FTGL_EXPORT #endif #include "FTPoint.h" #include "FTBBox.h" #include "FTBuffer.h" #include "FTGlyph.h" #include "FTBitmapGlyph.h" #include "FTBufferGlyph.h" #include "FTExtrdGlyph.h" #include "FTOutlineGlyph.h" #include "FTPixmapGlyph.h" #include "FTPolyGlyph.h" #include "FTTextureGlyph.h" #include "FTFont.h" #include "FTGLBitmapFont.h" #include "FTBufferFont.h" #include "FTGLExtrdFont.h" #include "FTGLOutlineFont.h" #include "FTGLPixmapFont.h" #include "FTGLPolygonFont.h" #include "FTGLTextureFont.h" #include "FTLayout.h" #include "FTSimpleLayout.h" #endif // __ftgl__ critterding-beta12.1/src/utils/ftgl/FTGL/FTBufferFont.h0000644000175000017500000000563411147116040021622 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __ftgl__ # warning Please use instead of . # include #endif #ifndef __FTBufferFont__ #define __FTBufferFont__ #ifdef __cplusplus /** * FTBufferFont is a specialisation of the FTFont class for handling * memory buffer fonts. * * @see FTFont */ class FTGL_EXPORT FTBufferFont : public FTFont { public: /** * Open and read a font file. Sets Error flag. * * @param fontFilePath font file path. */ FTBufferFont(const char* fontFilePath); /** * Open and read a font from a buffer in memory. Sets Error flag. * The buffer is owned by the client and is NOT copied by FTGL. The * pointer must be valid while using FTGL. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTBufferFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Destructor */ ~FTBufferFont(); protected: /** * Construct a glyph of the correct type. * * Clients must override the function and return their specialised * FTGlyph. * * @param slot A FreeType glyph slot. * @return An FT****Glyph or null on failure. */ virtual FTGlyph* MakeGlyph(FT_GlyphSlot slot); }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialised FTGLfont object for handling memory buffer fonts. * * @param file The font file name. * @return An FTGLfont* object. * * @see FTGLfont */ FTGL_EXPORT FTGLfont *ftglCreateBufferFont(const char *file); FTGL_END_C_DECLS #endif // __FTBufferFont__ critterding-beta12.1/src/utils/ftgl/FTGL/FTTextureGlyph.h0000644000175000017500000000677711147116040022237 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTTextureGlyph__ #define __FTTextureGlyph__ #ifdef __cplusplus /** * FTTextureGlyph is a specialisation of FTGlyph for creating texture * glyphs. */ class FTGL_EXPORT FTTextureGlyph : public FTGlyph { public: /** * Constructor * * @param glyph The Freetype glyph to be processed * @param id The id of the texture that this glyph will be * drawn in * @param xOffset The x offset into the parent texture to draw * this glyph * @param yOffset The y offset into the parent texture to draw * this glyph * @param width The width of the parent texture * @param height The height (number of rows) of the parent texture */ FTTextureGlyph(FT_GlyphSlot glyph, int id, int xOffset, int yOffset, int width, int height); /** * Destructor */ virtual ~FTTextureGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialisation of FTGLglyph for creating pixmaps. * * @param glyph The Freetype glyph to be processed. * @param id The id of the texture that this glyph will be drawn in. * @param xOffset The x offset into the parent texture to draw this glyph. * @param yOffset The y offset into the parent texture to draw this glyph. * @param width The width of the parent texture. * @param height The height (number of rows) of the parent texture. * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreateTextureGlyph(FT_GlyphSlot glyph, int id, int xOffset, int yOffset, int width, int height); FTGL_END_C_DECLS #endif // __FTTextureGlyph__ critterding-beta12.1/src/utils/ftgl/FTGL/FTBBox.h0000644000175000017500000001177711147116040020421 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTBBox__ #define __FTBBox__ #ifdef __cplusplus /** * FTBBox is a convenience class for handling bounding boxes. */ class FTGL_EXPORT FTBBox { public: /** * Default constructor. Bounding box is set to zero. */ FTBBox() : lower(0.0f, 0.0f, 0.0f), upper(0.0f, 0.0f, 0.0f) {} /** * Constructor. */ FTBBox(float lx, float ly, float lz, float ux, float uy, float uz) : lower(lx, ly, lz), upper(ux, uy, uz) {} /** * Constructor. */ FTBBox(FTPoint l, FTPoint u) : lower(l), upper(u) {} /** * Constructor. Extracts a bounding box from a freetype glyph. Uses * the control box for the glyph. FT_Glyph_Get_CBox() * * @param glyph A freetype glyph */ FTBBox(FT_GlyphSlot glyph) : lower(0.0f, 0.0f, 0.0f), upper(0.0f, 0.0f, 0.0f) { FT_BBox bbox; FT_Outline_Get_CBox(&(glyph->outline), &bbox); lower.X(static_cast(bbox.xMin) / 64.0f); lower.Y(static_cast(bbox.yMin) / 64.0f); lower.Z(0.0f); upper.X(static_cast(bbox.xMax) / 64.0f); upper.Y(static_cast(bbox.yMax) / 64.0f); upper.Z(0.0f); } /** * Destructor */ ~FTBBox() {} /** * Mark the bounds invalid by setting all lower dimensions greater * than the upper dimensions. */ void Invalidate() { lower = FTPoint(1.0f, 1.0f, 1.0f); upper = FTPoint(-1.0f, -1.0f, -1.0f); } /** * Determines if this bounding box is valid. * * @return True if all lower values are <= the corresponding * upper values. */ bool IsValid() { return lower.X() <= upper.X() && lower.Y() <= upper.Y() && lower.Z() <= upper.Z(); } /** * Move the Bounding Box by a vector. * * @param vector The vector to move the bbox in 3D space. */ FTBBox& operator += (const FTPoint vector) { lower += vector; upper += vector; return *this; } /** * Combine two bounding boxes. The result is the smallest bounding * box containing the two original boxes. * * @param bbox The bounding box to merge with the second one. */ FTBBox& operator |= (const FTBBox& bbox) { if(bbox.lower.X() < lower.X()) lower.X(bbox.lower.X()); if(bbox.lower.Y() < lower.Y()) lower.Y(bbox.lower.Y()); if(bbox.lower.Z() < lower.Z()) lower.Z(bbox.lower.Z()); if(bbox.upper.X() > upper.X()) upper.X(bbox.upper.X()); if(bbox.upper.Y() > upper.Y()) upper.Y(bbox.upper.Y()); if(bbox.upper.Z() > upper.Z()) upper.Z(bbox.upper.Z()); return *this; } void SetDepth(float depth) { if(depth > 0) upper.Z(lower.Z() + depth); else lower.Z(upper.Z() + depth); } inline FTPoint const Upper() const { return upper; } inline FTPoint const Lower() const { return lower; } private: /** * The bounds of the box */ FTPoint lower, upper; }; #endif //__cplusplus #endif // __FTBBox__ critterding-beta12.1/src/utils/ftgl/FTGL/FTPolyGlyph.h0000644000175000017500000000651111147116040021504 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Sean Morrison * * 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. */ #ifndef __ftgl__ # warning This header is deprecated. Please use from now. # include #endif #ifndef __FTPolygonGlyph__ #define __FTPolygonGlyph__ #ifdef __cplusplus /** * FTPolygonGlyph is a specialisation of FTGlyph for creating tessellated * polygon glyphs. */ class FTGL_EXPORT FTPolygonGlyph : public FTGlyph { public: /** * Constructor. Sets the Error to Invalid_Outline if the glyphs * isn't an outline. * * @param glyph The Freetype glyph to be processed * @param outset The outset distance * @param useDisplayList Enable or disable the use of Display Lists * for this glyph * true turns ON display lists. * false turns OFF display lists. */ FTPolygonGlyph(FT_GlyphSlot glyph, float outset, bool useDisplayList); /** * Destructor */ virtual ~FTPolygonGlyph(); /** * Render this glyph at the current pen position. * * @param pen The current pen position. * @param renderMode Render mode to display * @return The advance distance for this glyph. */ virtual const FTPoint& Render(const FTPoint& pen, int renderMode); }; #define FTPolyGlyph FTPolygonGlyph #endif //__cplusplus FTGL_BEGIN_C_DECLS /** * Create a specialisation of FTGLglyph for creating tessellated * polygon glyphs. * * @param glyph The Freetype glyph to be processed * @param outset outset contour size * @param useDisplayList Enable or disable the use of Display Lists * for this glyph * true turns ON display lists. * false turns OFF display lists. * @return An FTGLglyph* object. */ FTGL_EXPORT FTGLglyph *ftglCreatePolygonGlyph(FT_GlyphSlot glyph, float outset, int useDisplayList); FTGL_END_C_DECLS #endif // __FTPolygonGlyph__ critterding-beta12.1/src/utils/ftgl/FTCharToGlyphIndexMap.h0000644000175000017500000001143211147116040022631 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * 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. */ #ifndef __FTCharToGlyphIndexMap__ #define __FTCharToGlyphIndexMap__ #include #include "FTGL/ftgl.h" /** * Provides a non-STL alternative to the STL map * which maps character codes to glyph indices inside FTCharmap. * * Implementation: * - NumberOfBuckets buckets are considered. * - Each bucket has BucketSize entries. * - When the glyph index for the character code C has to be stored, the * bucket this character belongs to is found using 'C div BucketSize'. * If this bucket has not been allocated yet, do it now. * The entry in the bucked is found using 'C mod BucketSize'. * If it is set to IndexNotFound, then the glyph entry has not been set. * - Try to mimic the calls made to the STL map API. * * Caveats: * - The glyph index is now a signed long instead of unsigned long, so * the special value IndexNotFound (= -1) can be used to specify that the * glyph index has not been stored yet. */ class FTCharToGlyphIndexMap { public: typedef unsigned long CharacterCode; typedef signed long GlyphIndex; enum { NumberOfBuckets = 256, BucketSize = 256, IndexNotFound = -1 }; FTCharToGlyphIndexMap() { this->Indices = 0; } virtual ~FTCharToGlyphIndexMap() { if(this->Indices) { // Free all buckets this->clear(); // Free main structure delete [] this->Indices; this->Indices = 0; } } void clear() { if(this->Indices) { for(int i = 0; i < FTCharToGlyphIndexMap::NumberOfBuckets; i++) { if(this->Indices[i]) { delete [] this->Indices[i]; this->Indices[i] = 0; } } } } const GlyphIndex find(CharacterCode c) { if(!this->Indices) { return 0; } // Find position of char code in buckets div_t pos = div(c, FTCharToGlyphIndexMap::BucketSize); if(!this->Indices[pos.quot]) { return 0; } const FTCharToGlyphIndexMap::GlyphIndex *ptr = &this->Indices[pos.quot][pos.rem]; if(*ptr == FTCharToGlyphIndexMap::IndexNotFound) { return 0; } return *ptr; } void insert(CharacterCode c, GlyphIndex g) { if(!this->Indices) { this->Indices = new GlyphIndex* [FTCharToGlyphIndexMap::NumberOfBuckets]; for(int i = 0; i < FTCharToGlyphIndexMap::NumberOfBuckets; i++) { this->Indices[i] = 0; } } // Find position of char code in buckets div_t pos = div(c, FTCharToGlyphIndexMap::BucketSize); // Allocate bucket if does not exist yet if(!this->Indices[pos.quot]) { this->Indices[pos.quot] = new GlyphIndex [FTCharToGlyphIndexMap::BucketSize]; for(int i = 0; i < FTCharToGlyphIndexMap::BucketSize; i++) { this->Indices[pos.quot][i] = FTCharToGlyphIndexMap::IndexNotFound; } } this->Indices[pos.quot][pos.rem] = g; } private: GlyphIndex** Indices; }; #endif // __FTCharToGlyphIndexMap__ critterding-beta12.1/src/utils/ftgl/FTPoint.cpp0000644000175000017500000000363211147116040020446 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include #include "FTGL/ftgl.h" bool operator == (const FTPoint &a, const FTPoint &b) { return((a.values[0] == b.values[0]) && (a.values[1] == b.values[1]) && (a.values[2] == b.values[2])); } bool operator != (const FTPoint &a, const FTPoint &b) { return((a.values[0] != b.values[0]) || (a.values[1] != b.values[1]) || (a.values[2] != b.values[2])); } FTPoint FTPoint::Normalise() { double norm = sqrt(values[0] * values[0] + values[1] * values[1] + values[2] * values[2]); if(norm == 0.0) { return *this; } FTPoint temp(values[0] / norm, values[1] / norm, values[2] / norm); return temp; } critterding-beta12.1/src/utils/ftgl/FTBuffer.cpp0000644000175000017500000000324211147116040020563 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include "FTGL/ftgl.h" FTBuffer::FTBuffer() : width(0), height(0), pixels(0), pos(FTPoint()) { } FTBuffer::~FTBuffer() { if(pixels) { delete[] pixels; } } void FTBuffer::Size(int w, int h) { if(w == width && h == height) { return; } if(w * h != width * height) { if(pixels) { delete[] pixels; } pixels = new unsigned char[w * h]; } memset(pixels, 0, w * h); width = w; height = h; } critterding-beta12.1/src/utils/ftgl/FTLibrary.h0000644000175000017500000000750111147116040020425 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * 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. */ #ifndef __FTLibrary__ #define __FTLibrary__ #include #include FT_FREETYPE_H //#include FT_CACHE_H #include "FTGL/ftgl.h" /** * FTLibrary class is the global accessor for the Freetype library. * * This class encapsulates the Freetype Library. This is a singleton class * and ensures that only one FT_Library is in existence at any one time. * All constructors are private therefore clients cannot create or * instantiate this class themselves and must access it's methods via the * static FTLibrary::Instance() function. * * Just because this class returns a valid FTLibrary object * doesn't mean that the Freetype Library has been successfully initialised. * Clients should check for errors. You can initialse the library AND check * for errors using the following code... * err = FTLibrary::Instance().Error(); * * @see "Freetype 2 Documentation" * */ class FTLibrary { public: /** * Global acces point to the single FTLibrary object. * * @return The global FTLibrary object. */ static const FTLibrary& Instance(); /** * Gets a pointer to the native Freetype library. * * @return A handle to a FreeType library instance. */ const FT_Library* const GetLibrary() const { return library; } /** * Queries the library for errors. * * @return The current error code. */ FT_Error Error() const { return err; } /** * Destructor * * Disposes of the Freetype library */ ~FTLibrary(); private: /** * Default constructors. * * Made private to stop clients creating there own FTLibrary * objects. */ FTLibrary(); FTLibrary(const FT_Library&){} FTLibrary& operator=(const FT_Library&) { return *this; } /** * Initialises the Freetype library * * Even though this function indicates success via the return value, * clients can't see this so must check the error codes. This function * is only ever called by the default c_stor * * @return true if the Freetype library was * successfully initialised, false * otherwise. */ bool Initialise(); /** * Freetype library handle. */ FT_Library* library; // FTC_Manager* manager; /** * Current error code. Zero means no error. */ FT_Error err; }; #endif // __FTLibrary__ critterding-beta12.1/src/utils/ftgl/FTSize.cpp0000644000175000017500000000560711147116040020273 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * 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. */ #include "config.h" #include "FTSize.h" FTSize::FTSize() : ftFace(0), ftSize(0), size(0), xResolution(0), yResolution(0), err(0) {} FTSize::~FTSize() {} bool FTSize::CharSize(FT_Face* face, unsigned int pointSize, unsigned int xRes, unsigned int yRes) { if(size != pointSize || xResolution != xRes || yResolution != yRes) { err = FT_Set_Char_Size(*face, 0L, pointSize * 64, xResolution, yResolution); if(!err) { ftFace = face; size = pointSize; xResolution = xRes; yResolution = yRes; ftSize = (*ftFace)->size; } } return !err; } unsigned int FTSize::CharSize() const { return size; } float FTSize::Ascender() const { return ftSize == 0 ? 0.0f : static_cast(ftSize->metrics.ascender) / 64.0f; } float FTSize::Descender() const { return ftSize == 0 ? 0.0f : static_cast(ftSize->metrics.descender) / 64.0f; } float FTSize::Height() const { if(0 == ftSize) { return 0.0f; } if(FT_IS_SCALABLE((*ftFace))) { return ((*ftFace)->bbox.yMax - (*ftFace)->bbox.yMin) * ((float)ftSize->metrics.y_ppem / (float)(*ftFace)->units_per_EM); } else { return static_cast(ftSize->metrics.height) / 64.0f; } } float FTSize::Width() const { if(0 == ftSize) { return 0.0f; } if(FT_IS_SCALABLE((*ftFace))) { return ((*ftFace)->bbox.xMax - (*ftFace)->bbox.xMin) * (static_cast(ftSize->metrics.x_ppem) / static_cast((*ftFace)->units_per_EM)); } else { return static_cast(ftSize->metrics.max_advance) / 64.0f; } } float FTSize::Underline() const { return 0.0f; } critterding-beta12.1/src/utils/ftgl/FTContour.h0000644000175000017500000001431511147116040020453 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTContour__ #define __FTContour__ #include "FTGL/ftgl.h" #include "FTVector.h" /** * FTContour class is a container of points that describe a vector font * outline. It is used as a container for the output of the bezier curve * evaluator in FTVectoriser. * * @see FTOutlineGlyph * @see FTPolygonGlyph * @see FTPoint */ class FTContour { public: /** * Constructor * * @param contour * @param pointTags * @param numberOfPoints */ FTContour(FT_Vector* contour, char* pointTags, unsigned int numberOfPoints); /** * Destructor */ ~FTContour() { pointList.clear(); outsetPointList.clear(); frontPointList.clear(); backPointList.clear(); } /** * Return a point at index. * * @param index of the point in the curve. * @return const point reference */ const FTPoint& Point(size_t index) const { return pointList[index]; } /** * Return a point at index. * * @param index of the point in the outset curve. * @return const point reference */ const FTPoint& Outset(size_t index) const { return outsetPointList[index]; } /** * Return a point at index of the front outset contour. * * @param index of the point in the curve. * @return const point reference */ const FTPoint& FrontPoint(size_t index) const { if(frontPointList.size() == 0) return Point(index); return frontPointList[index]; } /** * Return a point at index of the back outset contour. * * @param index of the point in the curve. * @return const point reference */ const FTPoint& BackPoint(size_t index) const { if(backPointList.size() == 0) return Point(index); return backPointList[index]; } /** * How many points define this contour * * @return the number of points in this contour */ size_t PointCount() const { return pointList.size(); } /** * Make sure the glyph has the proper parity and create the front/back * outset contour. * * @param parity The contour's parity within the glyph. */ void SetParity(int parity); // FIXME: this should probably go away. void buildFrontOutset(float outset); void buildBackOutset(float outset); private: /** * Add a point to this contour. This function tests for duplicate * points. * * @param point The point to be added to the contour. */ inline void AddPoint(FTPoint point); /** * Add a point to this contour. This function tests for duplicate * points. * * @param point The point to be added to the contour. */ inline void AddOutsetPoint(FTPoint point); /* * Add a point to this outset contour. This function tests for duplicate * points. * * @param point The point to be added to the contour outset. */ inline void AddFrontPoint(FTPoint point); inline void AddBackPoint(FTPoint point); /** * De Casteljau (bezier) algorithm contributed by Jed Soane * Evaluates a quadratic or conic (second degree) curve */ inline void evaluateQuadraticCurve(FTPoint, FTPoint, FTPoint); /** * De Casteljau (bezier) algorithm contributed by Jed Soane * Evaluates a cubic (third degree) curve */ inline void evaluateCubicCurve(FTPoint, FTPoint, FTPoint, FTPoint); /** * Compute the vector norm */ inline FTGL_DOUBLE NormVector(const FTPoint &v); /** * Compute a rotation matrix from a vector */ inline void RotationMatrix(const FTPoint &a, const FTPoint &b, FTGL_DOUBLE *matRot, FTGL_DOUBLE *invRot); /** * Matrix and vector multiplication */ inline void MultMatrixVect(FTGL_DOUBLE *mat, FTPoint &v); /** * Compute the vector bisecting from a vector 'v' and a distance 'd' */ inline void ComputeBisec(FTPoint &v); /** * Compute the outset point coordinates */ inline FTPoint ComputeOutsetPoint(FTPoint a, FTPoint b, FTPoint c); /** * The list of points in this contour */ typedef FTVector PointVector; PointVector pointList; PointVector outsetPointList; PointVector frontPointList; PointVector backPointList; /** * Is this contour clockwise or anti-clockwise? */ bool clockwise; }; #endif // __FTContour__ critterding-beta12.1/src/utils/ftgl/FTContour.cpp0000644000175000017500000001625311147116040021011 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * Copyright (c) 2008 Éric Beets * * 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. */ #include "config.h" #include "FTContour.h" #include static const unsigned int BEZIER_STEPS = 5; void FTContour::AddPoint(FTPoint point) { if(pointList.empty() || (point != pointList[pointList.size() - 1] && point != pointList[0])) { pointList.push_back(point); } } void FTContour::AddOutsetPoint(FTPoint point) { outsetPointList.push_back(point); } void FTContour::AddFrontPoint(FTPoint point) { frontPointList.push_back(point); } void FTContour::AddBackPoint(FTPoint point) { backPointList.push_back(point); } void FTContour::evaluateQuadraticCurve(FTPoint A, FTPoint B, FTPoint C) { for(unsigned int i = 1; i < BEZIER_STEPS; i++) { float t = static_cast(i) / BEZIER_STEPS; FTPoint U = (1.0f - t) * A + t * B; FTPoint V = (1.0f - t) * B + t * C; AddPoint((1.0f - t) * U + t * V); } } void FTContour::evaluateCubicCurve(FTPoint A, FTPoint B, FTPoint C, FTPoint D) { for(unsigned int i = 0; i < BEZIER_STEPS; i++) { float t = static_cast(i) / BEZIER_STEPS; FTPoint U = (1.0f - t) * A + t * B; FTPoint V = (1.0f - t) * B + t * C; FTPoint W = (1.0f - t) * C + t * D; FTPoint M = (1.0f - t) * U + t * V; FTPoint N = (1.0f - t) * V + t * W; AddPoint((1.0f - t) * M + t * N); } } // This function is a bit tricky. Given a path ABC, it returns the // coordinates of the outset point facing B on the left at a distance // of 64.0. // M // - - - - - - X // ^ / ' // | 64.0 / ' // X---->-----X ==> X--v-------X ' // A B \ A B \ .>' // \ \<' 64.0 // \ \ . // \ \ . // C X C X // FTPoint FTContour::ComputeOutsetPoint(FTPoint A, FTPoint B, FTPoint C) { /* Build the rotation matrix from 'ba' vector */ FTPoint ba = (A - B).Normalise(); FTPoint bc = C - B; /* Rotate bc to the left */ FTPoint tmp(bc.X() * -ba.X() + bc.Y() * -ba.Y(), bc.X() * ba.Y() + bc.Y() * -ba.X()); /* Compute the vector bisecting 'abc' */ FTGL_DOUBLE norm = sqrt(tmp.X() * tmp.X() + tmp.Y() * tmp.Y()); FTGL_DOUBLE dist = 64.0 * sqrt((norm - tmp.X()) / (norm + tmp.X())); tmp.X(tmp.Y() < 0.0 ? dist : -dist); tmp.Y(64.0); /* Rotate the new bc to the right */ return FTPoint(tmp.X() * -ba.X() + tmp.Y() * ba.Y(), tmp.X() * -ba.Y() + tmp.Y() * -ba.X()); } void FTContour::SetParity(int parity) { size_t size = PointCount(); FTPoint vOutset; if(((parity & 1) && clockwise) || (!(parity & 1) && !clockwise)) { // Contour orientation is wrong! We must reverse all points. // FIXME: could it be worth writing FTVector::reverse() for this? for(size_t i = 0; i < size / 2; i++) { FTPoint tmp = pointList[i]; pointList[i] = pointList[size - 1 - i]; pointList[size - 1 -i] = tmp; } clockwise = !clockwise; } for(size_t i = 0; i < size; i++) { size_t prev, cur, next; prev = (i + size - 1) % size; cur = i; next = (i + size + 1) % size; vOutset = ComputeOutsetPoint(Point(prev), Point(cur), Point(next)); AddOutsetPoint(vOutset); } } FTContour::FTContour(FT_Vector* contour, char* tags, unsigned int n) { FTPoint prev, cur(contour[(n - 1) % n]), next(contour[0]); FTPoint a, b = next - cur; double olddir, dir = atan2((next - cur).Y(), (next - cur).X()); double angle = 0.0; // See http://freetype.sourceforge.net/freetype2/docs/glyphs/glyphs-6.html // for a full description of FreeType tags. for(unsigned int i = 0; i < n; i++) { prev = cur; cur = next; next = FTPoint(contour[(i + 1) % n]); olddir = dir; dir = atan2((next - cur).Y(), (next - cur).X()); // Compute our path's new direction. double t = dir - olddir; if(t < -M_PI) t += 2 * M_PI; if(t > M_PI) t -= 2 * M_PI; angle += t; // Only process point tags we know. if(n < 2 || FT_CURVE_TAG(tags[i]) == FT_Curve_Tag_On) { AddPoint(cur); } else if(FT_CURVE_TAG(tags[i]) == FT_Curve_Tag_Conic) { FTPoint prev2 = prev, next2 = next; // Previous point is either the real previous point (an "on" // point), or the midpoint between the current one and the // previous "conic off" point. if(FT_CURVE_TAG(tags[(i - 1 + n) % n]) == FT_Curve_Tag_Conic) { prev2 = (cur + prev) * 0.5; AddPoint(prev2); } // Next point is either the real next point or the midpoint. if(FT_CURVE_TAG(tags[(i + 1) % n]) == FT_Curve_Tag_Conic) { next2 = (cur + next) * 0.5; } evaluateQuadraticCurve(prev2, cur, next2); } else if(FT_CURVE_TAG(tags[i]) == FT_Curve_Tag_Cubic && FT_CURVE_TAG(tags[(i + 1) % n]) == FT_Curve_Tag_Cubic) { evaluateCubicCurve(prev, cur, next, FTPoint(contour[(i + 2) % n])); } } // If final angle is positive (+2PI), it's an anti-clockwise contour, // otherwise (-2PI) it's clockwise. clockwise = (angle < 0.0); } void FTContour::buildFrontOutset(float outset) { for(size_t i = 0; i < PointCount(); ++i) { AddFrontPoint(Point(i) + Outset(i) * outset); } } void FTContour::buildBackOutset(float outset) { for(size_t i = 0; i < PointCount(); ++i) { AddBackPoint(Point(i) + Outset(i) * outset); } } critterding-beta12.1/src/utils/ftgl/FTFace.cpp0000644000175000017500000001337211147116040020215 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include "FTFace.h" #include "FTLibrary.h" #include FT_TRUETYPE_TABLES_H FTFace::FTFace(const char* fontFilePath, bool precomputeKerning) : numGlyphs(0), fontEncodingList(0), kerningCache(0), err(0) { const FT_Long DEFAULT_FACE_INDEX = 0; ftFace = new FT_Face; err = FT_New_Face(*FTLibrary::Instance().GetLibrary(), fontFilePath, DEFAULT_FACE_INDEX, ftFace); if(err) { delete ftFace; ftFace = 0; return; } numGlyphs = (*ftFace)->num_glyphs; hasKerningTable = (FT_HAS_KERNING((*ftFace)) != 0); if(hasKerningTable && precomputeKerning) { BuildKerningCache(); } } FTFace::FTFace(const unsigned char *pBufferBytes, size_t bufferSizeInBytes, bool precomputeKerning) : numGlyphs(0), fontEncodingList(0), kerningCache(0), err(0) { const FT_Long DEFAULT_FACE_INDEX = 0; ftFace = new FT_Face; err = FT_New_Memory_Face(*FTLibrary::Instance().GetLibrary(), (FT_Byte const *)pBufferBytes, (FT_Long)bufferSizeInBytes, DEFAULT_FACE_INDEX, ftFace); if(err) { delete ftFace; ftFace = 0; return; } numGlyphs = (*ftFace)->num_glyphs; hasKerningTable = (FT_HAS_KERNING((*ftFace)) != 0); if(hasKerningTable && precomputeKerning) { BuildKerningCache(); } } FTFace::~FTFace() { if(kerningCache) { delete[] kerningCache; } if(ftFace) { FT_Done_Face(*ftFace); delete ftFace; ftFace = 0; } } bool FTFace::Attach(const char* fontFilePath) { err = FT_Attach_File(*ftFace, fontFilePath); return !err; } bool FTFace::Attach(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) { FT_Open_Args open; open.flags = FT_OPEN_MEMORY; open.memory_base = (FT_Byte const *)pBufferBytes; open.memory_size = (FT_Long)bufferSizeInBytes; err = FT_Attach_Stream(*ftFace, &open); return !err; } const FTSize& FTFace::Size(const unsigned int size, const unsigned int res) { charSize.CharSize(ftFace, size, res, res); err = charSize.Error(); return charSize; } unsigned int FTFace::CharMapCount() const { return (*ftFace)->num_charmaps; } FT_Encoding* FTFace::CharMapList() { if(0 == fontEncodingList) { fontEncodingList = new FT_Encoding[CharMapCount()]; for(size_t i = 0; i < CharMapCount(); ++i) { fontEncodingList[i] = (*ftFace)->charmaps[i]->encoding; } } return fontEncodingList; } FTPoint FTFace::KernAdvance(unsigned int index1, unsigned int index2) { float x, y; if(!hasKerningTable || !index1 || !index2) { return FTPoint(0.0f, 0.0f); } if(kerningCache && index1 < FTFace::MAX_PRECOMPUTED && index2 < FTFace::MAX_PRECOMPUTED) { x = kerningCache[2 * (index2 * FTFace::MAX_PRECOMPUTED + index1)]; y = kerningCache[2 * (index2 * FTFace::MAX_PRECOMPUTED + index1) + 1]; return FTPoint(x, y); } FT_Vector kernAdvance; kernAdvance.x = kernAdvance.y = 0; err = FT_Get_Kerning(*ftFace, index1, index2, ft_kerning_unfitted, &kernAdvance); if(err) { return FTPoint(0.0f, 0.0f); } x = static_cast(kernAdvance.x) / 64.0f; y = static_cast(kernAdvance.y) / 64.0f; return FTPoint(x, y); } FT_GlyphSlot FTFace::Glyph(unsigned int index, FT_Int load_flags) { err = FT_Load_Glyph(*ftFace, index, load_flags); if(err) { return NULL; } return (*ftFace)->glyph; } void FTFace::BuildKerningCache() { FT_Vector kernAdvance; kernAdvance.x = 0; kernAdvance.y = 0; kerningCache = new float[FTFace::MAX_PRECOMPUTED * FTFace::MAX_PRECOMPUTED * 2]; for(unsigned int j = 0; j < FTFace::MAX_PRECOMPUTED; j++) { for(unsigned int i = 0; i < FTFace::MAX_PRECOMPUTED; i++) { err = FT_Get_Kerning(*ftFace, i, j, ft_kerning_unfitted, &kernAdvance); if(err) { delete[] kerningCache; kerningCache = NULL; return; } kerningCache[2 * (j * FTFace::MAX_PRECOMPUTED + i)] = static_cast(kernAdvance.x) / 64.0f; kerningCache[2 * (j * FTFace::MAX_PRECOMPUTED + i) + 1] = static_cast(kernAdvance.y) / 64.0f; } } } critterding-beta12.1/src/utils/ftgl/FTGlyphContainer.cpp0000644000175000017500000000635211147116040022305 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTGlyphContainer.h" #include "FTFace.h" #include "FTCharmap.h" FTGlyphContainer::FTGlyphContainer(FTFace* f) : face(f), err(0) { glyphs.push_back(NULL); charMap = new FTCharmap(face); } FTGlyphContainer::~FTGlyphContainer() { GlyphVector::iterator it; for(it = glyphs.begin(); it != glyphs.end(); ++it) { delete *it; } glyphs.clear(); delete charMap; } bool FTGlyphContainer::CharMap(FT_Encoding encoding) { bool result = charMap->CharMap(encoding); err = charMap->Error(); return result; } unsigned int FTGlyphContainer::FontIndex(const unsigned int charCode) const { return charMap->FontIndex(charCode); } void FTGlyphContainer::Add(FTGlyph* tempGlyph, const unsigned int charCode) { charMap->InsertIndex(charCode, glyphs.size()); glyphs.push_back(tempGlyph); } const FTGlyph* const FTGlyphContainer::Glyph(const unsigned int charCode) const { unsigned int index = charMap->GlyphListIndex(charCode); return glyphs[index]; } FTBBox FTGlyphContainer::BBox(const unsigned int charCode) const { return Glyph(charCode)->BBox(); } float FTGlyphContainer::Advance(const unsigned int charCode, const unsigned int nextCharCode) { unsigned int left = charMap->FontIndex(charCode); unsigned int right = charMap->FontIndex(nextCharCode); return face->KernAdvance(left, right).Xf() + Glyph(charCode)->Advance(); } FTPoint FTGlyphContainer::Render(const unsigned int charCode, const unsigned int nextCharCode, FTPoint penPosition, int renderMode) { unsigned int left = charMap->FontIndex(charCode); unsigned int right = charMap->FontIndex(nextCharCode); FTPoint kernAdvance = face->KernAdvance(left, right); if(!face->Error()) { unsigned int index = charMap->GlyphListIndex(charCode); kernAdvance += glyphs[index]->Render(penPosition, renderMode); } return kernAdvance; } critterding-beta12.1/src/utils/ftgl/FTFace.h0000644000175000017500000001223511147116040017657 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * 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. */ #ifndef __FTFace__ #define __FTFace__ #include #include FT_FREETYPE_H #include FT_GLYPH_H #include "FTGL/ftgl.h" #include "FTSize.h" /** * FTFace class provides an abstraction layer for the Freetype Face. * * @see "Freetype 2 Documentation" * */ class FTFace { public: /** * Opens and reads a face file. Error is set. * * @param fontFilePath font file path. */ FTFace(const char* fontFilePath, bool precomputeKerning = true); /** * Read face data from an in-memory buffer. Error is set. * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes */ FTFace(const unsigned char *pBufferBytes, size_t bufferSizeInBytes, bool precomputeKerning = true); /** * Destructor * * Disposes of the current Freetype Face. */ virtual ~FTFace(); /** * Attach auxilliary file to font (e.g., font metrics). * * @param fontFilePath auxilliary font file path. * @return true if file has opened * successfully. */ bool Attach(const char* fontFilePath); /** * Attach auxilliary data to font (e.g., font metrics) from memory * * @param pBufferBytes the in-memory buffer * @param bufferSizeInBytes the length of the buffer in bytes * @return true if file has opened * successfully. */ bool Attach(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Get the freetype face object.. * * @return pointer to an FT_Face. */ FT_Face* Face() const { return ftFace; } /** * Sets the char size for the current face. * * This doesn't guarantee that the size was set correctly. Clients * should check errors. * * @param size the face size in points (1/72 inch) * @param res the resolution of the target device. * @return FTSize object */ const FTSize& Size(const unsigned int size, const unsigned int res); /** * Get the number of character maps in this face. * * @return character map count. */ unsigned int CharMapCount() const; /** * Get a list of character maps in this face. * * @return pointer to the first encoding. */ FT_Encoding* CharMapList(); /** * Gets the kerning vector between two glyphs */ FTPoint KernAdvance(unsigned int index1, unsigned int index2); /** * Loads and creates a Freetype glyph. */ FT_GlyphSlot Glyph(unsigned int index, FT_Int load_flags); /** * Gets the number of glyphs in the current face. */ unsigned int GlyphCount() const { return numGlyphs; } /** * Queries for errors. * * @return The current error code. */ FT_Error Error() const { return err; } private: /** * The Freetype face */ FT_Face* ftFace; /** * The size object associated with this face */ FTSize charSize; /** * The number of glyphs in this face */ int numGlyphs; FT_Encoding* fontEncodingList; /** * This face has kerning tables */ bool hasKerningTable; /** * If this face has kerning tables, we can cache them. */ void BuildKerningCache(); static const unsigned int MAX_PRECOMPUTED = 128; float *kerningCache; /** * Current error code. Zero means no error. */ FT_Error err; }; #endif // __FTFace__ critterding-beta12.1/src/utils/ftgl/FTGlyph/0000755000175000017500000000000011347266042017742 5ustar bobkebobkecritterding-beta12.1/src/utils/ftgl/FTGlyph/FTOutlineGlyphImpl.h0000644000175000017500000000403011147116040023575 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTOutlineGlyphImpl__ #define __FTOutlineGlyphImpl__ #include "FTGlyphImpl.h" class FTVectoriser; class FTOutlineGlyphImpl : public FTGlyphImpl { friend class FTOutlineGlyph; protected: FTOutlineGlyphImpl(FT_GlyphSlot glyph, float outset, bool useDisplayList); virtual ~FTOutlineGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: /** * Private rendering method. */ void DoRender(); /** * Private rendering variables. */ FTVectoriser *vectoriser; /** * Private rendering variables. */ float outset; /** * OpenGL display list */ GLuint glList; }; #endif // __FTOutlineGlyphImpl__ critterding-beta12.1/src/utils/ftgl/FTGlyph/FTPolygonGlyphImpl.h0000644000175000017500000000377211147116040023621 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTPolygonGlyphImpl__ #define __FTPolygonGlyphImpl__ #include "FTGlyphImpl.h" class FTVectoriser; class FTPolygonGlyphImpl : public FTGlyphImpl { friend class FTPolygonGlyph; public: FTPolygonGlyphImpl(FT_GlyphSlot glyph, float outset, bool useDisplayList); virtual ~FTPolygonGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: /** * Private rendering method. */ void DoRender(); /** * Private rendering variables. */ unsigned int hscale, vscale; FTVectoriser *vectoriser; float outset; /** * OpenGL display list */ GLuint glList; }; #endif // __FTPolygonGlyphImpl__ critterding-beta12.1/src/utils/ftgl/FTGlyph/FTPixmapGlyphImpl.h0000644000175000017500000000375511147116040023431 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTPixmapGlyphImpl__ #define __FTPixmapGlyphImpl__ #include "FTGlyphImpl.h" class FTPixmapGlyphImpl : public FTGlyphImpl { friend class FTPixmapGlyph; protected: FTPixmapGlyphImpl(FT_GlyphSlot glyph); virtual ~FTPixmapGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: /** * The width of the glyph 'image' */ int destWidth; /** * The height of the glyph 'image' */ int destHeight; /** * Vector from the pen position to the topleft corner of the pixmap */ FTPoint pos; /** * Pointer to the 'image' data */ unsigned char* data; }; #endif // __FTPixmapGlyphImpl__ critterding-beta12.1/src/utils/ftgl/FTGlyph/FTGlyphImpl.h0000644000175000017500000000354011147116040022242 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTGlyphImpl__ #define __FTGlyphImpl__ #include "FTGL/ftgl.h" class FTGlyphImpl { friend class FTGlyph; protected: FTGlyphImpl(FT_GlyphSlot glyph, bool useDisplayList = true); virtual ~FTGlyphImpl(); float Advance() const; const FTBBox& BBox() const; FT_Error Error() const; /** * The advance distance for this glyph */ FTPoint advance; /** * The bounding box of this glyph. */ FTBBox bBox; /** * Current error code. Zero means no error. */ FT_Error err; }; #endif // __FTGlyphImpl__ critterding-beta12.1/src/utils/ftgl/FTGlyph/FTOutlineGlyph.cpp0000644000175000017500000000732611147116040023321 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTOutlineGlyphImpl.h" #include "FTVectoriser.h" // // FTGLOutlineGlyph // FTOutlineGlyph::FTOutlineGlyph(FT_GlyphSlot glyph, float outset, bool useDisplayList) : FTGlyph(new FTOutlineGlyphImpl(glyph, outset, useDisplayList)) {} FTOutlineGlyph::~FTOutlineGlyph() {} const FTPoint& FTOutlineGlyph::Render(const FTPoint& pen, int renderMode) { FTOutlineGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLOutlineGlyphImpl // FTOutlineGlyphImpl::FTOutlineGlyphImpl(FT_GlyphSlot glyph, float _outset, bool useDisplayList) : FTGlyphImpl(glyph), glList(0) { if(ft_glyph_format_outline != glyph->format) { err = 0x14; // Invalid_Outline return; } vectoriser = new FTVectoriser(glyph); if((vectoriser->ContourCount() < 1) || (vectoriser->PointCount() < 3)) { delete vectoriser; vectoriser = NULL; return; } outset = _outset; if(useDisplayList) { glList = glGenLists(1); glNewList(glList, GL_COMPILE); DoRender(); glEndList(); delete vectoriser; vectoriser = NULL; } } FTOutlineGlyphImpl::~FTOutlineGlyphImpl() { if(glList) { glDeleteLists(glList, 1); } else if(vectoriser) { delete vectoriser; } } const FTPoint& FTOutlineGlyphImpl::RenderImpl(const FTPoint& pen, int renderMode) { glTranslatef(pen.Xf(), pen.Yf(), pen.Zf()); if(glList) { glCallList(glList); } else if(vectoriser) { DoRender(); } glTranslatef(-pen.Xf(), -pen.Yf(), -pen.Zf()); return advance; } void FTOutlineGlyphImpl::DoRender() { for(unsigned int c = 0; c < vectoriser->ContourCount(); ++c) { const FTContour* contour = vectoriser->Contour(c); glBegin(GL_LINE_LOOP); for(unsigned int i = 0; i < contour->PointCount(); ++i) { FTPoint point = FTPoint(contour->Point(i).X() + contour->Outset(i).X() * outset, contour->Point(i).Y() + contour->Outset(i).Y() * outset, 0); glVertex2f(point.Xf() / 64.0f, point.Yf() / 64.0f); } glEnd(); } } critterding-beta12.1/src/utils/ftgl/FTGlyph/FTExtrudeGlyphImpl.h0000644000175000017500000000420111147116040023576 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTExtrudeGlyphImpl__ #define __FTExtrudeGlyphImpl__ #include "FTGlyphImpl.h" class FTVectoriser; class FTExtrudeGlyphImpl : public FTGlyphImpl { friend class FTExtrudeGlyph; protected: FTExtrudeGlyphImpl(FT_GlyphSlot glyph, float depth, float frontOutset, float backOutset, bool useDisplayList); virtual ~FTExtrudeGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: /** * Private rendering methods. */ void RenderFront(); void RenderBack(); void RenderSide(); /** * Private rendering variables. */ unsigned int hscale, vscale; float depth; float frontOutset, backOutset; FTVectoriser *vectoriser; /** * OpenGL display list */ GLuint glList; }; #endif // __FTExtrudeGlyphImpl__ critterding-beta12.1/src/utils/ftgl/FTGlyph/FTPixmapGlyph.cpp0000644000175000017500000000676711147116040023150 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTPixmapGlyphImpl.h" // // FTGLPixmapGlyph // FTPixmapGlyph::FTPixmapGlyph(FT_GlyphSlot glyph) : FTGlyph(new FTPixmapGlyphImpl(glyph)) {} FTPixmapGlyph::~FTPixmapGlyph() {} const FTPoint& FTPixmapGlyph::Render(const FTPoint& pen, int renderMode) { FTPixmapGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLPixmapGlyphImpl // FTPixmapGlyphImpl::FTPixmapGlyphImpl(FT_GlyphSlot glyph) : FTGlyphImpl(glyph), destWidth(0), destHeight(0), data(0) { err = FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL); if(err || ft_glyph_format_bitmap != glyph->format) { return; } FT_Bitmap bitmap = glyph->bitmap; //check the pixel mode //ft_pixel_mode_grays int srcWidth = bitmap.width; int srcHeight = bitmap.rows; destWidth = srcWidth; destHeight = srcHeight; if(destWidth && destHeight) { data = new unsigned char[destWidth * destHeight * 2]; unsigned char* src = bitmap.buffer; unsigned char* dest = data + ((destHeight - 1) * destWidth * 2); size_t destStep = destWidth * 2 * 2; for(int y = 0; y < srcHeight; ++y) { for(int x = 0; x < srcWidth; ++x) { *dest++ = static_cast(255); *dest++ = *src++; } dest -= destStep; } destHeight = srcHeight; } pos.X(glyph->bitmap_left); pos.Y(srcHeight - glyph->bitmap_top); } FTPixmapGlyphImpl::~FTPixmapGlyphImpl() { delete [] data; } const FTPoint& FTPixmapGlyphImpl::RenderImpl(const FTPoint& pen, int renderMode) { if(data) { float dx, dy; dx = floor(pen.Xf() + pos.Xf()); dy = floor(pen.Yf() - pos.Yf()); glBitmap(0, 0, 0.0f, 0.0f, dx, dy, (const GLubyte*)0); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_ALIGNMENT, 2); glDrawPixels(destWidth, destHeight, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, (const GLvoid*)data); glBitmap(0, 0, 0.0f, 0.0f, -dx, -dy, (const GLubyte*)0); } return advance; } critterding-beta12.1/src/utils/ftgl/FTGlyph/FTGlyphGlue.cpp0000644000175000017500000001473411147116040022577 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTInternals.h" static const FTPoint static_ftpoint; static const FTBBox static_ftbbox; FTGL_BEGIN_C_DECLS #define C_TOR(cname, cargs, cxxname, cxxarg, cxxtype) \ FTGLglyph* cname cargs \ { \ cxxname *g = new cxxname cxxarg; \ if(g->Error()) \ { \ delete g; \ return NULL; \ } \ FTGLglyph *ftgl = (FTGLglyph *)malloc(sizeof(FTGLglyph)); \ ftgl->ptr = g; \ ftgl->type = cxxtype; \ return ftgl; \ } // FTBitmapGlyph::FTBitmapGlyph(); C_TOR(ftglCreateBitmapGlyph, (FT_GlyphSlot glyph), FTBitmapGlyph, (glyph), GLYPH_BITMAP); // FTBufferGlyph::FTBufferGlyph(); // FIXME: not implemented // FTExtrudeGlyph::FTExtrudeGlyph(); C_TOR(ftglCreateExtrudeGlyph, (FT_GlyphSlot glyph, float depth, float frontOutset, float backOutset, int useDisplayList), FTExtrudeGlyph, (glyph, depth, frontOutset, backOutset, (useDisplayList != 0)), GLYPH_EXTRUDE); // FTOutlineGlyph::FTOutlineGlyph(); C_TOR(ftglCreateOutlineGlyph, (FT_GlyphSlot glyph, float outset, int useDisplayList), FTOutlineGlyph, (glyph, outset, (useDisplayList != 0)), GLYPH_OUTLINE); // FTPixmapGlyph::FTPixmapGlyph(); C_TOR(ftglCreatePixmapGlyph, (FT_GlyphSlot glyph), FTPixmapGlyph, (glyph), GLYPH_PIXMAP); // FTPolygonGlyph::FTPolygonGlyph(); C_TOR(ftglCreatePolygonGlyph, (FT_GlyphSlot glyph, float outset, int useDisplayList), FTPolygonGlyph, (glyph, outset, (useDisplayList != 0)), GLYPH_POLYGON); // FTTextureGlyph::FTTextureGlyph(); C_TOR(ftglCreateTextureGlyph, (FT_GlyphSlot glyph, int id, int xOffset, int yOffset, int width, int height), FTTextureGlyph, (glyph, id, xOffset, yOffset, width, height), GLYPH_TEXTURE); // FTCustomGlyph::FTCustomGlyph(); class FTCustomGlyph : public FTGlyph { public: FTCustomGlyph(FTGLglyph *base, void *p, void (*render) (FTGLglyph *, void *, FTGL_DOUBLE, FTGL_DOUBLE, int, FTGL_DOUBLE *, FTGL_DOUBLE *), void (*destroy) (FTGLglyph *, void *)) : FTGlyph((FT_GlyphSlot)0), baseGlyph(base), data(p), renderCallback(render), destroyCallback(destroy) {} ~FTCustomGlyph() { destroyCallback(baseGlyph, data); } float Advance() const { return baseGlyph->ptr->Advance(); } const FTPoint& Render(const FTPoint& pen, int renderMode) { FTGL_DOUBLE advancex, advancey; renderCallback(baseGlyph, data, pen.X(), pen.Y(), renderMode, &advancex, &advancey); advance = FTPoint(advancex, advancey); return advance; } const FTBBox& BBox() const { return baseGlyph->ptr->BBox(); } FT_Error Error() const { return baseGlyph->ptr->Error(); } private: FTPoint advance; FTGLglyph *baseGlyph; void *data; void (*renderCallback) (FTGLglyph *, void *, FTGL_DOUBLE, FTGL_DOUBLE, int, FTGL_DOUBLE *, FTGL_DOUBLE *); void (*destroyCallback) (FTGLglyph *, void *); }; C_TOR(ftglCreateCustomGlyph, (FTGLglyph *base, void *data, void (*renderCallback) (FTGLglyph *, void *, FTGL_DOUBLE, FTGL_DOUBLE, int, FTGL_DOUBLE *, FTGL_DOUBLE *), void (*destroyCallback) (FTGLglyph *, void *)), FTCustomGlyph, (base, data, renderCallback, destroyCallback), GLYPH_CUSTOM); #define C_FUN(cret, cname, cargs, cxxerr, cxxname, cxxarg) \ cret cname cargs \ { \ if(!g || !g->ptr) \ { \ fprintf(stderr, "FTGL warning: NULL pointer in %s\n", #cname); \ cxxerr; \ } \ return g->ptr->cxxname cxxarg; \ } // FTGlyph::~FTGlyph(); void ftglDestroyGlyph(FTGLglyph *g) { if(!g || !g->ptr) { fprintf(stderr, "FTGL warning: NULL pointer in %s\n", __FUNCTION__); return; } delete g->ptr; free(g); } // const FTPoint& FTGlyph::Render(const FTPoint& pen, int renderMode); extern "C++" { C_FUN(static const FTPoint&, _ftglRenderGlyph, (FTGLglyph *g, const FTPoint& pen, int renderMode), return static_ftpoint, Render, (pen, renderMode)); } void ftglRenderGlyph(FTGLglyph *g, FTGL_DOUBLE penx, FTGL_DOUBLE peny, int renderMode, FTGL_DOUBLE *advancex, FTGL_DOUBLE *advancey) { FTPoint pen(penx, peny); FTPoint ret = _ftglRenderGlyph(g, pen, renderMode); *advancex = ret.X(); *advancey = ret.Y(); } // float FTGlyph::Advance() const; C_FUN(float, ftglGetGlyphAdvance, (FTGLglyph *g), return 0.0, Advance, ()); // const FTBBox& FTGlyph::BBox() const; extern "C++" { C_FUN(static const FTBBox&, _ftglGetGlyphBBox, (FTGLglyph *g), return static_ftbbox, BBox, ()); } void ftglGetGlyphBBox(FTGLglyph *g, float bounds[6]) { FTBBox ret = _ftglGetGlyphBBox(g); FTPoint lower = ret.Lower(), upper = ret.Upper(); bounds[0] = lower.Xf(); bounds[1] = lower.Yf(); bounds[2] = lower.Zf(); bounds[3] = upper.Xf(); bounds[4] = upper.Yf(); bounds[5] = upper.Zf(); } // FT_Error FTGlyph::Error() const; C_FUN(FT_Error, ftglGetGlyphError, (FTGLglyph *g), return -1, Error, ()); FTGL_END_C_DECLS critterding-beta12.1/src/utils/ftgl/FTGlyph/FTBufferGlyph.cpp0000644000175000017500000000625711147116040023115 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTBufferGlyphImpl.h" // // FTGLBufferGlyph // FTBufferGlyph::FTBufferGlyph(FT_GlyphSlot glyph, FTBuffer *buffer) : FTGlyph(new FTBufferGlyphImpl(glyph, buffer)) {} FTBufferGlyph::~FTBufferGlyph() {} const FTPoint& FTBufferGlyph::Render(const FTPoint& pen, int renderMode) { FTBufferGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLBufferGlyphImpl // FTBufferGlyphImpl::FTBufferGlyphImpl(FT_GlyphSlot glyph, FTBuffer *p) : FTGlyphImpl(glyph), has_bitmap(false), buffer(p) { err = FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL); if(err || glyph->format != ft_glyph_format_bitmap) { return; } bitmap = glyph->bitmap; pixels = new unsigned char[bitmap.pitch * bitmap.rows]; memcpy(pixels, bitmap.buffer, bitmap.pitch * bitmap.rows); if(bitmap.width && bitmap.rows) { has_bitmap = true; corner = FTPoint(glyph->bitmap_left, glyph->bitmap_top); } } FTBufferGlyphImpl::~FTBufferGlyphImpl() { delete[] pixels; } const FTPoint& FTBufferGlyphImpl::RenderImpl(const FTPoint& pen, int renderMode) { if(has_bitmap) { FTPoint pos(buffer->Pos() + pen + corner); int dx = (int)(pos.Xf() + 0.5f); int dy = buffer->Height() - (int)(pos.Yf() + 0.5f); unsigned char * dest = buffer->Pixels() + dx + dy * buffer->Width(); for(int y = 0; y < bitmap.rows; y++) { // FIXME: change the loop bounds instead of doing this test if(y + dy < 0 || y + dy >= buffer->Height()) continue; for(int x = 0; x < bitmap.width; x++) { if(x + dx < 0 || x + dx >= buffer->Width()) continue; unsigned char p = pixels[y * bitmap.pitch + x]; if(p) { dest[y * buffer->Width() + x] = p; } } } } return advance; } critterding-beta12.1/src/utils/ftgl/FTGlyph/FTBitmapGlyph.cpp0000644000175000017500000000640511147116040023113 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTBitmapGlyphImpl.h" // // FTGLBitmapGlyph // FTBitmapGlyph::FTBitmapGlyph(FT_GlyphSlot glyph) : FTGlyph(new FTBitmapGlyphImpl(glyph)) {} FTBitmapGlyph::~FTBitmapGlyph() {} const FTPoint& FTBitmapGlyph::Render(const FTPoint& pen, int renderMode) { FTBitmapGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLBitmapGlyphImpl // FTBitmapGlyphImpl::FTBitmapGlyphImpl(FT_GlyphSlot glyph) : FTGlyphImpl(glyph), destWidth(0), destHeight(0), data(0) { err = FT_Render_Glyph(glyph, FT_RENDER_MODE_MONO); if(err || ft_glyph_format_bitmap != glyph->format) { return; } FT_Bitmap bitmap = glyph->bitmap; unsigned int srcWidth = bitmap.width; unsigned int srcHeight = bitmap.rows; unsigned int srcPitch = bitmap.pitch; destWidth = srcWidth; destHeight = srcHeight; destPitch = srcPitch; if(destWidth && destHeight) { data = new unsigned char[destPitch * destHeight]; unsigned char* dest = data + ((destHeight - 1) * destPitch); unsigned char* src = bitmap.buffer; for(unsigned int y = 0; y < srcHeight; ++y) { memcpy(dest, src, srcPitch); dest -= destPitch; src += srcPitch; } } pos = FTPoint(glyph->bitmap_left, static_cast(srcHeight) - glyph->bitmap_top, 0.0); } FTBitmapGlyphImpl::~FTBitmapGlyphImpl() { delete [] data; } const FTPoint& FTBitmapGlyphImpl::RenderImpl(const FTPoint& pen, int renderMode) { if(data) { float dx, dy; dx = pen.Xf() + pos.Xf(); dy = pen.Yf() - pos.Yf(); glBitmap(0, 0, 0.0f, 0.0f, dx, dy, (const GLubyte*)0); glPixelStorei(GL_UNPACK_ROW_LENGTH, destPitch * 8); glBitmap(destWidth, destHeight, 0.0f, 0.0, 0.0, 0.0, (const GLubyte*)data); glBitmap(0, 0, 0.0f, 0.0f, -dx, -dy, (const GLubyte*)0); } return advance; } critterding-beta12.1/src/utils/ftgl/FTGlyph/FTGlyph.cpp0000644000175000017500000000423411147116040021754 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTGlyphImpl.h" // // FTGlyph // FTGlyph::FTGlyph(FT_GlyphSlot glyph) { impl = new FTGlyphImpl(glyph); } FTGlyph::FTGlyph(FTGlyphImpl *pImpl) { impl = pImpl; } FTGlyph::~FTGlyph() { delete impl; } float FTGlyph::Advance() const { return impl->Advance(); } const FTBBox& FTGlyph::BBox() const { return impl->BBox(); } FT_Error FTGlyph::Error() const { return impl->Error(); } // // FTGlyphImpl // FTGlyphImpl::FTGlyphImpl(FT_GlyphSlot glyph, bool useList) : err(0) { if(glyph) { bBox = FTBBox(glyph); advance = FTPoint(glyph->advance.x / 64.0f, glyph->advance.y / 64.0f); } } FTGlyphImpl::~FTGlyphImpl() {} float FTGlyphImpl::Advance() const { return advance.Xf(); } const FTBBox& FTGlyphImpl::BBox() const { return bBox; } FT_Error FTGlyphImpl::Error() const { return err; } critterding-beta12.1/src/utils/ftgl/FTGlyph/FTPolygonGlyph.cpp0000644000175000017500000000754411147116040023333 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTPolygonGlyphImpl.h" #include "FTVectoriser.h" // // FTGLPolyGlyph // FTPolygonGlyph::FTPolygonGlyph(FT_GlyphSlot glyph, float outset, bool useDisplayList) : FTGlyph(new FTPolygonGlyphImpl(glyph, outset, useDisplayList)) {} FTPolygonGlyph::~FTPolygonGlyph() {} const FTPoint& FTPolygonGlyph::Render(const FTPoint& pen, int renderMode) { FTPolygonGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLPolyGlyphImpl // FTPolygonGlyphImpl::FTPolygonGlyphImpl(FT_GlyphSlot glyph, float _outset, bool useDisplayList) : FTGlyphImpl(glyph), glList(0) { if(ft_glyph_format_outline != glyph->format) { err = 0x14; // Invalid_Outline return; } vectoriser = new FTVectoriser(glyph); if((vectoriser->ContourCount() < 1) || (vectoriser->PointCount() < 3)) { delete vectoriser; vectoriser = NULL; return; } hscale = glyph->face->size->metrics.x_ppem * 64; vscale = glyph->face->size->metrics.y_ppem * 64; outset = _outset; if(useDisplayList) { glList = glGenLists(1); glNewList(glList, GL_COMPILE); DoRender(); glEndList(); delete vectoriser; vectoriser = NULL; } } FTPolygonGlyphImpl::~FTPolygonGlyphImpl() { if(glList) { glDeleteLists(glList, 1); } else if(vectoriser) { delete vectoriser; } } const FTPoint& FTPolygonGlyphImpl::RenderImpl(const FTPoint& pen, int renderMode) { glTranslatef(pen.Xf(), pen.Yf(), pen.Zf()); if(glList) { glCallList(glList); } else if(vectoriser) { DoRender(); } glTranslatef(-pen.Xf(), -pen.Yf(), -pen.Zf()); return advance; } void FTPolygonGlyphImpl::DoRender() { vectoriser->MakeMesh(1.0, 1, outset); const FTMesh *mesh = vectoriser->GetMesh(); for(unsigned int t = 0; t < mesh->TesselationCount(); ++t) { const FTTesselation* subMesh = mesh->Tesselation(t); unsigned int polygonType = subMesh->PolygonType(); glBegin(polygonType); for(unsigned int i = 0; i < subMesh->PointCount(); ++i) { FTPoint point = subMesh->Point(i); glTexCoord2f(point.Xf() / hscale, point.Yf() / vscale); glVertex3f(point.Xf() / 64.0f, point.Yf() / 64.0f, 0.0f); } glEnd(); } } critterding-beta12.1/src/utils/ftgl/FTGlyph/FTExtrudeGlyph.cpp0000644000175000017500000001631311147116040023316 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTExtrudeGlyphImpl.h" #include "FTVectoriser.h" // // FTGLExtrudeGlyph // FTExtrudeGlyph::FTExtrudeGlyph(FT_GlyphSlot glyph, float depth, float frontOutset, float backOutset, bool useDisplayList) : FTGlyph(new FTExtrudeGlyphImpl(glyph, depth, frontOutset, backOutset, useDisplayList)) {} FTExtrudeGlyph::~FTExtrudeGlyph() {} const FTPoint& FTExtrudeGlyph::Render(const FTPoint& pen, int renderMode) { FTExtrudeGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLExtrudeGlyphImpl // FTExtrudeGlyphImpl::FTExtrudeGlyphImpl(FT_GlyphSlot glyph, float _depth, float _frontOutset, float _backOutset, bool useDisplayList) : FTGlyphImpl(glyph), vectoriser(0), glList(0) { bBox.SetDepth(-_depth); if(ft_glyph_format_outline != glyph->format) { err = 0x14; // Invalid_Outline return; } vectoriser = new FTVectoriser(glyph); if((vectoriser->ContourCount() < 1) || (vectoriser->PointCount() < 3)) { delete vectoriser; vectoriser = NULL; return; } hscale = glyph->face->size->metrics.x_ppem * 64; vscale = glyph->face->size->metrics.y_ppem * 64; depth = _depth; frontOutset = _frontOutset; backOutset = _backOutset; if(useDisplayList) { glList = glGenLists(3); /* Front face */ glNewList(glList + 0, GL_COMPILE); RenderFront(); glEndList(); /* Back face */ glNewList(glList + 1, GL_COMPILE); RenderBack(); glEndList(); /* Side face */ glNewList(glList + 2, GL_COMPILE); RenderSide(); glEndList(); delete vectoriser; vectoriser = NULL; } } FTExtrudeGlyphImpl::~FTExtrudeGlyphImpl() { if(glList) { glDeleteLists(glList, 3); } else if(vectoriser) { delete vectoriser; } } const FTPoint& FTExtrudeGlyphImpl::RenderImpl(const FTPoint& pen, int renderMode) { glTranslatef(pen.Xf(), pen.Yf(), pen.Zf()); if(glList) { if(renderMode & FTGL::RENDER_FRONT) glCallList(glList + 0); if(renderMode & FTGL::RENDER_BACK) glCallList(glList + 1); if(renderMode & FTGL::RENDER_SIDE) glCallList(glList + 2); } else if(vectoriser) { if(renderMode & FTGL::RENDER_FRONT) RenderFront(); if(renderMode & FTGL::RENDER_BACK) RenderBack(); if(renderMode & FTGL::RENDER_SIDE) RenderSide(); } glTranslatef(-pen.Xf(), -pen.Yf(), -pen.Zf()); return advance; } void FTExtrudeGlyphImpl::RenderFront() { vectoriser->MakeMesh(1.0, 1, frontOutset); glNormal3d(0.0, 0.0, 1.0); const FTMesh *mesh = vectoriser->GetMesh(); for(unsigned int j = 0; j < mesh->TesselationCount(); ++j) { const FTTesselation* subMesh = mesh->Tesselation(j); unsigned int polygonType = subMesh->PolygonType(); glBegin(polygonType); for(unsigned int i = 0; i < subMesh->PointCount(); ++i) { FTPoint pt = subMesh->Point(i); glTexCoord2f(pt.Xf() / hscale, pt.Yf() / vscale); glVertex3f(pt.Xf() / 64.0f, pt.Yf() / 64.0f, 0.0f); } glEnd(); } } void FTExtrudeGlyphImpl::RenderBack() { vectoriser->MakeMesh(-1.0, 2, backOutset); glNormal3d(0.0, 0.0, -1.0); const FTMesh *mesh = vectoriser->GetMesh(); for(unsigned int j = 0; j < mesh->TesselationCount(); ++j) { const FTTesselation* subMesh = mesh->Tesselation(j); unsigned int polygonType = subMesh->PolygonType(); glBegin(polygonType); for(unsigned int i = 0; i < subMesh->PointCount(); ++i) { FTPoint pt = subMesh->Point(i); glTexCoord2f(subMesh->Point(i).Xf() / hscale, subMesh->Point(i).Yf() / vscale); glVertex3f(subMesh->Point(i).Xf() / 64.0f, subMesh->Point(i).Yf() / 64.0f, -depth); } glEnd(); } } void FTExtrudeGlyphImpl::RenderSide() { int contourFlag = vectoriser->ContourFlag(); for(size_t c = 0; c < vectoriser->ContourCount(); ++c) { const FTContour* contour = vectoriser->Contour(c); size_t n = contour->PointCount(); if(n < 2) { continue; } glBegin(GL_QUAD_STRIP); for(size_t j = 0; j <= n; ++j) { size_t cur = (j == n) ? 0 : j; size_t next = (cur == n - 1) ? 0 : cur + 1; FTPoint frontPt = contour->FrontPoint(cur); FTPoint nextPt = contour->FrontPoint(next); FTPoint backPt = contour->BackPoint(cur); FTPoint normal = FTPoint(0.f, 0.f, 1.f) ^ (frontPt - nextPt); if(normal != FTPoint(0.0f, 0.0f, 0.0f)) { glNormal3dv(static_cast(normal.Normalise())); } glTexCoord2f(frontPt.Xf() / hscale, frontPt.Yf() / vscale); if(contourFlag & ft_outline_reverse_fill) { glVertex3f(backPt.Xf() / 64.0f, backPt.Yf() / 64.0f, 0.0f); glVertex3f(frontPt.Xf() / 64.0f, frontPt.Yf() / 64.0f, -depth); } else { glVertex3f(backPt.Xf() / 64.0f, backPt.Yf() / 64.0f, -depth); glVertex3f(frontPt.Xf() / 64.0f, frontPt.Yf() / 64.0f, 0.0f); } } glEnd(); } } critterding-beta12.1/src/utils/ftgl/FTGlyph/FTTextureGlyphImpl.h0000644000175000017500000000537711147116040023635 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTTextureGlyphImpl__ #define __FTTextureGlyphImpl__ #include "FTGlyphImpl.h" class FTTextureGlyphImpl : public FTGlyphImpl { friend class FTTextureGlyph; friend class FTTextureFontImpl; protected: FTTextureGlyphImpl(FT_GlyphSlot glyph, int id, int xOffset, int yOffset, int width, int height); virtual ~FTTextureGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: /** * Reset the currently active texture to zero to get into a known * state before drawing a string. This is to get round possible * threading issues. */ static void ResetActiveTexture() { activeTextureID = 0; } /** * The width of the glyph 'image' */ int destWidth; /** * The height of the glyph 'image' */ int destHeight; /** * Vector from the pen position to the topleft corner of the pixmap */ FTPoint corner; /** * The texture co-ords of this glyph within the texture. */ FTPoint uv[2]; /** * The texture index that this glyph is contained in. */ int glTextureID; /** * The texture index of the currently active texture * * We keep track of the currently active texture to try to reduce the * number of texture bind operations. */ static GLint activeTextureID; }; #endif // __FTTextureGlyphImpl__ critterding-beta12.1/src/utils/ftgl/FTGlyph/FTTextureGlyph.cpp0000644000175000017500000001034611147116040023336 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTTextureGlyphImpl.h" // // FTGLTextureGlyph // FTTextureGlyph::FTTextureGlyph(FT_GlyphSlot glyph, int id, int xOffset, int yOffset, int width, int height) : FTGlyph(new FTTextureGlyphImpl(glyph, id, xOffset, yOffset, width, height)) {} FTTextureGlyph::~FTTextureGlyph() {} const FTPoint& FTTextureGlyph::Render(const FTPoint& pen, int renderMode) { FTTextureGlyphImpl *myimpl = dynamic_cast(impl); return myimpl->RenderImpl(pen, renderMode); } // // FTGLTextureGlyphImpl // GLint FTTextureGlyphImpl::activeTextureID = 0; FTTextureGlyphImpl::FTTextureGlyphImpl(FT_GlyphSlot glyph, int id, int xOffset, int yOffset, int width, int height) : FTGlyphImpl(glyph), destWidth(0), destHeight(0), glTextureID(id) { /* FIXME: need to propagate the render mode all the way down to * here in order to get FT_RENDER_MODE_MONO aliased fonts. */ err = FT_Render_Glyph(glyph, FT_RENDER_MODE_NORMAL); if(err || glyph->format != ft_glyph_format_bitmap) { return; } FT_Bitmap bitmap = glyph->bitmap; destWidth = bitmap.width; destHeight = bitmap.rows; if(destWidth && destHeight) { glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glBindTexture(GL_TEXTURE_2D, glTextureID); glTexSubImage2D(GL_TEXTURE_2D, 0, xOffset, yOffset, destWidth, destHeight, GL_ALPHA, GL_UNSIGNED_BYTE, bitmap.buffer); glPopClientAttrib(); } // 0 // +----+ // | | // | | // | | // +----+ // 1 uv[0].X(static_cast(xOffset) / static_cast(width)); uv[0].Y(static_cast(yOffset) / static_cast(height)); uv[1].X(static_cast(xOffset + destWidth) / static_cast(width)); uv[1].Y(static_cast(yOffset + destHeight) / static_cast(height)); corner = FTPoint(glyph->bitmap_left, glyph->bitmap_top); } FTTextureGlyphImpl::~FTTextureGlyphImpl() {} const FTPoint& FTTextureGlyphImpl::RenderImpl(const FTPoint& pen, int renderMode) { float dx, dy; if(activeTextureID != glTextureID) { glBindTexture(GL_TEXTURE_2D, (GLuint)glTextureID); activeTextureID = glTextureID; } dx = floor(pen.Xf() + corner.Xf()); dy = floor(pen.Yf() + corner.Yf()); glBegin(GL_QUADS); glTexCoord2f(uv[0].Xf(), uv[0].Yf()); glVertex2f(dx, dy); glTexCoord2f(uv[0].Xf(), uv[1].Yf()); glVertex2f(dx, dy - destHeight); glTexCoord2f(uv[1].Xf(), uv[1].Yf()); glVertex2f(dx + destWidth, dy - destHeight); glTexCoord2f(uv[1].Xf(), uv[0].Yf()); glVertex2f(dx + destWidth, dy); glEnd(); return advance; } critterding-beta12.1/src/utils/ftgl/FTGlyph/FTBufferGlyphImpl.h0000644000175000017500000000326211147116040023375 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTBufferGlyphImpl__ #define __FTBufferGlyphImpl__ #include "FTGlyphImpl.h" class FTBufferGlyphImpl : public FTGlyphImpl { friend class FTBufferGlyph; protected: FTBufferGlyphImpl(FT_GlyphSlot glyph, FTBuffer *p); virtual ~FTBufferGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: bool has_bitmap; FT_Bitmap bitmap; unsigned char *pixels; FTPoint corner; FTBuffer *buffer; }; #endif // __FTBufferGlyphImpl__ critterding-beta12.1/src/utils/ftgl/FTGlyph/FTBitmapGlyphImpl.h0000644000175000017500000000414111147116040023375 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTBitmapGlyphImpl__ #define __FTBitmapGlyphImpl__ #include "FTGlyphImpl.h" class FTBitmapGlyphImpl : public FTGlyphImpl { friend class FTBitmapGlyph; protected: FTBitmapGlyphImpl(FT_GlyphSlot glyph); virtual ~FTBitmapGlyphImpl(); virtual const FTPoint& RenderImpl(const FTPoint& pen, int renderMode); private: /** * The width of the glyph 'image' */ unsigned int destWidth; /** * The height of the glyph 'image' */ unsigned int destHeight; /** * The pitch of the glyph 'image' */ unsigned int destPitch; /** * Vector from the pen position to the topleft corner of the bitmap */ FTPoint pos; /** * Pointer to the 'image' data */ unsigned char* data; }; #endif // __FTBitmapGlyphImpl__ critterding-beta12.1/src/utils/ftgl/FTLibrary.cpp0000644000175000017500000000404411147116040020757 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * 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. */ #include "config.h" #include "FTLibrary.h" const FTLibrary& FTLibrary::Instance() { static FTLibrary ftlib; return ftlib; } FTLibrary::~FTLibrary() { if(library != 0) { FT_Done_FreeType(*library); delete library; library= 0; } // if(manager != 0) // { // FTC_Manager_Done(manager); // // delete manager; // manager= 0; // } } FTLibrary::FTLibrary() : library(0), err(0) { Initialise(); } bool FTLibrary::Initialise() { if(library != 0) return true; library = new FT_Library; err = FT_Init_FreeType(library); if(err) { delete library; library = 0; return false; } // FTC_Manager* manager; // // if(FTC_Manager_New(lib, 0, 0, 0, my_face_requester, 0, manager) // { // delete manager; // manager= 0; // return false; // } return true; } critterding-beta12.1/src/utils/ftgl/FTUnicode.h0000644000175000017500000001773411147116040020420 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2008 Daniel Remenak * * Portions derived from ConvertUTF.c Copyright (C) 2001-2004 Unicode, Inc * Unicode, Inc. hereby grants the right to freely use the information * supplied in this file in the creation of products supporting the * Unicode Standard, and to make copies of this file in any form * for internal or external distribution as long as this notice * remains attached. * * 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. */ #ifndef __FTUnicode__ #define __FTUnicode__ /** * Provides a way to easily walk multibyte unicode strings in the various * Unicode encodings (UTF-8, UTF-16, UTF-32, UCS-2, and UCS-4). Encodings * with elements larger than one byte must already be in the correct endian * order for the current architecture. */ template class FTUnicodeStringItr { public: /** * Constructor. Also reads the first character and stores it. * * @param string The buffer to iterate. No copy is made. */ FTUnicodeStringItr(const T* string) : curPos(string), nextPos(string) { (*this)++; }; /** * Pre-increment operator. Reads the next unicode character and sets * the state appropriately. * Note - not protected against overruns. */ FTUnicodeStringItr& operator++() { curPos = nextPos; // unicode handling switch (sizeof(T)) { case 1: // UTF-8 // get this character readUTF8(); break; case 2: // UTF-16 readUTF16(); break; case 4: // UTF-32 // fall through default: // error condition really, but give it a shot anyway curChar = *nextPos++; } return *this; } /** * Post-increment operator. Reads the next character and sets * the state appropriately. * Note - not protected against overruns. */ FTUnicodeStringItr operator++(int) { FTUnicodeStringItr temp = *this; ++*this; return temp; } /** * Equality operator. Two FTUnicodeStringItrs are considered equal * if they have the same current buffer and buffer position. */ bool operator==(const FTUnicodeStringItr& right) const { if (curPos == right.getBufferFromHere()) return true; return false; } /** * Dereference operator. * * @return The unicode codepoint of the character currently pointed * to by the FTUnicodeStringItr. */ unsigned int operator*() const { return curChar; } /** * Buffer-fetching getter. You can use this to retreive the buffer * starting at the currently-iterated character for functions which * require a Unicode string as input. */ const T* getBufferFromHere() const { return curPos; } private: /** * Helper function for reading a single UTF8 character from the string. * Updates internal state appropriately. */ void readUTF8(); /** * Helper function for reading a single UTF16 character from the string. * Updates internal state appropriately. */ void readUTF16(); /** * The buffer position of the first element in the current character. */ const T* curPos; /** * The character stored at the current buffer position (prefetched on * increment, so there's no penalty for dereferencing more than once). */ unsigned int curChar; /** * The buffer position of the first element in the next character. */ const T* nextPos; // unicode magic numbers static const char utf8bytes[256]; static const unsigned long offsetsFromUTF8[6]; static const unsigned long highSurrogateStart; static const unsigned long highSurrogateEnd; static const unsigned long lowSurrogateStart; static const unsigned long lowSurrogateEnd; static const unsigned long highSurrogateShift; static const unsigned long lowSurrogateBase; }; /* The first character in a UTF8 sequence indicates how many bytes * to read (among other things) */ template const char FTUnicodeStringItr::utf8bytes[256] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2, 3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,5,5,5,5,6,6,6,6 }; /* Magic values subtracted from a buffer value during UTF8 conversion. * This table contains as many values as there might be trailing bytes * in a UTF-8 sequence. */ template const unsigned long FTUnicodeStringItr::offsetsFromUTF8[6] = { 0x00000000UL, 0x00003080UL, 0x000E2080UL, 0x03C82080UL, 0xFA082080UL, 0x82082080UL }; // get a UTF8 character; leave the tracking pointer at the start of the // next character // not protected against invalid UTF8 template inline void FTUnicodeStringItr::readUTF8() { unsigned int ch = 0; unsigned int extraBytesToRead = utf8bytes[(unsigned char)(*nextPos)]; // falls through switch (extraBytesToRead) { case 6: ch += *nextPos++; ch <<= 6; /* remember, illegal UTF-8 */ case 5: ch += *nextPos++; ch <<= 6; /* remember, illegal UTF-8 */ case 4: ch += *nextPos++; ch <<= 6; case 3: ch += *nextPos++; ch <<= 6; case 2: ch += *nextPos++; ch <<= 6; case 1: ch += *nextPos++; } ch -= offsetsFromUTF8[extraBytesToRead-1]; curChar = ch; } // Magic numbers for UTF-16 conversions template const unsigned long FTUnicodeStringItr::highSurrogateStart = 0xD800; template const unsigned long FTUnicodeStringItr::highSurrogateEnd = 0xDBFF; template const unsigned long FTUnicodeStringItr::lowSurrogateStart = 0xDC00; template const unsigned long FTUnicodeStringItr::lowSurrogateEnd = 0xDFFF; template const unsigned long FTUnicodeStringItr::highSurrogateShift = 10; template const unsigned long FTUnicodeStringItr::lowSurrogateBase = 0x0010000UL; template inline void FTUnicodeStringItr::readUTF16() { unsigned int ch = *nextPos++; // if we have the first half of the surrogate pair if (ch >= highSurrogateStart && ch <= highSurrogateEnd) { unsigned int ch2 = *curPos; // complete the surrogate pair if (ch2 >= lowSurrogateStart && ch2 <= lowSurrogateEnd) { ch = ((ch - highSurrogateStart) << highSurrogateShift) + (ch2 - lowSurrogateStart) + lowSurrogateBase; ++nextPos; } } curChar = ch; } #endif critterding-beta12.1/src/utils/ftgl/FTList.h0000644000175000017500000000630211147116040017732 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * 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. */ #ifndef __FTList__ #define __FTList__ #include "FTGL/ftgl.h" /** * Provides a non-STL alternative to the STL list */ template class FTList { public: typedef FT_LIST_ITEM_TYPE value_type; typedef value_type& reference; typedef const value_type& const_reference; typedef size_t size_type; /** * Constructor */ FTList() : listSize(0), tail(0) { tail = NULL; head = new Node; } /** * Destructor */ ~FTList() { Node* next; for(Node *walk = head; walk; walk = next) { next = walk->next; delete walk; } } /** * Get the number of items in the list */ size_type size() const { return listSize; } /** * Add an item to the end of the list */ void push_back(const value_type& item) { Node* node = new Node(item); if(head->next == NULL) { head->next = node; } if(tail) { tail->next = node; } tail = node; ++listSize; } /** * Get the item at the front of the list */ reference front() const { return head->next->payload; } /** * Get the item at the end of the list */ reference back() const { return tail->payload; } private: struct Node { Node() : next(NULL) {} Node(const value_type& item) : next(NULL) { payload = item; } Node* next; value_type payload; }; size_type listSize; Node* head; Node* tail; }; #endif // __FTList__ critterding-beta12.1/src/utils/ftgl/FTVectoriser.cpp0000644000175000017500000002106411147116040021501 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include "FTInternals.h" #include "FTVectoriser.h" #ifndef CALLBACK #define CALLBACK #endif #if defined __APPLE_CC__ && __APPLE_CC__ < 5465 typedef GLvoid (*GLUTesselatorFunction) (...); #elif defined WIN32 && !defined __CYGWIN__ typedef GLvoid (CALLBACK *GLUTesselatorFunction) (); #else typedef GLvoid (*GLUTesselatorFunction) (); #endif void CALLBACK ftglError(GLenum errCode, FTMesh* mesh) { mesh->Error(errCode); } void CALLBACK ftglVertex(void* data, FTMesh* mesh) { FTGL_DOUBLE* vertex = static_cast(data); mesh->AddPoint(vertex[0], vertex[1], vertex[2]); } void CALLBACK ftglCombine(FTGL_DOUBLE coords[3], void* vertex_data[4], GLfloat weight[4], void** outData, FTMesh* mesh) { const FTGL_DOUBLE* vertex = static_cast(coords); *outData = const_cast(mesh->Combine(vertex[0], vertex[1], vertex[2])); } void CALLBACK ftglBegin(GLenum type, FTMesh* mesh) { mesh->Begin(type); } void CALLBACK ftglEnd(FTMesh* mesh) { mesh->End(); } FTMesh::FTMesh() : currentTesselation(0), err(0) { tesselationList.reserve(16); } FTMesh::~FTMesh() { for(size_t t = 0; t < tesselationList.size(); ++t) { delete tesselationList[t]; } tesselationList.clear(); } void FTMesh::AddPoint(const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z) { currentTesselation->AddPoint(x, y, z); } const FTGL_DOUBLE* FTMesh::Combine(const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z) { tempPointList.push_back(FTPoint(x, y,z)); return static_cast(tempPointList.back()); } void FTMesh::Begin(GLenum meshType) { currentTesselation = new FTTesselation(meshType); } void FTMesh::End() { tesselationList.push_back(currentTesselation); } const FTTesselation* const FTMesh::Tesselation(size_t index) const { return (index < tesselationList.size()) ? tesselationList[index] : NULL; } FTVectoriser::FTVectoriser(const FT_GlyphSlot glyph) : contourList(0), mesh(0), ftContourCount(0), contourFlag(0) { if(glyph) { outline = glyph->outline; ftContourCount = outline.n_contours; contourList = 0; contourFlag = outline.flags; ProcessContours(); } } FTVectoriser::~FTVectoriser() { for(size_t c = 0; c < ContourCount(); ++c) { delete contourList[c]; } delete [] contourList; delete mesh; } void FTVectoriser::ProcessContours() { short contourLength = 0; short startIndex = 0; short endIndex = 0; contourList = new FTContour*[ftContourCount]; for(int i = 0; i < ftContourCount; ++i) { FT_Vector* pointList = &outline.points[startIndex]; char* tagList = &outline.tags[startIndex]; endIndex = outline.contours[i]; contourLength = (endIndex - startIndex) + 1; FTContour* contour = new FTContour(pointList, tagList, contourLength); contourList[i] = contour; startIndex = endIndex + 1; } // Compute each contour's parity. FIXME: see if FT_Outline_Get_Orientation // can do it for us. for(int i = 0; i < ftContourCount; i++) { FTContour *c1 = contourList[i]; // 1. Find the leftmost point. FTPoint leftmost(65536.0, 0.0); for(size_t n = 0; n < c1->PointCount(); n++) { FTPoint p = c1->Point(n); if(p.X() < leftmost.X()) { leftmost = p; } } // 2. Count how many other contours we cross when going further to // the left. int parity = 0; for(int j = 0; j < ftContourCount; j++) { if(j == i) { continue; } FTContour *c2 = contourList[j]; for(size_t n = 0; n < c2->PointCount(); n++) { FTPoint p1 = c2->Point(n); FTPoint p2 = c2->Point((n + 1) % c2->PointCount()); /* FIXME: combinations of >= > <= and < do not seem stable */ if((p1.Y() < leftmost.Y() && p2.Y() < leftmost.Y()) || (p1.Y() >= leftmost.Y() && p2.Y() >= leftmost.Y()) || (p1.X() > leftmost.X() && p2.X() > leftmost.X())) { continue; } else if(p1.X() < leftmost.X() && p2.X() < leftmost.X()) { parity++; } else { FTPoint a = p1 - leftmost; FTPoint b = p2 - leftmost; if(b.X() * a.Y() > b.Y() * a.X()) { parity++; } } } } // 3. Make sure the glyph has the proper parity. c1->SetParity(parity); } } size_t FTVectoriser::PointCount() { size_t s = 0; for(size_t c = 0; c < ContourCount(); ++c) { s += contourList[c]->PointCount(); } return s; } const FTContour* const FTVectoriser::Contour(size_t index) const { return (index < ContourCount()) ? contourList[index] : NULL; } void FTVectoriser::MakeMesh(FTGL_DOUBLE zNormal, int outsetType, float outsetSize) { if(mesh) { delete mesh; } mesh = new FTMesh; GLUtesselator* tobj = gluNewTess(); gluTessCallback(tobj, GLU_TESS_BEGIN_DATA, (GLUTesselatorFunction)ftglBegin); gluTessCallback(tobj, GLU_TESS_VERTEX_DATA, (GLUTesselatorFunction)ftglVertex); gluTessCallback(tobj, GLU_TESS_COMBINE_DATA, (GLUTesselatorFunction)ftglCombine); gluTessCallback(tobj, GLU_TESS_END_DATA, (GLUTesselatorFunction)ftglEnd); gluTessCallback(tobj, GLU_TESS_ERROR_DATA, (GLUTesselatorFunction)ftglError); if(contourFlag & ft_outline_even_odd_fill) // ft_outline_reverse_fill { gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_ODD); } else { gluTessProperty(tobj, GLU_TESS_WINDING_RULE, GLU_TESS_WINDING_NONZERO); } gluTessProperty(tobj, GLU_TESS_TOLERANCE, 0); gluTessNormal(tobj, 0.0f, 0.0f, zNormal); gluTessBeginPolygon(tobj, mesh); for(size_t c = 0; c < ContourCount(); ++c) { /* Build the */ switch(outsetType) { case 1 : contourList[c]->buildFrontOutset(outsetSize); break; case 2 : contourList[c]->buildBackOutset(outsetSize); break; } const FTContour* contour = contourList[c]; gluTessBeginContour(tobj); for(size_t p = 0; p < contour->PointCount(); ++p) { const FTGL_DOUBLE* d; switch(outsetType) { case 1: d = contour->FrontPoint(p); break; case 2: d = contour->BackPoint(p); break; case 0: default: d = contour->Point(p); break; } // XXX: gluTessVertex doesn't modify the data but does not // specify "const" in its prototype, so we cannot cast to // a const type. gluTessVertex(tobj, (GLdouble *)d, (GLvoid *)d); } gluTessEndContour(tobj); } gluTessEndPolygon(tobj); gluDeleteTess(tobj); } critterding-beta12.1/src/utils/ftgl/FTFont/0000755000175000017500000000000011347266042017565 5ustar bobkebobkecritterding-beta12.1/src/utils/ftgl/FTFont/FTPixmapFont.cpp0000644000175000017500000000753711147116040022612 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTPixmapFontImpl.h" // // FTPixmapFont // FTPixmapFont::FTPixmapFont(char const *fontFilePath) : FTFont(new FTPixmapFontImpl(this, fontFilePath)) {} FTPixmapFont::FTPixmapFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTPixmapFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTPixmapFont::~FTPixmapFont() {} FTGlyph* FTPixmapFont::MakeGlyph(FT_GlyphSlot ftGlyph) { return new FTPixmapGlyph(ftGlyph); } // // FTPixmapFontImpl // FTPixmapFontImpl::FTPixmapFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath) { load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; } FTPixmapFontImpl::FTPixmapFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes) { load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; } template inline FTPoint FTPixmapFontImpl::RenderI(const T* string, const int len, FTPoint position, FTPoint spacing, int renderMode) { // Protect GL_TEXTURE_2D and GL_BLEND, glPixelTransferf(), and blending // functions. glPushAttrib(GL_ENABLE_BIT | GL_PIXEL_MODE_BIT | GL_COLOR_BUFFER_BIT); // Protect glPixelStorei() calls (made by FTPixmapGlyphImpl::RenderImpl). glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glDisable(GL_TEXTURE_2D); GLfloat ftglColour[4]; glGetFloatv(GL_CURRENT_RASTER_COLOR, ftglColour); glPixelTransferf(GL_RED_SCALE, ftglColour[0]); glPixelTransferf(GL_GREEN_SCALE, ftglColour[1]); glPixelTransferf(GL_BLUE_SCALE, ftglColour[2]); glPixelTransferf(GL_ALPHA_SCALE, ftglColour[3]); FTPoint tmp = FTFontImpl::Render(string, len, position, spacing, renderMode); glPopClientAttrib(); glPopAttrib(); return tmp; } FTPoint FTPixmapFontImpl::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } FTPoint FTPixmapFontImpl::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } critterding-beta12.1/src/utils/ftgl/FTFont/FTFontGlue.cpp0000644000175000017500000001701011147116040022233 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include "FTInternals.h" static const FTPoint static_ftpoint; static const FTBBox static_ftbbox; FTGL_BEGIN_C_DECLS #define C_TOR(cname, cargs, cxxname, cxxarg, cxxtype) \ FTGLfont* cname cargs \ { \ cxxname *f = new cxxname cxxarg; \ if(f->Error()) \ { \ delete f; \ return NULL; \ } \ FTGLfont *ftgl = (FTGLfont *)malloc(sizeof(FTGLfont)); \ ftgl->ptr = f; \ ftgl->type = cxxtype; \ return ftgl; \ } // FTBitmapFont::FTBitmapFont(); C_TOR(ftglCreateBitmapFont, (const char *fontname), FTBitmapFont, (fontname), FONT_BITMAP); // FTBufferFont::FTBufferFont(); C_TOR(ftglCreateBufferFont, (const char *fontname), FTBufferFont, (fontname), FONT_BUFFER); // FTExtrudeFont::FTExtrudeFont(); C_TOR(ftglCreateExtrudeFont, (const char *fontname), FTExtrudeFont, (fontname), FONT_EXTRUDE); // FTOutlineFont::FTOutlineFont(); C_TOR(ftglCreateOutlineFont, (const char *fontname), FTOutlineFont, (fontname), FONT_OUTLINE); // FTPixmapFont::FTPixmapFont(); C_TOR(ftglCreatePixmapFont, (const char *fontname), FTPixmapFont, (fontname), FONT_PIXMAP); // FTPolygonFont::FTPolygonFont(); C_TOR(ftglCreatePolygonFont, (const char *fontname), FTPolygonFont, (fontname), FONT_POLYGON); // FTTextureFont::FTTextureFont(); C_TOR(ftglCreateTextureFont, (const char *fontname), FTTextureFont, (fontname), FONT_TEXTURE); // FTCustomFont::FTCustomFont(); class FTCustomFont : public FTFont { public: FTCustomFont(char const *fontFilePath, void *p, FTGLglyph * (*makeglyph) (FT_GlyphSlot, void *)) : FTFont(fontFilePath), data(p), makeglyphCallback(makeglyph) {} ~FTCustomFont() {} FTGlyph* MakeGlyph(FT_GlyphSlot slot) { FTGLglyph *g = makeglyphCallback(slot, data); FTGlyph *glyph = g->ptr; // XXX: we no longer need g, and no one will free it for us. Not // very elegant, and we need to make sure no one else will try to // use it. free(g); return glyph; } private: void *data; FTGLglyph *(*makeglyphCallback) (FT_GlyphSlot, void *); }; C_TOR(ftglCreateCustomFont, (char const *fontFilePath, void *data, FTGLglyph * (*makeglyphCallback) (FT_GlyphSlot, void *)), FTCustomFont, (fontFilePath, data, makeglyphCallback), FONT_CUSTOM); #define C_FUN(cret, cname, cargs, cxxerr, cxxname, cxxarg) \ cret cname cargs \ { \ if(!f || !f->ptr) \ { \ fprintf(stderr, "FTGL warning: NULL pointer in %s\n", #cname); \ cxxerr; \ } \ return f->ptr->cxxname cxxarg; \ } // FTFont::~FTFont(); void ftglDestroyFont(FTGLfont *f) { if(!f || !f->ptr) { fprintf(stderr, "FTGL warning: NULL pointer in %s\n", __FUNCTION__); return; } delete f->ptr; free(f); } // bool FTFont::Attach(const char* fontFilePath); C_FUN(int, ftglAttachFile, (FTGLfont *f, const char* path), return 0, Attach, (path)); // bool FTFont::Attach(const unsigned char *pBufferBytes, // size_t bufferSizeInBytes); C_FUN(int, ftglAttachData, (FTGLfont *f, const unsigned char *p, size_t s), return 0, Attach, (p, s)); // void FTFont::GlyphLoadFlags(FT_Int flags); C_FUN(void, ftglSetFontGlyphLoadFlags, (FTGLfont *f, FT_Int flags), return, GlyphLoadFlags, (flags)); // bool FTFont::CharMap(FT_Encoding encoding); C_FUN(int, ftglSetFontCharMap, (FTGLfont *f, FT_Encoding enc), return 0, CharMap, (enc)); // unsigned int FTFont::CharMapCount(); C_FUN(unsigned int, ftglGetFontCharMapCount, (FTGLfont *f), return 0, CharMapCount, ()); // FT_Encoding* FTFont::CharMapList(); C_FUN(FT_Encoding *, ftglGetFontCharMapList, (FTGLfont* f), return NULL, CharMapList, ()); // virtual bool FTFont::FaceSize(const unsigned int size, // const unsigned int res = 72); C_FUN(int, ftglSetFontFaceSize, (FTGLfont *f, unsigned int s, unsigned int r), return 0, FaceSize, (s, r > 0 ? r : 72)); // unsigned int FTFont::FaceSize() const; // XXX: need to call FaceSize() as FTFont::FaceSize() because of FTGLTexture C_FUN(unsigned int, ftglGetFontFaceSize, (FTGLfont *f), return 0, FTFont::FaceSize, ()); // virtual void FTFont::Depth(float depth); C_FUN(void, ftglSetFontDepth, (FTGLfont *f, float d), return, Depth, (d)); // virtual void FTFont::Outset(float front, float back); C_FUN(void, ftglSetFontOutset, (FTGLfont *f, float front, float back), return, FTFont::Outset, (front, back)); // void FTFont::UseDisplayList(bool useList); C_FUN(void, ftglSetFontDisplayList, (FTGLfont *f, int l), return, UseDisplayList, (l != 0)); // float FTFont::Ascender() const; C_FUN(float, ftglGetFontAscender, (FTGLfont *f), return 0.f, Ascender, ()); // float FTFont::Descender() const; C_FUN(float, ftglGetFontDescender, (FTGLfont *f), return 0.f, Descender, ()); // float FTFont::LineHeight() const; C_FUN(float, ftglGetFontLineHeight, (FTGLfont *f), return 0.f, LineHeight, ()); // void FTFont::BBox(const char* string, float& llx, float& lly, float& llz, // float& urx, float& ury, float& urz); extern "C++" { C_FUN(static FTBBox, _ftglGetFontBBox, (FTGLfont *f, char const *s, int len), return static_ftbbox, BBox, (s, len)); } void ftglGetFontBBox(FTGLfont *f, const char* s, int len, float c[6]) { FTBBox ret = _ftglGetFontBBox(f, s, len); FTPoint lower = ret.Lower(), upper = ret.Upper(); c[0] = lower.Xf(); c[1] = lower.Yf(); c[2] = lower.Zf(); c[3] = upper.Xf(); c[4] = upper.Yf(); c[5] = upper.Zf(); } // float FTFont::Advance(const char* string); C_FUN(float, ftglGetFontAdvance, (FTGLfont *f, char const *s), return 0.0, Advance, (s)); // virtual void Render(const char* string, int renderMode); extern "C++" { C_FUN(static FTPoint, _ftglRenderFont, (FTGLfont *f, char const *s, int len, FTPoint pos, FTPoint spacing, int mode), return static_ftpoint, Render, (s, len, pos, spacing, mode)); } void ftglRenderFont(FTGLfont *f, const char *s, int mode) { _ftglRenderFont(f, s, -1, FTPoint(), FTPoint(), mode); } // FT_Error FTFont::Error() const; C_FUN(FT_Error, ftglGetFontError, (FTGLfont *f), return -1, Error, ()); FTGL_END_C_DECLS critterding-beta12.1/src/utils/ftgl/FTFont/FTFontImpl.h0000644000175000017500000001135311147116040021711 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTFontImpl__ #define __FTFontImpl__ #include "FTGL/ftgl.h" #include "FTFace.h" class FTGlyphContainer; class FTGlyph; class FTFontImpl { friend class FTFont; protected: FTFontImpl(FTFont *ftFont, char const *fontFilePath); FTFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); virtual ~FTFontImpl(); virtual bool Attach(const char* fontFilePath); virtual bool Attach(const unsigned char *pBufferBytes, size_t bufferSizeInBytes); virtual void GlyphLoadFlags(FT_Int flags); virtual bool CharMap(FT_Encoding encoding); virtual unsigned int CharMapCount() const; virtual FT_Encoding* CharMapList(); virtual void UseDisplayList(bool useList); virtual float Ascender() const; virtual float Descender() const; virtual float LineHeight() const; virtual bool FaceSize(const unsigned int size, const unsigned int res); virtual unsigned int FaceSize() const; virtual void Depth(float depth); virtual void Outset(float outset); virtual void Outset(float front, float back); virtual FTBBox BBox(const char *s, const int len, FTPoint, FTPoint); virtual FTBBox BBox(const wchar_t *s, const int len, FTPoint, FTPoint); virtual float Advance(const char *s, const int len, FTPoint); virtual float Advance(const wchar_t *s, const int len, FTPoint); virtual FTPoint Render(const char *s, const int len, FTPoint, FTPoint, int); virtual FTPoint Render(const wchar_t *s, const int len, FTPoint, FTPoint, int); /** * Current face object */ FTFace face; /** * Current size object */ FTSize charSize; /** * Flag to enable or disable the use of Display Lists inside FTGL * true turns ON display lists. * false turns OFF display lists. */ bool useDisplayLists; /** * The default glyph loading flags. */ FT_Int load_flags; /** * Current error code. Zero means no error. */ FT_Error err; private: /** * A link back to the interface of which we are the implementation. */ FTFont *intf; /** * Check that the glyph at chr exist. If not load it. * * @param chr character index * @return true if the glyph can be created. */ bool CheckGlyph(const unsigned int chr); /** * An object that holds a list of glyphs */ FTGlyphContainer* glyphList; /** * Current pen or cursor position; */ FTPoint pen; /* Internal generic BBox() implementation */ template inline FTBBox BBoxI(const T *s, const int len, FTPoint position, FTPoint spacing); /* Internal generic Advance() implementation */ template inline float AdvanceI(const T *s, const int len, FTPoint spacing); /* Internal generic Render() implementation */ template inline FTPoint RenderI(const T *s, const int len, FTPoint position, FTPoint spacing, int mode); }; #endif // __FTFontImpl__ critterding-beta12.1/src/utils/ftgl/FTFont/FTExtrudeFontImpl.h0000644000175000017500000000510511147116040023250 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTExtrudeFontImpl__ #define __FTExtrudeFontImpl__ #include "FTFontImpl.h" class FTGlyph; class FTExtrudeFontImpl : public FTFontImpl { friend class FTExtrudeFont; protected: FTExtrudeFontImpl(FTFont *ftFont, const char* fontFilePath); FTExtrudeFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Set the extrusion distance for the font. * * @param d The extrusion distance. */ virtual void Depth(float d) { depth = d; } /** * Set the outset distance for the font. Only implemented by * FTOutlineFont, FTPolygonFont and FTExtrudeFont * * @param o The outset distance. */ virtual void Outset(float o) { front = back = o; } /** * Set the outset distance for the font. Only implemented by * FTExtrudeFont * * @param f The front outset distance. * @param b The back outset distance. */ virtual void Outset(float f, float b) { front = f; back = b; } private: /** * The extrusion distance for the font. */ float depth; /** * The outset distance (front and back) for the font. */ float front, back; }; #endif // __FTExtrudeFontImpl__ critterding-beta12.1/src/utils/ftgl/FTFont/FTOutlineFontImpl.h0000644000175000017500000000506011147116040023247 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTOutlineFontImpl__ #define __FTOutlineFontImpl__ #include "FTFontImpl.h" class FTGlyph; class FTOutlineFontImpl : public FTFontImpl { friend class FTOutlineFont; protected: FTOutlineFontImpl(FTFont *ftFont, const char* fontFilePath); FTOutlineFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Set the outset distance for the font. Only implemented by * FTOutlineFont, FTPolygonFont and FTExtrudeFont * * @param outset The outset distance. */ virtual void Outset(float o) { outset = o; } virtual FTPoint Render(const char *s, const int len, FTPoint position, FTPoint spacing, int renderMode); virtual FTPoint Render(const wchar_t *s, const int len, FTPoint position, FTPoint spacing, int renderMode); private: /** * The outset distance for the font. */ float outset; /* Internal generic Render() implementation */ template inline FTPoint RenderI(const T *s, const int len, FTPoint position, FTPoint spacing, int mode); }; #endif // __FTOutlineFontImpl__ critterding-beta12.1/src/utils/ftgl/FTFont/FTPolygonFont.cpp0000644000175000017500000000471711147116040023000 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTPolygonFontImpl.h" // // FTPolygonFont // FTPolygonFont::FTPolygonFont(char const *fontFilePath) : FTFont(new FTPolygonFontImpl(this, fontFilePath)) {} FTPolygonFont::FTPolygonFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTPolygonFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTPolygonFont::~FTPolygonFont() {} FTGlyph* FTPolygonFont::MakeGlyph(FT_GlyphSlot ftGlyph) { FTPolygonFontImpl *myimpl = dynamic_cast(impl); if(!myimpl) { return NULL; } return new FTPolygonGlyph(ftGlyph, myimpl->outset, myimpl->useDisplayLists); } // // FTPolygonFontImpl // FTPolygonFontImpl::FTPolygonFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath), outset(0.0f) { load_flags = FT_LOAD_NO_HINTING; } FTPolygonFontImpl::FTPolygonFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes), outset(0.0f) { load_flags = FT_LOAD_NO_HINTING; } critterding-beta12.1/src/utils/ftgl/FTFont/FTTextureFont.cpp0000644000175000017500000001644711147116040023014 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include #include // For memset #include "FTGL/ftgl.h" #include "FTInternals.h" #include "../FTGlyph/FTTextureGlyphImpl.h" #include "./FTTextureFontImpl.h" // // FTTextureFont // FTTextureFont::FTTextureFont(char const *fontFilePath) : FTFont(new FTTextureFontImpl(this, fontFilePath)) {} FTTextureFont::FTTextureFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTTextureFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTTextureFont::~FTTextureFont() {} FTGlyph* FTTextureFont::MakeGlyph(FT_GlyphSlot ftGlyph) { FTTextureFontImpl *myimpl = dynamic_cast(impl); if(!myimpl) { return NULL; } return myimpl->MakeGlyphImpl(ftGlyph); } // // FTTextureFontImpl // static inline GLuint NextPowerOf2(GLuint in) { in -= 1; in |= in >> 16; in |= in >> 8; in |= in >> 4; in |= in >> 2; in |= in >> 1; return in + 1; } FTTextureFontImpl::FTTextureFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath), maximumGLTextureSize(0), textureWidth(0), textureHeight(0), glyphHeight(0), glyphWidth(0), padding(3), xOffset(0), yOffset(0) { load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; remGlyphs = numGlyphs = face.GlyphCount(); } FTTextureFontImpl::FTTextureFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes), maximumGLTextureSize(0), textureWidth(0), textureHeight(0), glyphHeight(0), glyphWidth(0), padding(3), xOffset(0), yOffset(0) { load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; remGlyphs = numGlyphs = face.GlyphCount(); } FTTextureFontImpl::~FTTextureFontImpl() { if(textureIDList.size()) { glDeleteTextures((GLsizei)textureIDList.size(), (const GLuint*)&textureIDList[0]); } } FTGlyph* FTTextureFontImpl::MakeGlyphImpl(FT_GlyphSlot ftGlyph) { glyphHeight = static_cast(charSize.Height() + 0.5); glyphWidth = static_cast(charSize.Width() + 0.5); if(glyphHeight < 1) glyphHeight = 1; if(glyphWidth < 1) glyphWidth = 1; if(textureIDList.empty()) { textureIDList.push_back(CreateTexture()); xOffset = yOffset = padding; } if(xOffset > (textureWidth - glyphWidth)) { xOffset = padding; yOffset += glyphHeight; if(yOffset > (textureHeight - glyphHeight)) { textureIDList.push_back(CreateTexture()); yOffset = padding; } } FTTextureGlyph* tempGlyph = new FTTextureGlyph(ftGlyph, textureIDList[textureIDList.size() - 1], xOffset, yOffset, textureWidth, textureHeight); xOffset += static_cast(tempGlyph->BBox().Upper().X() - tempGlyph->BBox().Lower().X() + padding + 0.5); --remGlyphs; return tempGlyph; } void FTTextureFontImpl::CalculateTextureSize() { if(!maximumGLTextureSize) { maximumGLTextureSize = 1024; glGetIntegerv(GL_MAX_TEXTURE_SIZE, (GLint*)&maximumGLTextureSize); assert(maximumGLTextureSize); // If you hit this then you have an invalid OpenGL context. } textureWidth = NextPowerOf2((remGlyphs * glyphWidth) + (padding * 2)); textureWidth = textureWidth > maximumGLTextureSize ? maximumGLTextureSize : textureWidth; int h = static_cast((textureWidth - (padding * 2)) / glyphWidth + 0.5); textureHeight = NextPowerOf2(((numGlyphs / h) + 1) * glyphHeight); textureHeight = textureHeight > maximumGLTextureSize ? maximumGLTextureSize : textureHeight; } GLuint FTTextureFontImpl::CreateTexture() { CalculateTextureSize(); int totalMemory = textureWidth * textureHeight; unsigned char* textureMemory = new unsigned char[totalMemory]; memset(textureMemory, 0, totalMemory); GLuint textID; glGenTextures(1, (GLuint*)&textID); glBindTexture(GL_TEXTURE_2D, textID); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, textureWidth, textureHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, textureMemory); delete [] textureMemory; return textID; } bool FTTextureFontImpl::FaceSize(const unsigned int size, const unsigned int res) { if(!textureIDList.empty()) { glDeleteTextures((GLsizei)textureIDList.size(), (const GLuint*)&textureIDList[0]); textureIDList.clear(); remGlyphs = numGlyphs = face.GlyphCount(); } return FTFontImpl::FaceSize(size, res); } template inline FTPoint FTTextureFontImpl::RenderI(const T* string, const int len, FTPoint position, FTPoint spacing, int renderMode) { // Protect GL_TEXTURE_2D, GL_BLEND and blending functions glPushAttrib(GL_ENABLE_BIT | GL_COLOR_BUFFER_BIT); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE glEnable(GL_TEXTURE_2D); FTTextureGlyphImpl::ResetActiveTexture(); FTPoint tmp = FTFontImpl::Render(string, len, position, spacing, renderMode); glPopAttrib(); return tmp; } FTPoint FTTextureFontImpl::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } FTPoint FTTextureFontImpl::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } critterding-beta12.1/src/utils/ftgl/FTFont/FTBufferFontImpl.h0000644000175000017500000000541211147116040023042 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTBufferFontImpl__ #define __FTBufferFontImpl__ #include "FTFontImpl.h" class FTGlyph; class FTBuffer; class FTBufferFontImpl : public FTFontImpl { friend class FTBufferFont; protected: FTBufferFontImpl(FTFont *ftFont, const char* fontFilePath); FTBufferFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); virtual ~FTBufferFontImpl(); virtual FTPoint Render(const char *s, const int len, FTPoint position, FTPoint spacing, int renderMode); virtual FTPoint Render(const wchar_t *s, const int len, FTPoint position, FTPoint spacing, int renderMode); virtual bool FaceSize(const unsigned int size, const unsigned int res); private: /** * Create an FTBufferGlyph object for the base class. */ FTGlyph* MakeGlyphImpl(FT_GlyphSlot ftGlyph); /* Internal generic Render() implementation */ template inline FTPoint RenderI(const T *s, const int len, FTPoint position, FTPoint spacing, int mode); /* Pixel buffer */ FTBuffer *buffer; static const int BUFFER_CACHE_SIZE = 16; /* Texture IDs */ GLuint idCache[BUFFER_CACHE_SIZE]; void *stringCache[BUFFER_CACHE_SIZE]; FTBBox bboxCache[BUFFER_CACHE_SIZE]; FTPoint advanceCache[BUFFER_CACHE_SIZE]; int lastString; }; #endif // __FTBufferFontImpl__ critterding-beta12.1/src/utils/ftgl/FTFont/FTTextureFontImpl.h0000644000175000017500000001100511147116040023264 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTTextureFontImpl__ #define __FTTextureFontImpl__ #include "FTFontImpl.h" #include "FTVector.h" class FTTextureGlyph; class FTTextureFontImpl : public FTFontImpl { friend class FTTextureFont; protected: FTTextureFontImpl(FTFont *ftFont, const char* fontFilePath); FTTextureFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); virtual ~FTTextureFontImpl(); /** * Set the char size for the current face. * * @param size the face size in points (1/72 inch) * @param res the resolution of the target device. * @return true if size was set correctly */ virtual bool FaceSize(const unsigned int size, const unsigned int res = 72); virtual FTPoint Render(const char *s, const int len, FTPoint position, FTPoint spacing, int renderMode); virtual FTPoint Render(const wchar_t *s, const int len, FTPoint position, FTPoint spacing, int renderMode); private: /** * Create an FTTextureGlyph object for the base class. */ FTGlyph* MakeGlyphImpl(FT_GlyphSlot ftGlyph); /** * Get the size of a block of memory required to layout the glyphs * * Calculates a width and height based on the glyph sizes and the * number of glyphs. It over estimates. */ inline void CalculateTextureSize(); /** * Creates a 'blank' OpenGL texture object. * * The format is GL_ALPHA and the params are * GL_TEXTURE_WRAP_S = GL_CLAMP * GL_TEXTURE_WRAP_T = GL_CLAMP * GL_TEXTURE_MAG_FILTER = GL_LINEAR * GL_TEXTURE_MIN_FILTER = GL_LINEAR * Note that mipmapping is NOT used */ inline GLuint CreateTexture(); /** * The maximum texture dimension on this OpenGL implemetation */ GLsizei maximumGLTextureSize; /** * The minimum texture width required to hold the glyphs */ GLsizei textureWidth; /** * The minimum texture height required to hold the glyphs */ GLsizei textureHeight; /** *An array of texture ids */ FTVector textureIDList; /** * The max height for glyphs in the current font */ int glyphHeight; /** * The max width for glyphs in the current font */ int glyphWidth; /** * A value to be added to the height and width to ensure that * glyphs don't overlap in the texture */ unsigned int padding; /** * */ unsigned int numGlyphs; /** */ unsigned int remGlyphs; /** */ int xOffset; /** */ int yOffset; /* Internal generic Render() implementation */ template inline FTPoint RenderI(const T *s, const int len, FTPoint position, FTPoint spacing, int mode); }; #endif // __FTTextureFontImpl__ critterding-beta12.1/src/utils/ftgl/FTFont/FTBufferFont.cpp0000644000175000017500000002265111147116040022557 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTBufferFontImpl.h" // // FTBufferFont // FTBufferFont::FTBufferFont(char const *fontFilePath) : FTFont(new FTBufferFontImpl(this, fontFilePath)) {} FTBufferFont::FTBufferFont(unsigned char const *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTBufferFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTBufferFont::~FTBufferFont() {} FTGlyph* FTBufferFont::MakeGlyph(FT_GlyphSlot ftGlyph) { FTBufferFontImpl *myimpl = dynamic_cast(impl); if(!myimpl) { return NULL; } return myimpl->MakeGlyphImpl(ftGlyph); } // // FTBufferFontImpl // FTBufferFontImpl::FTBufferFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath), buffer(new FTBuffer()) { load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; glGenTextures(BUFFER_CACHE_SIZE, idCache); for(int i = 0; i < BUFFER_CACHE_SIZE; i++) { stringCache[i] = NULL; glBindTexture(GL_TEXTURE_2D, idCache[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } lastString = 0; } FTBufferFontImpl::FTBufferFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes), buffer(new FTBuffer()) { load_flags = FT_LOAD_NO_HINTING | FT_LOAD_NO_BITMAP; glGenTextures(BUFFER_CACHE_SIZE, idCache); for(int i = 0; i < BUFFER_CACHE_SIZE; i++) { stringCache[i] = NULL; glBindTexture(GL_TEXTURE_2D, idCache[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); } lastString = 0; } FTBufferFontImpl::~FTBufferFontImpl() { glDeleteTextures(BUFFER_CACHE_SIZE, idCache); for(int i = 0; i < BUFFER_CACHE_SIZE; i++) { if(stringCache[i]) { free(stringCache[i]); } } delete buffer; } FTGlyph* FTBufferFontImpl::MakeGlyphImpl(FT_GlyphSlot ftGlyph) { return new FTBufferGlyph(ftGlyph, buffer); } bool FTBufferFontImpl::FaceSize(const unsigned int size, const unsigned int res) { for(int i = 0; i < BUFFER_CACHE_SIZE; i++) { if(stringCache[i]) { free(stringCache[i]); stringCache[i] = NULL; } } return FTFontImpl::FaceSize(size, res); } static inline GLuint NextPowerOf2(GLuint in) { in -= 1; in |= in >> 16; in |= in >> 8; in |= in >> 4; in |= in >> 2; in |= in >> 1; return in + 1; } inline int StringCompare(void const *a, char const *b, int len) { return len < 0 ? strcmp((char const *)a, b) : strncmp((char const *)a, b, len); } inline int StringCompare(void const *a, wchar_t const *b, int len) { return len < 0 ? wcscmp((wchar_t const *)a, b) : wcsncmp((wchar_t const *)a, b, len); } inline char *StringCopy(char const *s, int len) { if(len < 0) { return strdup(s); } else { #ifdef HAVE_STRNDUP return strndup(s, len); #else char *s2 = (char*)malloc(len + 1); memcpy(s2, s, len); s2[len] = 0; return s2; #endif } } inline wchar_t *StringCopy(wchar_t const *s, int len) { if(len < 0) { #if defined HAVE_WCSDUP return wcsdup(s); #else len = (int)wcslen(s); #endif } wchar_t *s2 = (wchar_t *)malloc((len + 1) * sizeof(wchar_t)); memcpy(s2, s, len * sizeof(wchar_t)); s2[len] = 0; return s2; } template inline FTPoint FTBufferFontImpl::RenderI(const T* string, const int len, FTPoint position, FTPoint spacing, int renderMode) { const float padding = 3.0f; int width, height, texWidth, texHeight; int cacheIndex = -1; bool inCache = false; // Protect blending functions, GL_BLEND and GL_TEXTURE_2D glPushAttrib(GL_COLOR_BUFFER_BIT | GL_ENABLE_BIT); // Protect glPixelStorei() calls glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); glEnable(GL_BLEND); glEnable(GL_TEXTURE_2D); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE // Search whether the string is already in a texture we uploaded for(int n = 0; n < BUFFER_CACHE_SIZE; n++) { int i = (lastString + n + BUFFER_CACHE_SIZE) % BUFFER_CACHE_SIZE; if(stringCache[i] && !StringCompare(stringCache[i], string, len)) { cacheIndex = i; inCache = true; break; } } // If the string was not found, we need to put it in the cache and compute // its new bounding box. if(!inCache) { // FIXME: this cache is not very efficient. We should first expire // strings that are not used very often. cacheIndex = lastString; lastString = (lastString + 1) % BUFFER_CACHE_SIZE; if(stringCache[cacheIndex]) { free(stringCache[cacheIndex]); } // FIXME: only the first N bytes are copied; we want the first N chars. stringCache[cacheIndex] = StringCopy(string, len); bboxCache[cacheIndex] = BBox(string, len, FTPoint(), spacing); } FTBBox bbox = bboxCache[cacheIndex]; width = static_cast(bbox.Upper().X() - bbox.Lower().X() + padding + padding + 0.5); height = static_cast(bbox.Upper().Y() - bbox.Lower().Y() + padding + padding + 0.5); texWidth = NextPowerOf2(width); texHeight = NextPowerOf2(height); glBindTexture(GL_TEXTURE_2D, idCache[cacheIndex]); // If the string was not found, we need to render the text in a new // texture buffer, then upload it to the OpenGL layer. if(!inCache) { buffer->Size(texWidth, texHeight); buffer->Pos(FTPoint(padding, padding) - bbox.Lower()); advanceCache[cacheIndex] = FTFontImpl::Render(string, len, FTPoint(), spacing, renderMode); glBindTexture(GL_TEXTURE_2D, idCache[cacheIndex]); glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); glPixelStorei(GL_UNPACK_ROW_LENGTH, 0); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); /* TODO: use glTexSubImage2D later? */ glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, texWidth, texHeight, 0, GL_ALPHA, GL_UNSIGNED_BYTE, (GLvoid *)buffer->Pixels()); buffer->Size(0, 0); } FTPoint low = position + bbox.Lower(); FTPoint up = position + bbox.Upper(); glBegin(GL_QUADS); glNormal3f(0.0f, 0.0f, 1.0f); glTexCoord2f(padding / texWidth, (texHeight - height + padding) / texHeight); glVertex2f(low.Xf(), up.Yf()); glTexCoord2f(padding / texWidth, (texHeight - padding) / texHeight); glVertex2f(low.Xf(), low.Yf()); glTexCoord2f((width - padding) / texWidth, (texHeight - padding) / texHeight); glVertex2f(up.Xf(), low.Yf()); glTexCoord2f((width - padding) / texWidth, (texHeight - height + padding) / texHeight); glVertex2f(up.Xf(), up.Yf()); glEnd(); glPopClientAttrib(); glPopAttrib(); return position + advanceCache[cacheIndex]; } FTPoint FTBufferFontImpl::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } FTPoint FTBufferFontImpl::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } critterding-beta12.1/src/utils/ftgl/FTFont/FTBitmapFont.cpp0000644000175000017500000000577711147116040022574 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTBitmapFontImpl.h" // // FTBitmapFont // FTBitmapFont::FTBitmapFont(char const *fontFilePath) : FTFont(new FTBitmapFontImpl(this, fontFilePath)) {} FTBitmapFont::FTBitmapFont(unsigned char const *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTBitmapFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTBitmapFont::~FTBitmapFont() {} FTGlyph* FTBitmapFont::MakeGlyph(FT_GlyphSlot ftGlyph) { return new FTBitmapGlyph(ftGlyph); } // // FTBitmapFontImpl // template inline FTPoint FTBitmapFontImpl::RenderI(const T* string, const int len, FTPoint position, FTPoint spacing, int renderMode) { // Protect GL_BLEND glPushAttrib(GL_COLOR_BUFFER_BIT); // Protect glPixelStorei() calls (also in FTBitmapGlyphImpl::RenderImpl) glPushClientAttrib(GL_CLIENT_PIXEL_STORE_BIT); glPixelStorei(GL_UNPACK_LSB_FIRST, GL_FALSE); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); glDisable(GL_BLEND); FTPoint tmp = FTFontImpl::Render(string, len, position, spacing, renderMode); glPopClientAttrib(); glPopAttrib(); return tmp; } FTPoint FTBitmapFontImpl::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } FTPoint FTBitmapFontImpl::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } critterding-beta12.1/src/utils/ftgl/FTFont/FTBitmapFontImpl.h0000644000175000017500000000447611147116040023056 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTBitmapFontImpl__ #define __FTBitmapFontImpl__ #include "FTFontImpl.h" class FTGlyph; class FTBitmapFontImpl : public FTFontImpl { friend class FTBitmapFont; protected: FTBitmapFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath) {}; FTBitmapFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes) {}; virtual FTPoint Render(const char *s, const int len, FTPoint position, FTPoint spacing, int renderMode); virtual FTPoint Render(const wchar_t *s, const int len, FTPoint position, FTPoint spacing, int renderMode); private: /* Internal generic Render() implementation */ template inline FTPoint RenderI(const T *s, const int len, FTPoint position, FTPoint spacing, int mode); }; #endif // __FTBitmapFontImpl__ critterding-beta12.1/src/utils/ftgl/FTFont/FTPixmapFontImpl.h0000644000175000017500000000430711147116040023071 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTPixmapFontImpl__ #define __FTPixmapFontImpl__ #include "FTFontImpl.h" class FTGlyph; class FTPixmapFontImpl : public FTFontImpl { friend class FTPixmapFont; protected: FTPixmapFontImpl(FTFont *ftFont, const char* fontFilePath); FTPixmapFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); virtual FTPoint Render(const char *s, const int len, FTPoint position, FTPoint spacing, int renderMode); virtual FTPoint Render(const wchar_t *s, const int len, FTPoint position, FTPoint spacing, int renderMode); private: /* Internal generic Render() implementation */ template inline FTPoint RenderI(const T *s, const int len, FTPoint position, FTPoint spacing, int mode); }; #endif // __FTPixmapFontImpl__ critterding-beta12.1/src/utils/ftgl/FTFont/FTExtrudeFont.cpp0000644000175000017500000000503311147116040022761 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTExtrudeFontImpl.h" // // FTExtrudeFont // FTExtrudeFont::FTExtrudeFont(char const *fontFilePath) : FTFont(new FTExtrudeFontImpl(this, fontFilePath)) {} FTExtrudeFont::FTExtrudeFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTExtrudeFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTExtrudeFont::~FTExtrudeFont() {} FTGlyph* FTExtrudeFont::MakeGlyph(FT_GlyphSlot ftGlyph) { FTExtrudeFontImpl *myimpl = dynamic_cast(impl); if(!myimpl) { return NULL; } return new FTExtrudeGlyph(ftGlyph, myimpl->depth, myimpl->front, myimpl->back, myimpl->useDisplayLists); } // // FTExtrudeFontImpl // FTExtrudeFontImpl::FTExtrudeFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath), depth(0.0f), front(0.0f), back(0.0f) { load_flags = FT_LOAD_NO_HINTING; } FTExtrudeFontImpl::FTExtrudeFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes), depth(0.0f), front(0.0f), back(0.0f) { load_flags = FT_LOAD_NO_HINTING; } critterding-beta12.1/src/utils/ftgl/FTFont/FTPolygonFontImpl.h0000644000175000017500000000400211147116040023252 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTPolygonFontImpl__ #define __FTPolygonFontImpl__ #include "FTFontImpl.h" class FTGlyph; class FTPolygonFontImpl : public FTFontImpl { friend class FTPolygonFont; protected: FTPolygonFontImpl(FTFont *ftFont, const char* fontFilePath); FTPolygonFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes); /** * Set the outset distance for the font. Only implemented by * FTOutlineFont, FTPolygonFont and FTExtrudeFont * * @param depth The outset distance. */ virtual void Outset(float o) { outset = o; } private: /** * The outset distance (front and back) for the font. */ float outset; }; #endif // __FTPolygonFontImpl__ critterding-beta12.1/src/utils/ftgl/FTFont/FTFont.cpp0000644000175000017500000002601711147116040021425 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include "FTInternals.h" #include "FTUnicode.h" #include "FTFontImpl.h" #include "FTBitmapFontImpl.h" #include "FTExtrudeFontImpl.h" #include "FTOutlineFontImpl.h" #include "FTPixmapFontImpl.h" #include "FTPolygonFontImpl.h" #include "FTTextureFontImpl.h" #include "FTGlyphContainer.h" #include "FTFace.h" // // FTFont // FTFont::FTFont(char const *fontFilePath) { impl = new FTFontImpl(this, fontFilePath); } FTFont::FTFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) { impl = new FTFontImpl(this, pBufferBytes, bufferSizeInBytes); } FTFont::FTFont(FTFontImpl *pImpl) { impl = pImpl; } FTFont::~FTFont() { delete impl; } bool FTFont::Attach(const char* fontFilePath) { return impl->Attach(fontFilePath); } bool FTFont::Attach(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) { return impl->Attach(pBufferBytes, bufferSizeInBytes); } bool FTFont::FaceSize(const unsigned int size, const unsigned int res) { return impl->FaceSize(size, res); } unsigned int FTFont::FaceSize() const { return impl->FaceSize(); } void FTFont::Depth(float depth) { return impl->Depth(depth); } void FTFont::Outset(float outset) { return impl->Outset(outset); } void FTFont::Outset(float front, float back) { return impl->Outset(front, back); } void FTFont::GlyphLoadFlags(FT_Int flags) { return impl->GlyphLoadFlags(flags); } bool FTFont::CharMap(FT_Encoding encoding) { return impl->CharMap(encoding); } unsigned int FTFont::CharMapCount() const { return impl->CharMapCount(); } FT_Encoding* FTFont::CharMapList() { return impl->CharMapList(); } void FTFont::UseDisplayList(bool useList) { return impl->UseDisplayList(useList); } float FTFont::Ascender() const { return impl->Ascender(); } float FTFont::Descender() const { return impl->Descender(); } float FTFont::LineHeight() const { return impl->LineHeight(); } FTPoint FTFont::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return impl->Render(string, len, position, spacing, renderMode); } FTPoint FTFont::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return impl->Render(string, len, position, spacing, renderMode); } float FTFont::Advance(const char * string, const int len, FTPoint spacing) { return impl->Advance(string, len, spacing); } float FTFont::Advance(const wchar_t * string, const int len, FTPoint spacing) { return impl->Advance(string, len, spacing); } FTBBox FTFont::BBox(const char *string, const int len, FTPoint position, FTPoint spacing) { return impl->BBox(string, len, position, spacing); } FTBBox FTFont::BBox(const wchar_t *string, const int len, FTPoint position, FTPoint spacing) { return impl->BBox(string, len, position, spacing); } FT_Error FTFont::Error() const { return impl->err; } // // FTFontImpl // FTFontImpl::FTFontImpl(FTFont *ftFont, char const *fontFilePath) : face(fontFilePath), useDisplayLists(true), load_flags(FT_LOAD_DEFAULT), intf(ftFont), glyphList(0) { err = face.Error(); if(err == 0) { glyphList = new FTGlyphContainer(&face); } } FTFontImpl::FTFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : face(pBufferBytes, bufferSizeInBytes), useDisplayLists(true), load_flags(FT_LOAD_DEFAULT), intf(ftFont), glyphList(0) { err = face.Error(); if(err == 0) { glyphList = new FTGlyphContainer(&face); } } FTFontImpl::~FTFontImpl() { if(glyphList) { delete glyphList; } } bool FTFontImpl::Attach(const char* fontFilePath) { if(!face.Attach(fontFilePath)) { err = face.Error(); return false; } err = 0; return true; } bool FTFontImpl::Attach(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) { if(!face.Attach(pBufferBytes, bufferSizeInBytes)) { err = face.Error(); return false; } err = 0; return true; } bool FTFontImpl::FaceSize(const unsigned int size, const unsigned int res) { if(glyphList != NULL) { delete glyphList; glyphList = NULL; } charSize = face.Size(size, res); err = face.Error(); if(err != 0) { return false; } glyphList = new FTGlyphContainer(&face); return true; } unsigned int FTFontImpl::FaceSize() const { return charSize.CharSize(); } void FTFontImpl::Depth(float depth) { ; } void FTFontImpl::Outset(float outset) { ; } void FTFontImpl::Outset(float front, float back) { ; } void FTFontImpl::GlyphLoadFlags(FT_Int flags) { load_flags = flags; } bool FTFontImpl::CharMap(FT_Encoding encoding) { bool result = glyphList->CharMap(encoding); err = glyphList->Error(); return result; } unsigned int FTFontImpl::CharMapCount() const { return face.CharMapCount(); } FT_Encoding* FTFontImpl::CharMapList() { return face.CharMapList(); } void FTFontImpl::UseDisplayList(bool useList) { useDisplayLists = useList; } float FTFontImpl::Ascender() const { return charSize.Ascender(); } float FTFontImpl::Descender() const { return charSize.Descender(); } float FTFontImpl::LineHeight() const { return charSize.Height(); } template inline FTBBox FTFontImpl::BBoxI(const T* string, const int len, FTPoint position, FTPoint spacing) { FTBBox totalBBox; /* Only compute the bounds if string is non-empty. */ if(string && ('\0' != string[0])) { // for multibyte - we can't rely on sizeof(T) == character FTUnicodeStringItr ustr(string); unsigned int thisChar = *ustr++; unsigned int nextChar = *ustr; if(CheckGlyph(thisChar)) { totalBBox = glyphList->BBox(thisChar); totalBBox += position; position += FTPoint(glyphList->Advance(thisChar, nextChar), 0.0); } /* Expand totalBox by each glyph in string */ for(int i = 1; (len < 0 && *ustr) || (len >= 0 && i < len); i++) { thisChar = *ustr++; nextChar = *ustr; if(CheckGlyph(thisChar)) { position += spacing; FTBBox tempBBox = glyphList->BBox(thisChar); tempBBox += position; totalBBox |= tempBBox; position += FTPoint(glyphList->Advance(thisChar, nextChar), 0.0); } } } return totalBBox; } FTBBox FTFontImpl::BBox(const char *string, const int len, FTPoint position, FTPoint spacing) { /* The chars need to be unsigned because they are cast to int later */ return BBoxI((const unsigned char *)string, len, position, spacing); } FTBBox FTFontImpl::BBox(const wchar_t *string, const int len, FTPoint position, FTPoint spacing) { return BBoxI(string, len, position, spacing); } template inline float FTFontImpl::AdvanceI(const T* string, const int len, FTPoint spacing) { float advance = 0.0f; FTUnicodeStringItr ustr(string); for(int i = 0; (len < 0 && *ustr) || (len >= 0 && i < len); i++) { unsigned int thisChar = *ustr++; unsigned int nextChar = *ustr; if(CheckGlyph(thisChar)) { advance += glyphList->Advance(thisChar, nextChar); } if(nextChar) { advance += spacing.Xf(); } } return advance; } float FTFontImpl::Advance(const char* string, const int len, FTPoint spacing) { /* The chars need to be unsigned because they are cast to int later */ return AdvanceI((const unsigned char *)string, len, spacing); } float FTFontImpl::Advance(const wchar_t* string, const int len, FTPoint spacing) { return AdvanceI(string, len, spacing); } template inline FTPoint FTFontImpl::RenderI(const T* string, const int len, FTPoint position, FTPoint spacing, int renderMode) { // for multibyte - we can't rely on sizeof(T) == character FTUnicodeStringItr ustr(string); for(int i = 0; (len < 0 && *ustr) || (len >= 0 && i < len); i++) { unsigned int thisChar = *ustr++; unsigned int nextChar = *ustr; if(CheckGlyph(thisChar)) { position += glyphList->Render(thisChar, nextChar, position, renderMode); } if(nextChar) { position += spacing; } } return position; } FTPoint FTFontImpl::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI((const unsigned char *)string, len, position, spacing, renderMode); } FTPoint FTFontImpl::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } bool FTFontImpl::CheckGlyph(const unsigned int characterCode) { if(glyphList->Glyph(characterCode)) { return true; } unsigned int glyphIndex = glyphList->FontIndex(characterCode); FT_GlyphSlot ftSlot = face.Glyph(glyphIndex, load_flags); if(!ftSlot) { err = face.Error(); return false; } FTGlyph* tempGlyph = intf->MakeGlyph(ftSlot); if(!tempGlyph) { if(0 == err) { err = 0x13; } return false; } glyphList->Add(tempGlyph, characterCode); return true; } critterding-beta12.1/src/utils/ftgl/FTFont/FTOutlineFont.cpp0000644000175000017500000000733211147116040022764 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include "FTGL/ftgl.h" #include "FTInternals.h" #include "FTOutlineFontImpl.h" // // FTOutlineFont // FTOutlineFont::FTOutlineFont(char const *fontFilePath) : FTFont(new FTOutlineFontImpl(this, fontFilePath)) {} FTOutlineFont::FTOutlineFont(const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFont(new FTOutlineFontImpl(this, pBufferBytes, bufferSizeInBytes)) {} FTOutlineFont::~FTOutlineFont() {} FTGlyph* FTOutlineFont::MakeGlyph(FT_GlyphSlot ftGlyph) { FTOutlineFontImpl *myimpl = dynamic_cast(impl); if(!myimpl) { return NULL; } return new FTOutlineGlyph(ftGlyph, myimpl->outset, myimpl->useDisplayLists); } // // FTOutlineFontImpl // FTOutlineFontImpl::FTOutlineFontImpl(FTFont *ftFont, const char* fontFilePath) : FTFontImpl(ftFont, fontFilePath), outset(0.0f) { load_flags = FT_LOAD_NO_HINTING; } FTOutlineFontImpl::FTOutlineFontImpl(FTFont *ftFont, const unsigned char *pBufferBytes, size_t bufferSizeInBytes) : FTFontImpl(ftFont, pBufferBytes, bufferSizeInBytes), outset(0.0f) { load_flags = FT_LOAD_NO_HINTING; } template inline FTPoint FTOutlineFontImpl::RenderI(const T* string, const int len, FTPoint position, FTPoint spacing, int renderMode) { // Protect GL_TEXTURE_2D, glHint(), GL_LINE_SMOOTH and blending functions glPushAttrib(GL_ENABLE_BIT | GL_HINT_BIT | GL_LINE_BIT | GL_COLOR_BUFFER_BIT); glDisable(GL_TEXTURE_2D); glEnable(GL_LINE_SMOOTH); glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE FTPoint tmp = FTFontImpl::Render(string, len, position, spacing, renderMode); glPopAttrib(); return tmp; } FTPoint FTOutlineFontImpl::Render(const char * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } FTPoint FTOutlineFontImpl::Render(const wchar_t * string, const int len, FTPoint position, FTPoint spacing, int renderMode) { return RenderI(string, len, position, spacing, renderMode); } critterding-beta12.1/src/utils/ftgl/FTLayout/0000755000175000017500000000000011347266042020134 5ustar bobkebobkecritterding-beta12.1/src/utils/ftgl/FTLayout/FTSimpleLayoutImpl.h0000644000175000017500000002311311147116040023776 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTSimpleLayoutImpl__ #define __FTSimpleLayoutImpl__ #include "FTLayoutImpl.h" class FTFont; class FTSimpleLayoutImpl : public FTLayoutImpl { friend class FTSimpleLayout; protected: FTSimpleLayoutImpl(); virtual ~FTSimpleLayoutImpl() {}; virtual FTBBox BBox(const char* string, const int len, FTPoint position); virtual FTBBox BBox(const wchar_t* string, const int len, FTPoint position); virtual void Render(const char *string, const int len, FTPoint position, int renderMode); virtual void Render(const wchar_t *string, const int len, FTPoint position, int renderMode); /** * Render a string of characters and distribute extra space amongst * the whitespace regions of the string. * * @param string A buffer of wchar_t characters to output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered. * @param position TODO * @param renderMode Render mode to display * @param extraSpace The amount of extra space to distribute amongst * the characters. */ virtual void RenderSpace(const char *string, const int len, FTPoint position, int renderMode, const float extraSpace); /** * Render a string of characters and distribute extra space amongst * the whitespace regions of the string. * * @param string A buffer of wchar_t characters to output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered. * @param position TODO * @param renderMode Render mode to display * @param extraSpace The amount of extra space to distribute amongst * the characters. */ virtual void RenderSpace(const wchar_t *string, const int len, FTPoint position, int renderMode, const float extraSpace); private: /** * Either render a string of characters and wrap lines * longer than a threshold or compute the bounds * of a string of characters when wrapped. The functionality * of this method is exposed by the BBoxWrapped and * RenderWrapped methods. * * @param buf A char string to output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered. * @param position TODO * @param renderMode Render mode to display * @param bounds A pointer to a bounds object. If non null * the bounds of the text when laid out * will be stored in bounds. If null the * text will be rendered. */ virtual void WrapText(const char *buf, const int len, FTPoint position, int renderMode, FTBBox *bounds); /** * Either render a string of characters and wrap lines * longer than a threshold or compute the bounds * of a string of characters when wrapped. The functionality * of this method is exposed by the BBoxWrapped and * RenderWrapped methods. * * @param buf A wchar_t style string to output. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered. * @param position TODO * @param renderMode Render mode to display * @param bounds A pointer to a bounds object. If non null * the bounds of the text when laid out * will be stored in bounds. If null the * text will be rendered. */ virtual void WrapText(const wchar_t *buf, const int len, FTPoint position, int renderMode, FTBBox *bounds); /** * A helper method used by WrapText to either output the text or * compute it's bounds. * * @param buf A pointer to an array of character data. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered. * @param position TODO * @param renderMode Render mode to display * @param RemainingWidth The amount of extra space left on the line. * @param bounds A pointer to a bounds object. If non null the * bounds will be initialized or expanded by the * bounds of the line. If null the text will be * rendered. If the bounds are invalid (lower > upper) * they will be initialized. Otherwise they * will be expanded. */ void OutputWrapped(const char *buf, const int len, FTPoint position, int renderMode, const float RemainingWidth, FTBBox *bounds); /** * A helper method used by WrapText to either output the text or * compute it's bounds. * * @param buf A pointer to an array of character data. * @param len The length of the string. If < 0 then all characters * will be displayed until a null character is encountered. * @param position TODO * @param renderMode Render mode to display * @param RemainingWidth The amount of extra space left on the line. * @param bounds A pointer to a bounds object. If non null the * bounds will be initialized or expanded by the * bounds of the line. If null the text will be * rendered. If the bounds are invalid (lower > upper) * they will be initialized. Otherwise they * will be expanded. */ void OutputWrapped(const wchar_t *buf, const int len, FTPoint position, int renderMode, const float RemainingWidth, FTBBox *bounds); /** * The font to use for rendering the text. The font is * referenced by this but will not be disposed of when this * is deleted. */ FTFont *currentFont; /** * The maximum line length for formatting text. */ float lineLength; /** * The text alignment mode used to distribute * space within a line or rendered text. */ FTGL::TextAlignment alignment; /** * The height of each line of text expressed as * a percentage of the font's line height. */ float lineSpacing; /* Internal generic BBox() implementation */ template inline FTBBox BBoxI(const T* string, const int len, FTPoint position); /* Internal generic Render() implementation */ template inline void RenderI(const T* string, const int len, FTPoint position, int renderMode); /* Internal generic RenderSpace() implementation */ template inline void RenderSpaceI(const T* string, const int len, FTPoint position, int renderMode, const float extraSpace); /* Internal generic WrapText() implementation */ template void WrapTextI(const T* buf, const int len, FTPoint position, int renderMode, FTBBox *bounds); /* Internal generic OutputWrapped() implementation */ template void OutputWrappedI(const T* buf, const int len, FTPoint position, int renderMode, const float RemainingWidth, FTBBox *bounds); }; #endif // __FTSimpleLayoutImpl__ critterding-beta12.1/src/utils/ftgl/FTLayout/FTLayoutGlue.cpp0000644000175000017500000001255111147116040023156 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Éric Beets * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include "FTInternals.h" static const FTBBox static_ftbbox; FTGL_BEGIN_C_DECLS #define C_TOR(cname, cargs, cxxname, cxxarg, cxxtype) \ FTGLlayout* cname cargs \ { \ cxxname *l = new cxxname cxxarg; \ if(l->Error()) \ { \ delete l; \ return NULL; \ } \ FTGLlayout *ftgl = (FTGLlayout *)malloc(sizeof(FTGLlayout)); \ ftgl->ptr = l; \ ftgl->type = cxxtype; \ return ftgl; \ } // FTSimpleLayout::FTSimpleLayout(); C_TOR(ftglCreateSimpleLayout, (), FTSimpleLayout, (), LAYOUT_SIMPLE); #define C_FUN(cret, cname, cargs, cxxerr, cxxname, cxxarg) \ cret cname cargs \ { \ if(!l || !l->ptr) \ { \ fprintf(stderr, "FTGL warning: NULL pointer in %s\n", #cname); \ cxxerr; \ } \ return l->ptr->cxxname cxxarg; \ } // FTLayout::~FTLayout(); void ftglDestroyLayout(FTGLlayout *l) { if(!l || !l->ptr) { fprintf(stderr, "FTGL warning: NULL pointer in %s\n", __FUNCTION__); return; } delete l->ptr; free(l); } // virtual FTBBox FTLayout::BBox(const char* string) extern "C++" { C_FUN(static FTBBox, _ftgGetlLayoutBBox, (FTGLlayout *l, const char *s), return static_ftbbox, BBox, (s)); } void ftgGetlLayoutBBox(FTGLlayout *l, const char * s, float c[6]) { FTBBox ret = _ftgGetlLayoutBBox(l, s); FTPoint lower = ret.Lower(), upper = ret.Upper(); c[0] = lower.Xf(); c[1] = lower.Yf(); c[2] = lower.Zf(); c[3] = upper.Xf(); c[4] = upper.Yf(); c[5] = upper.Zf(); } // virtual void FTLayout::Render(const char* string, int renderMode); C_FUN(void, ftglRenderLayout, (FTGLlayout *l, const char *s, int r), return, Render, (s, r)); // FT_Error FTLayout::Error() const; C_FUN(FT_Error, ftglGetLayoutError, (FTGLlayout *l), return -1, Error, ()); // void FTSimpleLayout::SetFont(FTFont *fontInit) void ftglSetLayoutFont(FTGLlayout *l, FTGLfont *font) { if(!l || !l->ptr) { fprintf(stderr, "FTGL warning: NULL pointer in %s\n", __FUNCTION__); return; } if(l->type != FTGL::LAYOUT_SIMPLE) { fprintf(stderr, "FTGL warning: %s not implemented for %d\n", __FUNCTION__, l->type); } l->font = font; return dynamic_cast(l->ptr)->SetFont(font->ptr); } // FTFont *FTSimpleLayout::GetFont() FTGLfont *ftglGetLayoutFont(FTGLlayout *l) { if(!l || !l->ptr) { fprintf(stderr, "FTGL warning: NULL pointer in %s\n", __FUNCTION__); return NULL; } if(l->type != FTGL::LAYOUT_SIMPLE) { fprintf(stderr, "FTGL warning: %s not implemented for %d\n", __FUNCTION__, l->type); } return l->font; } #undef C_FUN #define C_FUN(cret, cname, cargs, cxxerr, cxxname, cxxarg) \ cret cname cargs \ { \ if(!l || !l->ptr) \ { \ fprintf(stderr, "FTGL warning: NULL pointer in %s\n", #cname); \ cxxerr; \ } \ if(l->type != FTGL::LAYOUT_SIMPLE) \ { \ fprintf(stderr, "FTGL warning: %s not implemented for %d\n", \ __FUNCTION__, l->type); \ cxxerr; \ } \ return dynamic_cast(l->ptr)->cxxname cxxarg; \ } // void FTSimpleLayout::SetLineLength(const float LineLength); C_FUN(void, ftglSetLayoutLineLength, (FTGLlayout *l, const float length), return, SetLineLength, (length)); // float FTSimpleLayout::GetLineLength() const C_FUN(float, ftglGetLayoutLineLength, (FTGLlayout *l), return 0.0f, GetLineLength, ()); // void FTSimpleLayout::SetAlignment(const TextAlignment Alignment) C_FUN(void, ftglSetLayoutAlignment, (FTGLlayout *l, const int a), return, SetAlignment, ((FTGL::TextAlignment)a)); // TextAlignment FTSimpleLayout::GetAlignment() const C_FUN(int, ftglGetLayoutAlignement, (FTGLlayout *l), return FTGL::ALIGN_LEFT, GetAlignment, ()); // void FTSimpleLayout::SetLineSpacing(const float LineSpacing) C_FUN(void, ftglSetLayoutLineSpacing, (FTGLlayout *l, const float f), return, SetLineSpacing, (f)); FTGL_END_C_DECLS critterding-beta12.1/src/utils/ftgl/FTLayout/FTLayoutImpl.h0000644000175000017500000000324111147116040022624 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTLayoutImpl__ #define __FTLayoutImpl__ #include "FTSize.h" #include "FTGlyphContainer.h" class FTLayoutImpl { friend class FTLayout; protected: FTLayoutImpl(); virtual ~FTLayoutImpl(); protected: /** * Current pen or cursor position; */ FTPoint pen; /** * Current error code. Zero means no error. */ FT_Error err; }; #endif // __FTLayoutImpl__ critterding-beta12.1/src/utils/ftgl/FTLayout/FTSimpleLayout.cpp0000644000175000017500000003411411147116040023512 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include #include #include "FTInternals.h" #include "FTUnicode.h" #include "FTGlyphContainer.h" #include "FTSimpleLayoutImpl.h" // // FTSimpleLayout // FTSimpleLayout::FTSimpleLayout() : FTLayout(new FTSimpleLayoutImpl()) {} FTSimpleLayout::~FTSimpleLayout() {} FTBBox FTSimpleLayout::BBox(const char *string, const int len, FTPoint pos) { return dynamic_cast(impl)->BBox(string, len, pos); } FTBBox FTSimpleLayout::BBox(const wchar_t *string, const int len, FTPoint pos) { return dynamic_cast(impl)->BBox(string, len, pos); } void FTSimpleLayout::Render(const char *string, const int len, FTPoint pos, int renderMode) { return dynamic_cast(impl)->Render(string, len, pos, renderMode); } void FTSimpleLayout::Render(const wchar_t* string, const int len, FTPoint pos, int renderMode) { return dynamic_cast(impl)->Render(string, len, pos, renderMode); } void FTSimpleLayout::SetFont(FTFont *fontInit) { dynamic_cast(impl)->currentFont = fontInit; } FTFont *FTSimpleLayout::GetFont() { return dynamic_cast(impl)->currentFont; } void FTSimpleLayout::SetLineLength(const float LineLength) { dynamic_cast(impl)->lineLength = LineLength; } float FTSimpleLayout::GetLineLength() const { return dynamic_cast(impl)->lineLength; } void FTSimpleLayout::SetAlignment(const FTGL::TextAlignment Alignment) { dynamic_cast(impl)->alignment = Alignment; } FTGL::TextAlignment FTSimpleLayout::GetAlignment() const { return dynamic_cast(impl)->alignment; } void FTSimpleLayout::SetLineSpacing(const float LineSpacing) { dynamic_cast(impl)->lineSpacing = LineSpacing; } float FTSimpleLayout::GetLineSpacing() const { return dynamic_cast(impl)->lineSpacing; } // // FTSimpleLayoutImpl // FTSimpleLayoutImpl::FTSimpleLayoutImpl() { currentFont = NULL; lineLength = 100.0f; alignment = FTGL::ALIGN_LEFT; lineSpacing = 1.0f; } template inline FTBBox FTSimpleLayoutImpl::BBoxI(const T* string, const int len, FTPoint position) { FTBBox tmp; WrapText(string, len, position, 0, &tmp); return tmp; } FTBBox FTSimpleLayoutImpl::BBox(const char *string, const int len, FTPoint position) { return BBoxI(string, len, position); } FTBBox FTSimpleLayoutImpl::BBox(const wchar_t *string, const int len, FTPoint position) { return BBoxI(string, len, position); } template inline void FTSimpleLayoutImpl::RenderI(const T *string, const int len, FTPoint position, int renderMode) { pen = FTPoint(0.0f, 0.0f); WrapText(string, len, position, renderMode, NULL); } void FTSimpleLayoutImpl::Render(const char *string, const int len, FTPoint position, int renderMode) { RenderI(string, len, position, renderMode); } void FTSimpleLayoutImpl::Render(const wchar_t* string, const int len, FTPoint position, int renderMode) { RenderI(string, len, position, renderMode); } template inline void FTSimpleLayoutImpl::WrapTextI(const T *buf, const int len, FTPoint position, int renderMode, FTBBox *bounds) { FTUnicodeStringItr breakItr(buf); // points to the last break character FTUnicodeStringItr lineStart(buf); // points to the line start float nextStart = 0.0; // total width of the current line float breakWidth = 0.0; // width of the line up to the last word break float currentWidth = 0.0; // width of all characters on the current line float prevWidth; // width of all characters but the current glyph float wordLength = 0.0; // length of the block since the last break char int charCount = 0; // number of characters so far on the line int breakCharCount = 0; // number of characters before the breakItr float glyphWidth, advance; FTBBox glyphBounds; // Reset the pen position pen.Y(0); // If we have bounds mark them invalid if(bounds) { bounds->Invalidate(); } // Scan the input for all characters that need output FTUnicodeStringItr prevItr(buf); for (FTUnicodeStringItr itr(buf); *itr; prevItr = itr++, charCount++) { // Find the width of the current glyph glyphBounds = currentFont->BBox(itr.getBufferFromHere(), 1); glyphWidth = glyphBounds.Upper().Xf() - glyphBounds.Lower().Xf(); advance = currentFont->Advance(itr.getBufferFromHere(), 1); prevWidth = currentWidth; // Compute the width of all glyphs up to the end of buf[i] currentWidth = nextStart + glyphWidth; // Compute the position of the next glyph nextStart += advance; // See if the current character is a space, a break or a regular character if((currentWidth > lineLength) || (*itr == '\n')) { // A non whitespace character has exceeded the line length. Or a // newline character has forced a line break. Output the last // line and start a new line after the break character. // If we have not yet found a break, break on the last character if(breakItr == lineStart || (*itr == '\n')) { // Break on the previous character breakItr = prevItr; breakCharCount = charCount - 1; breakWidth = prevWidth; // None of the previous words will be carried to the next line wordLength = 0; // If the current character is a newline discard its advance if(*itr == '\n') advance = 0; } float remainingWidth = lineLength - breakWidth; // Render the current substring FTUnicodeStringItr breakChar = breakItr; // move past the break character and don't count it on the next line either ++breakChar; --charCount; // If the break character is a newline do not render it if(*breakChar == '\n') { ++breakChar; --charCount; } OutputWrapped(lineStart.getBufferFromHere(), breakCharCount, //breakItr.getBufferFromHere() - lineStart.getBufferFromHere(), position, renderMode, remainingWidth, bounds); // Store the start of the next line lineStart = breakChar; // TODO: Is Height() the right value here? pen -= FTPoint(0, currentFont->LineHeight() * lineSpacing); // The current width is the width since the last break nextStart = wordLength + advance; wordLength += advance; currentWidth = wordLength + advance; // Reset the safe break for the next line breakItr = lineStart; charCount -= breakCharCount; } else if(iswspace(*itr)) { // This is the last word break position wordLength = 0; breakItr = itr; breakCharCount = charCount; // Check to see if this is the first whitespace character in a run if(buf == itr.getBufferFromHere() || !iswspace(*prevItr)) { // Record the width of the start of the block breakWidth = currentWidth; } } else { wordLength += advance; } } float remainingWidth = lineLength - currentWidth; // Render any remaining text on the last line // Disable justification for the last row if(alignment == FTGL::ALIGN_JUSTIFY) { alignment = FTGL::ALIGN_LEFT; OutputWrapped(lineStart.getBufferFromHere(), -1, position, renderMode, remainingWidth, bounds); alignment = FTGL::ALIGN_JUSTIFY; } else { OutputWrapped(lineStart.getBufferFromHere(), -1, position, renderMode, remainingWidth, bounds); } } void FTSimpleLayoutImpl::WrapText(const char *buf, const int len, FTPoint position, int renderMode, FTBBox *bounds) { WrapTextI(buf, len, position, renderMode, bounds); } void FTSimpleLayoutImpl::WrapText(const wchar_t* buf, const int len, FTPoint position, int renderMode, FTBBox *bounds) { WrapTextI(buf, len, position, renderMode, bounds); } template inline void FTSimpleLayoutImpl::OutputWrappedI(const T *buf, const int len, FTPoint position, int renderMode, const float remaining, FTBBox *bounds) { float distributeWidth = 0.0; // Align the text according as specified by Alignment switch (alignment) { case FTGL::ALIGN_LEFT: pen.X(0); break; case FTGL::ALIGN_CENTER: pen.X(remaining / 2); break; case FTGL::ALIGN_RIGHT: pen.X(remaining); break; case FTGL::ALIGN_JUSTIFY: pen.X(0); distributeWidth = remaining; break; } // If we have bounds expand them by the line's bounds, otherwise render // the line. if(bounds) { FTBBox temp = currentFont->BBox(buf, len); // Add the extra space to the upper x dimension temp = FTBBox(temp.Lower() + pen, temp.Upper() + pen + FTPoint(distributeWidth, 0)); // See if this is the first area to be added to the bounds if(bounds->IsValid()) { *bounds |= temp; } else { *bounds = temp; } } else { RenderSpace(buf, len, position, renderMode, distributeWidth); } } void FTSimpleLayoutImpl::OutputWrapped(const char *buf, const int len, FTPoint position, int renderMode, const float remaining, FTBBox *bounds) { OutputWrappedI(buf, len, position, renderMode, remaining, bounds); } void FTSimpleLayoutImpl::OutputWrapped(const wchar_t *buf, const int len, FTPoint position, int renderMode, const float remaining, FTBBox *bounds) { OutputWrappedI(buf, len, position, renderMode, remaining, bounds); } template inline void FTSimpleLayoutImpl::RenderSpaceI(const T *string, const int len, FTPoint position, int renderMode, const float extraSpace) { float space = 0.0; // If there is space to distribute, count the number of spaces if(extraSpace > 0.0) { int numSpaces = 0; // Count the number of space blocks in the input FTUnicodeStringItr prevItr(string), itr(string); for(int i = 0; ((len < 0) && *itr) || ((len >= 0) && (i <= len)); ++i, prevItr = itr++) { // If this is the end of a space block, increment the counter if((i > 0) && !iswspace(*itr) && iswspace(*prevItr)) { numSpaces++; } } space = extraSpace/numSpaces; } // Output all characters of the string FTUnicodeStringItr prevItr(string), itr(string); for(int i = 0; ((len < 0) && *itr) || ((len >= 0) && (i <= len)); ++i, prevItr = itr++) { // If this is the end of a space block, distribute the extra space // inside it if((i > 0) && !iswspace(*itr) && iswspace(*prevItr)) { pen += FTPoint(space, 0); } pen = currentFont->Render(itr.getBufferFromHere(), 1, pen, FTPoint(), renderMode); } } void FTSimpleLayoutImpl::RenderSpace(const char *string, const int len, FTPoint position, int renderMode, const float extraSpace) { RenderSpaceI(string, len, position, renderMode, extraSpace); } void FTSimpleLayoutImpl::RenderSpace(const wchar_t *string, const int len, FTPoint position, int renderMode, const float extraSpace) { RenderSpaceI(string, len, position, renderMode, extraSpace); } critterding-beta12.1/src/utils/ftgl/FTLayout/FTLayout.cpp0000644000175000017500000000325511147116040022342 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #include "config.h" #include "FTGL/ftgl.h" #include "../FTFont/FTFontImpl.h" #include "./FTLayoutImpl.h" // // FTLayout // FTLayout::FTLayout() { impl = new FTLayoutImpl(); } FTLayout::FTLayout(FTLayoutImpl *pImpl) { impl = pImpl; } FTLayout::~FTLayout() { delete impl; } FT_Error FTLayout::Error() const { return impl->err; } // // FTLayoutImpl // FTLayoutImpl::FTLayoutImpl() : err(0) { ; } FTLayoutImpl::~FTLayoutImpl() { ; } critterding-beta12.1/src/utils/ftgl/FTGlyphContainer.h0000644000175000017500000001151511147116040021747 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * * 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. */ #ifndef __FTGlyphContainer__ #define __FTGlyphContainer__ #include #include FT_FREETYPE_H #include FT_GLYPH_H #include "FTGL/ftgl.h" #include "FTVector.h" class FTFace; class FTGlyph; class FTCharmap; /** * FTGlyphContainer holds the post processed FTGlyph objects. * * @see FTGlyph */ class FTGlyphContainer { typedef FTVector GlyphVector; public: /** * Constructor * * @param face The Freetype face */ FTGlyphContainer(FTFace* face); /** * Destructor */ ~FTGlyphContainer(); /** * Sets the character map for the face. * * @param encoding the Freetype encoding symbol. See above. * @return true if charmap was valid * and set correctly */ bool CharMap(FT_Encoding encoding); /** * Get the font index of the input character. * * @param characterCode The character code of the requested glyph in the * current encoding eg apple roman. * @return The font index for the character. */ unsigned int FontIndex(const unsigned int characterCode) const; /** * Adds a glyph to this glyph list. * * @param glyph The FTGlyph to be inserted into the container * @param characterCode The char code of the glyph NOT the glyph index. */ void Add(FTGlyph* glyph, const unsigned int characterCode); /** * Get a glyph from the glyph list * * @param characterCode The char code of the glyph NOT the glyph index * @return An FTGlyph or null is it hasn't been * loaded. */ const FTGlyph* const Glyph(const unsigned int characterCode) const; /** * Get the bounding box for a character. * @param characterCode The char code of the glyph NOT the glyph index */ FTBBox BBox(const unsigned int characterCode) const; /** * Returns the kerned advance width for a glyph. * * @param characterCode glyph index of the character * @param nextCharacterCode the next glyph in a string * @return advance width */ float Advance(const unsigned int characterCode, const unsigned int nextCharacterCode); /** * Renders a character * @param characterCode the glyph to be Rendered * @param nextCharacterCode the next glyph in the string. Used for kerning. * @param penPosition the position to Render the glyph * @param renderMode Render mode to display * @return The distance to advance the pen position after Rendering */ FTPoint Render(const unsigned int characterCode, const unsigned int nextCharacterCode, FTPoint penPosition, int renderMode); /** * Queries the Font for errors. * * @return The current error code. */ FT_Error Error() const { return err; } private: /** * The FTGL face */ FTFace* face; /** * The Character Map object associated with the current face */ FTCharmap* charMap; /** * A structure to hold the glyphs */ GlyphVector glyphs; /** * Current error code. Zero means no error. */ FT_Error err; }; #endif // __FTGlyphContainer__ critterding-beta12.1/src/utils/ftgl/FTVectoriser.h0000644000175000017500000001722711147116040021154 0ustar bobkebobke/* * FTGL - OpenGL font library * * Copyright (c) 2001-2004 Henry Maddocks * Copyright (c) 2008 Sam Hocevar * * 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. */ #ifndef __FTVectoriser__ #define __FTVectoriser__ #include "FTGL/ftgl.h" #include "FTContour.h" #include "FTList.h" #include "FTVector.h" #ifndef CALLBACK #define CALLBACK #endif /** * FTTesselation captures points that are output by OpenGL's gluTesselator. */ class FTTesselation { public: /** * Default constructor */ FTTesselation(GLenum m) : meshType(m) { pointList.reserve(128); } /** * Destructor */ ~FTTesselation() { pointList.clear(); } /** * Add a point to the mesh. */ void AddPoint(const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z) { pointList.push_back(FTPoint(x, y, z)); } /** * The number of points in this mesh */ size_t PointCount() const { return pointList.size(); } /** * */ const FTPoint& Point(unsigned int index) const { return pointList[index]; } /** * Return the OpenGL polygon type. */ GLenum PolygonType() const { return meshType; } private: /** * Points generated by gluTesselator. */ typedef FTVector PointVector; PointVector pointList; /** * OpenGL primitive type from gluTesselator. */ GLenum meshType; }; /** * FTMesh is a container of FTTesselation's that make up a polygon glyph */ class FTMesh { typedef FTVector TesselationVector; typedef FTList PointList; public: /** * Default constructor */ FTMesh(); /** * Destructor */ ~FTMesh(); /** * Add a point to the mesh */ void AddPoint(const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z); /** * Create a combine point for the gluTesselator */ const FTGL_DOUBLE* Combine(const FTGL_DOUBLE x, const FTGL_DOUBLE y, const FTGL_DOUBLE z); /** * Begin a new polygon */ void Begin(GLenum meshType); /** * End a polygon */ void End(); /** * Record a gluTesselation error */ void Error(GLenum e) { err = e; } /** * The number of tesselations in the mesh */ size_t TesselationCount() const { return tesselationList.size(); } /** * Get a tesselation by index */ const FTTesselation* const Tesselation(size_t index) const; /** * Return the temporary point list. For testing only. */ const PointList& TempPointList() const { return tempPointList; } /** * Get the GL ERROR returned by the glu tesselator */ GLenum Error() const { return err; } private: /** * The current sub mesh that we are constructing. */ FTTesselation* currentTesselation; /** * Holds each sub mesh that comprises this glyph. */ TesselationVector tesselationList; /** * Holds extra points created by gluTesselator. See ftglCombine. */ PointList tempPointList; /** * GL ERROR returned by the glu tesselator */ GLenum err; }; const FTGL_DOUBLE FTGL_FRONT_FACING = 1.0; const FTGL_DOUBLE FTGL_BACK_FACING = -1.0; /** * FTVectoriser class is a helper class that converts font outlines into * point data. * * @see FTExtrudeGlyph * @see FTOutlineGlyph * @see FTPolygonGlyph * @see FTContour * @see FTPoint * */ class FTVectoriser { public: /** * Constructor * * @param glyph The freetype glyph to be processed */ FTVectoriser(const FT_GlyphSlot glyph); /** * Destructor */ virtual ~FTVectoriser(); /** * Build an FTMesh from the vector outline data. * * @param zNormal The direction of the z axis of the normal * for this mesh * FIXME: change the following for a constant * @param outsetType Specify the outset type contour * 0 : Original * 1 : Front * 2 : Back * @param outsetSize Specify the outset size contour */ void MakeMesh(FTGL_DOUBLE zNormal = FTGL_FRONT_FACING, int outsetType = 0, float outsetSize = 0.0f); /** * Get the current mesh. */ const FTMesh* const GetMesh() const { return mesh; } /** * Get the total count of points in this outline * * @return the number of points */ size_t PointCount(); /** * Get the count of contours in this outline * * @return the number of contours */ size_t ContourCount() const { return ftContourCount; } /** * Return a contour at index * * @return the number of contours */ const FTContour* const Contour(size_t index) const; /** * Get the number of points in a specific contour in this outline * * @param c The contour index * @return the number of points in contour[c] */ size_t ContourSize(int c) const { return contourList[c]->PointCount(); } /** * Get the flag for the tesselation rule for this outline * * @return The contour flag */ int ContourFlag() const { return contourFlag; } private: /** * Process the freetype outline data into contours of points * * @param front front outset distance * @param back back outset distance */ void ProcessContours(); /** * The list of contours in the glyph */ FTContour** contourList; /** * A Mesh for tesselations */ FTMesh* mesh; /** * The number of contours reported by Freetype */ short ftContourCount; /** * A flag indicating the tesselation rule for the glyph */ int contourFlag; /** * A Freetype outline */ FT_Outline outline; }; #endif // __FTVectoriser__ critterding-beta12.1/src/utils/ftgl/LICENCE0000644000175000017500000000226711254236527017423 0ustar bobkebobkeFTGL Herewith is a license. Basically I want you to use this software and if you think this license is preventing you from doing so let me know. Copyright (C) 2001-3 Henry Maddocks 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. critterding-beta12.1/src/utils/dir.h0000644000175000017500000000073610752437165016433 0ustar bobkebobke#ifndef DIR_H #define DIR_H #include #include #include #include // #include // #include #include #include #include using namespace std; class Dir { public: Dir(); ~Dir(); bool exists(string &directory); void make(string &directory); void listContents(string dir, vector &files); void listContentsFull(string dir, vector &files); }; #endif critterding-beta12.1/src/utils/bullet/0000755000175000017500000000000011347266042016760 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/Makefile.am0000644000175000017500000006200211345336346021017 0ustar bobkebobkeINCLUDES = $(all_includes) METASOURCES = AUTO noinst_LTLIBRARIES = libbulletmath.la libbulletcollision.la libbulletdynamics.la libbulletsoftbody.la # libbulletmultithreaded.la noinst_HEADERS = btBulletDynamicsCommon.h Bullet-C-Api.h btBulletCollisionCommon.h $(bullet_headers) libbulletmath_la_LDFLAGS = -avoid-version -no-undefined libbulletcollision_la_LDFLAGS = -avoid-version -no-undefined libbulletdynamics_la_LDFLAGS = -avoid-version -no-undefined libbulletsoftbody_la_LDFLAGS = -avoid-version -no-undefined # libbulletmultithreaded_la_LDFLAGS = -avoid-version -no-undefined # libbulletmultithreaded_la_SOURCES = \ # BulletMultiThreaded/PosixThreadSupport.h \ # BulletMultiThreaded/vectormath/scalar/cpp/mat_aos.h \ # BulletMultiThreaded/vectormath/scalar/cpp/vec_aos.h \ # BulletMultiThreaded/vectormath/scalar/cpp/quat_aos.h \ # BulletMultiThreaded/vectormath/scalar/cpp/vectormath_aos.h \ # BulletMultiThreaded/PpuAddressSpace.h \ # BulletMultiThreaded/PlatformDefinitions.h \ # BulletMultiThreaded/vectormath2bullet.h \ # BulletMultiThreaded/btThreadSupportInterface.h \ # BulletMultiThreaded/Win32ThreadSupport.h \ # BulletMultiThreaded/SequentialThreadSupport.h \ # BulletMultiThreaded/btThreadSupportInterface.cpp \ # BulletMultiThreaded/SequentialThreadSupport.cpp \ # BulletMultiThreaded/Win32ThreadSupport.cpp \ # BulletMultiThreaded/PosixThreadSupport.cpp \ # BulletMultiThreaded/SpuCollisionTaskProcess.h \ # BulletMultiThreaded/SpuCollisionTaskProcess.cpp \ # BulletMultiThreaded/SpuFakeDma.h \ # BulletMultiThreaded/SpuFakeDma.cpp \ # BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionShapes.h \ # BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionShapes.cpp \ # BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h \ # BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.cpp \ # BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuContactResult.cpp \ # BulletMultiThreaded/SpuGatheringCollisionDispatcher.h \ # BulletMultiThreaded/SpuGatheringCollisionDispatcher.cpp \ # BulletMultiThreaded/SpuContactManifoldCollisionAlgorithm.h \ # BulletMultiThreaded/SpuContactManifoldCollisionAlgorithm.cpp \ # BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuMinkowskiPenetrationDepthSolver.h \ # BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuMinkowskiPenetrationDepthSolver.cpp libbulletmath_la_SOURCES = \ LinearMath/btQuickprof.cpp \ LinearMath/btGeometryUtil.cpp \ LinearMath/btAlignedAllocator.cpp \ LinearMath/btConvexHull.cpp \ LinearMath/btHashMap.h \ LinearMath/btConvexHull.h \ LinearMath/btAabbUtil2.h \ LinearMath/btGeometryUtil.h \ LinearMath/btQuadWord.h \ LinearMath/btPoolAllocator.h \ LinearMath/btScalar.h \ LinearMath/btMinMax.h \ LinearMath/btVector3.h \ LinearMath/btList.h \ LinearMath/btStackAlloc.h \ LinearMath/btMatrix3x3.h \ LinearMath/btMotionState.h \ LinearMath/btAlignedAllocator.h \ LinearMath/btQuaternion.h \ LinearMath/btAlignedObjectArray.h \ LinearMath/btQuickprof.h \ LinearMath/btTransformUtil.h \ LinearMath/btTransform.h \ LinearMath/btDefaultMotionState.h \ LinearMath/btIDebugDraw.h \ LinearMath/btRandom.h \ $(NULL) libbulletcollision_la_SOURCES = \ BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp \ BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp \ BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cpp \ BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp \ BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp \ BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp \ BulletCollision/NarrowPhaseCollision/btConvexCast.cpp \ BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cpp \ BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp \ BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp \ BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cpp \ BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.cpp \ BulletCollision/CollisionDispatch/btCollisionObject.cpp \ BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.cpp \ BulletCollision/CollisionDispatch/btGhostObject.cpp \ BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp \ BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp \ BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp \ BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.cpp \ BulletCollision/CollisionDispatch/btSimulationIslandManager.cpp \ BulletCollision/CollisionDispatch/btBoxBoxDetector.cpp \ BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp \ BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp \ BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.cpp \ BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp \ BulletCollision/CollisionDispatch/btManifoldResult.cpp \ BulletCollision/CollisionDispatch/btCollisionWorld.cpp \ BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp \ BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp \ BulletCollision/CollisionDispatch/btUnionFind.cpp \ BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cpp \ BulletCollision/CollisionShapes/btTetrahedronShape.cpp \ BulletCollision/CollisionShapes/btShapeHull.cpp \ BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp \ BulletCollision/CollisionShapes/btCompoundShape.cpp \ BulletCollision/CollisionShapes/btConeShape.cpp \ BulletCollision/CollisionShapes/btMultiSphereShape.cpp \ BulletCollision/CollisionShapes/btUniformScalingShape.cpp \ BulletCollision/CollisionShapes/btSphereShape.cpp \ BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp \ BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp \ BulletCollision/CollisionShapes/btTriangleMeshShape.cpp \ BulletCollision/CollisionShapes/btTriangleBuffer.cpp \ BulletCollision/CollisionShapes/btStaticPlaneShape.cpp \ BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp \ BulletCollision/CollisionShapes/btEmptyShape.cpp \ BulletCollision/CollisionShapes/btCollisionShape.cpp \ BulletCollision/CollisionShapes/btConvexShape.cpp \ BulletCollision/CollisionShapes/btConvexInternalShape.cpp \ BulletCollision/CollisionShapes/btConvexHullShape.cpp \ BulletCollision/CollisionShapes/btTriangleCallback.cpp \ BulletCollision/CollisionShapes/btCapsuleShape.cpp \ BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp \ BulletCollision/CollisionShapes/btConcaveShape.cpp \ BulletCollision/CollisionShapes/btConvexPointCloudShape.cpp \ BulletCollision/CollisionShapes/btBoxShape.cpp \ BulletCollision/CollisionShapes/btOptimizedBvh.cpp \ BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp \ BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.cpp \ BulletCollision/CollisionShapes/btCylinderShape.cpp \ BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.cpp \ BulletCollision/CollisionShapes/btStridingMeshInterface.cpp \ BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.cpp \ BulletCollision/CollisionShapes/btTriangleMesh.cpp \ BulletCollision/BroadphaseCollision/btAxisSweep3.cpp \ BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp \ BulletCollision/BroadphaseCollision/btDbvtBroadphase.cpp \ BulletCollision/BroadphaseCollision/btMultiSapBroadphase.cpp \ BulletCollision/BroadphaseCollision/btDispatcher.cpp \ BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp \ BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp \ BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp \ BulletCollision/BroadphaseCollision/btDbvt.cpp \ BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp \ BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h \ BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h \ BulletCollision/NarrowPhaseCollision/btConvexCast.h \ BulletCollision/NarrowPhaseCollision/btGjkEpa2.h \ BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h \ BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h \ BulletCollision/NarrowPhaseCollision/btPointCollector.h \ BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h \ BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h \ BulletCollision/NarrowPhaseCollision/btRaycastCallback.h \ BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h \ BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h \ BulletCollision/NarrowPhaseCollision/btPersistentManifold.h \ BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h \ BulletCollision/NarrowPhaseCollision/btManifoldPoint.h \ BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h \ BulletCollision/CollisionDispatch/btCollisionObject.h \ BulletCollision/CollisionDispatch/btGhostObject.h \ BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h \ BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h \ BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.h \ BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h \ BulletCollision/CollisionDispatch/btCollisionCreateFunc.h \ BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h \ BulletCollision/CollisionDispatch/btBoxBoxDetector.h \ BulletCollision/CollisionDispatch/btCollisionDispatcher.h \ BulletCollision/CollisionDispatch/SphereTriangleDetector.h \ BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h \ BulletCollision/CollisionDispatch/btUnionFind.h \ BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h \ BulletCollision/CollisionDispatch/btSimulationIslandManager.h \ BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h \ BulletCollision/CollisionDispatch/btCollisionWorld.h \ BulletCollision/CollisionDispatch/btManifoldResult.h \ BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h \ BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h \ BulletCollision/CollisionDispatch/btCollisionConfiguration.h \ BulletCollision/CollisionShapes/btConvexShape.h \ BulletCollision/CollisionShapes/btTriangleCallback.h \ BulletCollision/CollisionShapes/btPolyhedralConvexShape.h \ BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h \ BulletCollision/CollisionShapes/btCompoundShape.h \ BulletCollision/CollisionShapes/btBoxShape.h \ BulletCollision/CollisionShapes/btMultiSphereShape.h \ BulletCollision/CollisionShapes/btCollisionMargin.h \ BulletCollision/CollisionShapes/btConcaveShape.h \ BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h \ BulletCollision/CollisionShapes/btEmptyShape.h \ BulletCollision/CollisionShapes/btUniformScalingShape.h \ BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h \ BulletCollision/CollisionShapes/btMaterial.h \ BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h \ BulletCollision/CollisionShapes/btSphereShape.h \ BulletCollision/CollisionShapes/btConvexPointCloudShape.h \ BulletCollision/CollisionShapes/btCapsuleShape.h \ BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h \ BulletCollision/CollisionShapes/btCollisionShape.h \ BulletCollision/CollisionShapes/btStaticPlaneShape.h \ BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h \ BulletCollision/CollisionShapes/btTriangleMeshShape.h \ BulletCollision/CollisionShapes/btStridingMeshInterface.h \ BulletCollision/CollisionShapes/btTriangleMesh.h \ BulletCollision/CollisionShapes/btTriangleBuffer.h \ BulletCollision/CollisionShapes/btShapeHull.h \ BulletCollision/CollisionShapes/btMinkowskiSumShape.h \ BulletCollision/CollisionShapes/btOptimizedBvh.h \ BulletCollision/CollisionShapes/btTriangleShape.h \ BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.h \ BulletCollision/CollisionShapes/btCylinderShape.h \ BulletCollision/CollisionShapes/btTetrahedronShape.h \ BulletCollision/CollisionShapes/btConvexInternalShape.h \ BulletCollision/CollisionShapes/btConeShape.h \ BulletCollision/CollisionShapes/btConvexHullShape.h \ BulletCollision/BroadphaseCollision/btAxisSweep3.h \ BulletCollision/BroadphaseCollision/btDbvtBroadphase.h \ BulletCollision/BroadphaseCollision/btSimpleBroadphase.h \ BulletCollision/BroadphaseCollision/btMultiSapBroadphase.h \ BulletCollision/BroadphaseCollision/btDbvt.h \ BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h \ BulletCollision/BroadphaseCollision/btDispatcher.h \ BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h \ BulletCollision/BroadphaseCollision/btBroadphaseProxy.h \ BulletCollision/BroadphaseCollision/btOverlappingPairCache.h \ BulletCollision/BroadphaseCollision/btBroadphaseInterface.h \ BulletCollision/BroadphaseCollision/btQuantizedBvh.h \ BulletCollision/Gimpact/btGImpactBvh.cpp\ BulletCollision/Gimpact/btGImpactQuantizedBvh.cpp\ BulletCollision/Gimpact/btTriangleShapeEx.cpp\ BulletCollision/Gimpact/btGImpactCollisionAlgorithm.cpp\ BulletCollision/Gimpact/btGImpactShape.cpp\ BulletCollision/Gimpact/gim_box_set.cpp\ BulletCollision/Gimpact/gim_contact.cpp\ BulletCollision/Gimpact/gim_memory.cpp\ BulletCollision/Gimpact/gim_tri_collision.cpp \ $(NULL) libbulletdynamics_la_SOURCES = \ BulletDynamics/Dynamics/btContinuousDynamicsWorld.cpp \ BulletDynamics/Dynamics/btRigidBody.cpp \ BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp \ BulletDynamics/Dynamics/Bullet-C-API.cpp \ BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp \ BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp \ BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp \ BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp \ BulletDynamics/ConstraintSolver/btTypedConstraint.cpp \ BulletDynamics/ConstraintSolver/btContactConstraint.cpp \ BulletDynamics/ConstraintSolver/btSliderConstraint.cpp \ BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp \ BulletDynamics/ConstraintSolver/btHingeConstraint.cpp \ BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cpp \ BulletDynamics/Vehicle/btWheelInfo.cpp \ BulletDynamics/Vehicle/btRaycastVehicle.cpp \ BulletDynamics/Character/btKinematicCharacterController.cpp \ BulletDynamics/Character/btKinematicCharacterController.h \ BulletDynamics/Character/btCharacterControllerInterface.h \ BulletDynamics/Dynamics/btContinuousDynamicsWorld.h \ BulletDynamics/Dynamics/btSimpleDynamicsWorld.h \ BulletDynamics/Dynamics/btRigidBody.h \ BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h \ BulletDynamics/Dynamics/btDynamicsWorld.h \ BulletDynamics/ConstraintSolver/btSolverBody.h \ BulletDynamics/ConstraintSolver/btConstraintSolver.h \ BulletDynamics/ConstraintSolver/btConeTwistConstraint.h \ BulletDynamics/ConstraintSolver/btTypedConstraint.h \ BulletDynamics/ConstraintSolver/btContactSolverInfo.h \ BulletDynamics/ConstraintSolver/btContactConstraint.h \ BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h \ BulletDynamics/ConstraintSolver/btJacobianEntry.h \ BulletDynamics/ConstraintSolver/btSolverConstraint.h \ BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h \ BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h \ BulletDynamics/ConstraintSolver/btSliderConstraint.h \ BulletDynamics/ConstraintSolver/btHingeConstraint.h \ BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.h \ BulletDynamics/Vehicle/btVehicleRaycaster.h \ BulletDynamics/Vehicle/btRaycastVehicle.h \ BulletDynamics/Vehicle/btWheelInfo.h \ $(NULL) libbulletsoftbody_la_SOURCES = \ BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.cpp \ BulletSoftBody/btSoftBody.cpp \ BulletSoftBody/btSoftRigidCollisionAlgorithm.cpp \ BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp \ BulletSoftBody/btSoftRigidDynamicsWorld.cpp \ BulletSoftBody/btSoftBodyHelpers.cpp \ BulletSoftBody/btSoftSoftCollisionAlgorithm.cpp \ BulletSoftBody/btSparseSDF.h \ BulletSoftBody/btSoftRigidCollisionAlgorithm.h \ BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h \ BulletSoftBody/btSoftBody.h \ BulletSoftBody/btSoftSoftCollisionAlgorithm.h \ BulletSoftBody/btSoftBodyInternals.h \ BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.h \ BulletSoftBody/btSoftRigidDynamicsWorld.h \ BulletSoftBody/btSoftBodyHelpers.h \ $(NULL) bullet_headers = \ BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h \ BulletSoftBody/btSoftBodyInternals.h \ BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.h \ BulletSoftBody/btSoftSoftCollisionAlgorithm.h \ BulletSoftBody/btSoftBody.h \ BulletSoftBody/btSoftBodyHelpers.h \ BulletSoftBody/btSparseSDF.h \ BulletSoftBody/btSoftRigidCollisionAlgorithm.h \ BulletSoftBody/btSoftRigidDynamicsWorld.h \ BulletDynamics/Vehicle/btRaycastVehicle.h \ BulletDynamics/Vehicle/btWheelInfo.h \ BulletDynamics/Vehicle/btVehicleRaycaster.h \ BulletDynamics/Dynamics/btContinuousDynamicsWorld.h \ BulletDynamics/Dynamics/btRigidBody.h \ BulletDynamics/Dynamics/btDynamicsWorld.h \ BulletDynamics/Dynamics/btSimpleDynamicsWorld.h \ BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h \ BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h \ BulletDynamics/ConstraintSolver/btSolverConstraint.h \ BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h \ BulletDynamics/ConstraintSolver/btTypedConstraint.h \ BulletDynamics/ConstraintSolver/btSliderConstraint.h \ BulletDynamics/ConstraintSolver/btConstraintSolver.h \ BulletDynamics/ConstraintSolver/btContactConstraint.h \ BulletDynamics/ConstraintSolver/btContactSolverInfo.h \ BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h \ BulletDynamics/ConstraintSolver/btJacobianEntry.h \ BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.h \ BulletDynamics/ConstraintSolver/btConeTwistConstraint.h \ BulletDynamics/ConstraintSolver/btHingeConstraint.h \ BulletDynamics/ConstraintSolver/btSolverBody.h \ BulletDynamics/Character/btCharacterControllerInterface.h \ BulletDynamics/Character/btKinematicCharacterController.h \ BulletCollision/CollisionShapes/btShapeHull.h \ BulletCollision/CollisionShapes/btConcaveShape.h \ BulletCollision/CollisionShapes/btCollisionMargin.h \ BulletCollision/CollisionShapes/btCompoundShape.h \ BulletCollision/CollisionShapes/btConvexHullShape.h \ BulletCollision/CollisionShapes/btCylinderShape.h \ BulletCollision/CollisionShapes/btTriangleMesh.h \ BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h \ BulletCollision/CollisionShapes/btUniformScalingShape.h \ BulletCollision/CollisionShapes/btConvexPointCloudShape.h \ BulletCollision/CollisionShapes/btTetrahedronShape.h \ BulletCollision/CollisionShapes/btCapsuleShape.h \ BulletCollision/CollisionShapes/btSphereShape.h \ BulletCollision/CollisionShapes/btMultiSphereShape.h \ BulletCollision/CollisionShapes/btConvexInternalShape.h \ BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h \ BulletCollision/CollisionShapes/btStridingMeshInterface.h \ BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h \ BulletCollision/CollisionShapes/btEmptyShape.h \ BulletCollision/CollisionShapes/btOptimizedBvh.h \ BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h \ BulletCollision/CollisionShapes/btTriangleCallback.h \ BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.h \ BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h \ BulletCollision/CollisionShapes/btTriangleBuffer.h \ BulletCollision/CollisionShapes/btConvexShape.h \ BulletCollision/CollisionShapes/btStaticPlaneShape.h \ BulletCollision/CollisionShapes/btConeShape.h \ BulletCollision/CollisionShapes/btCollisionShape.h \ BulletCollision/CollisionShapes/btTriangleShape.h \ BulletCollision/CollisionShapes/btBoxShape.h \ BulletCollision/CollisionShapes/btMinkowskiSumShape.h \ BulletCollision/CollisionShapes/btTriangleMeshShape.h \ BulletCollision/CollisionShapes/btMaterial.h \ BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h \ BulletCollision/CollisionShapes/btPolyhedralConvexShape.h \ BulletCollision/NarrowPhaseCollision/btConvexCast.h \ BulletCollision/NarrowPhaseCollision/btGjkEpa2.h \ BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h \ BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h \ BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h \ BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h \ BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h \ BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h \ BulletCollision/NarrowPhaseCollision/btPersistentManifold.h \ BulletCollision/NarrowPhaseCollision/btManifoldPoint.h \ BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h \ BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h \ BulletCollision/NarrowPhaseCollision/btRaycastCallback.h \ BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h \ BulletCollision/NarrowPhaseCollision/btPointCollector.h \ BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h \ BulletCollision/BroadphaseCollision/btDbvt.h \ BulletCollision/BroadphaseCollision/btDispatcher.h \ BulletCollision/BroadphaseCollision/btDbvtBroadphase.h \ BulletCollision/BroadphaseCollision/btSimpleBroadphase.h \ BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h \ BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h \ BulletCollision/BroadphaseCollision/btMultiSapBroadphase.h \ BulletCollision/BroadphaseCollision/btQuantizedBvh.h \ BulletCollision/BroadphaseCollision/btAxisSweep3.h \ BulletCollision/BroadphaseCollision/btBroadphaseInterface.h \ BulletCollision/BroadphaseCollision/btOverlappingPairCache.h \ BulletCollision/BroadphaseCollision/btBroadphaseProxy.h \ BulletCollision/CollisionDispatch/btUnionFind.h \ BulletCollision/CollisionDispatch/btCollisionConfiguration.h \ BulletCollision/CollisionDispatch/btCollisionDispatcher.h \ BulletCollision/CollisionDispatch/SphereTriangleDetector.h \ BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h \ BulletCollision/CollisionDispatch/btCollisionWorld.h \ BulletCollision/CollisionDispatch/btCollisionCreateFunc.h \ BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.h \ BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h \ BulletCollision/CollisionDispatch/btCollisionObject.h \ BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.h \ BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h \ BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h \ BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h \ BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h \ BulletCollision/CollisionDispatch/btGhostObject.h \ BulletCollision/CollisionDispatch/btSimulationIslandManager.h \ BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h \ BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.h \ BulletCollision/CollisionDispatch/btBoxBoxDetector.h \ BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h \ BulletCollision/CollisionDispatch/btManifoldResult.h \ BulletCollision/Gimpact/gim_memory.h \ BulletCollision/Gimpact/gim_clip_polygon.h \ BulletCollision/Gimpact/gim_bitset.h \ BulletCollision/Gimpact/gim_linear_math.h \ BulletCollision/Gimpact/btGeometryOperations.h \ BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h \ BulletCollision/Gimpact/btGImpactBvh.h \ BulletCollision/Gimpact/gim_box_set.h \ BulletCollision/Gimpact/gim_array.h \ BulletCollision/Gimpact/btGImpactShape.h \ BulletCollision/Gimpact/btTriangleShapeEx.h \ BulletCollision/Gimpact/btClipPolygon.h \ BulletCollision/Gimpact/gim_box_collision.h \ BulletCollision/Gimpact/gim_tri_collision.h \ BulletCollision/Gimpact/gim_geometry.h \ BulletCollision/Gimpact/gim_math.h \ BulletCollision/Gimpact/btQuantization.h \ BulletCollision/Gimpact/btGImpactQuantizedBvh.h \ BulletCollision/Gimpact/gim_geom_types.h \ BulletCollision/Gimpact/gim_basic_geometry_operations.h \ BulletCollision/Gimpact/gim_contact.h \ BulletCollision/Gimpact/gim_hash_table.h \ BulletCollision/Gimpact/gim_radixsort.h \ BulletCollision/Gimpact/btGImpactMassUtil.h \ BulletCollision/Gimpact/btGenericPoolAllocator.h \ BulletCollision/Gimpact/btBoxCollision.h \ BulletCollision/Gimpact/btContactProcessing.h \ LinearMath/btGeometryUtil.h \ LinearMath/btConvexHull.h \ LinearMath/btList.h \ LinearMath/btMatrix3x3.h \ LinearMath/btVector3.h \ LinearMath/btPoolAllocator.h \ LinearMath/btScalar.h \ LinearMath/btDefaultMotionState.h \ LinearMath/btTransform.h \ LinearMath/btQuadWord.h \ LinearMath/btAabbUtil2.h \ LinearMath/btTransformUtil.h \ LinearMath/btRandom.h \ LinearMath/btQuaternion.h \ LinearMath/btMinMax.h \ LinearMath/btMotionState.h \ LinearMath/btIDebugDraw.h \ LinearMath/btAlignedAllocator.h \ LinearMath/btStackAlloc.h \ LinearMath/btAlignedObjectArray.h \ LinearMath/btHashMap.h \ LinearMath/btQuickprof.h \ ${NULL} NULL =critterding-beta12.1/src/utils/bullet/BulletDynamics/0000755000175000017500000000000011347266042021677 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletDynamics/Character/0000755000175000017500000000000011347266042023573 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletDynamics/Character/btCharacterControllerInterface.h0000644000175000017500000000345511337071441032056 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com 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 CHARACTER_CONTROLLER_INTERFACE_H #define CHARACTER_CONTROLLER_INTERFACE_H #include "LinearMath/btVector3.h" #include "BulletDynamics/Dynamics/btActionInterface.h" class btCollisionShape; class btRigidBody; class btCollisionWorld; class btCharacterControllerInterface : public btActionInterface { public: btCharacterControllerInterface () {}; virtual ~btCharacterControllerInterface () {}; virtual void setWalkDirection(const btVector3& walkDirection) = 0; virtual void setVelocityForTimeInterval(const btVector3& velocity, btScalar timeInterval) = 0; virtual void reset () = 0; virtual void warp (const btVector3& origin) = 0; virtual void preStep ( btCollisionWorld* collisionWorld) = 0; virtual void playerStep (btCollisionWorld* collisionWorld, btScalar dt) = 0; virtual bool canJump () const = 0; virtual void jump () = 0; virtual bool onGround () const = 0; }; #endif critterding-beta12.1/src/utils/bullet/BulletDynamics/Character/btKinematicCharacterController.h0000644000175000017500000001217611344267705032072 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com 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 KINEMATIC_CHARACTER_CONTROLLER_H #define KINEMATIC_CHARACTER_CONTROLLER_H #include "LinearMath/btVector3.h" #include "btCharacterControllerInterface.h" #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" class btCollisionShape; class btRigidBody; class btCollisionWorld; class btCollisionDispatcher; class btPairCachingGhostObject; ///btKinematicCharacterController is an object that supports a sliding motion in a world. ///It uses a ghost object and convex sweep test to test for upcoming collisions. This is combined with discrete collision detection to recover from penetrations. ///Interaction between btKinematicCharacterController and dynamic rigid bodies needs to be explicity implemented by the user. class btKinematicCharacterController : public btCharacterControllerInterface { protected: btScalar m_halfHeight; btPairCachingGhostObject* m_ghostObject; btConvexShape* m_convexShape;//is also in m_ghostObject, but it needs to be convex, so we store it here to avoid upcast btScalar m_fallSpeed; btScalar m_jumpSpeed; btScalar m_maxJumpHeight; btScalar m_turnAngle; btScalar m_stepHeight; btScalar m_addedMargin;//@todo: remove this and fix the code ///this is the desired walk direction, set by the user btVector3 m_walkDirection; btVector3 m_normalizedDirection; //some internal variables btVector3 m_currentPosition; btScalar m_currentStepOffset; btVector3 m_targetPosition; ///keep track of the contact manifolds btManifoldArray m_manifoldArray; bool m_touchingContact; btVector3 m_touchingNormal; bool m_useGhostObjectSweepTest; bool m_useWalkDirection; btScalar m_velocityTimeInterval; int m_upAxis; static btVector3* getUpAxisDirections(); btVector3 computeReflectionDirection (const btVector3& direction, const btVector3& normal); btVector3 parallelComponent (const btVector3& direction, const btVector3& normal); btVector3 perpindicularComponent (const btVector3& direction, const btVector3& normal); bool recoverFromPenetration ( btCollisionWorld* collisionWorld); void stepUp (btCollisionWorld* collisionWorld); void updateTargetPositionBasedOnCollision (const btVector3& hit_normal, btScalar tangentMag = btScalar(0.0), btScalar normalMag = btScalar(1.0)); void stepForwardAndStrafe (btCollisionWorld* collisionWorld, const btVector3& walkMove); void stepDown (btCollisionWorld* collisionWorld, btScalar dt); public: btKinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, int upAxis = 1); ~btKinematicCharacterController (); ///btActionInterface interface virtual void updateAction( btCollisionWorld* collisionWorld,btScalar deltaTime) { preStep ( collisionWorld); playerStep (collisionWorld, deltaTime); } ///btActionInterface interface void debugDraw(btIDebugDraw* debugDrawer); void setUpAxis (int axis) { if (axis < 0) axis = 0; if (axis > 2) axis = 2; m_upAxis = axis; } /// This should probably be called setPositionIncrementPerSimulatorStep. /// This is neither a direction nor a velocity, but the amount to /// increment the position each simulation iteration, regardless /// of dt. /// This call will reset any velocity set by setVelocityForTimeInterval(). virtual void setWalkDirection(const btVector3& walkDirection); /// Caller provides a velocity with which the character should move for /// the given time period. After the time period, velocity is reset /// to zero. /// This call will reset any walk direction set by setWalkDirection(). /// Negative time intervals will result in no motion. virtual void setVelocityForTimeInterval(const btVector3& velocity, btScalar timeInterval); void reset (); void warp (const btVector3& origin); void preStep ( btCollisionWorld* collisionWorld); void playerStep ( btCollisionWorld* collisionWorld, btScalar dt); void setFallSpeed (btScalar fallSpeed); void setJumpSpeed (btScalar jumpSpeed); void setMaxJumpHeight (btScalar maxJumpHeight); bool canJump () const; void jump (); btPairCachingGhostObject* getGhostObject(); void setUseGhostSweepTest(bool useGhostObjectSweepTest) { m_useGhostObjectSweepTest = useGhostObjectSweepTest; } bool onGround () const; }; #endif // KINEMATIC_CHARACTER_CONTROLLER_H critterding-beta12.1/src/utils/bullet/BulletDynamics/Character/btKinematicCharacterController.cpp0000644000175000017500000004102111344267705032414 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com 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 "LinearMath/btIDebugDraw.h" #include "BulletCollision/CollisionDispatch/btGhostObject.h" #include "BulletCollision/CollisionShapes/btMultiSphereShape.h" #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btCollisionWorld.h" #include "LinearMath/btDefaultMotionState.h" #include "btKinematicCharacterController.h" // static helper method static btVector3 getNormalizedVector(const btVector3& v) { btVector3 n = v.normalized(); if (n.length() < SIMD_EPSILON) { n.setValue(0, 0, 0); } return n; } ///@todo Interact with dynamic objects, ///Ride kinematicly animated platforms properly ///More realistic (or maybe just a config option) falling /// -> Should integrate falling velocity manually and use that in stepDown() ///Support jumping ///Support ducking class btKinematicClosestNotMeRayResultCallback : public btCollisionWorld::ClosestRayResultCallback { public: btKinematicClosestNotMeRayResultCallback (btCollisionObject* me) : btCollisionWorld::ClosestRayResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) { m_me = me; } virtual btScalar addSingleResult(btCollisionWorld::LocalRayResult& rayResult,bool normalInWorldSpace) { if (rayResult.m_collisionObject == m_me) return 1.0; return ClosestRayResultCallback::addSingleResult (rayResult, normalInWorldSpace); } protected: btCollisionObject* m_me; }; class btKinematicClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { public: btKinematicClosestNotMeConvexResultCallback (btCollisionObject* me) : btCollisionWorld::ClosestConvexResultCallback(btVector3(0.0, 0.0, 0.0), btVector3(0.0, 0.0, 0.0)) { m_me = me; } virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace) { if (convexResult.m_hitCollisionObject == m_me) return 1.0; return ClosestConvexResultCallback::addSingleResult (convexResult, normalInWorldSpace); } protected: btCollisionObject* m_me; }; /* * Returns the reflection direction of a ray going 'direction' hitting a surface with normal 'normal' * * from: http://www-cs-students.stanford.edu/~adityagp/final/node3.html */ btVector3 btKinematicCharacterController::computeReflectionDirection (const btVector3& direction, const btVector3& normal) { return direction - (btScalar(2.0) * direction.dot(normal)) * normal; } /* * Returns the portion of 'direction' that is parallel to 'normal' */ btVector3 btKinematicCharacterController::parallelComponent (const btVector3& direction, const btVector3& normal) { btScalar magnitude = direction.dot(normal); return normal * magnitude; } /* * Returns the portion of 'direction' that is perpindicular to 'normal' */ btVector3 btKinematicCharacterController::perpindicularComponent (const btVector3& direction, const btVector3& normal) { return direction - parallelComponent(direction, normal); } btKinematicCharacterController::btKinematicCharacterController (btPairCachingGhostObject* ghostObject,btConvexShape* convexShape,btScalar stepHeight, int upAxis) { m_upAxis = upAxis; m_addedMargin = 0.02f; m_walkDirection.setValue(0,0,0); m_useGhostObjectSweepTest = true; m_ghostObject = ghostObject; m_stepHeight = stepHeight; m_turnAngle = btScalar(0.0); m_convexShape=convexShape; m_useWalkDirection = true; // use walk direction by default, legacy behavior m_velocityTimeInterval = 0.0; } btKinematicCharacterController::~btKinematicCharacterController () { } btPairCachingGhostObject* btKinematicCharacterController::getGhostObject() { return m_ghostObject; } bool btKinematicCharacterController::recoverFromPenetration ( btCollisionWorld* collisionWorld) { bool penetration = false; collisionWorld->getDispatcher()->dispatchAllCollisionPairs(m_ghostObject->getOverlappingPairCache(), collisionWorld->getDispatchInfo(), collisionWorld->getDispatcher()); m_currentPosition = m_ghostObject->getWorldTransform().getOrigin(); btScalar maxPen = btScalar(0.0); for (int i = 0; i < m_ghostObject->getOverlappingPairCache()->getNumOverlappingPairs(); i++) { m_manifoldArray.resize(0); btBroadphasePair* collisionPair = &m_ghostObject->getOverlappingPairCache()->getOverlappingPairArray()[i]; if (collisionPair->m_algorithm) collisionPair->m_algorithm->getAllContactManifolds(m_manifoldArray); for (int j=0;jgetBody0() == m_ghostObject ? btScalar(-1.0) : btScalar(1.0); for (int p=0;pgetNumContacts();p++) { const btManifoldPoint&pt = manifold->getContactPoint(p); if (pt.getDistance() < 0.0) { if (pt.getDistance() < maxPen) { maxPen = pt.getDistance(); m_touchingNormal = pt.m_normalWorldOnB * directionSign;//?? } m_currentPosition += pt.m_normalWorldOnB * directionSign * pt.getDistance() * btScalar(0.2); penetration = true; } else { //printf("touching %f\n", pt.getDistance()); } } //manifold->clearManifold(); } } btTransform newTrans = m_ghostObject->getWorldTransform(); newTrans.setOrigin(m_currentPosition); m_ghostObject->setWorldTransform(newTrans); // printf("m_touchingNormal = %f,%f,%f\n",m_touchingNormal[0],m_touchingNormal[1],m_touchingNormal[2]); return penetration; } void btKinematicCharacterController::stepUp ( btCollisionWorld* world) { // phase 1: up btTransform start, end; m_targetPosition = m_currentPosition + getUpAxisDirections()[m_upAxis] * m_stepHeight; start.setIdentity (); end.setIdentity (); /* FIXME: Handle penetration properly */ start.setOrigin (m_currentPosition + getUpAxisDirections()[m_upAxis] * btScalar(0.1f)); end.setOrigin (m_targetPosition); btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject); callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; if (m_useGhostObjectSweepTest) { m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, world->getDispatchInfo().m_allowedCcdPenetration); } else { world->convexSweepTest (m_convexShape, start, end, callback); } if (callback.hasHit()) { // we moved up only a fraction of the step height m_currentStepOffset = m_stepHeight * callback.m_closestHitFraction; m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); } else { m_currentStepOffset = m_stepHeight; m_currentPosition = m_targetPosition; } } void btKinematicCharacterController::updateTargetPositionBasedOnCollision (const btVector3& hitNormal, btScalar tangentMag, btScalar normalMag) { btVector3 movementDirection = m_targetPosition - m_currentPosition; btScalar movementLength = movementDirection.length(); if (movementLength>SIMD_EPSILON) { movementDirection.normalize(); btVector3 reflectDir = computeReflectionDirection (movementDirection, hitNormal); reflectDir.normalize(); btVector3 parallelDir, perpindicularDir; parallelDir = parallelComponent (reflectDir, hitNormal); perpindicularDir = perpindicularComponent (reflectDir, hitNormal); m_targetPosition = m_currentPosition; if (0)//tangentMag != 0.0) { btVector3 parComponent = parallelDir * btScalar (tangentMag*movementLength); // printf("parComponent=%f,%f,%f\n",parComponent[0],parComponent[1],parComponent[2]); m_targetPosition += parComponent; } if (normalMag != 0.0) { btVector3 perpComponent = perpindicularDir * btScalar (normalMag*movementLength); // printf("perpComponent=%f,%f,%f\n",perpComponent[0],perpComponent[1],perpComponent[2]); m_targetPosition += perpComponent; } } else { // printf("movementLength don't normalize a zero vector\n"); } } void btKinematicCharacterController::stepForwardAndStrafe ( btCollisionWorld* collisionWorld, const btVector3& walkMove) { // printf("m_normalizedDirection=%f,%f,%f\n", // m_normalizedDirection[0],m_normalizedDirection[1],m_normalizedDirection[2]); // phase 2: forward and strafe btTransform start, end; m_targetPosition = m_currentPosition + walkMove; start.setIdentity (); end.setIdentity (); btScalar fraction = 1.0; btScalar distance2 = (m_currentPosition-m_targetPosition).length2(); // printf("distance2=%f\n",distance2); if (m_touchingContact) { if (m_normalizedDirection.dot(m_touchingNormal) > btScalar(0.0)) updateTargetPositionBasedOnCollision (m_touchingNormal); } int maxIter = 10; while (fraction > btScalar(0.01) && maxIter-- > 0) { start.setOrigin (m_currentPosition); end.setOrigin (m_targetPosition); btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject); callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; btScalar margin = m_convexShape->getMargin(); m_convexShape->setMargin(margin + m_addedMargin); if (m_useGhostObjectSweepTest) { m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); } else { collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); } m_convexShape->setMargin(margin); fraction -= callback.m_closestHitFraction; if (callback.hasHit()) { // we moved only a fraction btScalar hitDistance = (callback.m_hitPointWorld - m_currentPosition).length(); if (hitDistance<0.f) { // printf("neg dist?\n"); } /* If the distance is farther than the collision margin, move */ if (hitDistance > m_addedMargin) { // printf("callback.m_closestHitFraction=%f\n",callback.m_closestHitFraction); m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); } updateTargetPositionBasedOnCollision (callback.m_hitNormalWorld); btVector3 currentDir = m_targetPosition - m_currentPosition; distance2 = currentDir.length2(); if (distance2 > SIMD_EPSILON) { currentDir.normalize(); /* See Quake2: "If velocity is against original velocity, stop ead to avoid tiny oscilations in sloping corners." */ if (currentDir.dot(m_normalizedDirection) <= btScalar(0.0)) { break; } } else { // printf("currentDir: don't normalize a zero vector\n"); break; } } else { // we moved whole way m_currentPosition = m_targetPosition; } // if (callback.m_closestHitFraction == 0.f) // break; } } void btKinematicCharacterController::stepDown ( btCollisionWorld* collisionWorld, btScalar dt) { btTransform start, end; // phase 3: down btVector3 step_drop = getUpAxisDirections()[m_upAxis] * m_currentStepOffset; btVector3 gravity_drop = getUpAxisDirections()[m_upAxis] * m_stepHeight; m_targetPosition -= (step_drop + gravity_drop); start.setIdentity (); end.setIdentity (); start.setOrigin (m_currentPosition); end.setOrigin (m_targetPosition); btKinematicClosestNotMeConvexResultCallback callback (m_ghostObject); callback.m_collisionFilterGroup = getGhostObject()->getBroadphaseHandle()->m_collisionFilterGroup; callback.m_collisionFilterMask = getGhostObject()->getBroadphaseHandle()->m_collisionFilterMask; if (m_useGhostObjectSweepTest) { m_ghostObject->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); } else { collisionWorld->convexSweepTest (m_convexShape, start, end, callback, collisionWorld->getDispatchInfo().m_allowedCcdPenetration); } if (callback.hasHit()) { // we dropped a fraction of the height -> hit floor m_currentPosition.setInterpolate3 (m_currentPosition, m_targetPosition, callback.m_closestHitFraction); } else { // we dropped the full height m_currentPosition = m_targetPosition; } } void btKinematicCharacterController::setWalkDirection ( const btVector3& walkDirection ) { m_useWalkDirection = true; m_walkDirection = walkDirection; m_normalizedDirection = getNormalizedVector(m_walkDirection); } void btKinematicCharacterController::setVelocityForTimeInterval ( const btVector3& velocity, btScalar timeInterval ) { // printf("setVelocity!\n"); // printf(" interval: %f\n", timeInterval); // printf(" velocity: (%f, %f, %f)\n", // velocity.x(), velocity.y(), velocity.z()); m_useWalkDirection = false; m_walkDirection = velocity; m_normalizedDirection = getNormalizedVector(m_walkDirection); m_velocityTimeInterval = timeInterval; } void btKinematicCharacterController::reset () { } void btKinematicCharacterController::warp (const btVector3& origin) { btTransform xform; xform.setIdentity(); xform.setOrigin (origin); m_ghostObject->setWorldTransform (xform); } void btKinematicCharacterController::preStep ( btCollisionWorld* collisionWorld) { int numPenetrationLoops = 0; m_touchingContact = false; while (recoverFromPenetration (collisionWorld)) { numPenetrationLoops++; m_touchingContact = true; if (numPenetrationLoops > 4) { // printf("character could not recover from penetration = %d\n", numPenetrationLoops); break; } } m_currentPosition = m_ghostObject->getWorldTransform().getOrigin(); m_targetPosition = m_currentPosition; // printf("m_targetPosition=%f,%f,%f\n",m_targetPosition[0],m_targetPosition[1],m_targetPosition[2]); } void btKinematicCharacterController::playerStep ( btCollisionWorld* collisionWorld, btScalar dt) { // printf("playerStep(): "); // printf(" dt = %f", dt); // quick check... if (!m_useWalkDirection && m_velocityTimeInterval <= 0.0) { // printf("\n"); return; // no motion } btTransform xform; xform = m_ghostObject->getWorldTransform (); // printf("walkDirection(%f,%f,%f)\n",walkDirection[0],walkDirection[1],walkDirection[2]); // printf("walkSpeed=%f\n",walkSpeed); stepUp (collisionWorld); if (m_useWalkDirection) { stepForwardAndStrafe (collisionWorld, m_walkDirection); } else { //printf(" time: %f", m_velocityTimeInterval); // still have some time left for moving! btScalar dtMoving = (dt < m_velocityTimeInterval) ? dt : m_velocityTimeInterval; m_velocityTimeInterval -= dt; // how far will we move while we are moving? btVector3 move = m_walkDirection * dtMoving; // printf(" dtMoving: %f", dtMoving); // okay, step stepForwardAndStrafe(collisionWorld, move); } stepDown (collisionWorld, dt); // printf("\n"); xform.setOrigin (m_currentPosition); m_ghostObject->setWorldTransform (xform); } void btKinematicCharacterController::setFallSpeed (btScalar fallSpeed) { m_fallSpeed = fallSpeed; } void btKinematicCharacterController::setJumpSpeed (btScalar jumpSpeed) { m_jumpSpeed = jumpSpeed; } void btKinematicCharacterController::setMaxJumpHeight (btScalar maxJumpHeight) { m_maxJumpHeight = maxJumpHeight; } bool btKinematicCharacterController::canJump () const { return onGround(); } void btKinematicCharacterController::jump () { if (!canJump()) return; #if 0 currently no jumping. btTransform xform; m_rigidBody->getMotionState()->getWorldTransform (xform); btVector3 up = xform.getBasis()[1]; up.normalize (); btScalar magnitude = (btScalar(1.0)/m_rigidBody->getInvMass()) * btScalar(8.0); m_rigidBody->applyCentralImpulse (up * magnitude); #endif } bool btKinematicCharacterController::onGround () const { return true; } void btKinematicCharacterController::debugDraw(btIDebugDraw* debugDrawer) { } btVector3* btKinematicCharacterController::getUpAxisDirections() { static btVector3 sUpAxisDirection[3] = { btVector3(1.0f, 0.0f, 0.0f), btVector3(0.0f, 1.0f, 0.0f), btVector3(0.0f, 0.0f, 1.0f) }; return sUpAxisDirection; }critterding-beta12.1/src/utils/bullet/BulletDynamics/Jamfile0000644000175000017500000000050511337071441023165 0ustar bobkebobke SubDir TOP src BulletDynamics ; Description bulletdynamics : "Bullet Rigidbody Dynamics" ; Library bulletdynamics : [ Wildcard ConstraintSolver : *.h *.cpp ] [ Wildcard Dynamics : *.h *.cpp ] [ Wildcard Vehicle : *.h *.cpp ] [ Wildcard Character : *.h *.cpp ] ; LibDepends bulletdynamics : bulletcollision ; critterding-beta12.1/src/utils/bullet/BulletDynamics/Dynamics/0000755000175000017500000000000011347266042023446 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletDynamics/Dynamics/btSimpleDynamicsWorld.cpp0000644000175000017500000001513611337071441030433 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btSimpleDynamicsWorld.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h" #include "BulletCollision/CollisionShapes/btCollisionShape.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h" #include "BulletDynamics/ConstraintSolver/btContactSolverInfo.h" /* Make sure this dummy function never changes so that it can be used by probes that are checking whether the library is actually installed. */ extern "C" { void btBulletDynamicsProbe (); void btBulletDynamicsProbe () {} } btSimpleDynamicsWorld::btSimpleDynamicsWorld(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolver* constraintSolver,btCollisionConfiguration* collisionConfiguration) :btDynamicsWorld(dispatcher,pairCache,collisionConfiguration), m_constraintSolver(constraintSolver), m_ownsConstraintSolver(false), m_gravity(0,0,-10) { } btSimpleDynamicsWorld::~btSimpleDynamicsWorld() { if (m_ownsConstraintSolver) btAlignedFree( m_constraintSolver); } int btSimpleDynamicsWorld::stepSimulation( btScalar timeStep,int maxSubSteps, btScalar fixedTimeStep) { (void)fixedTimeStep; (void)maxSubSteps; ///apply gravity, predict motion predictUnconstraintMotion(timeStep); btDispatcherInfo& dispatchInfo = getDispatchInfo(); dispatchInfo.m_timeStep = timeStep; dispatchInfo.m_stepCount = 0; dispatchInfo.m_debugDraw = getDebugDrawer(); ///perform collision detection performDiscreteCollisionDetection(); ///solve contact constraints int numManifolds = m_dispatcher1->getNumManifolds(); if (numManifolds) { btPersistentManifold** manifoldPtr = ((btCollisionDispatcher*)m_dispatcher1)->getInternalManifoldPointer(); btContactSolverInfo infoGlobal; infoGlobal.m_timeStep = timeStep; m_constraintSolver->prepareSolve(0,numManifolds); m_constraintSolver->solveGroup(0,0,manifoldPtr, numManifolds,0,0,infoGlobal,m_debugDrawer, m_stackAlloc,m_dispatcher1); m_constraintSolver->allSolved(infoGlobal,m_debugDrawer, m_stackAlloc); } ///integrate transforms integrateTransforms(timeStep); updateAabbs(); synchronizeMotionStates(); clearForces(); return 1; } void btSimpleDynamicsWorld::clearForces() { ///@todo: iterate over awake simulation islands! for ( int i=0;iclearForces(); } } } void btSimpleDynamicsWorld::setGravity(const btVector3& gravity) { m_gravity = gravity; for ( int i=0;isetGravity(gravity); } } } btVector3 btSimpleDynamicsWorld::getGravity () const { return m_gravity; } void btSimpleDynamicsWorld::removeRigidBody(btRigidBody* body) { btCollisionWorld::removeCollisionObject(body); } void btSimpleDynamicsWorld::removeCollisionObject(btCollisionObject* collisionObject) { btRigidBody* body = btRigidBody::upcast(collisionObject); if (body) removeRigidBody(body); else btCollisionWorld::removeCollisionObject(collisionObject); } void btSimpleDynamicsWorld::addRigidBody(btRigidBody* body) { body->setGravity(m_gravity); if (body->getCollisionShape()) { addCollisionObject(body); } } void btSimpleDynamicsWorld::updateAabbs() { btTransform predictedTrans; for ( int i=0;iisActive() && (!body->isStaticObject())) { btVector3 minAabb,maxAabb; colObj->getCollisionShape()->getAabb(colObj->getWorldTransform(), minAabb,maxAabb); btBroadphaseInterface* bp = getBroadphase(); bp->setAabb(body->getBroadphaseHandle(),minAabb,maxAabb, m_dispatcher1); } } } } void btSimpleDynamicsWorld::integrateTransforms(btScalar timeStep) { btTransform predictedTrans; for ( int i=0;iisActive() && (!body->isStaticObject())) { body->predictIntegratedTransform(timeStep, predictedTrans); body->proceedToTransform( predictedTrans); } } } } void btSimpleDynamicsWorld::predictUnconstraintMotion(btScalar timeStep) { for ( int i=0;iisStaticObject()) { if (body->isActive()) { body->applyGravity(); body->integrateVelocities( timeStep); body->applyDamping(timeStep); body->predictIntegratedTransform(timeStep,body->getInterpolationWorldTransform()); } } } } } void btSimpleDynamicsWorld::synchronizeMotionStates() { ///@todo: iterate over awake simulation islands! for ( int i=0;igetMotionState()) { if (body->getActivationState() != ISLAND_SLEEPING) { body->getMotionState()->setWorldTransform(body->getWorldTransform()); } } } } void btSimpleDynamicsWorld::setConstraintSolver(btConstraintSolver* solver) { if (m_ownsConstraintSolver) { btAlignedFree(m_constraintSolver); } m_ownsConstraintSolver = false; m_constraintSolver = solver; } btConstraintSolver* btSimpleDynamicsWorld::getConstraintSolver() { return m_constraintSolver; } critterding-beta12.1/src/utils/bullet/BulletDynamics/Dynamics/btDynamicsWorld.h0000644000175000017500000001207611337071441026726 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BT_DYNAMICS_WORLD_H #define BT_DYNAMICS_WORLD_H #include "BulletCollision/CollisionDispatch/btCollisionWorld.h" #include "BulletDynamics/ConstraintSolver/btContactSolverInfo.h" class btTypedConstraint; class btActionInterface; class btConstraintSolver; class btDynamicsWorld; /// Type for the callback for each tick typedef void (*btInternalTickCallback)(btDynamicsWorld *world, btScalar timeStep); enum btDynamicsWorldType { BT_SIMPLE_DYNAMICS_WORLD=1, BT_DISCRETE_DYNAMICS_WORLD=2, BT_CONTINUOUS_DYNAMICS_WORLD=3 }; ///The btDynamicsWorld is the interface class for several dynamics implementation, basic, discrete, parallel, and continuous etc. class btDynamicsWorld : public btCollisionWorld { protected: btInternalTickCallback m_internalTickCallback; btInternalTickCallback m_internalPreTickCallback; void* m_worldUserInfo; btContactSolverInfo m_solverInfo; public: btDynamicsWorld(btDispatcher* dispatcher,btBroadphaseInterface* broadphase,btCollisionConfiguration* collisionConfiguration) :btCollisionWorld(dispatcher,broadphase,collisionConfiguration), m_internalTickCallback(0),m_internalPreTickCallback(0), m_worldUserInfo(0) { } virtual ~btDynamicsWorld() { } ///stepSimulation proceeds the simulation over 'timeStep', units in preferably in seconds. ///By default, Bullet will subdivide the timestep in constant substeps of each 'fixedTimeStep'. ///in order to keep the simulation real-time, the maximum number of substeps can be clamped to 'maxSubSteps'. ///You can disable subdividing the timestep/substepping by passing maxSubSteps=0 as second argument to stepSimulation, but in that case you have to keep the timeStep constant. virtual int stepSimulation( btScalar timeStep,int maxSubSteps=1, btScalar fixedTimeStep=btScalar(1.)/btScalar(60.))=0; virtual void debugDrawWorld() = 0; virtual void addConstraint(btTypedConstraint* constraint, bool disableCollisionsBetweenLinkedBodies=false) { (void)constraint; (void)disableCollisionsBetweenLinkedBodies; } virtual void removeConstraint(btTypedConstraint* constraint) {(void)constraint;} virtual void addAction(btActionInterface* action) = 0; virtual void removeAction(btActionInterface* action) = 0; //once a rigidbody is added to the dynamics world, it will get this gravity assigned //existing rigidbodies in the world get gravity assigned too, during this method virtual void setGravity(const btVector3& gravity) = 0; virtual btVector3 getGravity () const = 0; virtual void synchronizeMotionStates() = 0; virtual void addRigidBody(btRigidBody* body) = 0; virtual void removeRigidBody(btRigidBody* body) = 0; virtual void setConstraintSolver(btConstraintSolver* solver) = 0; virtual btConstraintSolver* getConstraintSolver() = 0; virtual int getNumConstraints() const { return 0; } virtual btTypedConstraint* getConstraint(int index) { (void)index; return 0; } virtual const btTypedConstraint* getConstraint(int index) const { (void)index; return 0; } virtual btDynamicsWorldType getWorldType() const=0; virtual void clearForces() = 0; /// Set the callback for when an internal tick (simulation substep) happens, optional user info void setInternalTickCallback(btInternalTickCallback cb, void* worldUserInfo=0,bool isPreTick=false) { if (isPreTick) { m_internalPreTickCallback = cb; } else { m_internalTickCallback = cb; } m_worldUserInfo = worldUserInfo; } void setWorldUserInfo(void* worldUserInfo) { m_worldUserInfo = worldUserInfo; } void* getWorldUserInfo() const { return m_worldUserInfo; } btContactSolverInfo& getSolverInfo() { return m_solverInfo; } ///obsolete, use addAction instead. virtual void addVehicle(btActionInterface* vehicle) {(void)vehicle;} ///obsolete, use removeAction instead virtual void removeVehicle(btActionInterface* vehicle) {(void)vehicle;} ///obsolete, use addAction instead. virtual void addCharacter(btActionInterface* character) {(void)character;} ///obsolete, use removeAction instead virtual void removeCharacter(btActionInterface* character) {(void)character;} }; #endif //BT_DYNAMICS_WORLD_H critterding-beta12.1/src/utils/bullet/BulletDynamics/Dynamics/btSimpleDynamicsWorld.h0000644000175000017500000000560111337071441030074 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BT_SIMPLE_DYNAMICS_WORLD_H #define BT_SIMPLE_DYNAMICS_WORLD_H #include "btDynamicsWorld.h" class btDispatcher; class btOverlappingPairCache; class btConstraintSolver; ///The btSimpleDynamicsWorld serves as unit-test and to verify more complicated and optimized dynamics worlds. ///Please use btDiscreteDynamicsWorld instead (or btContinuousDynamicsWorld once it is finished). class btSimpleDynamicsWorld : public btDynamicsWorld { protected: btConstraintSolver* m_constraintSolver; bool m_ownsConstraintSolver; void predictUnconstraintMotion(btScalar timeStep); void integrateTransforms(btScalar timeStep); btVector3 m_gravity; public: ///this btSimpleDynamicsWorld constructor creates dispatcher, broadphase pairCache and constraintSolver btSimpleDynamicsWorld(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolver* constraintSolver,btCollisionConfiguration* collisionConfiguration); virtual ~btSimpleDynamicsWorld(); ///maxSubSteps/fixedTimeStep for interpolation is currently ignored for btSimpleDynamicsWorld, use btDiscreteDynamicsWorld instead virtual int stepSimulation( btScalar timeStep,int maxSubSteps=1, btScalar fixedTimeStep=btScalar(1.)/btScalar(60.)); virtual void setGravity(const btVector3& gravity); virtual btVector3 getGravity () const; virtual void addRigidBody(btRigidBody* body); virtual void removeRigidBody(btRigidBody* body); ///removeCollisionObject will first check if it is a rigid body, if so call removeRigidBody otherwise call btCollisionWorld::removeCollisionObject virtual void removeCollisionObject(btCollisionObject* collisionObject); virtual void updateAabbs(); virtual void synchronizeMotionStates(); virtual void setConstraintSolver(btConstraintSolver* solver); virtual btConstraintSolver* getConstraintSolver(); virtual btDynamicsWorldType getWorldType() const { return BT_SIMPLE_DYNAMICS_WORLD; } virtual void clearForces(); }; #endif //BT_SIMPLE_DYNAMICS_WORLD_H critterding-beta12.1/src/utils/bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.cpp0000644000175000017500000010307511344267705030754 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btDiscreteDynamicsWorld.h" //collision detection #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h" #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" #include "BulletCollision/CollisionShapes/btCollisionShape.h" #include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h" #include "LinearMath/btTransformUtil.h" #include "LinearMath/btQuickprof.h" //rigidbody & constraints #include "BulletDynamics/Dynamics/btRigidBody.h" #include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h" #include "BulletDynamics/ConstraintSolver/btContactSolverInfo.h" #include "BulletDynamics/ConstraintSolver/btTypedConstraint.h" #include "BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h" #include "BulletDynamics/ConstraintSolver/btHingeConstraint.h" #include "BulletDynamics/ConstraintSolver/btConeTwistConstraint.h" #include "BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h" #include "BulletDynamics/ConstraintSolver/btSliderConstraint.h" #include "LinearMath/btIDebugDraw.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" #include "BulletDynamics/Dynamics/btActionInterface.h" #include "LinearMath/btQuickprof.h" #include "LinearMath/btMotionState.h" #include "LinearMath/btSerializer.h" btDiscreteDynamicsWorld::btDiscreteDynamicsWorld(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolver* constraintSolver, btCollisionConfiguration* collisionConfiguration) :btDynamicsWorld(dispatcher,pairCache,collisionConfiguration), m_constraintSolver(constraintSolver), m_gravity(0,-10,0), m_localTime(btScalar(1.)/btScalar(60.)), m_synchronizeAllMotionStates(false), m_profileTimings(0) { if (!m_constraintSolver) { void* mem = btAlignedAlloc(sizeof(btSequentialImpulseConstraintSolver),16); m_constraintSolver = new (mem) btSequentialImpulseConstraintSolver; m_ownsConstraintSolver = true; } else { m_ownsConstraintSolver = false; } { void* mem = btAlignedAlloc(sizeof(btSimulationIslandManager),16); m_islandManager = new (mem) btSimulationIslandManager(); } m_ownsIslandManager = true; } btDiscreteDynamicsWorld::~btDiscreteDynamicsWorld() { //only delete it when we created it if (m_ownsIslandManager) { m_islandManager->~btSimulationIslandManager(); btAlignedFree( m_islandManager); } if (m_ownsConstraintSolver) { m_constraintSolver->~btConstraintSolver(); btAlignedFree(m_constraintSolver); } } void btDiscreteDynamicsWorld::saveKinematicState(btScalar timeStep) { ///would like to iterate over m_nonStaticRigidBodies, but unfortunately old API allows ///to switch status _after_ adding kinematic objects to the world ///fix it for Bullet 3.x release for (int i=0;igetActivationState() != ISLAND_SLEEPING) { if (body->isKinematicObject()) { //to calculate velocities next frame body->saveKinematicState(timeStep); } } } } void btDiscreteDynamicsWorld::debugDrawWorld() { BT_PROFILE("debugDrawWorld"); btCollisionWorld::debugDrawWorld(); bool drawConstraints = false; if (getDebugDrawer()) { int mode = getDebugDrawer()->getDebugMode(); if(mode & (btIDebugDraw::DBG_DrawConstraints | btIDebugDraw::DBG_DrawConstraintLimits)) { drawConstraints = true; } } if(drawConstraints) { for(int i = getNumConstraints()-1; i>=0 ;i--) { btTypedConstraint* constraint = getConstraint(i); debugDrawConstraint(constraint); } } if (getDebugDrawer() && getDebugDrawer()->getDebugMode() & (btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawAabb)) { int i; if (getDebugDrawer() && getDebugDrawer()->getDebugMode()) { for (i=0;idebugDraw(m_debugDrawer); } } } } void btDiscreteDynamicsWorld::clearForces() { ///@todo: iterate over awake simulation islands! for ( int i=0;iclearForces(); } } ///apply gravity, call this once per timestep void btDiscreteDynamicsWorld::applyGravity() { ///@todo: iterate over awake simulation islands! for ( int i=0;iisActive()) { body->applyGravity(); } } } void btDiscreteDynamicsWorld::synchronizeSingleMotionState(btRigidBody* body) { btAssert(body); if (body->getMotionState() && !body->isStaticOrKinematicObject()) { //we need to call the update at least once, even for sleeping objects //otherwise the 'graphics' transform never updates properly ///@todo: add 'dirty' flag //if (body->getActivationState() != ISLAND_SLEEPING) { btTransform interpolatedTransform; btTransformUtil::integrateTransform(body->getInterpolationWorldTransform(), body->getInterpolationLinearVelocity(),body->getInterpolationAngularVelocity(),m_localTime*body->getHitFraction(),interpolatedTransform); body->getMotionState()->setWorldTransform(interpolatedTransform); } } } void btDiscreteDynamicsWorld::synchronizeMotionStates() { BT_PROFILE("synchronizeMotionStates"); if (m_synchronizeAllMotionStates) { //iterate over all collision objects for ( int i=0;iisActive()) synchronizeSingleMotionState(body); } } } int btDiscreteDynamicsWorld::stepSimulation( btScalar timeStep,int maxSubSteps, btScalar fixedTimeStep) { startProfiling(timeStep); BT_PROFILE("stepSimulation"); int numSimulationSubSteps = 0; if (maxSubSteps) { //fixed timestep with interpolation m_localTime += timeStep; if (m_localTime >= fixedTimeStep) { numSimulationSubSteps = int( m_localTime / fixedTimeStep); m_localTime -= numSimulationSubSteps * fixedTimeStep; } } else { //variable timestep fixedTimeStep = timeStep; m_localTime = timeStep; if (btFuzzyZero(timeStep)) { numSimulationSubSteps = 0; maxSubSteps = 0; } else { numSimulationSubSteps = 1; maxSubSteps = 1; } } //process some debugging flags if (getDebugDrawer()) { btIDebugDraw* debugDrawer = getDebugDrawer (); gDisableDeactivation = (debugDrawer->getDebugMode() & btIDebugDraw::DBG_NoDeactivation) != 0; } if (numSimulationSubSteps) { //clamp the number of substeps, to prevent simulation grinding spiralling down to a halt int clampedSimulationSteps = (numSimulationSubSteps > maxSubSteps)? maxSubSteps : numSimulationSubSteps; saveKinematicState(fixedTimeStep*clampedSimulationSteps); applyGravity(); for (int i=0;iisActive() && !(body->getFlags() &BT_DISABLE_WORLD_GRAVITY)) { body->setGravity(gravity); } } } btVector3 btDiscreteDynamicsWorld::getGravity () const { return m_gravity; } void btDiscreteDynamicsWorld::addCollisionObject(btCollisionObject* collisionObject,short int collisionFilterGroup,short int collisionFilterMask) { btCollisionWorld::addCollisionObject(collisionObject,collisionFilterGroup,collisionFilterMask); } void btDiscreteDynamicsWorld::removeCollisionObject(btCollisionObject* collisionObject) { btRigidBody* body = btRigidBody::upcast(collisionObject); if (body) removeRigidBody(body); else btCollisionWorld::removeCollisionObject(collisionObject); } void btDiscreteDynamicsWorld::removeRigidBody(btRigidBody* body) { m_nonStaticRigidBodies.remove(body); btCollisionWorld::removeCollisionObject(body); } void btDiscreteDynamicsWorld::addRigidBody(btRigidBody* body) { if (!body->isStaticOrKinematicObject() && !(body->getFlags() &BT_DISABLE_WORLD_GRAVITY)) { body->setGravity(m_gravity); } if (body->getCollisionShape()) { if (!body->isStaticObject()) { m_nonStaticRigidBodies.push_back(body); } else { body->setActivationState(ISLAND_SLEEPING); } bool isDynamic = !(body->isStaticObject() || body->isKinematicObject()); short collisionFilterGroup = isDynamic? short(btBroadphaseProxy::DefaultFilter) : short(btBroadphaseProxy::StaticFilter); short collisionFilterMask = isDynamic? short(btBroadphaseProxy::AllFilter) : short(btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::StaticFilter); addCollisionObject(body,collisionFilterGroup,collisionFilterMask); } } void btDiscreteDynamicsWorld::addRigidBody(btRigidBody* body, short group, short mask) { if (!body->isStaticOrKinematicObject() && !(body->getFlags() &BT_DISABLE_WORLD_GRAVITY)) { body->setGravity(m_gravity); } if (body->getCollisionShape()) { if (!body->isStaticObject()) { m_nonStaticRigidBodies.push_back(body); } else { body->setActivationState(ISLAND_SLEEPING); } addCollisionObject(body,group,mask); } } void btDiscreteDynamicsWorld::updateActions(btScalar timeStep) { BT_PROFILE("updateActions"); for ( int i=0;iupdateAction( this, timeStep); } } void btDiscreteDynamicsWorld::updateActivationState(btScalar timeStep) { BT_PROFILE("updateActivationState"); for ( int i=0;iupdateDeactivation(timeStep); if (body->wantsSleeping()) { if (body->isStaticOrKinematicObject()) { body->setActivationState(ISLAND_SLEEPING); } else { if (body->getActivationState() == ACTIVE_TAG) body->setActivationState( WANTS_DEACTIVATION ); if (body->getActivationState() == ISLAND_SLEEPING) { body->setAngularVelocity(btVector3(0,0,0)); body->setLinearVelocity(btVector3(0,0,0)); } } } else { if (body->getActivationState() != DISABLE_DEACTIVATION) body->setActivationState( ACTIVE_TAG ); } } } } void btDiscreteDynamicsWorld::addConstraint(btTypedConstraint* constraint,bool disableCollisionsBetweenLinkedBodies) { m_constraints.push_back(constraint); if (disableCollisionsBetweenLinkedBodies) { constraint->getRigidBodyA().addConstraintRef(constraint); constraint->getRigidBodyB().addConstraintRef(constraint); } } void btDiscreteDynamicsWorld::removeConstraint(btTypedConstraint* constraint) { m_constraints.remove(constraint); constraint->getRigidBodyA().removeConstraintRef(constraint); constraint->getRigidBodyB().removeConstraintRef(constraint); } void btDiscreteDynamicsWorld::addAction(btActionInterface* action) { m_actions.push_back(action); } void btDiscreteDynamicsWorld::removeAction(btActionInterface* action) { m_actions.remove(action); } void btDiscreteDynamicsWorld::addVehicle(btActionInterface* vehicle) { addAction(vehicle); } void btDiscreteDynamicsWorld::removeVehicle(btActionInterface* vehicle) { removeAction(vehicle); } void btDiscreteDynamicsWorld::addCharacter(btActionInterface* character) { addAction(character); } void btDiscreteDynamicsWorld::removeCharacter(btActionInterface* character) { removeAction(character); } SIMD_FORCE_INLINE int btGetConstraintIslandId(const btTypedConstraint* lhs) { int islandId; const btCollisionObject& rcolObj0 = lhs->getRigidBodyA(); const btCollisionObject& rcolObj1 = lhs->getRigidBodyB(); islandId= rcolObj0.getIslandTag()>=0?rcolObj0.getIslandTag():rcolObj1.getIslandTag(); return islandId; } class btSortConstraintOnIslandPredicate { public: bool operator() ( const btTypedConstraint* lhs, const btTypedConstraint* rhs ) { int rIslandId0,lIslandId0; rIslandId0 = btGetConstraintIslandId(rhs); lIslandId0 = btGetConstraintIslandId(lhs); return lIslandId0 < rIslandId0; } }; void btDiscreteDynamicsWorld::solveConstraints(btContactSolverInfo& solverInfo) { BT_PROFILE("solveConstraints"); struct InplaceSolverIslandCallback : public btSimulationIslandManager::IslandCallback { btContactSolverInfo& m_solverInfo; btConstraintSolver* m_solver; btTypedConstraint** m_sortedConstraints; int m_numConstraints; btIDebugDraw* m_debugDrawer; btStackAlloc* m_stackAlloc; btDispatcher* m_dispatcher; btAlignedObjectArray m_bodies; btAlignedObjectArray m_manifolds; btAlignedObjectArray m_constraints; InplaceSolverIslandCallback( btContactSolverInfo& solverInfo, btConstraintSolver* solver, btTypedConstraint** sortedConstraints, int numConstraints, btIDebugDraw* debugDrawer, btStackAlloc* stackAlloc, btDispatcher* dispatcher) :m_solverInfo(solverInfo), m_solver(solver), m_sortedConstraints(sortedConstraints), m_numConstraints(numConstraints), m_debugDrawer(debugDrawer), m_stackAlloc(stackAlloc), m_dispatcher(dispatcher) { } InplaceSolverIslandCallback& operator=(InplaceSolverIslandCallback& other) { btAssert(0); (void)other; return *this; } virtual void ProcessIsland(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifolds,int numManifolds, int islandId) { if (islandId<0) { if (numManifolds + m_numConstraints) { ///we don't split islands, so all constraints/contact manifolds/bodies are passed into the solver regardless the island id m_solver->solveGroup( bodies,numBodies,manifolds, numManifolds,&m_sortedConstraints[0],m_numConstraints,m_solverInfo,m_debugDrawer,m_stackAlloc,m_dispatcher); } } else { //also add all non-contact constraints/joints for this island btTypedConstraint** startConstraint = 0; int numCurConstraints = 0; int i; //find the first constraint for this island for (i=0;isolveGroup( bodies,numBodies,manifolds, numManifolds,startConstraint,numCurConstraints,m_solverInfo,m_debugDrawer,m_stackAlloc,m_dispatcher); } } else { for (i=0;im_solverInfo.m_minimumSolverBatchSize) { processConstraints(); } else { //printf("deferred\n"); } } } } void processConstraints() { if (m_manifolds.size() + m_constraints.size()>0) { m_solver->solveGroup( &m_bodies[0],m_bodies.size(), &m_manifolds[0], m_manifolds.size(), &m_constraints[0], m_constraints.size() ,m_solverInfo,m_debugDrawer,m_stackAlloc,m_dispatcher); } m_bodies.resize(0); m_manifolds.resize(0); m_constraints.resize(0); } }; //sorted version of all btTypedConstraint, based on islandId btAlignedObjectArray sortedConstraints; sortedConstraints.resize( m_constraints.size()); int i; for (i=0;iprepareSolve(getCollisionWorld()->getNumCollisionObjects(), getCollisionWorld()->getDispatcher()->getNumManifolds()); /// solve all the constraints for this island m_islandManager->buildAndProcessIslands(getCollisionWorld()->getDispatcher(),getCollisionWorld(),&solverCallback); solverCallback.processConstraints(); m_constraintSolver->allSolved(solverInfo, m_debugDrawer, m_stackAlloc); } void btDiscreteDynamicsWorld::calculateSimulationIslands() { BT_PROFILE("calculateSimulationIslands"); getSimulationIslandManager()->updateActivationState(getCollisionWorld(),getCollisionWorld()->getDispatcher()); { int i; int numConstraints = int(m_constraints.size()); for (i=0;i< numConstraints ; i++ ) { btTypedConstraint* constraint = m_constraints[i]; const btRigidBody* colObj0 = &constraint->getRigidBodyA(); const btRigidBody* colObj1 = &constraint->getRigidBodyB(); if (((colObj0) && (!(colObj0)->isStaticOrKinematicObject())) && ((colObj1) && (!(colObj1)->isStaticOrKinematicObject()))) { if (colObj0->isActive() || colObj1->isActive()) { getSimulationIslandManager()->getUnionFind().unite((colObj0)->getIslandTag(), (colObj1)->getIslandTag()); } } } } //Store the island id in each body getSimulationIslandManager()->storeIslandActivationState(getCollisionWorld()); } class btClosestNotMeConvexResultCallback : public btCollisionWorld::ClosestConvexResultCallback { btCollisionObject* m_me; btScalar m_allowedPenetration; btOverlappingPairCache* m_pairCache; btDispatcher* m_dispatcher; public: btClosestNotMeConvexResultCallback (btCollisionObject* me,const btVector3& fromA,const btVector3& toA,btOverlappingPairCache* pairCache,btDispatcher* dispatcher) : btCollisionWorld::ClosestConvexResultCallback(fromA,toA), m_me(me), m_allowedPenetration(0.0f), m_pairCache(pairCache), m_dispatcher(dispatcher) { } virtual btScalar addSingleResult(btCollisionWorld::LocalConvexResult& convexResult,bool normalInWorldSpace) { if (convexResult.m_hitCollisionObject == m_me) return 1.0f; //ignore result if there is no contact response if(!convexResult.m_hitCollisionObject->hasContactResponse()) return 1.0f; btVector3 linVelA,linVelB; linVelA = m_convexToWorld-m_convexFromWorld; linVelB = btVector3(0,0,0);//toB.getOrigin()-fromB.getOrigin(); btVector3 relativeVelocity = (linVelA-linVelB); //don't report time of impact for motion away from the contact normal (or causes minor penetration) if (convexResult.m_hitNormalLocal.dot(relativeVelocity)>=-m_allowedPenetration) return 1.f; return ClosestConvexResultCallback::addSingleResult (convexResult, normalInWorldSpace); } virtual bool needsCollision(btBroadphaseProxy* proxy0) const { //don't collide with itself if (proxy0->m_clientObject == m_me) return false; ///don't do CCD when the collision filters are not matching if (!ClosestConvexResultCallback::needsCollision(proxy0)) return false; btCollisionObject* otherObj = (btCollisionObject*) proxy0->m_clientObject; //call needsResponse, see http://code.google.com/p/bullet/issues/detail?id=179 if (m_dispatcher->needsResponse(m_me,otherObj)) { ///don't do CCD when there are already contact points (touching contact/penetration) btAlignedObjectArray manifoldArray; btBroadphasePair* collisionPair = m_pairCache->findPair(m_me->getBroadphaseHandle(),proxy0); if (collisionPair) { if (collisionPair->m_algorithm) { manifoldArray.resize(0); collisionPair->m_algorithm->getAllContactManifolds(manifoldArray); for (int j=0;jgetNumContacts()>0) return false; } } } } return true; } }; ///internal debugging variable. this value shouldn't be too high int gNumClampedCcdMotions=0; //#include "stdio.h" void btDiscreteDynamicsWorld::integrateTransforms(btScalar timeStep) { BT_PROFILE("integrateTransforms"); btTransform predictedTrans; for ( int i=0;isetHitFraction(1.f); if (body->isActive() && (!body->isStaticOrKinematicObject())) { body->predictIntegratedTransform(timeStep, predictedTrans); btScalar squareMotion = (predictedTrans.getOrigin()-body->getWorldTransform().getOrigin()).length2(); if (body->getCcdSquareMotionThreshold() && body->getCcdSquareMotionThreshold() < squareMotion) { BT_PROFILE("CCD motion clamping"); if (body->getCollisionShape()->isConvex()) { gNumClampedCcdMotions++; btClosestNotMeConvexResultCallback sweepResults(body,body->getWorldTransform().getOrigin(),predictedTrans.getOrigin(),getBroadphase()->getOverlappingPairCache(),getDispatcher()); //btConvexShape* convexShape = static_cast(body->getCollisionShape()); btSphereShape tmpSphere(body->getCcdSweptSphereRadius());//btConvexShape* convexShape = static_cast(body->getCollisionShape()); sweepResults.m_collisionFilterGroup = body->getBroadphaseProxy()->m_collisionFilterGroup; sweepResults.m_collisionFilterMask = body->getBroadphaseProxy()->m_collisionFilterMask; convexSweepTest(&tmpSphere,body->getWorldTransform(),predictedTrans,sweepResults); if (sweepResults.hasHit() && (sweepResults.m_closestHitFraction < 1.f)) { body->setHitFraction(sweepResults.m_closestHitFraction); body->predictIntegratedTransform(timeStep*body->getHitFraction(), predictedTrans); body->setHitFraction(0.f); // printf("clamped integration to hit fraction = %f\n",fraction); } } } body->proceedToTransform( predictedTrans); } } } void btDiscreteDynamicsWorld::predictUnconstraintMotion(btScalar timeStep) { BT_PROFILE("predictUnconstraintMotion"); for ( int i=0;iisStaticOrKinematicObject()) { body->integrateVelocities( timeStep); //damping body->applyDamping(timeStep); body->predictIntegratedTransform(timeStep,body->getInterpolationWorldTransform()); } } } void btDiscreteDynamicsWorld::startProfiling(btScalar timeStep) { (void)timeStep; #ifndef BT_NO_PROFILE CProfileManager::Reset(); #endif //BT_NO_PROFILE } void btDiscreteDynamicsWorld::debugDrawConstraint(btTypedConstraint* constraint) { bool drawFrames = (getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawConstraints) != 0; bool drawLimits = (getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawConstraintLimits) != 0; btScalar dbgDrawSize = constraint->getDbgDrawSize(); if(dbgDrawSize <= btScalar(0.f)) { return; } switch(constraint->getConstraintType()) { case POINT2POINT_CONSTRAINT_TYPE: { btPoint2PointConstraint* p2pC = (btPoint2PointConstraint*)constraint; btTransform tr; tr.setIdentity(); btVector3 pivot = p2pC->getPivotInA(); pivot = p2pC->getRigidBodyA().getCenterOfMassTransform() * pivot; tr.setOrigin(pivot); getDebugDrawer()->drawTransform(tr, dbgDrawSize); // that ideally should draw the same frame pivot = p2pC->getPivotInB(); pivot = p2pC->getRigidBodyB().getCenterOfMassTransform() * pivot; tr.setOrigin(pivot); if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize); } break; case HINGE_CONSTRAINT_TYPE: { btHingeConstraint* pHinge = (btHingeConstraint*)constraint; btTransform tr = pHinge->getRigidBodyA().getCenterOfMassTransform() * pHinge->getAFrame(); if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize); tr = pHinge->getRigidBodyB().getCenterOfMassTransform() * pHinge->getBFrame(); if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize); btScalar minAng = pHinge->getLowerLimit(); btScalar maxAng = pHinge->getUpperLimit(); if(minAng == maxAng) { break; } bool drawSect = true; if(minAng > maxAng) { minAng = btScalar(0.f); maxAng = SIMD_2_PI; drawSect = false; } if(drawLimits) { btVector3& center = tr.getOrigin(); btVector3 normal = tr.getBasis().getColumn(2); btVector3 axis = tr.getBasis().getColumn(0); getDebugDrawer()->drawArc(center, normal, axis, dbgDrawSize, dbgDrawSize, minAng, maxAng, btVector3(0,0,0), drawSect); } } break; case CONETWIST_CONSTRAINT_TYPE: { btConeTwistConstraint* pCT = (btConeTwistConstraint*)constraint; btTransform tr = pCT->getRigidBodyA().getCenterOfMassTransform() * pCT->getAFrame(); if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize); tr = pCT->getRigidBodyB().getCenterOfMassTransform() * pCT->getBFrame(); if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize); if(drawLimits) { //const btScalar length = btScalar(5); const btScalar length = dbgDrawSize; static int nSegments = 8*4; btScalar fAngleInRadians = btScalar(2.*3.1415926) * (btScalar)(nSegments-1)/btScalar(nSegments); btVector3 pPrev = pCT->GetPointForAngle(fAngleInRadians, length); pPrev = tr * pPrev; for (int i=0; iGetPointForAngle(fAngleInRadians, length); pCur = tr * pCur; getDebugDrawer()->drawLine(pPrev, pCur, btVector3(0,0,0)); if (i%(nSegments/8) == 0) getDebugDrawer()->drawLine(tr.getOrigin(), pCur, btVector3(0,0,0)); pPrev = pCur; } btScalar tws = pCT->getTwistSpan(); btScalar twa = pCT->getTwistAngle(); bool useFrameB = (pCT->getRigidBodyB().getInvMass() > btScalar(0.f)); if(useFrameB) { tr = pCT->getRigidBodyB().getCenterOfMassTransform() * pCT->getBFrame(); } else { tr = pCT->getRigidBodyA().getCenterOfMassTransform() * pCT->getAFrame(); } btVector3 pivot = tr.getOrigin(); btVector3 normal = tr.getBasis().getColumn(0); btVector3 axis1 = tr.getBasis().getColumn(1); getDebugDrawer()->drawArc(pivot, normal, axis1, dbgDrawSize, dbgDrawSize, -twa-tws, -twa+tws, btVector3(0,0,0), true); } } break; case D6_CONSTRAINT_TYPE: { btGeneric6DofConstraint* p6DOF = (btGeneric6DofConstraint*)constraint; btTransform tr = p6DOF->getCalculatedTransformA(); if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize); tr = p6DOF->getCalculatedTransformB(); if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize); if(drawLimits) { tr = p6DOF->getCalculatedTransformA(); const btVector3& center = p6DOF->getCalculatedTransformB().getOrigin(); btVector3 up = tr.getBasis().getColumn(2); btVector3 axis = tr.getBasis().getColumn(0); btScalar minTh = p6DOF->getRotationalLimitMotor(1)->m_loLimit; btScalar maxTh = p6DOF->getRotationalLimitMotor(1)->m_hiLimit; btScalar minPs = p6DOF->getRotationalLimitMotor(2)->m_loLimit; btScalar maxPs = p6DOF->getRotationalLimitMotor(2)->m_hiLimit; getDebugDrawer()->drawSpherePatch(center, up, axis, dbgDrawSize * btScalar(.9f), minTh, maxTh, minPs, maxPs, btVector3(0,0,0)); axis = tr.getBasis().getColumn(1); btScalar ay = p6DOF->getAngle(1); btScalar az = p6DOF->getAngle(2); btScalar cy = btCos(ay); btScalar sy = btSin(ay); btScalar cz = btCos(az); btScalar sz = btSin(az); btVector3 ref; ref[0] = cy*cz*axis[0] + cy*sz*axis[1] - sy*axis[2]; ref[1] = -sz*axis[0] + cz*axis[1]; ref[2] = cz*sy*axis[0] + sz*sy*axis[1] + cy*axis[2]; tr = p6DOF->getCalculatedTransformB(); btVector3 normal = -tr.getBasis().getColumn(0); btScalar minFi = p6DOF->getRotationalLimitMotor(0)->m_loLimit; btScalar maxFi = p6DOF->getRotationalLimitMotor(0)->m_hiLimit; if(minFi > maxFi) { getDebugDrawer()->drawArc(center, normal, ref, dbgDrawSize, dbgDrawSize, -SIMD_PI, SIMD_PI, btVector3(0,0,0), false); } else if(minFi < maxFi) { getDebugDrawer()->drawArc(center, normal, ref, dbgDrawSize, dbgDrawSize, minFi, maxFi, btVector3(0,0,0), true); } tr = p6DOF->getCalculatedTransformA(); btVector3 bbMin = p6DOF->getTranslationalLimitMotor()->m_lowerLimit; btVector3 bbMax = p6DOF->getTranslationalLimitMotor()->m_upperLimit; getDebugDrawer()->drawBox(bbMin, bbMax, tr, btVector3(0,0,0)); } } break; case SLIDER_CONSTRAINT_TYPE: { btSliderConstraint* pSlider = (btSliderConstraint*)constraint; btTransform tr = pSlider->getCalculatedTransformA(); if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize); tr = pSlider->getCalculatedTransformB(); if(drawFrames) getDebugDrawer()->drawTransform(tr, dbgDrawSize); if(drawLimits) { btTransform tr = pSlider->getUseLinearReferenceFrameA() ? pSlider->getCalculatedTransformA() : pSlider->getCalculatedTransformB(); btVector3 li_min = tr * btVector3(pSlider->getLowerLinLimit(), 0.f, 0.f); btVector3 li_max = tr * btVector3(pSlider->getUpperLinLimit(), 0.f, 0.f); getDebugDrawer()->drawLine(li_min, li_max, btVector3(0, 0, 0)); btVector3 normal = tr.getBasis().getColumn(0); btVector3 axis = tr.getBasis().getColumn(1); btScalar a_min = pSlider->getLowerAngLimit(); btScalar a_max = pSlider->getUpperAngLimit(); const btVector3& center = pSlider->getCalculatedTransformB().getOrigin(); getDebugDrawer()->drawArc(center, normal, axis, dbgDrawSize, dbgDrawSize, a_min, a_max, btVector3(0,0,0), true); } } break; default : break; } return; } void btDiscreteDynamicsWorld::setConstraintSolver(btConstraintSolver* solver) { if (m_ownsConstraintSolver) { btAlignedFree( m_constraintSolver); } m_ownsConstraintSolver = false; m_constraintSolver = solver; } btConstraintSolver* btDiscreteDynamicsWorld::getConstraintSolver() { return m_constraintSolver; } int btDiscreteDynamicsWorld::getNumConstraints() const { return int(m_constraints.size()); } btTypedConstraint* btDiscreteDynamicsWorld::getConstraint(int index) { return m_constraints[index]; } const btTypedConstraint* btDiscreteDynamicsWorld::getConstraint(int index) const { return m_constraints[index]; } void btDiscreteDynamicsWorld::serializeRigidBodies(btSerializer* serializer) { int i; //serialize all collision objects for (i=0;igetInternalType() == btCollisionObject::CO_RIGID_BODY) { int len = colObj->calculateSerializeBufferSize(); btChunk* chunk = serializer->allocate(len,1); const char* structType = colObj->serialize(chunk->m_oldPtr, serializer); serializer->finalizeChunk(chunk,structType,BT_RIGIDBODY_CODE,colObj); } } for (i=0;icalculateSerializeBufferSize(); btChunk* chunk = serializer->allocate(size,1); const char* structType = constraint->serialize(chunk->m_oldPtr,serializer); serializer->finalizeChunk(chunk,structType,BT_CONSTRAINT_CODE,constraint); } } void btDiscreteDynamicsWorld::serialize(btSerializer* serializer) { serializer->startSerialization(); serializeRigidBodies(serializer); serializeCollisionObjects(serializer); serializer->finishSerialization(); } critterding-beta12.1/src/utils/bullet/BulletDynamics/Dynamics/btRigidBody.h0000644000175000017500000004612211344267705026032 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 RIGIDBODY_H #define RIGIDBODY_H #include "LinearMath/btAlignedObjectArray.h" #include "LinearMath/btTransform.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" class btCollisionShape; class btMotionState; class btTypedConstraint; extern btScalar gDeactivationTime; extern bool gDisableDeactivation; #ifdef BT_USE_DOUBLE_PRECISION #define btRigidBodyData btRigidBodyDoubleData #define btRigidBodyDataName "btRigidBodyDoubleData" #else #define btRigidBodyData btRigidBodyFloatData #define btRigidBodyDataName "btRigidBodyFloatData" #endif //BT_USE_DOUBLE_PRECISION enum btRigidBodyFlags { BT_DISABLE_WORLD_GRAVITY = 1 }; ///The btRigidBody is the main class for rigid body objects. It is derived from btCollisionObject, so it keeps a pointer to a btCollisionShape. ///It is recommended for performance and memory use to share btCollisionShape objects whenever possible. ///There are 3 types of rigid bodies: ///- A) Dynamic rigid bodies, with positive mass. Motion is controlled by rigid body dynamics. ///- B) Fixed objects with zero mass. They are not moving (basically collision objects) ///- C) Kinematic objects, which are objects without mass, but the user can move them. There is on-way interaction, and Bullet calculates a velocity based on the timestep and previous and current world transform. ///Bullet automatically deactivates dynamic rigid bodies, when the velocity is below a threshold for a given time. ///Deactivated (sleeping) rigid bodies don't take any processing time, except a minor broadphase collision detection impact (to allow active objects to activate/wake up sleeping objects) class btRigidBody : public btCollisionObject { btMatrix3x3 m_invInertiaTensorWorld; btVector3 m_linearVelocity; btVector3 m_angularVelocity; btScalar m_inverseMass; btVector3 m_linearFactor; btVector3 m_gravity; btVector3 m_gravity_acceleration; btVector3 m_invInertiaLocal; btVector3 m_totalForce; btVector3 m_totalTorque; btScalar m_linearDamping; btScalar m_angularDamping; bool m_additionalDamping; btScalar m_additionalDampingFactor; btScalar m_additionalLinearDampingThresholdSqr; btScalar m_additionalAngularDampingThresholdSqr; btScalar m_additionalAngularDampingFactor; btScalar m_linearSleepingThreshold; btScalar m_angularSleepingThreshold; //m_optionalMotionState allows to automatic synchronize the world transform for active objects btMotionState* m_optionalMotionState; //keep track of typed constraints referencing this rigid body btAlignedObjectArray m_constraintRefs; int m_rigidbodyFlags; int m_debugBodyId; protected: ATTRIBUTE_ALIGNED64(btVector3 m_deltaLinearVelocity); btVector3 m_deltaAngularVelocity; btVector3 m_angularFactor; btVector3 m_invMass; btVector3 m_pushVelocity; btVector3 m_turnVelocity; public: ///The btRigidBodyConstructionInfo structure provides information to create a rigid body. Setting mass to zero creates a fixed (non-dynamic) rigid body. ///For dynamic objects, you can use the collision shape to approximate the local inertia tensor, otherwise use the zero vector (default argument) ///You can use the motion state to synchronize the world transform between physics and graphics objects. ///And if the motion state is provided, the rigid body will initialize its initial world transform from the motion state, ///m_startWorldTransform is only used when you don't provide a motion state. struct btRigidBodyConstructionInfo { btScalar m_mass; ///When a motionState is provided, the rigid body will initialize its world transform from the motion state ///In this case, m_startWorldTransform is ignored. btMotionState* m_motionState; btTransform m_startWorldTransform; btCollisionShape* m_collisionShape; btVector3 m_localInertia; btScalar m_linearDamping; btScalar m_angularDamping; ///best simulation results when friction is non-zero btScalar m_friction; ///best simulation results using zero restitution. btScalar m_restitution; btScalar m_linearSleepingThreshold; btScalar m_angularSleepingThreshold; //Additional damping can help avoiding lowpass jitter motion, help stability for ragdolls etc. //Such damping is undesirable, so once the overall simulation quality of the rigid body dynamics system has improved, this should become obsolete bool m_additionalDamping; btScalar m_additionalDampingFactor; btScalar m_additionalLinearDampingThresholdSqr; btScalar m_additionalAngularDampingThresholdSqr; btScalar m_additionalAngularDampingFactor; btRigidBodyConstructionInfo( btScalar mass, btMotionState* motionState, btCollisionShape* collisionShape, const btVector3& localInertia=btVector3(0,0,0)): m_mass(mass), m_motionState(motionState), m_collisionShape(collisionShape), m_localInertia(localInertia), m_linearDamping(btScalar(0.)), m_angularDamping(btScalar(0.)), m_friction(btScalar(0.5)), m_restitution(btScalar(0.)), m_linearSleepingThreshold(btScalar(0.8)), m_angularSleepingThreshold(btScalar(1.f)), m_additionalDamping(false), m_additionalDampingFactor(btScalar(0.005)), m_additionalLinearDampingThresholdSqr(btScalar(0.01)), m_additionalAngularDampingThresholdSqr(btScalar(0.01)), m_additionalAngularDampingFactor(btScalar(0.01)) { m_startWorldTransform.setIdentity(); } }; ///btRigidBody constructor using construction info btRigidBody( const btRigidBodyConstructionInfo& constructionInfo); ///btRigidBody constructor for backwards compatibility. ///To specify friction (etc) during rigid body construction, please use the other constructor (using btRigidBodyConstructionInfo) btRigidBody( btScalar mass, btMotionState* motionState, btCollisionShape* collisionShape, const btVector3& localInertia=btVector3(0,0,0)); virtual ~btRigidBody() { //No constraints should point to this rigidbody //Remove constraints from the dynamics world before you delete the related rigidbodies. btAssert(m_constraintRefs.size()==0); } protected: ///setupRigidBody is only used internally by the constructor void setupRigidBody(const btRigidBodyConstructionInfo& constructionInfo); public: void proceedToTransform(const btTransform& newTrans); ///to keep collision detection and dynamics separate we don't store a rigidbody pointer ///but a rigidbody is derived from btCollisionObject, so we can safely perform an upcast static const btRigidBody* upcast(const btCollisionObject* colObj) { if (colObj->getInternalType()==btCollisionObject::CO_RIGID_BODY) return (const btRigidBody*)colObj; return 0; } static btRigidBody* upcast(btCollisionObject* colObj) { if (colObj->getInternalType()==btCollisionObject::CO_RIGID_BODY) return (btRigidBody*)colObj; return 0; } /// continuous collision detection needs prediction void predictIntegratedTransform(btScalar step, btTransform& predictedTransform) ; void saveKinematicState(btScalar step); void applyGravity(); void setGravity(const btVector3& acceleration); const btVector3& getGravity() const { return m_gravity_acceleration; } void setDamping(btScalar lin_damping, btScalar ang_damping); btScalar getLinearDamping() const { return m_linearDamping; } btScalar getAngularDamping() const { return m_angularDamping; } btScalar getLinearSleepingThreshold() const { return m_linearSleepingThreshold; } btScalar getAngularSleepingThreshold() const { return m_angularSleepingThreshold; } void applyDamping(btScalar timeStep); SIMD_FORCE_INLINE const btCollisionShape* getCollisionShape() const { return m_collisionShape; } SIMD_FORCE_INLINE btCollisionShape* getCollisionShape() { return m_collisionShape; } void setMassProps(btScalar mass, const btVector3& inertia); const btVector3& getLinearFactor() const { return m_linearFactor; } void setLinearFactor(const btVector3& linearFactor) { m_linearFactor = linearFactor; m_invMass = m_linearFactor*m_inverseMass; } btScalar getInvMass() const { return m_inverseMass; } const btMatrix3x3& getInvInertiaTensorWorld() const { return m_invInertiaTensorWorld; } void integrateVelocities(btScalar step); void setCenterOfMassTransform(const btTransform& xform); void applyCentralForce(const btVector3& force) { m_totalForce += force*m_linearFactor; } const btVector3& getTotalForce() { return m_totalForce; }; const btVector3& getTotalTorque() { return m_totalTorque; }; const btVector3& getInvInertiaDiagLocal() const { return m_invInertiaLocal; }; void setInvInertiaDiagLocal(const btVector3& diagInvInertia) { m_invInertiaLocal = diagInvInertia; } void setSleepingThresholds(btScalar linear,btScalar angular) { m_linearSleepingThreshold = linear; m_angularSleepingThreshold = angular; } void applyTorque(const btVector3& torque) { m_totalTorque += torque*m_angularFactor; } void applyForce(const btVector3& force, const btVector3& rel_pos) { applyCentralForce(force); applyTorque(rel_pos.cross(force*m_linearFactor)); } void applyCentralImpulse(const btVector3& impulse) { m_linearVelocity += impulse *m_linearFactor * m_inverseMass; } void applyTorqueImpulse(const btVector3& torque) { m_angularVelocity += m_invInertiaTensorWorld * torque * m_angularFactor; } void applyImpulse(const btVector3& impulse, const btVector3& rel_pos) { if (m_inverseMass != btScalar(0.)) { applyCentralImpulse(impulse); if (m_angularFactor) { applyTorqueImpulse(rel_pos.cross(impulse*m_linearFactor)); } } } void clearForces() { m_totalForce.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0)); m_totalTorque.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0)); } void updateInertiaTensor(); const btVector3& getCenterOfMassPosition() const { return m_worldTransform.getOrigin(); } btQuaternion getOrientation() const; const btTransform& getCenterOfMassTransform() const { return m_worldTransform; } const btVector3& getLinearVelocity() const { return m_linearVelocity; } const btVector3& getAngularVelocity() const { return m_angularVelocity; } inline void setLinearVelocity(const btVector3& lin_vel) { m_linearVelocity = lin_vel; } inline void setAngularVelocity(const btVector3& ang_vel) { m_angularVelocity = ang_vel; } btVector3 getVelocityInLocalPoint(const btVector3& rel_pos) const { //we also calculate lin/ang velocity for kinematic objects return m_linearVelocity + m_angularVelocity.cross(rel_pos); //for kinematic objects, we could also use use: // return (m_worldTransform(rel_pos) - m_interpolationWorldTransform(rel_pos)) / m_kinematicTimeStep; } void translate(const btVector3& v) { m_worldTransform.getOrigin() += v; } void getAabb(btVector3& aabbMin,btVector3& aabbMax) const; SIMD_FORCE_INLINE btScalar computeImpulseDenominator(const btVector3& pos, const btVector3& normal) const { btVector3 r0 = pos - getCenterOfMassPosition(); btVector3 c0 = (r0).cross(normal); btVector3 vec = (c0 * getInvInertiaTensorWorld()).cross(r0); return m_inverseMass + normal.dot(vec); } SIMD_FORCE_INLINE btScalar computeAngularImpulseDenominator(const btVector3& axis) const { btVector3 vec = axis * getInvInertiaTensorWorld(); return axis.dot(vec); } SIMD_FORCE_INLINE void updateDeactivation(btScalar timeStep) { if ( (getActivationState() == ISLAND_SLEEPING) || (getActivationState() == DISABLE_DEACTIVATION)) return; if ((getLinearVelocity().length2() < m_linearSleepingThreshold*m_linearSleepingThreshold) && (getAngularVelocity().length2() < m_angularSleepingThreshold*m_angularSleepingThreshold)) { m_deactivationTime += timeStep; } else { m_deactivationTime=btScalar(0.); setActivationState(0); } } SIMD_FORCE_INLINE bool wantsSleeping() { if (getActivationState() == DISABLE_DEACTIVATION) return false; //disable deactivation if (gDisableDeactivation || (gDeactivationTime == btScalar(0.))) return false; if ( (getActivationState() == ISLAND_SLEEPING) || (getActivationState() == WANTS_DEACTIVATION)) return true; if (m_deactivationTime> gDeactivationTime) { return true; } return false; } const btBroadphaseProxy* getBroadphaseProxy() const { return m_broadphaseHandle; } btBroadphaseProxy* getBroadphaseProxy() { return m_broadphaseHandle; } void setNewBroadphaseProxy(btBroadphaseProxy* broadphaseProxy) { m_broadphaseHandle = broadphaseProxy; } //btMotionState allows to automatic synchronize the world transform for active objects btMotionState* getMotionState() { return m_optionalMotionState; } const btMotionState* getMotionState() const { return m_optionalMotionState; } void setMotionState(btMotionState* motionState) { m_optionalMotionState = motionState; if (m_optionalMotionState) motionState->getWorldTransform(m_worldTransform); } //for experimental overriding of friction/contact solver func int m_contactSolverType; int m_frictionSolverType; void setAngularFactor(const btVector3& angFac) { m_angularFactor = angFac; } void setAngularFactor(btScalar angFac) { m_angularFactor.setValue(angFac,angFac,angFac); } const btVector3& getAngularFactor() const { return m_angularFactor; } //is this rigidbody added to a btCollisionWorld/btDynamicsWorld/btBroadphase? bool isInWorld() const { return (getBroadphaseProxy() != 0); } virtual bool checkCollideWithOverride(btCollisionObject* co); void addConstraintRef(btTypedConstraint* c); void removeConstraintRef(btTypedConstraint* c); btTypedConstraint* getConstraintRef(int index) { return m_constraintRefs[index]; } int getNumConstraintRefs() { return m_constraintRefs.size(); } void setFlags(int flags) { m_rigidbodyFlags = flags; } int getFlags() const { return m_rigidbodyFlags; } //////////////////////////////////////////////// ///some internal methods, don't use them btVector3& internalGetDeltaLinearVelocity() { return m_deltaLinearVelocity; } btVector3& internalGetDeltaAngularVelocity() { return m_deltaAngularVelocity; } const btVector3& internalGetAngularFactor() const { return m_angularFactor; } const btVector3& internalGetInvMass() const { return m_invMass; } btVector3& internalGetPushVelocity() { return m_pushVelocity; } btVector3& internalGetTurnVelocity() { return m_turnVelocity; } SIMD_FORCE_INLINE void internalGetVelocityInLocalPointObsolete(const btVector3& rel_pos, btVector3& velocity ) const { velocity = getLinearVelocity()+m_deltaLinearVelocity + (getAngularVelocity()+m_deltaAngularVelocity).cross(rel_pos); } SIMD_FORCE_INLINE void internalGetAngularVelocity(btVector3& angVel) const { angVel = getAngularVelocity()+m_deltaAngularVelocity; } //Optimization for the iterative solver: avoid calculating constant terms involving inertia, normal, relative position SIMD_FORCE_INLINE void internalApplyImpulse(const btVector3& linearComponent, const btVector3& angularComponent,const btScalar impulseMagnitude) { if (m_inverseMass) { m_deltaLinearVelocity += linearComponent*impulseMagnitude; m_deltaAngularVelocity += angularComponent*(impulseMagnitude*m_angularFactor); } } SIMD_FORCE_INLINE void internalApplyPushImpulse(const btVector3& linearComponent, const btVector3& angularComponent,btScalar impulseMagnitude) { if (m_inverseMass) { m_pushVelocity += linearComponent*impulseMagnitude; m_turnVelocity += angularComponent*(impulseMagnitude*m_angularFactor); } } void internalWritebackVelocity() { if (m_inverseMass) { setLinearVelocity(getLinearVelocity()+ m_deltaLinearVelocity); setAngularVelocity(getAngularVelocity()+m_deltaAngularVelocity); m_deltaLinearVelocity.setZero(); m_deltaAngularVelocity .setZero(); //m_originalBody->setCompanionId(-1); } } void internalWritebackVelocity(btScalar timeStep); /////////////////////////////////////////////// virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, class btSerializer* serializer) const; virtual void serializeSingleObject(class btSerializer* serializer) const; }; //@todo add m_optionalMotionState and m_constraintRefs to btRigidBodyData ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btRigidBodyFloatData { btCollisionObjectFloatData m_collisionObjectData; btMatrix3x3FloatData m_invInertiaTensorWorld; btVector3FloatData m_linearVelocity; btVector3FloatData m_angularVelocity; btVector3FloatData m_angularFactor; btVector3FloatData m_linearFactor; btVector3FloatData m_gravity; btVector3FloatData m_gravity_acceleration; btVector3FloatData m_invInertiaLocal; btVector3FloatData m_totalForce; btVector3FloatData m_totalTorque; float m_inverseMass; float m_linearDamping; float m_angularDamping; float m_additionalDampingFactor; float m_additionalLinearDampingThresholdSqr; float m_additionalAngularDampingThresholdSqr; float m_additionalAngularDampingFactor; float m_linearSleepingThreshold; float m_angularSleepingThreshold; int m_additionalDamping; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btRigidBodyDoubleData { btCollisionObjectDoubleData m_collisionObjectData; btMatrix3x3DoubleData m_invInertiaTensorWorld; btVector3DoubleData m_linearVelocity; btVector3DoubleData m_angularVelocity; btVector3DoubleData m_angularFactor; btVector3DoubleData m_linearFactor; btVector3DoubleData m_gravity; btVector3DoubleData m_gravity_acceleration; btVector3DoubleData m_invInertiaLocal; btVector3DoubleData m_totalForce; btVector3DoubleData m_totalTorque; double m_inverseMass; double m_linearDamping; double m_angularDamping; double m_additionalDampingFactor; double m_additionalLinearDampingThresholdSqr; double m_additionalAngularDampingThresholdSqr; double m_additionalAngularDampingFactor; double m_linearSleepingThreshold; double m_angularSleepingThreshold; int m_additionalDamping; char m_padding[4]; }; #endif critterding-beta12.1/src/utils/bullet/BulletDynamics/Dynamics/btContinuousDynamicsWorld.cpp0000644000175000017500000001373111337071441031347 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btContinuousDynamicsWorld.h" #include "LinearMath/btQuickprof.h" //collision detection #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h" #include "BulletCollision/CollisionShapes/btCollisionShape.h" #include "BulletCollision/CollisionDispatch/btSimulationIslandManager.h" //rigidbody & constraints #include "BulletDynamics/Dynamics/btRigidBody.h" #include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h" #include "BulletDynamics/ConstraintSolver/btContactSolverInfo.h" #include "BulletDynamics/ConstraintSolver/btTypedConstraint.h" #include btContinuousDynamicsWorld::btContinuousDynamicsWorld(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolver* constraintSolver,btCollisionConfiguration* collisionConfiguration) :btDiscreteDynamicsWorld(dispatcher,pairCache,constraintSolver,collisionConfiguration) { } btContinuousDynamicsWorld::~btContinuousDynamicsWorld() { } void btContinuousDynamicsWorld::internalSingleStepSimulation( btScalar timeStep) { startProfiling(timeStep); if(0 != m_internalPreTickCallback) { (*m_internalPreTickCallback)(this, timeStep); } ///update aabbs information updateAabbs(); //static int frame=0; // printf("frame %d\n",frame++); ///apply gravity, predict motion predictUnconstraintMotion(timeStep); btDispatcherInfo& dispatchInfo = getDispatchInfo(); dispatchInfo.m_timeStep = timeStep; dispatchInfo.m_stepCount = 0; dispatchInfo.m_debugDraw = getDebugDrawer(); ///perform collision detection performDiscreteCollisionDetection(); calculateSimulationIslands(); getSolverInfo().m_timeStep = timeStep; ///solve contact and other joint constraints solveConstraints(getSolverInfo()); ///CallbackTriggers(); calculateTimeOfImpacts(timeStep); btScalar toi = dispatchInfo.m_timeOfImpact; // if (toi < 1.f) // printf("toi = %f\n",toi); if (toi < 0.f) printf("toi = %f\n",toi); ///integrate transforms integrateTransforms(timeStep * toi); ///update vehicle simulation updateActions(timeStep); updateActivationState( timeStep ); if(0 != m_internalTickCallback) { (*m_internalTickCallback)(this, timeStep); } } void btContinuousDynamicsWorld::calculateTimeOfImpacts(btScalar timeStep) { ///these should be 'temporal' aabbs! updateTemporalAabbs(timeStep); ///'toi' is the global smallest time of impact. However, we just calculate the time of impact for each object individually. ///so we handle the case moving versus static properly, and we cheat for moving versus moving btScalar toi = 1.f; btDispatcherInfo& dispatchInfo = getDispatchInfo(); dispatchInfo.m_timeStep = timeStep; dispatchInfo.m_timeOfImpact = 1.f; dispatchInfo.m_stepCount = 0; dispatchInfo.m_dispatchFunc = btDispatcherInfo::DISPATCH_CONTINUOUS; ///calculate time of impact for overlapping pairs btDispatcher* dispatcher = getDispatcher(); if (dispatcher) dispatcher->dispatchAllCollisionPairs(m_broadphasePairCache->getOverlappingPairCache(),dispatchInfo,m_dispatcher1); toi = dispatchInfo.m_timeOfImpact; dispatchInfo.m_dispatchFunc = btDispatcherInfo::DISPATCH_DISCRETE; } void btContinuousDynamicsWorld::updateTemporalAabbs(btScalar timeStep) { btVector3 temporalAabbMin,temporalAabbMax; for ( int i=0;igetCollisionShape()->getAabb(m_collisionObjects[i]->getWorldTransform(),temporalAabbMin,temporalAabbMax); const btVector3& linvel = body->getLinearVelocity(); //make the AABB temporal btScalar temporalAabbMaxx = temporalAabbMax.getX(); btScalar temporalAabbMaxy = temporalAabbMax.getY(); btScalar temporalAabbMaxz = temporalAabbMax.getZ(); btScalar temporalAabbMinx = temporalAabbMin.getX(); btScalar temporalAabbMiny = temporalAabbMin.getY(); btScalar temporalAabbMinz = temporalAabbMin.getZ(); // add linear motion btVector3 linMotion = linvel*timeStep; if (linMotion.x() > 0.f) temporalAabbMaxx += linMotion.x(); else temporalAabbMinx += linMotion.x(); if (linMotion.y() > 0.f) temporalAabbMaxy += linMotion.y(); else temporalAabbMiny += linMotion.y(); if (linMotion.z() > 0.f) temporalAabbMaxz += linMotion.z(); else temporalAabbMinz += linMotion.z(); //add conservative angular motion btScalar angularMotion(0);// = angvel.length() * GetAngularMotionDisc() * timeStep; btVector3 angularMotion3d(angularMotion,angularMotion,angularMotion); temporalAabbMin = btVector3(temporalAabbMinx,temporalAabbMiny,temporalAabbMinz); temporalAabbMax = btVector3(temporalAabbMaxx,temporalAabbMaxy,temporalAabbMaxz); temporalAabbMin -= angularMotion3d; temporalAabbMax += angularMotion3d; m_broadphasePairCache->setAabb(body->getBroadphaseHandle(),temporalAabbMin,temporalAabbMax,m_dispatcher1); } } //update aabb (of all moved objects) m_broadphasePairCache->calculateOverlappingPairs(m_dispatcher1); } critterding-beta12.1/src/utils/bullet/BulletDynamics/Dynamics/btRigidBody.cpp0000644000175000017500000003137711344267705026373 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btRigidBody.h" #include "BulletCollision/CollisionShapes/btConvexShape.h" #include "LinearMath/btMinMax.h" #include "LinearMath/btTransformUtil.h" #include "LinearMath/btMotionState.h" #include "BulletDynamics/ConstraintSolver/btTypedConstraint.h" #include "LinearMath/btSerializer.h" //'temporarily' global variables btScalar gDeactivationTime = btScalar(2.); bool gDisableDeactivation = false; static int uniqueId = 0; btRigidBody::btRigidBody(const btRigidBody::btRigidBodyConstructionInfo& constructionInfo) { setupRigidBody(constructionInfo); } btRigidBody::btRigidBody(btScalar mass, btMotionState *motionState, btCollisionShape *collisionShape, const btVector3 &localInertia) { btRigidBodyConstructionInfo cinfo(mass,motionState,collisionShape,localInertia); setupRigidBody(cinfo); } void btRigidBody::setupRigidBody(const btRigidBody::btRigidBodyConstructionInfo& constructionInfo) { m_internalType=CO_RIGID_BODY; m_linearVelocity.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0)); m_angularVelocity.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); m_angularFactor.setValue(1,1,1); m_linearFactor.setValue(1,1,1); m_gravity.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0)); m_gravity_acceleration.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0)); m_totalForce.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0)); m_totalTorque.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0)), m_linearDamping = btScalar(0.); m_angularDamping = btScalar(0.5); m_linearSleepingThreshold = constructionInfo.m_linearSleepingThreshold; m_angularSleepingThreshold = constructionInfo.m_angularSleepingThreshold; m_optionalMotionState = constructionInfo.m_motionState; m_contactSolverType = 0; m_frictionSolverType = 0; m_additionalDamping = constructionInfo.m_additionalDamping; m_additionalDampingFactor = constructionInfo.m_additionalDampingFactor; m_additionalLinearDampingThresholdSqr = constructionInfo.m_additionalLinearDampingThresholdSqr; m_additionalAngularDampingThresholdSqr = constructionInfo.m_additionalAngularDampingThresholdSqr; m_additionalAngularDampingFactor = constructionInfo.m_additionalAngularDampingFactor; if (m_optionalMotionState) { m_optionalMotionState->getWorldTransform(m_worldTransform); } else { m_worldTransform = constructionInfo.m_startWorldTransform; } m_interpolationWorldTransform = m_worldTransform; m_interpolationLinearVelocity.setValue(0,0,0); m_interpolationAngularVelocity.setValue(0,0,0); //moved to btCollisionObject m_friction = constructionInfo.m_friction; m_restitution = constructionInfo.m_restitution; setCollisionShape( constructionInfo.m_collisionShape ); m_debugBodyId = uniqueId++; setMassProps(constructionInfo.m_mass, constructionInfo.m_localInertia); setDamping(constructionInfo.m_linearDamping, constructionInfo.m_angularDamping); updateInertiaTensor(); m_rigidbodyFlags = 0; m_deltaLinearVelocity.setZero(); m_deltaAngularVelocity.setZero(); m_invMass = m_inverseMass*m_linearFactor; m_pushVelocity.setZero(); m_turnVelocity.setZero(); } void btRigidBody::predictIntegratedTransform(btScalar timeStep,btTransform& predictedTransform) { btTransformUtil::integrateTransform(m_worldTransform,m_linearVelocity,m_angularVelocity,timeStep,predictedTransform); } void btRigidBody::saveKinematicState(btScalar timeStep) { //todo: clamp to some (user definable) safe minimum timestep, to limit maximum angular/linear velocities if (timeStep != btScalar(0.)) { //if we use motionstate to synchronize world transforms, get the new kinematic/animated world transform if (getMotionState()) getMotionState()->getWorldTransform(m_worldTransform); btVector3 linVel,angVel; btTransformUtil::calculateVelocity(m_interpolationWorldTransform,m_worldTransform,timeStep,m_linearVelocity,m_angularVelocity); m_interpolationLinearVelocity = m_linearVelocity; m_interpolationAngularVelocity = m_angularVelocity; m_interpolationWorldTransform = m_worldTransform; //printf("angular = %f %f %f\n",m_angularVelocity.getX(),m_angularVelocity.getY(),m_angularVelocity.getZ()); } } void btRigidBody::getAabb(btVector3& aabbMin,btVector3& aabbMax) const { getCollisionShape()->getAabb(m_worldTransform,aabbMin,aabbMax); } void btRigidBody::setGravity(const btVector3& acceleration) { if (m_inverseMass != btScalar(0.0)) { m_gravity = acceleration * (btScalar(1.0) / m_inverseMass); } m_gravity_acceleration = acceleration; } void btRigidBody::setDamping(btScalar lin_damping, btScalar ang_damping) { m_linearDamping = GEN_clamped(lin_damping, (btScalar)btScalar(0.0), (btScalar)btScalar(1.0)); m_angularDamping = GEN_clamped(ang_damping, (btScalar)btScalar(0.0), (btScalar)btScalar(1.0)); } ///applyDamping damps the velocity, using the given m_linearDamping and m_angularDamping void btRigidBody::applyDamping(btScalar timeStep) { //On new damping: see discussion/issue report here: http://code.google.com/p/bullet/issues/detail?id=74 //todo: do some performance comparisons (but other parts of the engine are probably bottleneck anyway //#define USE_OLD_DAMPING_METHOD 1 #ifdef USE_OLD_DAMPING_METHOD m_linearVelocity *= GEN_clamped((btScalar(1.) - timeStep * m_linearDamping), (btScalar)btScalar(0.0), (btScalar)btScalar(1.0)); m_angularVelocity *= GEN_clamped((btScalar(1.) - timeStep * m_angularDamping), (btScalar)btScalar(0.0), (btScalar)btScalar(1.0)); #else m_linearVelocity *= btPow(btScalar(1)-m_linearDamping, timeStep); m_angularVelocity *= btPow(btScalar(1)-m_angularDamping, timeStep); #endif if (m_additionalDamping) { //Additional damping can help avoiding lowpass jitter motion, help stability for ragdolls etc. //Such damping is undesirable, so once the overall simulation quality of the rigid body dynamics system has improved, this should become obsolete if ((m_angularVelocity.length2() < m_additionalAngularDampingThresholdSqr) && (m_linearVelocity.length2() < m_additionalLinearDampingThresholdSqr)) { m_angularVelocity *= m_additionalDampingFactor; m_linearVelocity *= m_additionalDampingFactor; } btScalar speed = m_linearVelocity.length(); if (speed < m_linearDamping) { btScalar dampVel = btScalar(0.005); if (speed > dampVel) { btVector3 dir = m_linearVelocity.normalized(); m_linearVelocity -= dir * dampVel; } else { m_linearVelocity.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); } } btScalar angSpeed = m_angularVelocity.length(); if (angSpeed < m_angularDamping) { btScalar angDampVel = btScalar(0.005); if (angSpeed > angDampVel) { btVector3 dir = m_angularVelocity.normalized(); m_angularVelocity -= dir * angDampVel; } else { m_angularVelocity.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); } } } } void btRigidBody::applyGravity() { if (isStaticOrKinematicObject()) return; applyCentralForce(m_gravity); } void btRigidBody::proceedToTransform(const btTransform& newTrans) { setCenterOfMassTransform( newTrans ); } void btRigidBody::setMassProps(btScalar mass, const btVector3& inertia) { if (mass == btScalar(0.)) { m_collisionFlags |= btCollisionObject::CF_STATIC_OBJECT; m_inverseMass = btScalar(0.); } else { m_collisionFlags &= (~btCollisionObject::CF_STATIC_OBJECT); m_inverseMass = btScalar(1.0) / mass; } m_invInertiaLocal.setValue(inertia.x() != btScalar(0.0) ? btScalar(1.0) / inertia.x(): btScalar(0.0), inertia.y() != btScalar(0.0) ? btScalar(1.0) / inertia.y(): btScalar(0.0), inertia.z() != btScalar(0.0) ? btScalar(1.0) / inertia.z(): btScalar(0.0)); m_invMass = m_linearFactor*m_inverseMass; } void btRigidBody::updateInertiaTensor() { m_invInertiaTensorWorld = m_worldTransform.getBasis().scaled(m_invInertiaLocal) * m_worldTransform.getBasis().transpose(); } void btRigidBody::integrateVelocities(btScalar step) { if (isStaticOrKinematicObject()) return; m_linearVelocity += m_totalForce * (m_inverseMass * step); m_angularVelocity += m_invInertiaTensorWorld * m_totalTorque * step; #define MAX_ANGVEL SIMD_HALF_PI /// clamp angular velocity. collision calculations will fail on higher angular velocities btScalar angvel = m_angularVelocity.length(); if (angvel*step > MAX_ANGVEL) { m_angularVelocity *= (MAX_ANGVEL/step) /angvel; } } btQuaternion btRigidBody::getOrientation() const { btQuaternion orn; m_worldTransform.getBasis().getRotation(orn); return orn; } void btRigidBody::setCenterOfMassTransform(const btTransform& xform) { if (isStaticOrKinematicObject()) { m_interpolationWorldTransform = m_worldTransform; } else { m_interpolationWorldTransform = xform; } m_interpolationLinearVelocity = getLinearVelocity(); m_interpolationAngularVelocity = getAngularVelocity(); m_worldTransform = xform; updateInertiaTensor(); } bool btRigidBody::checkCollideWithOverride(btCollisionObject* co) { btRigidBody* otherRb = btRigidBody::upcast(co); if (!otherRb) return true; for (int i = 0; i < m_constraintRefs.size(); ++i) { btTypedConstraint* c = m_constraintRefs[i]; if (&c->getRigidBodyA() == otherRb || &c->getRigidBodyB() == otherRb) return false; } return true; } void btRigidBody::internalWritebackVelocity(btScalar timeStep) { (void) timeStep; if (m_inverseMass) { setLinearVelocity(getLinearVelocity()+ m_deltaLinearVelocity); setAngularVelocity(getAngularVelocity()+m_deltaAngularVelocity); //correct the position/orientation based on push/turn recovery btTransform newTransform; btTransformUtil::integrateTransform(getWorldTransform(),m_pushVelocity,m_turnVelocity,timeStep,newTransform); setWorldTransform(newTransform); //m_originalBody->setCompanionId(-1); } m_deltaLinearVelocity.setZero(); m_deltaAngularVelocity .setZero(); m_pushVelocity.setZero(); m_turnVelocity.setZero(); } void btRigidBody::addConstraintRef(btTypedConstraint* c) { int index = m_constraintRefs.findLinearSearch(c); if (index == m_constraintRefs.size()) m_constraintRefs.push_back(c); m_checkCollideWith = true; } void btRigidBody::removeConstraintRef(btTypedConstraint* c) { m_constraintRefs.remove(c); m_checkCollideWith = m_constraintRefs.size() > 0; } int btRigidBody::calculateSerializeBufferSize() const { int sz = sizeof(btRigidBodyData); return sz; } ///fills the dataBuffer and returns the struct name (and 0 on failure) const char* btRigidBody::serialize(void* dataBuffer, class btSerializer* serializer) const { btRigidBodyData* rbd = (btRigidBodyData*) dataBuffer; btCollisionObject::serialize(&rbd->m_collisionObjectData, serializer); m_invInertiaTensorWorld.serialize(rbd->m_invInertiaTensorWorld); m_linearVelocity.serialize(rbd->m_linearVelocity); m_angularVelocity.serialize(rbd->m_angularVelocity); rbd->m_inverseMass = m_inverseMass; m_angularFactor.serialize(rbd->m_angularFactor); m_linearFactor.serialize(rbd->m_linearFactor); m_gravity.serialize(rbd->m_gravity); m_gravity_acceleration.serialize(rbd->m_gravity_acceleration); m_invInertiaLocal.serialize(rbd->m_invInertiaLocal); m_totalForce.serialize(rbd->m_totalForce); m_totalTorque.serialize(rbd->m_totalTorque); rbd->m_linearDamping = m_linearDamping; rbd->m_angularDamping = m_angularDamping; rbd->m_additionalDamping = m_additionalDamping; rbd->m_additionalDampingFactor = m_additionalDampingFactor; rbd->m_additionalLinearDampingThresholdSqr = m_additionalLinearDampingThresholdSqr; rbd->m_additionalAngularDampingThresholdSqr = m_additionalAngularDampingThresholdSqr; rbd->m_additionalAngularDampingFactor = m_additionalAngularDampingFactor; rbd->m_linearSleepingThreshold=m_linearSleepingThreshold; rbd->m_angularSleepingThreshold = m_angularSleepingThreshold; return btRigidBodyDataName; } void btRigidBody::serializeSingleObject(class btSerializer* serializer) const { btChunk* chunk = serializer->allocate(calculateSerializeBufferSize(),1); const char* structType = serialize(chunk->m_oldPtr, serializer); serializer->finalizeChunk(chunk,structType,BT_RIGIDBODY_CODE,(void*)this); } critterding-beta12.1/src/utils/bullet/BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h0000644000175000017500000001376011344267705030422 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 BT_DISCRETE_DYNAMICS_WORLD_H #define BT_DISCRETE_DYNAMICS_WORLD_H #include "btDynamicsWorld.h" class btDispatcher; class btOverlappingPairCache; class btConstraintSolver; class btSimulationIslandManager; class btTypedConstraint; class btActionInterface; class btIDebugDraw; #include "LinearMath/btAlignedObjectArray.h" ///btDiscreteDynamicsWorld provides discrete rigid body simulation ///those classes replace the obsolete CcdPhysicsEnvironment/CcdPhysicsController class btDiscreteDynamicsWorld : public btDynamicsWorld { protected: btConstraintSolver* m_constraintSolver; btSimulationIslandManager* m_islandManager; btAlignedObjectArray m_constraints; btAlignedObjectArray m_nonStaticRigidBodies; btVector3 m_gravity; //for variable timesteps btScalar m_localTime; //for variable timesteps bool m_ownsIslandManager; bool m_ownsConstraintSolver; bool m_synchronizeAllMotionStates; btAlignedObjectArray m_actions; int m_profileTimings; virtual void predictUnconstraintMotion(btScalar timeStep); virtual void integrateTransforms(btScalar timeStep); virtual void calculateSimulationIslands(); virtual void solveConstraints(btContactSolverInfo& solverInfo); void updateActivationState(btScalar timeStep); void updateActions(btScalar timeStep); void startProfiling(btScalar timeStep); virtual void internalSingleStepSimulation( btScalar timeStep); virtual void saveKinematicState(btScalar timeStep); void serializeRigidBodies(btSerializer* serializer); public: ///this btDiscreteDynamicsWorld constructor gets created objects from the user, and will not delete those btDiscreteDynamicsWorld(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolver* constraintSolver,btCollisionConfiguration* collisionConfiguration); virtual ~btDiscreteDynamicsWorld(); ///if maxSubSteps > 0, it will interpolate motion between fixedTimeStep's virtual int stepSimulation( btScalar timeStep,int maxSubSteps=1, btScalar fixedTimeStep=btScalar(1.)/btScalar(60.)); virtual void synchronizeMotionStates(); ///this can be useful to synchronize a single rigid body -> graphics object void synchronizeSingleMotionState(btRigidBody* body); virtual void addConstraint(btTypedConstraint* constraint, bool disableCollisionsBetweenLinkedBodies=false); virtual void removeConstraint(btTypedConstraint* constraint); virtual void addAction(btActionInterface*); virtual void removeAction(btActionInterface*); btSimulationIslandManager* getSimulationIslandManager() { return m_islandManager; } const btSimulationIslandManager* getSimulationIslandManager() const { return m_islandManager; } btCollisionWorld* getCollisionWorld() { return this; } virtual void setGravity(const btVector3& gravity); virtual btVector3 getGravity () const; virtual void addCollisionObject(btCollisionObject* collisionObject,short int collisionFilterGroup=btBroadphaseProxy::StaticFilter,short int collisionFilterMask=btBroadphaseProxy::AllFilter ^ btBroadphaseProxy::StaticFilter); virtual void addRigidBody(btRigidBody* body); virtual void addRigidBody(btRigidBody* body, short group, short mask); virtual void removeRigidBody(btRigidBody* body); ///removeCollisionObject will first check if it is a rigid body, if so call removeRigidBody otherwise call btCollisionWorld::removeCollisionObject virtual void removeCollisionObject(btCollisionObject* collisionObject); void debugDrawConstraint(btTypedConstraint* constraint); virtual void debugDrawWorld(); virtual void setConstraintSolver(btConstraintSolver* solver); virtual btConstraintSolver* getConstraintSolver(); virtual int getNumConstraints() const; virtual btTypedConstraint* getConstraint(int index) ; virtual const btTypedConstraint* getConstraint(int index) const; virtual btDynamicsWorldType getWorldType() const { return BT_DISCRETE_DYNAMICS_WORLD; } ///the forces on each rigidbody is accumulating together with gravity. clear this after each timestep. virtual void clearForces(); ///apply gravity, call this once per timestep virtual void applyGravity(); virtual void setNumTasks(int numTasks) { (void) numTasks; } ///obsolete, use updateActions instead virtual void updateVehicles(btScalar timeStep) { updateActions(timeStep); } ///obsolete, use addAction instead virtual void addVehicle(btActionInterface* vehicle); ///obsolete, use removeAction instead virtual void removeVehicle(btActionInterface* vehicle); ///obsolete, use addAction instead virtual void addCharacter(btActionInterface* character); ///obsolete, use removeAction instead virtual void removeCharacter(btActionInterface* character); void setSynchronizeAllMotionStates(bool synchronizeAll) { m_synchronizeAllMotionStates = synchronizeAll; } bool getSynchronizeAllMotionStates() const { return m_synchronizeAllMotionStates; } ///Preliminary serialization test for Bullet 2.76. Loading those files requires a separate parser (see Bullet/Demos/SerializeDemo) virtual void serialize(btSerializer* serializer); }; #endif //BT_DISCRETE_DYNAMICS_WORLD_H critterding-beta12.1/src/utils/bullet/BulletDynamics/Dynamics/btActionInterface.h0000644000175000017500000000330211344267705027205 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 _BT_ACTION_INTERFACE_H #define _BT_ACTION_INTERFACE_H class btIDebugDraw; class btCollisionWorld; #include "LinearMath/btScalar.h" #include "btRigidBody.h" ///Basic interface to allow actions such as vehicles and characters to be updated inside a btDynamicsWorld class btActionInterface { protected: static btRigidBody& getFixedBody() { static btRigidBody s_fixed(0, 0,0); s_fixed.setMassProps(btScalar(0.),btVector3(btScalar(0.),btScalar(0.),btScalar(0.))); return s_fixed; } public: virtual ~btActionInterface() { } virtual void updateAction( btCollisionWorld* collisionWorld, btScalar deltaTimeStep)=0; virtual void debugDraw(btIDebugDraw* debugDrawer) = 0; }; #endif //_BT_ACTION_INTERFACE_H critterding-beta12.1/src/utils/bullet/BulletDynamics/Dynamics/btContinuousDynamicsWorld.h0000644000175000017500000000403111337071441031005 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BT_CONTINUOUS_DYNAMICS_WORLD_H #define BT_CONTINUOUS_DYNAMICS_WORLD_H #include "btDiscreteDynamicsWorld.h" ///btContinuousDynamicsWorld adds optional (per object) continuous collision detection for fast moving objects to the btDiscreteDynamicsWorld. ///This copes with fast moving objects that otherwise would tunnel/miss collisions. ///Under construction, don't use yet! Please use btDiscreteDynamicsWorld instead. class btContinuousDynamicsWorld : public btDiscreteDynamicsWorld { void updateTemporalAabbs(btScalar timeStep); public: btContinuousDynamicsWorld(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolver* constraintSolver,btCollisionConfiguration* collisionConfiguration); virtual ~btContinuousDynamicsWorld(); ///time stepping with calculation of time of impact for selected fast moving objects virtual void internalSingleStepSimulation( btScalar timeStep); virtual void calculateTimeOfImpacts(btScalar timeStep); virtual btDynamicsWorldType getWorldType() const { return BT_CONTINUOUS_DYNAMICS_WORLD; } }; #endif //BT_CONTINUOUS_DYNAMICS_WORLD_H critterding-beta12.1/src/utils/bullet/BulletDynamics/Dynamics/Bullet-C-API.cpp0000644000175000017500000003246011344267705026201 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ /* Draft high-level generic physics C-API. For low-level access, use the physics SDK native API's. Work in progress, functionality will be added on demand. If possible, use the richer Bullet C++ API, by including */ #include "Bullet-C-Api.h" #include "btBulletDynamicsCommon.h" #include "LinearMath/btAlignedAllocator.h" #include "LinearMath/btVector3.h" #include "LinearMath/btScalar.h" #include "LinearMath/btMatrix3x3.h" #include "LinearMath/btTransform.h" #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" #include "BulletCollision/CollisionShapes/btTriangleShape.h" #include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" #include "BulletCollision/NarrowPhaseCollision/btPointCollector.h" #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" #include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h" #include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h" #include "BulletCollision/CollisionShapes/btMinkowskiSumShape.h" #include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" #include "BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h" #include "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h" /* Create and Delete a Physics SDK */ struct btPhysicsSdk { // btDispatcher* m_dispatcher; // btOverlappingPairCache* m_pairCache; // btConstraintSolver* m_constraintSolver btVector3 m_worldAabbMin; btVector3 m_worldAabbMax; //todo: version, hardware/optimization settings etc? btPhysicsSdk() :m_worldAabbMin(-1000,-1000,-1000), m_worldAabbMax(1000,1000,1000) { } }; plPhysicsSdkHandle plNewBulletSdk() { void* mem = btAlignedAlloc(sizeof(btPhysicsSdk),16); return (plPhysicsSdkHandle)new (mem)btPhysicsSdk; } void plDeletePhysicsSdk(plPhysicsSdkHandle physicsSdk) { btPhysicsSdk* phys = reinterpret_cast(physicsSdk); btAlignedFree(phys); } /* Dynamics World */ plDynamicsWorldHandle plCreateDynamicsWorld(plPhysicsSdkHandle physicsSdkHandle) { btPhysicsSdk* physicsSdk = reinterpret_cast(physicsSdkHandle); void* mem = btAlignedAlloc(sizeof(btDefaultCollisionConfiguration),16); btDefaultCollisionConfiguration* collisionConfiguration = new (mem)btDefaultCollisionConfiguration(); mem = btAlignedAlloc(sizeof(btCollisionDispatcher),16); btDispatcher* dispatcher = new (mem)btCollisionDispatcher(collisionConfiguration); mem = btAlignedAlloc(sizeof(btAxisSweep3),16); btBroadphaseInterface* pairCache = new (mem)btAxisSweep3(physicsSdk->m_worldAabbMin,physicsSdk->m_worldAabbMax); mem = btAlignedAlloc(sizeof(btSequentialImpulseConstraintSolver),16); btConstraintSolver* constraintSolver = new(mem) btSequentialImpulseConstraintSolver(); mem = btAlignedAlloc(sizeof(btDiscreteDynamicsWorld),16); return (plDynamicsWorldHandle) new (mem)btDiscreteDynamicsWorld(dispatcher,pairCache,constraintSolver,collisionConfiguration); } void plDeleteDynamicsWorld(plDynamicsWorldHandle world) { //todo: also clean up the other allocations, axisSweep, pairCache,dispatcher,constraintSolver,collisionConfiguration btDynamicsWorld* dynamicsWorld = reinterpret_cast< btDynamicsWorld* >(world); btAlignedFree(dynamicsWorld); } void plStepSimulation(plDynamicsWorldHandle world, plReal timeStep) { btDynamicsWorld* dynamicsWorld = reinterpret_cast< btDynamicsWorld* >(world); btAssert(dynamicsWorld); dynamicsWorld->stepSimulation(timeStep); } void plAddRigidBody(plDynamicsWorldHandle world, plRigidBodyHandle object) { btDynamicsWorld* dynamicsWorld = reinterpret_cast< btDynamicsWorld* >(world); btAssert(dynamicsWorld); btRigidBody* body = reinterpret_cast< btRigidBody* >(object); btAssert(body); dynamicsWorld->addRigidBody(body); } void plRemoveRigidBody(plDynamicsWorldHandle world, plRigidBodyHandle object) { btDynamicsWorld* dynamicsWorld = reinterpret_cast< btDynamicsWorld* >(world); btAssert(dynamicsWorld); btRigidBody* body = reinterpret_cast< btRigidBody* >(object); btAssert(body); dynamicsWorld->removeRigidBody(body); } /* Rigid Body */ plRigidBodyHandle plCreateRigidBody( void* user_data, float mass, plCollisionShapeHandle cshape ) { btTransform trans; trans.setIdentity(); btVector3 localInertia(0,0,0); btCollisionShape* shape = reinterpret_cast( cshape); btAssert(shape); if (mass) { shape->calculateLocalInertia(mass,localInertia); } void* mem = btAlignedAlloc(sizeof(btRigidBody),16); btRigidBody::btRigidBodyConstructionInfo rbci(mass, 0,shape,localInertia); btRigidBody* body = new (mem)btRigidBody(rbci); body->setWorldTransform(trans); body->setUserPointer(user_data); return (plRigidBodyHandle) body; } void plDeleteRigidBody(plRigidBodyHandle cbody) { btRigidBody* body = reinterpret_cast< btRigidBody* >(cbody); btAssert(body); btAlignedFree( body); } /* Collision Shape definition */ plCollisionShapeHandle plNewSphereShape(plReal radius) { void* mem = btAlignedAlloc(sizeof(btSphereShape),16); return (plCollisionShapeHandle) new (mem)btSphereShape(radius); } plCollisionShapeHandle plNewBoxShape(plReal x, plReal y, plReal z) { void* mem = btAlignedAlloc(sizeof(btBoxShape),16); return (plCollisionShapeHandle) new (mem)btBoxShape(btVector3(x,y,z)); } plCollisionShapeHandle plNewCapsuleShape(plReal radius, plReal height) { //capsule is convex hull of 2 spheres, so use btMultiSphereShape const int numSpheres = 2; btVector3 positions[numSpheres] = {btVector3(0,height,0),btVector3(0,-height,0)}; btScalar radi[numSpheres] = {radius,radius}; void* mem = btAlignedAlloc(sizeof(btMultiSphereShape),16); return (plCollisionShapeHandle) new (mem)btMultiSphereShape(positions,radi,numSpheres); } plCollisionShapeHandle plNewConeShape(plReal radius, plReal height) { void* mem = btAlignedAlloc(sizeof(btConeShape),16); return (plCollisionShapeHandle) new (mem)btConeShape(radius,height); } plCollisionShapeHandle plNewCylinderShape(plReal radius, plReal height) { void* mem = btAlignedAlloc(sizeof(btCylinderShape),16); return (plCollisionShapeHandle) new (mem)btCylinderShape(btVector3(radius,height,radius)); } /* Convex Meshes */ plCollisionShapeHandle plNewConvexHullShape() { void* mem = btAlignedAlloc(sizeof(btConvexHullShape),16); return (plCollisionShapeHandle) new (mem)btConvexHullShape(); } /* Concave static triangle meshes */ plMeshInterfaceHandle plNewMeshInterface() { return 0; } plCollisionShapeHandle plNewCompoundShape() { void* mem = btAlignedAlloc(sizeof(btCompoundShape),16); return (plCollisionShapeHandle) new (mem)btCompoundShape(); } void plAddChildShape(plCollisionShapeHandle compoundShapeHandle,plCollisionShapeHandle childShapeHandle, plVector3 childPos,plQuaternion childOrn) { btCollisionShape* colShape = reinterpret_cast(compoundShapeHandle); btAssert(colShape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE); btCompoundShape* compoundShape = reinterpret_cast(colShape); btCollisionShape* childShape = reinterpret_cast(childShapeHandle); btTransform localTrans; localTrans.setIdentity(); localTrans.setOrigin(btVector3(childPos[0],childPos[1],childPos[2])); localTrans.setRotation(btQuaternion(childOrn[0],childOrn[1],childOrn[2],childOrn[3])); compoundShape->addChildShape(localTrans,childShape); } void plSetEuler(plReal yaw,plReal pitch,plReal roll, plQuaternion orient) { btQuaternion orn; orn.setEuler(yaw,pitch,roll); orient[0] = orn.getX(); orient[1] = orn.getY(); orient[2] = orn.getZ(); orient[3] = orn.getW(); } // extern void plAddTriangle(plMeshInterfaceHandle meshHandle, plVector3 v0,plVector3 v1,plVector3 v2); // extern plCollisionShapeHandle plNewStaticTriangleMeshShape(plMeshInterfaceHandle); void plAddVertex(plCollisionShapeHandle cshape, plReal x,plReal y,plReal z) { btCollisionShape* colShape = reinterpret_cast( cshape); (void)colShape; btAssert(colShape->getShapeType()==CONVEX_HULL_SHAPE_PROXYTYPE); btConvexHullShape* convexHullShape = reinterpret_cast( cshape); convexHullShape->addPoint(btVector3(x,y,z)); } void plDeleteShape(plCollisionShapeHandle cshape) { btCollisionShape* shape = reinterpret_cast( cshape); btAssert(shape); btAlignedFree(shape); } void plSetScaling(plCollisionShapeHandle cshape, plVector3 cscaling) { btCollisionShape* shape = reinterpret_cast( cshape); btAssert(shape); btVector3 scaling(cscaling[0],cscaling[1],cscaling[2]); shape->setLocalScaling(scaling); } void plSetPosition(plRigidBodyHandle object, const plVector3 position) { btRigidBody* body = reinterpret_cast< btRigidBody* >(object); btAssert(body); btVector3 pos(position[0],position[1],position[2]); btTransform worldTrans = body->getWorldTransform(); worldTrans.setOrigin(pos); body->setWorldTransform(worldTrans); } void plSetOrientation(plRigidBodyHandle object, const plQuaternion orientation) { btRigidBody* body = reinterpret_cast< btRigidBody* >(object); btAssert(body); btQuaternion orn(orientation[0],orientation[1],orientation[2],orientation[3]); btTransform worldTrans = body->getWorldTransform(); worldTrans.setRotation(orn); body->setWorldTransform(worldTrans); } void plSetOpenGLMatrix(plRigidBodyHandle object, plReal* matrix) { btRigidBody* body = reinterpret_cast< btRigidBody* >(object); btAssert(body); btTransform& worldTrans = body->getWorldTransform(); worldTrans.setFromOpenGLMatrix(matrix); } void plGetOpenGLMatrix(plRigidBodyHandle object, plReal* matrix) { btRigidBody* body = reinterpret_cast< btRigidBody* >(object); btAssert(body); body->getWorldTransform().getOpenGLMatrix(matrix); } void plGetPosition(plRigidBodyHandle object,plVector3 position) { btRigidBody* body = reinterpret_cast< btRigidBody* >(object); btAssert(body); const btVector3& pos = body->getWorldTransform().getOrigin(); position[0] = pos.getX(); position[1] = pos.getY(); position[2] = pos.getZ(); } void plGetOrientation(plRigidBodyHandle object,plQuaternion orientation) { btRigidBody* body = reinterpret_cast< btRigidBody* >(object); btAssert(body); const btQuaternion& orn = body->getWorldTransform().getRotation(); orientation[0] = orn.getX(); orientation[1] = orn.getY(); orientation[2] = orn.getZ(); orientation[3] = orn.getW(); } //plRigidBodyHandle plRayCast(plDynamicsWorldHandle world, const plVector3 rayStart, const plVector3 rayEnd, plVector3 hitpoint, plVector3 normal); // extern plRigidBodyHandle plObjectCast(plDynamicsWorldHandle world, const plVector3 rayStart, const plVector3 rayEnd, plVector3 hitpoint, plVector3 normal); double plNearestPoints(float p1[3], float p2[3], float p3[3], float q1[3], float q2[3], float q3[3], float *pa, float *pb, float normal[3]) { btVector3 vp(p1[0], p1[1], p1[2]); btTriangleShape trishapeA(vp, btVector3(p2[0], p2[1], p2[2]), btVector3(p3[0], p3[1], p3[2])); trishapeA.setMargin(0.000001f); btVector3 vq(q1[0], q1[1], q1[2]); btTriangleShape trishapeB(vq, btVector3(q2[0], q2[1], q2[2]), btVector3(q3[0], q3[1], q3[2])); trishapeB.setMargin(0.000001f); // btVoronoiSimplexSolver sGjkSimplexSolver; // btGjkEpaPenetrationDepthSolver penSolverPtr; static btSimplexSolverInterface sGjkSimplexSolver; sGjkSimplexSolver.reset(); static btGjkEpaPenetrationDepthSolver Solver0; static btMinkowskiPenetrationDepthSolver Solver1; btConvexPenetrationDepthSolver* Solver = NULL; Solver = &Solver1; btGjkPairDetector convexConvex(&trishapeA ,&trishapeB,&sGjkSimplexSolver,Solver); convexConvex.m_catchDegeneracies = 1; // btGjkPairDetector convexConvex(&trishapeA ,&trishapeB,&sGjkSimplexSolver,0); btPointCollector gjkOutput; btGjkPairDetector::ClosestPointInput input; btTransform tr; tr.setIdentity(); input.m_transformA = tr; input.m_transformB = tr; convexConvex.getClosestPoints(input, gjkOutput, 0); if (gjkOutput.m_hasResult) { pb[0] = pa[0] = gjkOutput.m_pointInWorld[0]; pb[1] = pa[1] = gjkOutput.m_pointInWorld[1]; pb[2] = pa[2] = gjkOutput.m_pointInWorld[2]; pb[0]+= gjkOutput.m_normalOnBInWorld[0] * gjkOutput.m_distance; pb[1]+= gjkOutput.m_normalOnBInWorld[1] * gjkOutput.m_distance; pb[2]+= gjkOutput.m_normalOnBInWorld[2] * gjkOutput.m_distance; normal[0] = gjkOutput.m_normalOnBInWorld[0]; normal[1] = gjkOutput.m_normalOnBInWorld[1]; normal[2] = gjkOutput.m_normalOnBInWorld[2]; return gjkOutput.m_distance; } return -1.0f; } critterding-beta12.1/src/utils/bullet/BulletDynamics/ibmsdk/0000755000175000017500000000000011347266042023150 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletDynamics/ibmsdk/Makefile0000644000175000017500000000217011337071441024604 0ustar bobkebobke#### Source code Dirs VPATH = \ ../ConstraintSolver \ ../Dynamics \ ../Vehicle ROOT = ../../.. #### Library LIBRARY_ppu = bulletdynamics.a #### Compiler flags CPPFLAGS = \ -DUSE_LIBSPE2 \ -I../ConstraintSolver \ -I../Dynamics \ -I../Vehicle \ -I$(ROOT)/src \ -I$(SDKINC) #### Optimization level flags #CC_OPT_LEVEL = $(CC_OPT_LEVEL_DEBUG) CC_OPT_LEVEL = -O3 ##### Objects to be archived in lib OBJS = \ btContactConstraint.o \ btGeneric6DofConstraint.o \ btHingeConstraint.o \ btPoint2PointConstraint.o \ btSequentialImpulseConstraintSolver.o \ btSolve2LinearConstraint.o \ btTypedConstraint.o \ btDiscreteDynamicsWorld.o \ btRigidBody.o \ btSimpleDynamicsWorld.o \ btRaycastVehicle.o \ btWheelInfo.o #### Install directories INSTALL_DIR = $(ROOT)/lib/ibmsdk INSTALL_FILES = $(LIBRARY_ppu) IBM_CELLSDK_VERSION := $(shell if [ -d /opt/cell ]; then echo "3.0"; fi) ifeq ("$(IBM_CELLSDK_VERSION)","3.0") CELL_TOP ?= /opt/cell/sdk include $(CELL_TOP)/buildutils/make.footer else CELL_TOP ?= /opt/ibm/cell-sdk/prototype include $(CELL_TOP)/make.footer endif critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/0000755000175000017500000000000011347266042025216 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.h0000644000175000017500000000662111337071441032270 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 SOLVE_2LINEAR_CONSTRAINT_H #define SOLVE_2LINEAR_CONSTRAINT_H #include "LinearMath/btMatrix3x3.h" #include "LinearMath/btVector3.h" class btRigidBody; /// constraint class used for lateral tyre friction. class btSolve2LinearConstraint { btScalar m_tau; btScalar m_damping; public: btSolve2LinearConstraint(btScalar tau,btScalar damping) { m_tau = tau; m_damping = damping; } // // solve unilateral constraint (equality, direct method) // void resolveUnilateralPairConstraint( btRigidBody* body0, btRigidBody* body1, const btMatrix3x3& world2A, const btMatrix3x3& world2B, const btVector3& invInertiaADiag, const btScalar invMassA, const btVector3& linvelA,const btVector3& angvelA, const btVector3& rel_posA1, const btVector3& invInertiaBDiag, const btScalar invMassB, const btVector3& linvelB,const btVector3& angvelB, const btVector3& rel_posA2, btScalar depthA, const btVector3& normalA, const btVector3& rel_posB1,const btVector3& rel_posB2, btScalar depthB, const btVector3& normalB, btScalar& imp0,btScalar& imp1); // // solving 2x2 lcp problem (inequality, direct solution ) // void resolveBilateralPairConstraint( btRigidBody* body0, btRigidBody* body1, const btMatrix3x3& world2A, const btMatrix3x3& world2B, const btVector3& invInertiaADiag, const btScalar invMassA, const btVector3& linvelA,const btVector3& angvelA, const btVector3& rel_posA1, const btVector3& invInertiaBDiag, const btScalar invMassB, const btVector3& linvelB,const btVector3& angvelB, const btVector3& rel_posA2, btScalar depthA, const btVector3& normalA, const btVector3& rel_posB1,const btVector3& rel_posB2, btScalar depthB, const btVector3& normalB, btScalar& imp0,btScalar& imp1); /* void resolveAngularConstraint( const btMatrix3x3& invInertiaAWS, const btScalar invMassA, const btVector3& linvelA,const btVector3& angvelA, const btVector3& rel_posA1, const btMatrix3x3& invInertiaBWS, const btScalar invMassB, const btVector3& linvelB,const btVector3& angvelB, const btVector3& rel_posA2, btScalar depthA, const btVector3& normalA, const btVector3& rel_posB1,const btVector3& rel_posB2, btScalar depthB, const btVector3& normalB, btScalar& imp0,btScalar& imp1); */ }; #endif //SOLVE_2LINEAR_CONSTRAINT_H ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.hcritterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.0000644000175000017500000000517611337071441033075 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. 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 GENERIC_6DOF_SPRING_CONSTRAINT_H #define GENERIC_6DOF_SPRING_CONSTRAINT_H #include "LinearMath/btVector3.h" #include "btTypedConstraint.h" #include "btGeneric6DofConstraint.h" /// Generic 6 DOF constraint that allows to set spring motors to any translational and rotational DOF /// DOF index used in enableSpring() and setStiffness() means: /// 0 : translation X /// 1 : translation Y /// 2 : translation Z /// 3 : rotation X (3rd Euler rotational around new position of X axis, range [-PI+epsilon, PI-epsilon] ) /// 4 : rotation Y (2nd Euler rotational around new position of Y axis, range [-PI/2+epsilon, PI/2-epsilon] ) /// 5 : rotation Z (1st Euler rotational around Z axis, range [-PI+epsilon, PI-epsilon] ) class btGeneric6DofSpringConstraint : public btGeneric6DofConstraint { protected: bool m_springEnabled[6]; btScalar m_equilibriumPoint[6]; btScalar m_springStiffness[6]; btScalar m_springDamping[6]; // between 0 and 1 (1 == no damping) void internalUpdateSprings(btConstraintInfo2* info); public: btGeneric6DofSpringConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB ,bool useLinearReferenceFrameA); void enableSpring(int index, bool onOff); void setStiffness(int index, btScalar stiffness); void setDamping(int index, btScalar damping); void setEquilibriumPoint(); // set the current constraint position/orientation as an equilibrium point for all DOF void setEquilibriumPoint(int index); // set the current constraint position/orientation as an equilibrium point for given DOF virtual void getInfo2 (btConstraintInfo2* info); }; #endif // GENERIC_6DOF_SPRING_CONSTRAINT_H critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btSolverConstraint.h0000644000175000017500000000465111344267705031246 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BT_SOLVER_CONSTRAINT_H #define BT_SOLVER_CONSTRAINT_H class btRigidBody; #include "LinearMath/btVector3.h" #include "LinearMath/btMatrix3x3.h" #include "btJacobianEntry.h" //#define NO_FRICTION_TANGENTIALS 1 #include "btSolverBody.h" ///1D constraint along a normal axis between bodyA and bodyB. It can be combined to solve contact and friction constraints. ATTRIBUTE_ALIGNED64 (struct) btSolverConstraint { BT_DECLARE_ALIGNED_ALLOCATOR(); btVector3 m_relpos1CrossNormal; btVector3 m_contactNormal; btVector3 m_relpos2CrossNormal; //btVector3 m_contactNormal2;//usually m_contactNormal2 == -m_contactNormal btVector3 m_angularComponentA; btVector3 m_angularComponentB; mutable btSimdScalar m_appliedPushImpulse; mutable btSimdScalar m_appliedImpulse; btScalar m_friction; btScalar m_jacDiagABInv; union { int m_numConsecutiveRowsPerKernel; btScalar m_unusedPadding0; }; union { int m_frictionIndex; btScalar m_unusedPadding1; }; union { btRigidBody* m_solverBodyA; btScalar m_unusedPadding2; }; union { btRigidBody* m_solverBodyB; btScalar m_unusedPadding3; }; union { void* m_originalContactPoint; btScalar m_unusedPadding4; }; btScalar m_rhs; btScalar m_cfm; btScalar m_lowerLimit; btScalar m_upperLimit; btScalar m_rhsPenetration; enum btSolverConstraintType { BT_SOLVER_CONTACT_1D = 0, BT_SOLVER_FRICTION_1D }; }; typedef btAlignedObjectArray btConstraintArray; #endif //BT_SOLVER_CONSTRAINT_H critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btContactSolverInfo.h0000644000175000017500000000565011344267705031331 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 CONTACT_SOLVER_INFO #define CONTACT_SOLVER_INFO enum btSolverMode { SOLVER_RANDMIZE_ORDER = 1, SOLVER_FRICTION_SEPARATE = 2, SOLVER_USE_WARMSTARTING = 4, SOLVER_USE_FRICTION_WARMSTARTING = 8, SOLVER_USE_2_FRICTION_DIRECTIONS = 16, SOLVER_ENABLE_FRICTION_DIRECTION_CACHING = 32, SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION = 64, SOLVER_CACHE_FRIENDLY = 128, SOLVER_SIMD = 256, //enabled for Windows, the solver innerloop is branchless SIMD, 40% faster than FPU/scalar version SOLVER_CUDA = 512 //will be open sourced during Game Developers Conference 2009. Much faster. }; struct btContactSolverInfoData { btScalar m_tau; btScalar m_damping; btScalar m_friction; btScalar m_timeStep; btScalar m_restitution; int m_numIterations; btScalar m_maxErrorReduction; btScalar m_sor; btScalar m_erp;//used as Baumgarte factor btScalar m_erp2;//used in Split Impulse btScalar m_globalCfm;//constraint force mixing int m_splitImpulse; btScalar m_splitImpulsePenetrationThreshold; btScalar m_linearSlop; btScalar m_warmstartingFactor; int m_solverMode; int m_restingContactRestitutionThreshold; int m_minimumSolverBatchSize; }; struct btContactSolverInfo : public btContactSolverInfoData { inline btContactSolverInfo() { m_tau = btScalar(0.6); m_damping = btScalar(1.0); m_friction = btScalar(0.3); m_restitution = btScalar(0.); m_maxErrorReduction = btScalar(20.); m_numIterations = 10; m_erp = btScalar(0.2); m_erp2 = btScalar(0.1); m_globalCfm = btScalar(0.); m_sor = btScalar(1.); m_splitImpulse = false; m_splitImpulsePenetrationThreshold = -0.02f; m_linearSlop = btScalar(0.0); m_warmstartingFactor=btScalar(0.85); m_solverMode = SOLVER_USE_WARMSTARTING | SOLVER_SIMD;// | SOLVER_RANDMIZE_ORDER; m_restingContactRestitutionThreshold = 2;//resting contact lifetime threshold to disable restitution m_minimumSolverBatchSize = 128; //try to combine islands until the amount of constraints reaches this limit } }; #endif //CONTACT_SOLVER_INFO critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h0000644000175000017500000004327711344267705032076 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ /// 2009 March: btGeneric6DofConstraint refactored by Roman Ponomarev /// Added support for generic constraint solver through getInfo1/getInfo2 methods /* 2007-09-09 btGeneric6DofConstraint Refactored by Francisco Le?n email: projectileman@yahoo.com http://gimpact.sf.net */ #ifndef GENERIC_6DOF_CONSTRAINT_H #define GENERIC_6DOF_CONSTRAINT_H #include "LinearMath/btVector3.h" #include "btJacobianEntry.h" #include "btTypedConstraint.h" class btRigidBody; //! Rotation Limit structure for generic joints class btRotationalLimitMotor { public: //! limit_parameters //!@{ btScalar m_loLimit;//!< joint limit btScalar m_hiLimit;//!< joint limit btScalar m_targetVelocity;//!< target motor velocity btScalar m_maxMotorForce;//!< max force on motor btScalar m_maxLimitForce;//!< max force on limit btScalar m_damping;//!< Damping. btScalar m_limitSoftness;//! Relaxation factor btScalar m_normalCFM;//!< Constraint force mixing factor btScalar m_stopERP;//!< Error tolerance factor when joint is at limit btScalar m_stopCFM;//!< Constraint force mixing factor when joint is at limit btScalar m_bounce;//!< restitution factor bool m_enableMotor; //!@} //! temp_variables //!@{ btScalar m_currentLimitError;//! How much is violated this limit btScalar m_currentPosition; //! current value of angle int m_currentLimit;//!< 0=free, 1=at lo limit, 2=at hi limit btScalar m_accumulatedImpulse; //!@} btRotationalLimitMotor() { m_accumulatedImpulse = 0.f; m_targetVelocity = 0; m_maxMotorForce = 0.1f; m_maxLimitForce = 300.0f; m_loLimit = 1.0f; m_hiLimit = -1.0f; m_normalCFM = 0.f; m_stopERP = 0.2f; m_stopCFM = 0.f; m_bounce = 0.0f; m_damping = 1.0f; m_limitSoftness = 0.5f; m_currentLimit = 0; m_currentLimitError = 0; m_enableMotor = false; } btRotationalLimitMotor(const btRotationalLimitMotor & limot) { m_targetVelocity = limot.m_targetVelocity; m_maxMotorForce = limot.m_maxMotorForce; m_limitSoftness = limot.m_limitSoftness; m_loLimit = limot.m_loLimit; m_hiLimit = limot.m_hiLimit; m_normalCFM = limot.m_normalCFM; m_stopERP = limot.m_stopERP; m_stopCFM = limot.m_stopCFM; m_bounce = limot.m_bounce; m_currentLimit = limot.m_currentLimit; m_currentLimitError = limot.m_currentLimitError; m_enableMotor = limot.m_enableMotor; } //! Is limited bool isLimited() { if(m_loLimit > m_hiLimit) return false; return true; } //! Need apply correction bool needApplyTorques() { if(m_currentLimit == 0 && m_enableMotor == false) return false; return true; } //! calculates error /*! calculates m_currentLimit and m_currentLimitError. */ int testLimitValue(btScalar test_value); //! apply the correction impulses for two bodies btScalar solveAngularLimits(btScalar timeStep,btVector3& axis, btScalar jacDiagABInv,btRigidBody * body0, btRigidBody * body1); }; class btTranslationalLimitMotor { public: btVector3 m_lowerLimit;//!< the constraint lower limits btVector3 m_upperLimit;//!< the constraint upper limits btVector3 m_accumulatedImpulse; //! Linear_Limit_parameters //!@{ btScalar m_limitSoftness;//!< Softness for linear limit btScalar m_damping;//!< Damping for linear limit btScalar m_restitution;//! Bounce parameter for linear limit btVector3 m_normalCFM;//!< Constraint force mixing factor btVector3 m_stopERP;//!< Error tolerance factor when joint is at limit btVector3 m_stopCFM;//!< Constraint force mixing factor when joint is at limit //!@} bool m_enableMotor[3]; btVector3 m_targetVelocity;//!< target motor velocity btVector3 m_maxMotorForce;//!< max force on motor btVector3 m_currentLimitError;//! How much is violated this limit btVector3 m_currentLinearDiff;//! Current relative offset of constraint frames int m_currentLimit[3];//!< 0=free, 1=at lower limit, 2=at upper limit btTranslationalLimitMotor() { m_lowerLimit.setValue(0.f,0.f,0.f); m_upperLimit.setValue(0.f,0.f,0.f); m_accumulatedImpulse.setValue(0.f,0.f,0.f); m_normalCFM.setValue(0.f, 0.f, 0.f); m_stopERP.setValue(0.2f, 0.2f, 0.2f); m_stopCFM.setValue(0.f, 0.f, 0.f); m_limitSoftness = 0.7f; m_damping = btScalar(1.0f); m_restitution = btScalar(0.5f); for(int i=0; i < 3; i++) { m_enableMotor[i] = false; m_targetVelocity[i] = btScalar(0.f); m_maxMotorForce[i] = btScalar(0.f); } } btTranslationalLimitMotor(const btTranslationalLimitMotor & other ) { m_lowerLimit = other.m_lowerLimit; m_upperLimit = other.m_upperLimit; m_accumulatedImpulse = other.m_accumulatedImpulse; m_limitSoftness = other.m_limitSoftness ; m_damping = other.m_damping; m_restitution = other.m_restitution; m_normalCFM = other.m_normalCFM; m_stopERP = other.m_stopERP; m_stopCFM = other.m_stopCFM; for(int i=0; i < 3; i++) { m_enableMotor[i] = other.m_enableMotor[i]; m_targetVelocity[i] = other.m_targetVelocity[i]; m_maxMotorForce[i] = other.m_maxMotorForce[i]; } } //! Test limit /*! - free means upper < lower, - locked means upper == lower - limited means upper > lower - limitIndex: first 3 are linear, next 3 are angular */ inline bool isLimited(int limitIndex) { return (m_upperLimit[limitIndex] >= m_lowerLimit[limitIndex]); } inline bool needApplyForce(int limitIndex) { if(m_currentLimit[limitIndex] == 0 && m_enableMotor[limitIndex] == false) return false; return true; } int testLimitValue(int limitIndex, btScalar test_value); btScalar solveLinearAxis( btScalar timeStep, btScalar jacDiagABInv, btRigidBody& body1,const btVector3 &pointInA, btRigidBody& body2,const btVector3 &pointInB, int limit_index, const btVector3 & axis_normal_on_a, const btVector3 & anchorPos); }; enum bt6DofFlags { BT_6DOF_FLAGS_CFM_NORM = 1, BT_6DOF_FLAGS_CFM_STOP = 2, BT_6DOF_FLAGS_ERP_STOP = 4 }; #define BT_6DOF_FLAGS_AXIS_SHIFT 3 // bits per axis /// btGeneric6DofConstraint between two rigidbodies each with a pivotpoint that descibes the axis location in local space /*! btGeneric6DofConstraint can leave any of the 6 degree of freedom 'free' or 'locked'. currently this limit supports rotational motors
  • For Linear limits, use btGeneric6DofConstraint.setLinearUpperLimit, btGeneric6DofConstraint.setLinearLowerLimit. You can set the parameters with the btTranslationalLimitMotor structure accsesible through the btGeneric6DofConstraint.getTranslationalLimitMotor method. At this moment translational motors are not supported. May be in the future.
  • For Angular limits, use the btRotationalLimitMotor structure for configuring the limit. This is accessible through btGeneric6DofConstraint.getLimitMotor method, This brings support for limit parameters and motors.
  • Angulars limits have these possible ranges:
    AXIS MIN ANGLE MAX ANGLE
    X -PI PI
    Y -PI/2 PI/2
    Z -PI PI
*/ class btGeneric6DofConstraint : public btTypedConstraint { protected: //! relative_frames //!@{ btTransform m_frameInA;//!< the constraint space w.r.t body A btTransform m_frameInB;//!< the constraint space w.r.t body B //!@} //! Jacobians //!@{ btJacobianEntry m_jacLinear[3];//!< 3 orthogonal linear constraints btJacobianEntry m_jacAng[3];//!< 3 orthogonal angular constraints //!@} //! Linear_Limit_parameters //!@{ btTranslationalLimitMotor m_linearLimits; //!@} //! hinge_parameters //!@{ btRotationalLimitMotor m_angularLimits[3]; //!@} protected: //! temporal variables //!@{ btScalar m_timeStep; btTransform m_calculatedTransformA; btTransform m_calculatedTransformB; btVector3 m_calculatedAxisAngleDiff; btVector3 m_calculatedAxis[3]; btVector3 m_calculatedLinearDiff; btScalar m_factA; btScalar m_factB; bool m_hasStaticBody; btVector3 m_AnchorPos; // point betwen pivots of bodies A and B to solve linear axes bool m_useLinearReferenceFrameA; bool m_useOffsetForConstraintFrame; int m_flags; //!@} btGeneric6DofConstraint& operator=(btGeneric6DofConstraint& other) { btAssert(0); (void) other; return *this; } int setAngularLimits(btConstraintInfo2 *info, int row_offset,const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB); int setLinearLimits(btConstraintInfo2 *info, int row, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB); void buildLinearJacobian( btJacobianEntry & jacLinear,const btVector3 & normalWorld, const btVector3 & pivotAInW,const btVector3 & pivotBInW); void buildAngularJacobian(btJacobianEntry & jacAngular,const btVector3 & jointAxisW); // tests linear limits void calculateLinearInfo(); //! calcs the euler angles between the two bodies. void calculateAngleInfo(); public: ///for backwards compatibility during the transition to 'getInfo/getInfo2' bool m_useSolveConstraintObsolete; btGeneric6DofConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB ,bool useLinearReferenceFrameA); btGeneric6DofConstraint(btRigidBody& rbB, const btTransform& frameInB, bool useLinearReferenceFrameB); //! Calcs global transform of the offsets /*! Calcs the global transform for the joint offset for body A an B, and also calcs the agle differences between the bodies. \sa btGeneric6DofConstraint.getCalculatedTransformA , btGeneric6DofConstraint.getCalculatedTransformB, btGeneric6DofConstraint.calculateAngleInfo */ void calculateTransforms(const btTransform& transA,const btTransform& transB); void calculateTransforms(); //! Gets the global transform of the offset for body A /*! \sa btGeneric6DofConstraint.getFrameOffsetA, btGeneric6DofConstraint.getFrameOffsetB, btGeneric6DofConstraint.calculateAngleInfo. */ const btTransform & getCalculatedTransformA() const { return m_calculatedTransformA; } //! Gets the global transform of the offset for body B /*! \sa btGeneric6DofConstraint.getFrameOffsetA, btGeneric6DofConstraint.getFrameOffsetB, btGeneric6DofConstraint.calculateAngleInfo. */ const btTransform & getCalculatedTransformB() const { return m_calculatedTransformB; } const btTransform & getFrameOffsetA() const { return m_frameInA; } const btTransform & getFrameOffsetB() const { return m_frameInB; } btTransform & getFrameOffsetA() { return m_frameInA; } btTransform & getFrameOffsetB() { return m_frameInB; } //! performs Jacobian calculation, and also calculates angle differences and axis virtual void buildJacobian(); virtual void getInfo1 (btConstraintInfo1* info); void getInfo1NonVirtual (btConstraintInfo1* info); virtual void getInfo2 (btConstraintInfo2* info); void getInfo2NonVirtual (btConstraintInfo2* info,const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB); void updateRHS(btScalar timeStep); //! Get the rotation axis in global coordinates /*! \pre btGeneric6DofConstraint.buildJacobian must be called previously. */ btVector3 getAxis(int axis_index) const; //! Get the relative Euler angle /*! \pre btGeneric6DofConstraint::calculateTransforms() must be called previously. */ btScalar getAngle(int axis_index) const; //! Get the relative position of the constraint pivot /*! \pre btGeneric6DofConstraint::calculateTransforms() must be called previously. */ btScalar getRelativePivotPosition(int axis_index) const; //! Test angular limit. /*! Calculates angular correction and returns true if limit needs to be corrected. \pre btGeneric6DofConstraint::calculateTransforms() must be called previously. */ bool testAngularLimitMotor(int axis_index); void setLinearLowerLimit(const btVector3& linearLower) { m_linearLimits.m_lowerLimit = linearLower; } void setLinearUpperLimit(const btVector3& linearUpper) { m_linearLimits.m_upperLimit = linearUpper; } void setAngularLowerLimit(const btVector3& angularLower) { for(int i = 0; i < 3; i++) m_angularLimits[i].m_loLimit = btNormalizeAngle(angularLower[i]); } void setAngularUpperLimit(const btVector3& angularUpper) { for(int i = 0; i < 3; i++) m_angularLimits[i].m_hiLimit = btNormalizeAngle(angularUpper[i]); } //! Retrieves the angular limit informacion btRotationalLimitMotor * getRotationalLimitMotor(int index) { return &m_angularLimits[index]; } //! Retrieves the limit informacion btTranslationalLimitMotor * getTranslationalLimitMotor() { return &m_linearLimits; } //first 3 are linear, next 3 are angular void setLimit(int axis, btScalar lo, btScalar hi) { if(axis<3) { m_linearLimits.m_lowerLimit[axis] = lo; m_linearLimits.m_upperLimit[axis] = hi; } else { lo = btNormalizeAngle(lo); hi = btNormalizeAngle(hi); m_angularLimits[axis-3].m_loLimit = lo; m_angularLimits[axis-3].m_hiLimit = hi; } } //! Test limit /*! - free means upper < lower, - locked means upper == lower - limited means upper > lower - limitIndex: first 3 are linear, next 3 are angular */ bool isLimited(int limitIndex) { if(limitIndex<3) { return m_linearLimits.isLimited(limitIndex); } return m_angularLimits[limitIndex-3].isLimited(); } virtual void calcAnchorPos(void); // overridable int get_limit_motor_info2( btRotationalLimitMotor * limot, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB, btConstraintInfo2 *info, int row, btVector3& ax1, int rotational, int rotAllowed = false); // access for UseFrameOffset bool getUseFrameOffset() { return m_useOffsetForConstraintFrame; } void setUseFrameOffset(bool frameOffsetOnOff) { m_useOffsetForConstraintFrame = frameOffsetOnOff; } ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). ///If no axis is provided, it uses the default axis for this constraint. virtual void setParam(int num, btScalar value, int axis = -1); ///return the local value of parameter virtual btScalar getParam(int num, int axis = -1) const; virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btGeneric6DofConstraintData { btTypedConstraintData m_typeConstraintData; btTransformFloatData m_rbAFrame; // constraint axii. Assumes z is hinge axis. btTransformFloatData m_rbBFrame; btVector3FloatData m_linearUpperLimit; btVector3FloatData m_linearLowerLimit; btVector3FloatData m_angularUpperLimit; btVector3FloatData m_angularLowerLimit; int m_useLinearReferenceFrameA; int m_useOffsetForConstraintFrame; }; SIMD_FORCE_INLINE int btGeneric6DofConstraint::calculateSerializeBufferSize() const { return sizeof(btGeneric6DofConstraintData); } ///fills the dataBuffer and returns the struct name (and 0 on failure) SIMD_FORCE_INLINE const char* btGeneric6DofConstraint::serialize(void* dataBuffer, btSerializer* serializer) const { btGeneric6DofConstraintData* dof = (btGeneric6DofConstraintData*)dataBuffer; btTypedConstraint::serialize(&dof->m_typeConstraintData,serializer); m_frameInA.serializeFloat(dof->m_rbAFrame); m_frameInB.serializeFloat(dof->m_rbBFrame); int i; for (i=0;i<3;i++) { dof->m_angularLowerLimit.m_floats[i] = float(m_angularLimits[i].m_loLimit); dof->m_angularUpperLimit.m_floats[i] = float(m_angularLimits[i].m_hiLimit); dof->m_linearLowerLimit.m_floats[i] = float(m_linearLimits.m_lowerLimit[i]); dof->m_linearUpperLimit.m_floats[i] = float(m_linearLimits.m_upperLimit[i]); } dof->m_useLinearReferenceFrameA = m_useLinearReferenceFrameA? 1 : 0; dof->m_useOffsetForConstraintFrame = m_useOffsetForConstraintFrame ? 1 : 0; return "btGeneric6DofConstraintData"; } #endif //GENERIC_6DOF_CONSTRAINT_H critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.cpp0000644000175000017500000007400111344267705032416 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ /* 2007-09-09 Refactored by Francisco Le?n email: projectileman@yahoo.com http://gimpact.sf.net */ #include "btGeneric6DofConstraint.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "LinearMath/btTransformUtil.h" #include "LinearMath/btTransformUtil.h" #include #define D6_USE_OBSOLETE_METHOD false #define D6_USE_FRAME_OFFSET true btGeneric6DofConstraint::btGeneric6DofConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, bool useLinearReferenceFrameA) : btTypedConstraint(D6_CONSTRAINT_TYPE, rbA, rbB) , m_frameInA(frameInA) , m_frameInB(frameInB), m_useLinearReferenceFrameA(useLinearReferenceFrameA), m_useOffsetForConstraintFrame(D6_USE_FRAME_OFFSET), m_flags(0), m_useSolveConstraintObsolete(D6_USE_OBSOLETE_METHOD) { calculateTransforms(); } btGeneric6DofConstraint::btGeneric6DofConstraint(btRigidBody& rbB, const btTransform& frameInB, bool useLinearReferenceFrameB) : btTypedConstraint(D6_CONSTRAINT_TYPE, getFixedBody(), rbB), m_frameInB(frameInB), m_useLinearReferenceFrameA(useLinearReferenceFrameB), m_useOffsetForConstraintFrame(D6_USE_FRAME_OFFSET), m_flags(0), m_useSolveConstraintObsolete(false) { ///not providing rigidbody A means implicitly using worldspace for body A m_frameInA = rbB.getCenterOfMassTransform() * m_frameInB; calculateTransforms(); } #define GENERIC_D6_DISABLE_WARMSTARTING 1 btScalar btGetMatrixElem(const btMatrix3x3& mat, int index); btScalar btGetMatrixElem(const btMatrix3x3& mat, int index) { int i = index%3; int j = index/3; return mat[i][j]; } ///MatrixToEulerXYZ from http://www.geometrictools.com/LibFoundation/Mathematics/Wm4Matrix3.inl.html bool matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz); bool matrixToEulerXYZ(const btMatrix3x3& mat,btVector3& xyz) { // // rot = cy*cz -cy*sz sy // // cz*sx*sy+cx*sz cx*cz-sx*sy*sz -cy*sx // // -cx*cz*sy+sx*sz cz*sx+cx*sy*sz cx*cy // btScalar fi = btGetMatrixElem(mat,2); if (fi < btScalar(1.0f)) { if (fi > btScalar(-1.0f)) { xyz[0] = btAtan2(-btGetMatrixElem(mat,5),btGetMatrixElem(mat,8)); xyz[1] = btAsin(btGetMatrixElem(mat,2)); xyz[2] = btAtan2(-btGetMatrixElem(mat,1),btGetMatrixElem(mat,0)); return true; } else { // WARNING. Not unique. XA - ZA = -atan2(r10,r11) xyz[0] = -btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4)); xyz[1] = -SIMD_HALF_PI; xyz[2] = btScalar(0.0); return false; } } else { // WARNING. Not unique. XAngle + ZAngle = atan2(r10,r11) xyz[0] = btAtan2(btGetMatrixElem(mat,3),btGetMatrixElem(mat,4)); xyz[1] = SIMD_HALF_PI; xyz[2] = 0.0; } return false; } //////////////////////////// btRotationalLimitMotor //////////////////////////////////// int btRotationalLimitMotor::testLimitValue(btScalar test_value) { if(m_loLimit>m_hiLimit) { m_currentLimit = 0;//Free from violation return 0; } if (test_value < m_loLimit) { m_currentLimit = 1;//low limit violation m_currentLimitError = test_value - m_loLimit; return 1; } else if (test_value> m_hiLimit) { m_currentLimit = 2;//High limit violation m_currentLimitError = test_value - m_hiLimit; return 2; }; m_currentLimit = 0;//Free from violation return 0; } btScalar btRotationalLimitMotor::solveAngularLimits( btScalar timeStep,btVector3& axis,btScalar jacDiagABInv, btRigidBody * body0, btRigidBody * body1 ) { if (needApplyTorques()==false) return 0.0f; btScalar target_velocity = m_targetVelocity; btScalar maxMotorForce = m_maxMotorForce; //current error correction if (m_currentLimit!=0) { target_velocity = -m_stopERP*m_currentLimitError/(timeStep); maxMotorForce = m_maxLimitForce; } maxMotorForce *= timeStep; // current velocity difference btVector3 angVelA; body0->internalGetAngularVelocity(angVelA); btVector3 angVelB; body1->internalGetAngularVelocity(angVelB); btVector3 vel_diff; vel_diff = angVelA-angVelB; btScalar rel_vel = axis.dot(vel_diff); // correction velocity btScalar motor_relvel = m_limitSoftness*(target_velocity - m_damping*rel_vel); if ( motor_relvel < SIMD_EPSILON && motor_relvel > -SIMD_EPSILON ) { return 0.0f;//no need for applying force } // correction impulse btScalar unclippedMotorImpulse = (1+m_bounce)*motor_relvel*jacDiagABInv; // clip correction impulse btScalar clippedMotorImpulse; ///@todo: should clip against accumulated impulse if (unclippedMotorImpulse>0.0f) { clippedMotorImpulse = unclippedMotorImpulse > maxMotorForce? maxMotorForce: unclippedMotorImpulse; } else { clippedMotorImpulse = unclippedMotorImpulse < -maxMotorForce ? -maxMotorForce: unclippedMotorImpulse; } // sort with accumulated impulses btScalar lo = btScalar(-BT_LARGE_FLOAT); btScalar hi = btScalar(BT_LARGE_FLOAT); btScalar oldaccumImpulse = m_accumulatedImpulse; btScalar sum = oldaccumImpulse + clippedMotorImpulse; m_accumulatedImpulse = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum; clippedMotorImpulse = m_accumulatedImpulse - oldaccumImpulse; btVector3 motorImp = clippedMotorImpulse * axis; //body0->applyTorqueImpulse(motorImp); //body1->applyTorqueImpulse(-motorImp); body0->internalApplyImpulse(btVector3(0,0,0), body0->getInvInertiaTensorWorld()*axis,clippedMotorImpulse); body1->internalApplyImpulse(btVector3(0,0,0), body1->getInvInertiaTensorWorld()*axis,-clippedMotorImpulse); return clippedMotorImpulse; } //////////////////////////// End btRotationalLimitMotor //////////////////////////////////// //////////////////////////// btTranslationalLimitMotor //////////////////////////////////// int btTranslationalLimitMotor::testLimitValue(int limitIndex, btScalar test_value) { btScalar loLimit = m_lowerLimit[limitIndex]; btScalar hiLimit = m_upperLimit[limitIndex]; if(loLimit > hiLimit) { m_currentLimit[limitIndex] = 0;//Free from violation m_currentLimitError[limitIndex] = btScalar(0.f); return 0; } if (test_value < loLimit) { m_currentLimit[limitIndex] = 2;//low limit violation m_currentLimitError[limitIndex] = test_value - loLimit; return 2; } else if (test_value> hiLimit) { m_currentLimit[limitIndex] = 1;//High limit violation m_currentLimitError[limitIndex] = test_value - hiLimit; return 1; }; m_currentLimit[limitIndex] = 0;//Free from violation m_currentLimitError[limitIndex] = btScalar(0.f); return 0; } btScalar btTranslationalLimitMotor::solveLinearAxis( btScalar timeStep, btScalar jacDiagABInv, btRigidBody& body1,const btVector3 &pointInA, btRigidBody& body2,const btVector3 &pointInB, int limit_index, const btVector3 & axis_normal_on_a, const btVector3 & anchorPos) { ///find relative velocity // btVector3 rel_pos1 = pointInA - body1.getCenterOfMassPosition(); // btVector3 rel_pos2 = pointInB - body2.getCenterOfMassPosition(); btVector3 rel_pos1 = anchorPos - body1.getCenterOfMassPosition(); btVector3 rel_pos2 = anchorPos - body2.getCenterOfMassPosition(); btVector3 vel1; body1.internalGetVelocityInLocalPointObsolete(rel_pos1,vel1); btVector3 vel2; body2.internalGetVelocityInLocalPointObsolete(rel_pos2,vel2); btVector3 vel = vel1 - vel2; btScalar rel_vel = axis_normal_on_a.dot(vel); /// apply displacement correction //positional error (zeroth order error) btScalar depth = -(pointInA - pointInB).dot(axis_normal_on_a); btScalar lo = btScalar(-BT_LARGE_FLOAT); btScalar hi = btScalar(BT_LARGE_FLOAT); btScalar minLimit = m_lowerLimit[limit_index]; btScalar maxLimit = m_upperLimit[limit_index]; //handle the limits if (minLimit < maxLimit) { { if (depth > maxLimit) { depth -= maxLimit; lo = btScalar(0.); } else { if (depth < minLimit) { depth -= minLimit; hi = btScalar(0.); } else { return 0.0f; } } } } btScalar normalImpulse= m_limitSoftness*(m_restitution*depth/timeStep - m_damping*rel_vel) * jacDiagABInv; btScalar oldNormalImpulse = m_accumulatedImpulse[limit_index]; btScalar sum = oldNormalImpulse + normalImpulse; m_accumulatedImpulse[limit_index] = sum > hi ? btScalar(0.) : sum < lo ? btScalar(0.) : sum; normalImpulse = m_accumulatedImpulse[limit_index] - oldNormalImpulse; btVector3 impulse_vector = axis_normal_on_a * normalImpulse; //body1.applyImpulse( impulse_vector, rel_pos1); //body2.applyImpulse(-impulse_vector, rel_pos2); btVector3 ftorqueAxis1 = rel_pos1.cross(axis_normal_on_a); btVector3 ftorqueAxis2 = rel_pos2.cross(axis_normal_on_a); body1.internalApplyImpulse(axis_normal_on_a*body1.getInvMass(), body1.getInvInertiaTensorWorld()*ftorqueAxis1,normalImpulse); body2.internalApplyImpulse(axis_normal_on_a*body2.getInvMass(), body2.getInvInertiaTensorWorld()*ftorqueAxis2,-normalImpulse); return normalImpulse; } //////////////////////////// btTranslationalLimitMotor //////////////////////////////////// void btGeneric6DofConstraint::calculateAngleInfo() { btMatrix3x3 relative_frame = m_calculatedTransformA.getBasis().inverse()*m_calculatedTransformB.getBasis(); matrixToEulerXYZ(relative_frame,m_calculatedAxisAngleDiff); // in euler angle mode we do not actually constrain the angular velocity // along the axes axis[0] and axis[2] (although we do use axis[1]) : // // to get constrain w2-w1 along ...not // ------ --------------------- ------ // d(angle[0])/dt = 0 ax[1] x ax[2] ax[0] // d(angle[1])/dt = 0 ax[1] // d(angle[2])/dt = 0 ax[0] x ax[1] ax[2] // // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0. // to prove the result for angle[0], write the expression for angle[0] from // GetInfo1 then take the derivative. to prove this for angle[2] it is // easier to take the euler rate expression for d(angle[2])/dt with respect // to the components of w and set that to 0. btVector3 axis0 = m_calculatedTransformB.getBasis().getColumn(0); btVector3 axis2 = m_calculatedTransformA.getBasis().getColumn(2); m_calculatedAxis[1] = axis2.cross(axis0); m_calculatedAxis[0] = m_calculatedAxis[1].cross(axis2); m_calculatedAxis[2] = axis0.cross(m_calculatedAxis[1]); m_calculatedAxis[0].normalize(); m_calculatedAxis[1].normalize(); m_calculatedAxis[2].normalize(); } void btGeneric6DofConstraint::calculateTransforms() { calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); } void btGeneric6DofConstraint::calculateTransforms(const btTransform& transA,const btTransform& transB) { m_calculatedTransformA = transA * m_frameInA; m_calculatedTransformB = transB * m_frameInB; calculateLinearInfo(); calculateAngleInfo(); if(m_useOffsetForConstraintFrame) { // get weight factors depending on masses btScalar miA = getRigidBodyA().getInvMass(); btScalar miB = getRigidBodyB().getInvMass(); m_hasStaticBody = (miA < SIMD_EPSILON) || (miB < SIMD_EPSILON); btScalar miS = miA + miB; if(miS > btScalar(0.f)) { m_factA = miB / miS; } else { m_factA = btScalar(0.5f); } m_factB = btScalar(1.0f) - m_factA; } } void btGeneric6DofConstraint::buildLinearJacobian( btJacobianEntry & jacLinear,const btVector3 & normalWorld, const btVector3 & pivotAInW,const btVector3 & pivotBInW) { new (&jacLinear) btJacobianEntry( m_rbA.getCenterOfMassTransform().getBasis().transpose(), m_rbB.getCenterOfMassTransform().getBasis().transpose(), pivotAInW - m_rbA.getCenterOfMassPosition(), pivotBInW - m_rbB.getCenterOfMassPosition(), normalWorld, m_rbA.getInvInertiaDiagLocal(), m_rbA.getInvMass(), m_rbB.getInvInertiaDiagLocal(), m_rbB.getInvMass()); } void btGeneric6DofConstraint::buildAngularJacobian( btJacobianEntry & jacAngular,const btVector3 & jointAxisW) { new (&jacAngular) btJacobianEntry(jointAxisW, m_rbA.getCenterOfMassTransform().getBasis().transpose(), m_rbB.getCenterOfMassTransform().getBasis().transpose(), m_rbA.getInvInertiaDiagLocal(), m_rbB.getInvInertiaDiagLocal()); } bool btGeneric6DofConstraint::testAngularLimitMotor(int axis_index) { btScalar angle = m_calculatedAxisAngleDiff[axis_index]; angle = btAdjustAngleToLimits(angle, m_angularLimits[axis_index].m_loLimit, m_angularLimits[axis_index].m_hiLimit); m_angularLimits[axis_index].m_currentPosition = angle; //test limits m_angularLimits[axis_index].testLimitValue(angle); return m_angularLimits[axis_index].needApplyTorques(); } void btGeneric6DofConstraint::buildJacobian() { #ifndef __SPU__ if (m_useSolveConstraintObsolete) { // Clear accumulated impulses for the next simulation step m_linearLimits.m_accumulatedImpulse.setValue(btScalar(0.), btScalar(0.), btScalar(0.)); int i; for(i = 0; i < 3; i++) { m_angularLimits[i].m_accumulatedImpulse = btScalar(0.); } //calculates transform calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); // const btVector3& pivotAInW = m_calculatedTransformA.getOrigin(); // const btVector3& pivotBInW = m_calculatedTransformB.getOrigin(); calcAnchorPos(); btVector3 pivotAInW = m_AnchorPos; btVector3 pivotBInW = m_AnchorPos; // not used here // btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition(); // btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition(); btVector3 normalWorld; //linear part for (i=0;i<3;i++) { if (m_linearLimits.isLimited(i)) { if (m_useLinearReferenceFrameA) normalWorld = m_calculatedTransformA.getBasis().getColumn(i); else normalWorld = m_calculatedTransformB.getBasis().getColumn(i); buildLinearJacobian( m_jacLinear[i],normalWorld , pivotAInW,pivotBInW); } } // angular part for (i=0;i<3;i++) { //calculates error angle if (testAngularLimitMotor(i)) { normalWorld = this->getAxis(i); // Create angular atom buildAngularJacobian(m_jacAng[i],normalWorld); } } } #endif //__SPU__ } void btGeneric6DofConstraint::getInfo1 (btConstraintInfo1* info) { if (m_useSolveConstraintObsolete) { info->m_numConstraintRows = 0; info->nub = 0; } else { //prepare constraint calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); info->m_numConstraintRows = 0; info->nub = 6; int i; //test linear limits for(i = 0; i < 3; i++) { if(m_linearLimits.needApplyForce(i)) { info->m_numConstraintRows++; info->nub--; } } //test angular limits for (i=0;i<3 ;i++ ) { if(testAngularLimitMotor(i)) { info->m_numConstraintRows++; info->nub--; } } } } void btGeneric6DofConstraint::getInfo1NonVirtual (btConstraintInfo1* info) { if (m_useSolveConstraintObsolete) { info->m_numConstraintRows = 0; info->nub = 0; } else { //pre-allocate all 6 info->m_numConstraintRows = 6; info->nub = 0; } } void btGeneric6DofConstraint::getInfo2 (btConstraintInfo2* info) { getInfo2NonVirtual(info,m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(), m_rbA.getLinearVelocity(),m_rbB.getLinearVelocity(),m_rbA.getAngularVelocity(), m_rbB.getAngularVelocity()); } void btGeneric6DofConstraint::getInfo2NonVirtual (btConstraintInfo2* info, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB) { btAssert(!m_useSolveConstraintObsolete); //prepare constraint calculateTransforms(transA,transB); if(m_useOffsetForConstraintFrame) { // for stability better to solve angular limits first int row = setAngularLimits(info, 0,transA,transB,linVelA,linVelB,angVelA,angVelB); setLinearLimits(info, row, transA,transB,linVelA,linVelB,angVelA,angVelB); } else { // leave old version for compatibility int row = setLinearLimits(info, 0, transA,transB,linVelA,linVelB,angVelA,angVelB); setAngularLimits(info, row,transA,transB,linVelA,linVelB,angVelA,angVelB); } } int btGeneric6DofConstraint::setLinearLimits(btConstraintInfo2* info, int row, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB) { // int row = 0; //solve linear limits btRotationalLimitMotor limot; for (int i=0;i<3 ;i++ ) { if(m_linearLimits.needApplyForce(i)) { // re-use rotational motor code limot.m_bounce = btScalar(0.f); limot.m_currentLimit = m_linearLimits.m_currentLimit[i]; limot.m_currentPosition = m_linearLimits.m_currentLinearDiff[i]; limot.m_currentLimitError = m_linearLimits.m_currentLimitError[i]; limot.m_damping = m_linearLimits.m_damping; limot.m_enableMotor = m_linearLimits.m_enableMotor[i]; limot.m_hiLimit = m_linearLimits.m_upperLimit[i]; limot.m_limitSoftness = m_linearLimits.m_limitSoftness; limot.m_loLimit = m_linearLimits.m_lowerLimit[i]; limot.m_maxLimitForce = btScalar(0.f); limot.m_maxMotorForce = m_linearLimits.m_maxMotorForce[i]; limot.m_targetVelocity = m_linearLimits.m_targetVelocity[i]; btVector3 axis = m_calculatedTransformA.getBasis().getColumn(i); int flags = m_flags >> (i * BT_6DOF_FLAGS_AXIS_SHIFT); limot.m_normalCFM = (flags & BT_6DOF_FLAGS_CFM_NORM) ? m_linearLimits.m_normalCFM[i] : info->cfm[0]; limot.m_stopCFM = (flags & BT_6DOF_FLAGS_CFM_STOP) ? m_linearLimits.m_stopCFM[i] : info->cfm[0]; limot.m_stopERP = (flags & BT_6DOF_FLAGS_ERP_STOP) ? m_linearLimits.m_stopERP[i] : info->erp; if(m_useOffsetForConstraintFrame) { int indx1 = (i + 1) % 3; int indx2 = (i + 2) % 3; int rotAllowed = 1; // rotations around orthos to current axis if(m_angularLimits[indx1].m_currentLimit && m_angularLimits[indx2].m_currentLimit) { rotAllowed = 0; } row += get_limit_motor_info2(&limot, transA,transB,linVelA,linVelB,angVelA,angVelB, info, row, axis, 0, rotAllowed); } else { row += get_limit_motor_info2(&limot, transA,transB,linVelA,linVelB,angVelA,angVelB, info, row, axis, 0); } } } return row; } int btGeneric6DofConstraint::setAngularLimits(btConstraintInfo2 *info, int row_offset, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB) { btGeneric6DofConstraint * d6constraint = this; int row = row_offset; //solve angular limits for (int i=0;i<3 ;i++ ) { if(d6constraint->getRotationalLimitMotor(i)->needApplyTorques()) { btVector3 axis = d6constraint->getAxis(i); int flags = m_flags >> ((i + 3) * BT_6DOF_FLAGS_AXIS_SHIFT); if(!(flags & BT_6DOF_FLAGS_CFM_NORM)) { m_angularLimits[i].m_normalCFM = info->cfm[0]; } if(!(flags & BT_6DOF_FLAGS_CFM_STOP)) { m_angularLimits[i].m_stopCFM = info->cfm[0]; } if(!(flags & BT_6DOF_FLAGS_ERP_STOP)) { m_angularLimits[i].m_stopERP = info->erp; } row += get_limit_motor_info2(d6constraint->getRotationalLimitMotor(i), transA,transB,linVelA,linVelB,angVelA,angVelB, info,row,axis,1); } } return row; } void btGeneric6DofConstraint::updateRHS(btScalar timeStep) { (void)timeStep; } btVector3 btGeneric6DofConstraint::getAxis(int axis_index) const { return m_calculatedAxis[axis_index]; } btScalar btGeneric6DofConstraint::getRelativePivotPosition(int axisIndex) const { return m_calculatedLinearDiff[axisIndex]; } btScalar btGeneric6DofConstraint::getAngle(int axisIndex) const { return m_calculatedAxisAngleDiff[axisIndex]; } void btGeneric6DofConstraint::calcAnchorPos(void) { btScalar imA = m_rbA.getInvMass(); btScalar imB = m_rbB.getInvMass(); btScalar weight; if(imB == btScalar(0.0)) { weight = btScalar(1.0); } else { weight = imA / (imA + imB); } const btVector3& pA = m_calculatedTransformA.getOrigin(); const btVector3& pB = m_calculatedTransformB.getOrigin(); m_AnchorPos = pA * weight + pB * (btScalar(1.0) - weight); return; } void btGeneric6DofConstraint::calculateLinearInfo() { m_calculatedLinearDiff = m_calculatedTransformB.getOrigin() - m_calculatedTransformA.getOrigin(); m_calculatedLinearDiff = m_calculatedTransformA.getBasis().inverse() * m_calculatedLinearDiff; for(int i = 0; i < 3; i++) { m_linearLimits.m_currentLinearDiff[i] = m_calculatedLinearDiff[i]; m_linearLimits.testLimitValue(i, m_calculatedLinearDiff[i]); } } int btGeneric6DofConstraint::get_limit_motor_info2( btRotationalLimitMotor * limot, const btTransform& transA,const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB,const btVector3& angVelA,const btVector3& angVelB, btConstraintInfo2 *info, int row, btVector3& ax1, int rotational,int rotAllowed) { int srow = row * info->rowskip; int powered = limot->m_enableMotor; int limit = limot->m_currentLimit; if (powered || limit) { // if the joint is powered, or has joint limits, add in the extra row btScalar *J1 = rotational ? info->m_J1angularAxis : info->m_J1linearAxis; btScalar *J2 = rotational ? info->m_J2angularAxis : 0; J1[srow+0] = ax1[0]; J1[srow+1] = ax1[1]; J1[srow+2] = ax1[2]; if(rotational) { J2[srow+0] = -ax1[0]; J2[srow+1] = -ax1[1]; J2[srow+2] = -ax1[2]; } if((!rotational)) { if (m_useOffsetForConstraintFrame) { btVector3 tmpA, tmpB, relA, relB; // get vector from bodyB to frameB in WCS relB = m_calculatedTransformB.getOrigin() - transB.getOrigin(); // get its projection to constraint axis btVector3 projB = ax1 * relB.dot(ax1); // get vector directed from bodyB to constraint axis (and orthogonal to it) btVector3 orthoB = relB - projB; // same for bodyA relA = m_calculatedTransformA.getOrigin() - transA.getOrigin(); btVector3 projA = ax1 * relA.dot(ax1); btVector3 orthoA = relA - projA; // get desired offset between frames A and B along constraint axis btScalar desiredOffs = limot->m_currentPosition - limot->m_currentLimitError; // desired vector from projection of center of bodyA to projection of center of bodyB to constraint axis btVector3 totalDist = projA + ax1 * desiredOffs - projB; // get offset vectors relA and relB relA = orthoA + totalDist * m_factA; relB = orthoB - totalDist * m_factB; tmpA = relA.cross(ax1); tmpB = relB.cross(ax1); if(m_hasStaticBody && (!rotAllowed)) { tmpA *= m_factA; tmpB *= m_factB; } int i; for (i=0; i<3; i++) info->m_J1angularAxis[srow+i] = tmpA[i]; for (i=0; i<3; i++) info->m_J2angularAxis[srow+i] = -tmpB[i]; } else { btVector3 ltd; // Linear Torque Decoupling vector btVector3 c = m_calculatedTransformB.getOrigin() - transA.getOrigin(); ltd = c.cross(ax1); info->m_J1angularAxis[srow+0] = ltd[0]; info->m_J1angularAxis[srow+1] = ltd[1]; info->m_J1angularAxis[srow+2] = ltd[2]; c = m_calculatedTransformB.getOrigin() - transB.getOrigin(); ltd = -c.cross(ax1); info->m_J2angularAxis[srow+0] = ltd[0]; info->m_J2angularAxis[srow+1] = ltd[1]; info->m_J2angularAxis[srow+2] = ltd[2]; } } // if we're limited low and high simultaneously, the joint motor is // ineffective if (limit && (limot->m_loLimit == limot->m_hiLimit)) powered = 0; info->m_constraintError[srow] = btScalar(0.f); if (powered) { info->cfm[srow] = limot->m_normalCFM; if(!limit) { btScalar tag_vel = rotational ? limot->m_targetVelocity : -limot->m_targetVelocity; btScalar mot_fact = getMotorFactor( limot->m_currentPosition, limot->m_loLimit, limot->m_hiLimit, tag_vel, info->fps * limot->m_stopERP); info->m_constraintError[srow] += mot_fact * limot->m_targetVelocity; info->m_lowerLimit[srow] = -limot->m_maxMotorForce; info->m_upperLimit[srow] = limot->m_maxMotorForce; } } if(limit) { btScalar k = info->fps * limot->m_stopERP; if(!rotational) { info->m_constraintError[srow] += k * limot->m_currentLimitError; } else { info->m_constraintError[srow] += -k * limot->m_currentLimitError; } info->cfm[srow] = limot->m_stopCFM; if (limot->m_loLimit == limot->m_hiLimit) { // limited low and high simultaneously info->m_lowerLimit[srow] = -SIMD_INFINITY; info->m_upperLimit[srow] = SIMD_INFINITY; } else { if (limit == 1) { info->m_lowerLimit[srow] = 0; info->m_upperLimit[srow] = SIMD_INFINITY; } else { info->m_lowerLimit[srow] = -SIMD_INFINITY; info->m_upperLimit[srow] = 0; } // deal with bounce if (limot->m_bounce > 0) { // calculate joint velocity btScalar vel; if (rotational) { vel = angVelA.dot(ax1); //make sure that if no body -> angVelB == zero vec // if (body1) vel -= angVelB.dot(ax1); } else { vel = linVelA.dot(ax1); //make sure that if no body -> angVelB == zero vec // if (body1) vel -= linVelB.dot(ax1); } // only apply bounce if the velocity is incoming, and if the // resulting c[] exceeds what we already have. if (limit == 1) { if (vel < 0) { btScalar newc = -limot->m_bounce* vel; if (newc > info->m_constraintError[srow]) info->m_constraintError[srow] = newc; } } else { if (vel > 0) { btScalar newc = -limot->m_bounce * vel; if (newc < info->m_constraintError[srow]) info->m_constraintError[srow] = newc; } } } } } return 1; } else return 0; } ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). ///If no axis is provided, it uses the default axis for this constraint. void btGeneric6DofConstraint::setParam(int num, btScalar value, int axis) { if((axis >= 0) && (axis < 3)) { switch(num) { case BT_CONSTRAINT_STOP_ERP : m_linearLimits.m_stopERP[axis] = value; m_flags |= BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT); break; case BT_CONSTRAINT_STOP_CFM : m_linearLimits.m_stopCFM[axis] = value; m_flags |= BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT); break; case BT_CONSTRAINT_CFM : m_linearLimits.m_normalCFM[axis] = value; m_flags |= BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT); break; default : btAssertConstrParams(0); } } else if((axis >=3) && (axis < 6)) { switch(num) { case BT_CONSTRAINT_STOP_ERP : m_angularLimits[axis - 3].m_stopERP = value; m_flags |= BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT); break; case BT_CONSTRAINT_STOP_CFM : m_angularLimits[axis - 3].m_stopCFM = value; m_flags |= BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT); break; case BT_CONSTRAINT_CFM : m_angularLimits[axis - 3].m_normalCFM = value; m_flags |= BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT); break; default : btAssertConstrParams(0); } } else { btAssertConstrParams(0); } } ///return the local value of parameter btScalar btGeneric6DofConstraint::getParam(int num, int axis) const { btScalar retVal = 0; if((axis >= 0) && (axis < 3)) { switch(num) { case BT_CONSTRAINT_STOP_ERP : btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT))); retVal = m_linearLimits.m_stopERP[axis]; break; case BT_CONSTRAINT_STOP_CFM : btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT))); retVal = m_linearLimits.m_stopCFM[axis]; break; case BT_CONSTRAINT_CFM : btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT))); retVal = m_linearLimits.m_normalCFM[axis]; break; default : btAssertConstrParams(0); } } else if((axis >=3) && (axis < 6)) { switch(num) { case BT_CONSTRAINT_STOP_ERP : btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_ERP_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT))); retVal = m_angularLimits[axis - 3].m_stopERP; break; case BT_CONSTRAINT_STOP_CFM : btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_STOP << (axis * BT_6DOF_FLAGS_AXIS_SHIFT))); retVal = m_angularLimits[axis - 3].m_stopCFM; break; case BT_CONSTRAINT_CFM : btAssertConstrParams(m_flags & (BT_6DOF_FLAGS_CFM_NORM << (axis * BT_6DOF_FLAGS_AXIS_SHIFT))); retVal = m_angularLimits[axis - 3].m_normalCFM; break; default : btAssertConstrParams(0); } } else { btAssertConstrParams(0); } return retVal; } critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btContactConstraint.h0000644000175000017500000000445211344267705031366 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 CONTACT_CONSTRAINT_H #define CONTACT_CONSTRAINT_H #include "LinearMath/btVector3.h" #include "btJacobianEntry.h" #include "btTypedConstraint.h" #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" ///btContactConstraint can be automatically created to solve contact constraints using the unified btTypedConstraint interface ATTRIBUTE_ALIGNED16(class) btContactConstraint : public btTypedConstraint { protected: btPersistentManifold m_contactManifold; public: btContactConstraint(btPersistentManifold* contactManifold,btRigidBody& rbA,btRigidBody& rbB); void setContactManifold(btPersistentManifold* contactManifold); btPersistentManifold* getContactManifold() { return &m_contactManifold; } const btPersistentManifold* getContactManifold() const { return &m_contactManifold; } virtual ~btContactConstraint(); virtual void getInfo1 (btConstraintInfo1* info); virtual void getInfo2 (btConstraintInfo2* info); ///obsolete methods virtual void buildJacobian(); }; ///resolveSingleBilateral is an obsolete methods used for vehicle friction between two dynamic objects void resolveSingleBilateral(btRigidBody& body1, const btVector3& pos1, btRigidBody& body2, const btVector3& pos2, btScalar distance, const btVector3& normal,btScalar& impulse ,btScalar timeStep); #endif //CONTACT_CONSTRAINT_H critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btHingeConstraint.cpp0000644000175000017500000007553411344267705031371 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btHingeConstraint.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "LinearMath/btTransformUtil.h" #include "LinearMath/btMinMax.h" #include #include "btSolverBody.h" //#define HINGE_USE_OBSOLETE_SOLVER false #define HINGE_USE_OBSOLETE_SOLVER false #define HINGE_USE_FRAME_OFFSET true #ifndef __SPU__ btHingeConstraint::btHingeConstraint(btRigidBody& rbA,btRigidBody& rbB, const btVector3& pivotInA,const btVector3& pivotInB, btVector3& axisInA,btVector3& axisInB, bool useReferenceFrameA) :btTypedConstraint(HINGE_CONSTRAINT_TYPE, rbA,rbB), m_angularOnly(false), m_enableAngularMotor(false), m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER), m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET), m_useReferenceFrameA(useReferenceFrameA), m_flags(0) { m_rbAFrame.getOrigin() = pivotInA; // since no frame is given, assume this to be zero angle and just pick rb transform axis btVector3 rbAxisA1 = rbA.getCenterOfMassTransform().getBasis().getColumn(0); btVector3 rbAxisA2; btScalar projection = axisInA.dot(rbAxisA1); if (projection >= 1.0f - SIMD_EPSILON) { rbAxisA1 = -rbA.getCenterOfMassTransform().getBasis().getColumn(2); rbAxisA2 = rbA.getCenterOfMassTransform().getBasis().getColumn(1); } else if (projection <= -1.0f + SIMD_EPSILON) { rbAxisA1 = rbA.getCenterOfMassTransform().getBasis().getColumn(2); rbAxisA2 = rbA.getCenterOfMassTransform().getBasis().getColumn(1); } else { rbAxisA2 = axisInA.cross(rbAxisA1); rbAxisA1 = rbAxisA2.cross(axisInA); } m_rbAFrame.getBasis().setValue( rbAxisA1.getX(),rbAxisA2.getX(),axisInA.getX(), rbAxisA1.getY(),rbAxisA2.getY(),axisInA.getY(), rbAxisA1.getZ(),rbAxisA2.getZ(),axisInA.getZ() ); btQuaternion rotationArc = shortestArcQuat(axisInA,axisInB); btVector3 rbAxisB1 = quatRotate(rotationArc,rbAxisA1); btVector3 rbAxisB2 = axisInB.cross(rbAxisB1); m_rbBFrame.getOrigin() = pivotInB; m_rbBFrame.getBasis().setValue( rbAxisB1.getX(),rbAxisB2.getX(),axisInB.getX(), rbAxisB1.getY(),rbAxisB2.getY(),axisInB.getY(), rbAxisB1.getZ(),rbAxisB2.getZ(),axisInB.getZ() ); //start with free m_lowerLimit = btScalar(1.0f); m_upperLimit = btScalar(-1.0f); m_biasFactor = 0.3f; m_relaxationFactor = 1.0f; m_limitSoftness = 0.9f; m_solveLimit = false; m_referenceSign = m_useReferenceFrameA ? btScalar(-1.f) : btScalar(1.f); } btHingeConstraint::btHingeConstraint(btRigidBody& rbA,const btVector3& pivotInA,btVector3& axisInA, bool useReferenceFrameA) :btTypedConstraint(HINGE_CONSTRAINT_TYPE, rbA), m_angularOnly(false), m_enableAngularMotor(false), m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER), m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET), m_useReferenceFrameA(useReferenceFrameA), m_flags(0) { // since no frame is given, assume this to be zero angle and just pick rb transform axis // fixed axis in worldspace btVector3 rbAxisA1, rbAxisA2; btPlaneSpace1(axisInA, rbAxisA1, rbAxisA2); m_rbAFrame.getOrigin() = pivotInA; m_rbAFrame.getBasis().setValue( rbAxisA1.getX(),rbAxisA2.getX(),axisInA.getX(), rbAxisA1.getY(),rbAxisA2.getY(),axisInA.getY(), rbAxisA1.getZ(),rbAxisA2.getZ(),axisInA.getZ() ); btVector3 axisInB = rbA.getCenterOfMassTransform().getBasis() * axisInA; btQuaternion rotationArc = shortestArcQuat(axisInA,axisInB); btVector3 rbAxisB1 = quatRotate(rotationArc,rbAxisA1); btVector3 rbAxisB2 = axisInB.cross(rbAxisB1); m_rbBFrame.getOrigin() = rbA.getCenterOfMassTransform()(pivotInA); m_rbBFrame.getBasis().setValue( rbAxisB1.getX(),rbAxisB2.getX(),axisInB.getX(), rbAxisB1.getY(),rbAxisB2.getY(),axisInB.getY(), rbAxisB1.getZ(),rbAxisB2.getZ(),axisInB.getZ() ); //start with free m_lowerLimit = btScalar(1.0f); m_upperLimit = btScalar(-1.0f); m_biasFactor = 0.3f; m_relaxationFactor = 1.0f; m_limitSoftness = 0.9f; m_solveLimit = false; m_referenceSign = m_useReferenceFrameA ? btScalar(-1.f) : btScalar(1.f); } btHingeConstraint::btHingeConstraint(btRigidBody& rbA,btRigidBody& rbB, const btTransform& rbAFrame, const btTransform& rbBFrame, bool useReferenceFrameA) :btTypedConstraint(HINGE_CONSTRAINT_TYPE, rbA,rbB),m_rbAFrame(rbAFrame),m_rbBFrame(rbBFrame), m_angularOnly(false), m_enableAngularMotor(false), m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER), m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET), m_useReferenceFrameA(useReferenceFrameA), m_flags(0) { //start with free m_lowerLimit = btScalar(1.0f); m_upperLimit = btScalar(-1.0f); m_biasFactor = 0.3f; m_relaxationFactor = 1.0f; m_limitSoftness = 0.9f; m_solveLimit = false; m_referenceSign = m_useReferenceFrameA ? btScalar(-1.f) : btScalar(1.f); } btHingeConstraint::btHingeConstraint(btRigidBody& rbA, const btTransform& rbAFrame, bool useReferenceFrameA) :btTypedConstraint(HINGE_CONSTRAINT_TYPE, rbA),m_rbAFrame(rbAFrame),m_rbBFrame(rbAFrame), m_angularOnly(false), m_enableAngularMotor(false), m_useSolveConstraintObsolete(HINGE_USE_OBSOLETE_SOLVER), m_useOffsetForConstraintFrame(HINGE_USE_FRAME_OFFSET), m_useReferenceFrameA(useReferenceFrameA), m_flags(0) { ///not providing rigidbody B means implicitly using worldspace for body B m_rbBFrame.getOrigin() = m_rbA.getCenterOfMassTransform()(m_rbAFrame.getOrigin()); //start with free m_lowerLimit = btScalar(1.0f); m_upperLimit = btScalar(-1.0f); m_biasFactor = 0.3f; m_relaxationFactor = 1.0f; m_limitSoftness = 0.9f; m_solveLimit = false; m_referenceSign = m_useReferenceFrameA ? btScalar(-1.f) : btScalar(1.f); } void btHingeConstraint::buildJacobian() { if (m_useSolveConstraintObsolete) { m_appliedImpulse = btScalar(0.); m_accMotorImpulse = btScalar(0.); if (!m_angularOnly) { btVector3 pivotAInW = m_rbA.getCenterOfMassTransform()*m_rbAFrame.getOrigin(); btVector3 pivotBInW = m_rbB.getCenterOfMassTransform()*m_rbBFrame.getOrigin(); btVector3 relPos = pivotBInW - pivotAInW; btVector3 normal[3]; if (relPos.length2() > SIMD_EPSILON) { normal[0] = relPos.normalized(); } else { normal[0].setValue(btScalar(1.0),0,0); } btPlaneSpace1(normal[0], normal[1], normal[2]); for (int i=0;i<3;i++) { new (&m_jac[i]) btJacobianEntry( m_rbA.getCenterOfMassTransform().getBasis().transpose(), m_rbB.getCenterOfMassTransform().getBasis().transpose(), pivotAInW - m_rbA.getCenterOfMassPosition(), pivotBInW - m_rbB.getCenterOfMassPosition(), normal[i], m_rbA.getInvInertiaDiagLocal(), m_rbA.getInvMass(), m_rbB.getInvInertiaDiagLocal(), m_rbB.getInvMass()); } } //calculate two perpendicular jointAxis, orthogonal to hingeAxis //these two jointAxis require equal angular velocities for both bodies //this is unused for now, it's a todo btVector3 jointAxis0local; btVector3 jointAxis1local; btPlaneSpace1(m_rbAFrame.getBasis().getColumn(2),jointAxis0local,jointAxis1local); btVector3 jointAxis0 = getRigidBodyA().getCenterOfMassTransform().getBasis() * jointAxis0local; btVector3 jointAxis1 = getRigidBodyA().getCenterOfMassTransform().getBasis() * jointAxis1local; btVector3 hingeAxisWorld = getRigidBodyA().getCenterOfMassTransform().getBasis() * m_rbAFrame.getBasis().getColumn(2); new (&m_jacAng[0]) btJacobianEntry(jointAxis0, m_rbA.getCenterOfMassTransform().getBasis().transpose(), m_rbB.getCenterOfMassTransform().getBasis().transpose(), m_rbA.getInvInertiaDiagLocal(), m_rbB.getInvInertiaDiagLocal()); new (&m_jacAng[1]) btJacobianEntry(jointAxis1, m_rbA.getCenterOfMassTransform().getBasis().transpose(), m_rbB.getCenterOfMassTransform().getBasis().transpose(), m_rbA.getInvInertiaDiagLocal(), m_rbB.getInvInertiaDiagLocal()); new (&m_jacAng[2]) btJacobianEntry(hingeAxisWorld, m_rbA.getCenterOfMassTransform().getBasis().transpose(), m_rbB.getCenterOfMassTransform().getBasis().transpose(), m_rbA.getInvInertiaDiagLocal(), m_rbB.getInvInertiaDiagLocal()); // clear accumulator m_accLimitImpulse = btScalar(0.); // test angular limit testLimit(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); //Compute K = J*W*J' for hinge axis btVector3 axisA = getRigidBodyA().getCenterOfMassTransform().getBasis() * m_rbAFrame.getBasis().getColumn(2); m_kHinge = 1.0f / (getRigidBodyA().computeAngularImpulseDenominator(axisA) + getRigidBodyB().computeAngularImpulseDenominator(axisA)); } } #endif //__SPU__ void btHingeConstraint::getInfo1(btConstraintInfo1* info) { if (m_useSolveConstraintObsolete) { info->m_numConstraintRows = 0; info->nub = 0; } else { info->m_numConstraintRows = 5; // Fixed 3 linear + 2 angular info->nub = 1; //always add the row, to avoid computation (data is not available yet) //prepare constraint testLimit(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); if(getSolveLimit() || getEnableAngularMotor()) { info->m_numConstraintRows++; // limit 3rd anguar as well info->nub--; } } } void btHingeConstraint::getInfo1NonVirtual(btConstraintInfo1* info) { if (m_useSolveConstraintObsolete) { info->m_numConstraintRows = 0; info->nub = 0; } else { //always add the 'limit' row, to avoid computation (data is not available yet) info->m_numConstraintRows = 6; // Fixed 3 linear + 2 angular info->nub = 0; } } void btHingeConstraint::getInfo2 (btConstraintInfo2* info) { if(m_useOffsetForConstraintFrame) { getInfo2InternalUsingFrameOffset(info, m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(),m_rbA.getAngularVelocity(),m_rbB.getAngularVelocity()); } else { getInfo2Internal(info, m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(),m_rbA.getAngularVelocity(),m_rbB.getAngularVelocity()); } } void btHingeConstraint::getInfo2NonVirtual (btConstraintInfo2* info,const btTransform& transA,const btTransform& transB,const btVector3& angVelA,const btVector3& angVelB) { ///the regular (virtual) implementation getInfo2 already performs 'testLimit' during getInfo1, so we need to do it now testLimit(transA,transB); getInfo2Internal(info,transA,transB,angVelA,angVelB); } void btHingeConstraint::getInfo2Internal(btConstraintInfo2* info, const btTransform& transA,const btTransform& transB,const btVector3& angVelA,const btVector3& angVelB) { btAssert(!m_useSolveConstraintObsolete); int i, skip = info->rowskip; // transforms in world space btTransform trA = transA*m_rbAFrame; btTransform trB = transB*m_rbBFrame; // pivot point btVector3 pivotAInW = trA.getOrigin(); btVector3 pivotBInW = trB.getOrigin(); #if 0 if (0) { for (i=0;i<6;i++) { info->m_J1linearAxis[i*skip]=0; info->m_J1linearAxis[i*skip+1]=0; info->m_J1linearAxis[i*skip+2]=0; info->m_J1angularAxis[i*skip]=0; info->m_J1angularAxis[i*skip+1]=0; info->m_J1angularAxis[i*skip+2]=0; info->m_J2angularAxis[i*skip]=0; info->m_J2angularAxis[i*skip+1]=0; info->m_J2angularAxis[i*skip+2]=0; info->m_constraintError[i*skip]=0.f; } } #endif //#if 0 // linear (all fixed) info->m_J1linearAxis[0] = 1; info->m_J1linearAxis[skip + 1] = 1; info->m_J1linearAxis[2 * skip + 2] = 1; btVector3 a1 = pivotAInW - transA.getOrigin(); { btVector3* angular0 = (btVector3*)(info->m_J1angularAxis); btVector3* angular1 = (btVector3*)(info->m_J1angularAxis + skip); btVector3* angular2 = (btVector3*)(info->m_J1angularAxis + 2 * skip); btVector3 a1neg = -a1; a1neg.getSkewSymmetricMatrix(angular0,angular1,angular2); } btVector3 a2 = pivotBInW - transB.getOrigin(); { btVector3* angular0 = (btVector3*)(info->m_J2angularAxis); btVector3* angular1 = (btVector3*)(info->m_J2angularAxis + skip); btVector3* angular2 = (btVector3*)(info->m_J2angularAxis + 2 * skip); a2.getSkewSymmetricMatrix(angular0,angular1,angular2); } // linear RHS btScalar k = info->fps * info->erp; for(i = 0; i < 3; i++) { info->m_constraintError[i * skip] = k * (pivotBInW[i] - pivotAInW[i]); } // make rotations around X and Y equal // the hinge axis should be the only unconstrained // rotational axis, the angular velocity of the two bodies perpendicular to // the hinge axis should be equal. thus the constraint equations are // p*w1 - p*w2 = 0 // q*w1 - q*w2 = 0 // where p and q are unit vectors normal to the hinge axis, and w1 and w2 // are the angular velocity vectors of the two bodies. // get hinge axis (Z) btVector3 ax1 = trA.getBasis().getColumn(2); // get 2 orthos to hinge axis (X, Y) btVector3 p = trA.getBasis().getColumn(0); btVector3 q = trA.getBasis().getColumn(1); // set the two hinge angular rows int s3 = 3 * info->rowskip; int s4 = 4 * info->rowskip; info->m_J1angularAxis[s3 + 0] = p[0]; info->m_J1angularAxis[s3 + 1] = p[1]; info->m_J1angularAxis[s3 + 2] = p[2]; info->m_J1angularAxis[s4 + 0] = q[0]; info->m_J1angularAxis[s4 + 1] = q[1]; info->m_J1angularAxis[s4 + 2] = q[2]; info->m_J2angularAxis[s3 + 0] = -p[0]; info->m_J2angularAxis[s3 + 1] = -p[1]; info->m_J2angularAxis[s3 + 2] = -p[2]; info->m_J2angularAxis[s4 + 0] = -q[0]; info->m_J2angularAxis[s4 + 1] = -q[1]; info->m_J2angularAxis[s4 + 2] = -q[2]; // compute the right hand side of the constraint equation. set relative // body velocities along p and q to bring the hinge back into alignment. // if ax1,ax2 are the unit length hinge axes as computed from body1 and // body2, we need to rotate both bodies along the axis u = (ax1 x ax2). // if `theta' is the angle between ax1 and ax2, we need an angular velocity // along u to cover angle erp*theta in one step : // |angular_velocity| = angle/time = erp*theta / stepsize // = (erp*fps) * theta // angular_velocity = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2| // = (erp*fps) * theta * (ax1 x ax2) / sin(theta) // ...as ax1 and ax2 are unit length. if theta is smallish, // theta ~= sin(theta), so // angular_velocity = (erp*fps) * (ax1 x ax2) // ax1 x ax2 is in the plane space of ax1, so we project the angular // velocity to p and q to find the right hand side. btVector3 ax2 = trB.getBasis().getColumn(2); btVector3 u = ax1.cross(ax2); info->m_constraintError[s3] = k * u.dot(p); info->m_constraintError[s4] = k * u.dot(q); // check angular limits int nrow = 4; // last filled row int srow; btScalar limit_err = btScalar(0.0); int limit = 0; if(getSolveLimit()) { limit_err = m_correction * m_referenceSign; limit = (limit_err > btScalar(0.0)) ? 1 : 2; } // if the hinge has joint limits or motor, add in the extra row int powered = 0; if(getEnableAngularMotor()) { powered = 1; } if(limit || powered) { nrow++; srow = nrow * info->rowskip; info->m_J1angularAxis[srow+0] = ax1[0]; info->m_J1angularAxis[srow+1] = ax1[1]; info->m_J1angularAxis[srow+2] = ax1[2]; info->m_J2angularAxis[srow+0] = -ax1[0]; info->m_J2angularAxis[srow+1] = -ax1[1]; info->m_J2angularAxis[srow+2] = -ax1[2]; btScalar lostop = getLowerLimit(); btScalar histop = getUpperLimit(); if(limit && (lostop == histop)) { // the joint motor is ineffective powered = 0; } info->m_constraintError[srow] = btScalar(0.0f); btScalar currERP = (m_flags & BT_HINGE_FLAGS_ERP_STOP) ? m_stopERP : info->erp; if(powered) { if(m_flags & BT_HINGE_FLAGS_CFM_NORM) { info->cfm[srow] = m_normalCFM; } btScalar mot_fact = getMotorFactor(m_hingeAngle, lostop, histop, m_motorTargetVelocity, info->fps * currERP); info->m_constraintError[srow] += mot_fact * m_motorTargetVelocity * m_referenceSign; info->m_lowerLimit[srow] = - m_maxMotorImpulse; info->m_upperLimit[srow] = m_maxMotorImpulse; } if(limit) { k = info->fps * currERP; info->m_constraintError[srow] += k * limit_err; if(m_flags & BT_HINGE_FLAGS_CFM_STOP) { info->cfm[srow] = m_stopCFM; } if(lostop == histop) { // limited low and high simultaneously info->m_lowerLimit[srow] = -SIMD_INFINITY; info->m_upperLimit[srow] = SIMD_INFINITY; } else if(limit == 1) { // low limit info->m_lowerLimit[srow] = 0; info->m_upperLimit[srow] = SIMD_INFINITY; } else { // high limit info->m_lowerLimit[srow] = -SIMD_INFINITY; info->m_upperLimit[srow] = 0; } // bounce (we'll use slider parameter abs(1.0 - m_dampingLimAng) for that) btScalar bounce = m_relaxationFactor; if(bounce > btScalar(0.0)) { btScalar vel = angVelA.dot(ax1); vel -= angVelB.dot(ax1); // only apply bounce if the velocity is incoming, and if the // resulting c[] exceeds what we already have. if(limit == 1) { // low limit if(vel < 0) { btScalar newc = -bounce * vel; if(newc > info->m_constraintError[srow]) { info->m_constraintError[srow] = newc; } } } else { // high limit - all those computations are reversed if(vel > 0) { btScalar newc = -bounce * vel; if(newc < info->m_constraintError[srow]) { info->m_constraintError[srow] = newc; } } } } info->m_constraintError[srow] *= m_biasFactor; } // if(limit) } // if angular limit or powered } void btHingeConstraint::updateRHS(btScalar timeStep) { (void)timeStep; } btScalar btHingeConstraint::getHingeAngle() { return getHingeAngle(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); } btScalar btHingeConstraint::getHingeAngle(const btTransform& transA,const btTransform& transB) { const btVector3 refAxis0 = transA.getBasis() * m_rbAFrame.getBasis().getColumn(0); const btVector3 refAxis1 = transA.getBasis() * m_rbAFrame.getBasis().getColumn(1); const btVector3 swingAxis = transB.getBasis() * m_rbBFrame.getBasis().getColumn(1); // btScalar angle = btAtan2Fast(swingAxis.dot(refAxis0), swingAxis.dot(refAxis1)); btScalar angle = btAtan2(swingAxis.dot(refAxis0), swingAxis.dot(refAxis1)); return m_referenceSign * angle; } #if 0 void btHingeConstraint::testLimit() { // Compute limit information m_hingeAngle = getHingeAngle(); m_correction = btScalar(0.); m_limitSign = btScalar(0.); m_solveLimit = false; if (m_lowerLimit <= m_upperLimit) { if (m_hingeAngle <= m_lowerLimit) { m_correction = (m_lowerLimit - m_hingeAngle); m_limitSign = 1.0f; m_solveLimit = true; } else if (m_hingeAngle >= m_upperLimit) { m_correction = m_upperLimit - m_hingeAngle; m_limitSign = -1.0f; m_solveLimit = true; } } return; } #else void btHingeConstraint::testLimit(const btTransform& transA,const btTransform& transB) { // Compute limit information m_hingeAngle = getHingeAngle(transA,transB); m_correction = btScalar(0.); m_limitSign = btScalar(0.); m_solveLimit = false; if (m_lowerLimit <= m_upperLimit) { m_hingeAngle = btAdjustAngleToLimits(m_hingeAngle, m_lowerLimit, m_upperLimit); if (m_hingeAngle <= m_lowerLimit) { m_correction = (m_lowerLimit - m_hingeAngle); m_limitSign = 1.0f; m_solveLimit = true; } else if (m_hingeAngle >= m_upperLimit) { m_correction = m_upperLimit - m_hingeAngle; m_limitSign = -1.0f; m_solveLimit = true; } } return; } #endif static btVector3 vHinge(0, 0, btScalar(1)); void btHingeConstraint::setMotorTarget(const btQuaternion& qAinB, btScalar dt) { // convert target from body to constraint space btQuaternion qConstraint = m_rbBFrame.getRotation().inverse() * qAinB * m_rbAFrame.getRotation(); qConstraint.normalize(); // extract "pure" hinge component btVector3 vNoHinge = quatRotate(qConstraint, vHinge); vNoHinge.normalize(); btQuaternion qNoHinge = shortestArcQuat(vHinge, vNoHinge); btQuaternion qHinge = qNoHinge.inverse() * qConstraint; qHinge.normalize(); // compute angular target, clamped to limits btScalar targetAngle = qHinge.getAngle(); if (targetAngle > SIMD_PI) // long way around. flip quat and recalculate. { qHinge = operator-(qHinge); targetAngle = qHinge.getAngle(); } if (qHinge.getZ() < 0) targetAngle = -targetAngle; setMotorTarget(targetAngle, dt); } void btHingeConstraint::setMotorTarget(btScalar targetAngle, btScalar dt) { if (m_lowerLimit < m_upperLimit) { if (targetAngle < m_lowerLimit) targetAngle = m_lowerLimit; else if (targetAngle > m_upperLimit) targetAngle = m_upperLimit; } // compute angular velocity btScalar curAngle = getHingeAngle(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); btScalar dAngle = targetAngle - curAngle; m_motorTargetVelocity = dAngle / dt; } void btHingeConstraint::getInfo2InternalUsingFrameOffset(btConstraintInfo2* info, const btTransform& transA,const btTransform& transB,const btVector3& angVelA,const btVector3& angVelB) { btAssert(!m_useSolveConstraintObsolete); int i, s = info->rowskip; // transforms in world space btTransform trA = transA*m_rbAFrame; btTransform trB = transB*m_rbBFrame; // pivot point btVector3 pivotAInW = trA.getOrigin(); btVector3 pivotBInW = trB.getOrigin(); #if 1 // difference between frames in WCS btVector3 ofs = trB.getOrigin() - trA.getOrigin(); // now get weight factors depending on masses btScalar miA = getRigidBodyA().getInvMass(); btScalar miB = getRigidBodyB().getInvMass(); bool hasStaticBody = (miA < SIMD_EPSILON) || (miB < SIMD_EPSILON); btScalar miS = miA + miB; btScalar factA, factB; if(miS > btScalar(0.f)) { factA = miB / miS; } else { factA = btScalar(0.5f); } factB = btScalar(1.0f) - factA; // get the desired direction of hinge axis // as weighted sum of Z-orthos of frameA and frameB in WCS btVector3 ax1A = trA.getBasis().getColumn(2); btVector3 ax1B = trB.getBasis().getColumn(2); btVector3 ax1 = ax1A * factA + ax1B * factB; ax1.normalize(); // fill first 3 rows // we want: velA + wA x relA == velB + wB x relB btTransform bodyA_trans = transA; btTransform bodyB_trans = transB; int s0 = 0; int s1 = s; int s2 = s * 2; int nrow = 2; // last filled row btVector3 tmpA, tmpB, relA, relB, p, q; // get vector from bodyB to frameB in WCS relB = trB.getOrigin() - bodyB_trans.getOrigin(); // get its projection to hinge axis btVector3 projB = ax1 * relB.dot(ax1); // get vector directed from bodyB to hinge axis (and orthogonal to it) btVector3 orthoB = relB - projB; // same for bodyA relA = trA.getOrigin() - bodyA_trans.getOrigin(); btVector3 projA = ax1 * relA.dot(ax1); btVector3 orthoA = relA - projA; btVector3 totalDist = projA - projB; // get offset vectors relA and relB relA = orthoA + totalDist * factA; relB = orthoB - totalDist * factB; // now choose average ortho to hinge axis p = orthoB * factA + orthoA * factB; btScalar len2 = p.length2(); if(len2 > SIMD_EPSILON) { p /= btSqrt(len2); } else { p = trA.getBasis().getColumn(1); } // make one more ortho q = ax1.cross(p); // fill three rows tmpA = relA.cross(p); tmpB = relB.cross(p); for (i=0; i<3; i++) info->m_J1angularAxis[s0+i] = tmpA[i]; for (i=0; i<3; i++) info->m_J2angularAxis[s0+i] = -tmpB[i]; tmpA = relA.cross(q); tmpB = relB.cross(q); if(hasStaticBody && getSolveLimit()) { // to make constraint between static and dynamic objects more rigid // remove wA (or wB) from equation if angular limit is hit tmpB *= factB; tmpA *= factA; } for (i=0; i<3; i++) info->m_J1angularAxis[s1+i] = tmpA[i]; for (i=0; i<3; i++) info->m_J2angularAxis[s1+i] = -tmpB[i]; tmpA = relA.cross(ax1); tmpB = relB.cross(ax1); if(hasStaticBody) { // to make constraint between static and dynamic objects more rigid // remove wA (or wB) from equation tmpB *= factB; tmpA *= factA; } for (i=0; i<3; i++) info->m_J1angularAxis[s2+i] = tmpA[i]; for (i=0; i<3; i++) info->m_J2angularAxis[s2+i] = -tmpB[i]; for (i=0; i<3; i++) info->m_J1linearAxis[s0+i] = p[i]; for (i=0; i<3; i++) info->m_J1linearAxis[s1+i] = q[i]; for (i=0; i<3; i++) info->m_J1linearAxis[s2+i] = ax1[i]; // compute three elements of right hand side btScalar k = info->fps * info->erp; btScalar rhs = k * p.dot(ofs); info->m_constraintError[s0] = rhs; rhs = k * q.dot(ofs); info->m_constraintError[s1] = rhs; rhs = k * ax1.dot(ofs); info->m_constraintError[s2] = rhs; // the hinge axis should be the only unconstrained // rotational axis, the angular velocity of the two bodies perpendicular to // the hinge axis should be equal. thus the constraint equations are // p*w1 - p*w2 = 0 // q*w1 - q*w2 = 0 // where p and q are unit vectors normal to the hinge axis, and w1 and w2 // are the angular velocity vectors of the two bodies. int s3 = 3 * s; int s4 = 4 * s; info->m_J1angularAxis[s3 + 0] = p[0]; info->m_J1angularAxis[s3 + 1] = p[1]; info->m_J1angularAxis[s3 + 2] = p[2]; info->m_J1angularAxis[s4 + 0] = q[0]; info->m_J1angularAxis[s4 + 1] = q[1]; info->m_J1angularAxis[s4 + 2] = q[2]; info->m_J2angularAxis[s3 + 0] = -p[0]; info->m_J2angularAxis[s3 + 1] = -p[1]; info->m_J2angularAxis[s3 + 2] = -p[2]; info->m_J2angularAxis[s4 + 0] = -q[0]; info->m_J2angularAxis[s4 + 1] = -q[1]; info->m_J2angularAxis[s4 + 2] = -q[2]; // compute the right hand side of the constraint equation. set relative // body velocities along p and q to bring the hinge back into alignment. // if ax1A,ax1B are the unit length hinge axes as computed from bodyA and // bodyB, we need to rotate both bodies along the axis u = (ax1 x ax2). // if "theta" is the angle between ax1 and ax2, we need an angular velocity // along u to cover angle erp*theta in one step : // |angular_velocity| = angle/time = erp*theta / stepsize // = (erp*fps) * theta // angular_velocity = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2| // = (erp*fps) * theta * (ax1 x ax2) / sin(theta) // ...as ax1 and ax2 are unit length. if theta is smallish, // theta ~= sin(theta), so // angular_velocity = (erp*fps) * (ax1 x ax2) // ax1 x ax2 is in the plane space of ax1, so we project the angular // velocity to p and q to find the right hand side. k = info->fps * info->erp; btVector3 u = ax1A.cross(ax1B); info->m_constraintError[s3] = k * u.dot(p); info->m_constraintError[s4] = k * u.dot(q); #endif // check angular limits nrow = 4; // last filled row int srow; btScalar limit_err = btScalar(0.0); int limit = 0; if(getSolveLimit()) { limit_err = m_correction * m_referenceSign; limit = (limit_err > btScalar(0.0)) ? 1 : 2; } // if the hinge has joint limits or motor, add in the extra row int powered = 0; if(getEnableAngularMotor()) { powered = 1; } if(limit || powered) { nrow++; srow = nrow * info->rowskip; info->m_J1angularAxis[srow+0] = ax1[0]; info->m_J1angularAxis[srow+1] = ax1[1]; info->m_J1angularAxis[srow+2] = ax1[2]; info->m_J2angularAxis[srow+0] = -ax1[0]; info->m_J2angularAxis[srow+1] = -ax1[1]; info->m_J2angularAxis[srow+2] = -ax1[2]; btScalar lostop = getLowerLimit(); btScalar histop = getUpperLimit(); if(limit && (lostop == histop)) { // the joint motor is ineffective powered = 0; } info->m_constraintError[srow] = btScalar(0.0f); btScalar currERP = (m_flags & BT_HINGE_FLAGS_ERP_STOP) ? m_stopERP : info->erp; if(powered) { if(m_flags & BT_HINGE_FLAGS_CFM_NORM) { info->cfm[srow] = m_normalCFM; } btScalar mot_fact = getMotorFactor(m_hingeAngle, lostop, histop, m_motorTargetVelocity, info->fps * currERP); info->m_constraintError[srow] += mot_fact * m_motorTargetVelocity * m_referenceSign; info->m_lowerLimit[srow] = - m_maxMotorImpulse; info->m_upperLimit[srow] = m_maxMotorImpulse; } if(limit) { k = info->fps * currERP; info->m_constraintError[srow] += k * limit_err; if(m_flags & BT_HINGE_FLAGS_CFM_STOP) { info->cfm[srow] = m_stopCFM; } if(lostop == histop) { // limited low and high simultaneously info->m_lowerLimit[srow] = -SIMD_INFINITY; info->m_upperLimit[srow] = SIMD_INFINITY; } else if(limit == 1) { // low limit info->m_lowerLimit[srow] = 0; info->m_upperLimit[srow] = SIMD_INFINITY; } else { // high limit info->m_lowerLimit[srow] = -SIMD_INFINITY; info->m_upperLimit[srow] = 0; } // bounce (we'll use slider parameter abs(1.0 - m_dampingLimAng) for that) btScalar bounce = m_relaxationFactor; if(bounce > btScalar(0.0)) { btScalar vel = angVelA.dot(ax1); vel -= angVelB.dot(ax1); // only apply bounce if the velocity is incoming, and if the // resulting c[] exceeds what we already have. if(limit == 1) { // low limit if(vel < 0) { btScalar newc = -bounce * vel; if(newc > info->m_constraintError[srow]) { info->m_constraintError[srow] = newc; } } } else { // high limit - all those computations are reversed if(vel > 0) { btScalar newc = -bounce * vel; if(newc < info->m_constraintError[srow]) { info->m_constraintError[srow] = newc; } } } } info->m_constraintError[srow] *= m_biasFactor; } // if(limit) } // if angular limit or powered } ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). ///If no axis is provided, it uses the default axis for this constraint. void btHingeConstraint::setParam(int num, btScalar value, int axis) { if((axis == -1) || (axis == 5)) { switch(num) { case BT_CONSTRAINT_STOP_ERP : m_stopERP = value; m_flags |= BT_HINGE_FLAGS_ERP_STOP; break; case BT_CONSTRAINT_STOP_CFM : m_stopCFM = value; m_flags |= BT_HINGE_FLAGS_CFM_STOP; break; case BT_CONSTRAINT_CFM : m_normalCFM = value; m_flags |= BT_HINGE_FLAGS_CFM_NORM; break; default : btAssertConstrParams(0); } } else { btAssertConstrParams(0); } } ///return the local value of parameter btScalar btHingeConstraint::getParam(int num, int axis) const { btScalar retVal = 0; if((axis == -1) || (axis == 5)) { switch(num) { case BT_CONSTRAINT_STOP_ERP : btAssertConstrParams(m_flags & BT_HINGE_FLAGS_ERP_STOP); retVal = m_stopERP; break; case BT_CONSTRAINT_STOP_CFM : btAssertConstrParams(m_flags & BT_HINGE_FLAGS_CFM_STOP); retVal = m_stopCFM; break; case BT_CONSTRAINT_CFM : btAssertConstrParams(m_flags & BT_HINGE_FLAGS_CFM_NORM); retVal = m_normalCFM; break; default : btAssertConstrParams(0); } } else { btAssertConstrParams(0); } return retVal; } critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btSliderConstraint.cpp0000755000175000017500000006115111344267705031552 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ /* Added by Roman Ponomarev (rponom@gmail.com) April 04, 2008 */ #include "btSliderConstraint.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "LinearMath/btTransformUtil.h" #include #define USE_OFFSET_FOR_CONSTANT_FRAME true void btSliderConstraint::initParams() { m_lowerLinLimit = btScalar(1.0); m_upperLinLimit = btScalar(-1.0); m_lowerAngLimit = btScalar(0.); m_upperAngLimit = btScalar(0.); m_softnessDirLin = SLIDER_CONSTRAINT_DEF_SOFTNESS; m_restitutionDirLin = SLIDER_CONSTRAINT_DEF_RESTITUTION; m_dampingDirLin = btScalar(0.); m_cfmDirLin = SLIDER_CONSTRAINT_DEF_CFM; m_softnessDirAng = SLIDER_CONSTRAINT_DEF_SOFTNESS; m_restitutionDirAng = SLIDER_CONSTRAINT_DEF_RESTITUTION; m_dampingDirAng = btScalar(0.); m_cfmDirAng = SLIDER_CONSTRAINT_DEF_CFM; m_softnessOrthoLin = SLIDER_CONSTRAINT_DEF_SOFTNESS; m_restitutionOrthoLin = SLIDER_CONSTRAINT_DEF_RESTITUTION; m_dampingOrthoLin = SLIDER_CONSTRAINT_DEF_DAMPING; m_cfmOrthoLin = SLIDER_CONSTRAINT_DEF_CFM; m_softnessOrthoAng = SLIDER_CONSTRAINT_DEF_SOFTNESS; m_restitutionOrthoAng = SLIDER_CONSTRAINT_DEF_RESTITUTION; m_dampingOrthoAng = SLIDER_CONSTRAINT_DEF_DAMPING; m_cfmOrthoAng = SLIDER_CONSTRAINT_DEF_CFM; m_softnessLimLin = SLIDER_CONSTRAINT_DEF_SOFTNESS; m_restitutionLimLin = SLIDER_CONSTRAINT_DEF_RESTITUTION; m_dampingLimLin = SLIDER_CONSTRAINT_DEF_DAMPING; m_cfmLimLin = SLIDER_CONSTRAINT_DEF_CFM; m_softnessLimAng = SLIDER_CONSTRAINT_DEF_SOFTNESS; m_restitutionLimAng = SLIDER_CONSTRAINT_DEF_RESTITUTION; m_dampingLimAng = SLIDER_CONSTRAINT_DEF_DAMPING; m_cfmLimAng = SLIDER_CONSTRAINT_DEF_CFM; m_poweredLinMotor = false; m_targetLinMotorVelocity = btScalar(0.); m_maxLinMotorForce = btScalar(0.); m_accumulatedLinMotorImpulse = btScalar(0.0); m_poweredAngMotor = false; m_targetAngMotorVelocity = btScalar(0.); m_maxAngMotorForce = btScalar(0.); m_accumulatedAngMotorImpulse = btScalar(0.0); m_flags = 0; m_flags = 0; m_useOffsetForConstraintFrame = USE_OFFSET_FOR_CONSTANT_FRAME; calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); } btSliderConstraint::btSliderConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB, bool useLinearReferenceFrameA) : btTypedConstraint(SLIDER_CONSTRAINT_TYPE, rbA, rbB), m_useSolveConstraintObsolete(false), m_frameInA(frameInA), m_frameInB(frameInB), m_useLinearReferenceFrameA(useLinearReferenceFrameA) { initParams(); } btSliderConstraint::btSliderConstraint(btRigidBody& rbB, const btTransform& frameInB, bool useLinearReferenceFrameA) : btTypedConstraint(SLIDER_CONSTRAINT_TYPE, getFixedBody(), rbB), m_useSolveConstraintObsolete(false), m_frameInB(frameInB), m_useLinearReferenceFrameA(useLinearReferenceFrameA) { ///not providing rigidbody A means implicitly using worldspace for body A m_frameInA = rbB.getCenterOfMassTransform() * m_frameInB; // m_frameInA.getOrigin() = m_rbA.getCenterOfMassTransform()(m_frameInA.getOrigin()); initParams(); } void btSliderConstraint::getInfo1(btConstraintInfo1* info) { if (m_useSolveConstraintObsolete) { info->m_numConstraintRows = 0; info->nub = 0; } else { info->m_numConstraintRows = 4; // Fixed 2 linear + 2 angular info->nub = 2; //prepare constraint calculateTransforms(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); testAngLimits(); testLinLimits(); if(getSolveLinLimit() || getPoweredLinMotor()) { info->m_numConstraintRows++; // limit 3rd linear as well info->nub--; } if(getSolveAngLimit() || getPoweredAngMotor()) { info->m_numConstraintRows++; // limit 3rd angular as well info->nub--; } } } void btSliderConstraint::getInfo1NonVirtual(btConstraintInfo1* info) { info->m_numConstraintRows = 6; // Fixed 2 linear + 2 angular + 1 limit (even if not used) info->nub = 0; } void btSliderConstraint::getInfo2(btConstraintInfo2* info) { getInfo2NonVirtual(info,m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(), m_rbA.getLinearVelocity(),m_rbB.getLinearVelocity(), m_rbA.getInvMass(),m_rbB.getInvMass()); } void btSliderConstraint::calculateTransforms(const btTransform& transA,const btTransform& transB) { if(m_useLinearReferenceFrameA || (!m_useSolveConstraintObsolete)) { m_calculatedTransformA = transA * m_frameInA; m_calculatedTransformB = transB * m_frameInB; } else { m_calculatedTransformA = transB * m_frameInB; m_calculatedTransformB = transA * m_frameInA; } m_realPivotAInW = m_calculatedTransformA.getOrigin(); m_realPivotBInW = m_calculatedTransformB.getOrigin(); m_sliderAxis = m_calculatedTransformA.getBasis().getColumn(0); // along X if(m_useLinearReferenceFrameA || m_useSolveConstraintObsolete) { m_delta = m_realPivotBInW - m_realPivotAInW; } else { m_delta = m_realPivotAInW - m_realPivotBInW; } m_projPivotInW = m_realPivotAInW + m_sliderAxis.dot(m_delta) * m_sliderAxis; btVector3 normalWorld; int i; //linear part for(i = 0; i < 3; i++) { normalWorld = m_calculatedTransformA.getBasis().getColumn(i); m_depth[i] = m_delta.dot(normalWorld); } } void btSliderConstraint::testLinLimits(void) { m_solveLinLim = false; m_linPos = m_depth[0]; if(m_lowerLinLimit <= m_upperLinLimit) { if(m_depth[0] > m_upperLinLimit) { m_depth[0] -= m_upperLinLimit; m_solveLinLim = true; } else if(m_depth[0] < m_lowerLinLimit) { m_depth[0] -= m_lowerLinLimit; m_solveLinLim = true; } else { m_depth[0] = btScalar(0.); } } else { m_depth[0] = btScalar(0.); } } void btSliderConstraint::testAngLimits(void) { m_angDepth = btScalar(0.); m_solveAngLim = false; if(m_lowerAngLimit <= m_upperAngLimit) { const btVector3 axisA0 = m_calculatedTransformA.getBasis().getColumn(1); const btVector3 axisA1 = m_calculatedTransformA.getBasis().getColumn(2); const btVector3 axisB0 = m_calculatedTransformB.getBasis().getColumn(1); // btScalar rot = btAtan2Fast(axisB0.dot(axisA1), axisB0.dot(axisA0)); btScalar rot = btAtan2(axisB0.dot(axisA1), axisB0.dot(axisA0)); rot = btAdjustAngleToLimits(rot, m_lowerAngLimit, m_upperAngLimit); m_angPos = rot; if(rot < m_lowerAngLimit) { m_angDepth = rot - m_lowerAngLimit; m_solveAngLim = true; } else if(rot > m_upperAngLimit) { m_angDepth = rot - m_upperAngLimit; m_solveAngLim = true; } } } btVector3 btSliderConstraint::getAncorInA(void) { btVector3 ancorInA; ancorInA = m_realPivotAInW + (m_lowerLinLimit + m_upperLinLimit) * btScalar(0.5) * m_sliderAxis; ancorInA = m_rbA.getCenterOfMassTransform().inverse() * ancorInA; return ancorInA; } btVector3 btSliderConstraint::getAncorInB(void) { btVector3 ancorInB; ancorInB = m_frameInB.getOrigin(); return ancorInB; } void btSliderConstraint::getInfo2NonVirtual(btConstraintInfo2* info, const btTransform& transA,const btTransform& transB, const btVector3& linVelA,const btVector3& linVelB, btScalar rbAinvMass,btScalar rbBinvMass ) { const btTransform& trA = getCalculatedTransformA(); const btTransform& trB = getCalculatedTransformB(); btAssert(!m_useSolveConstraintObsolete); int i, s = info->rowskip; btScalar signFact = m_useLinearReferenceFrameA ? btScalar(1.0f) : btScalar(-1.0f); // difference between frames in WCS btVector3 ofs = trB.getOrigin() - trA.getOrigin(); // now get weight factors depending on masses btScalar miA = rbAinvMass; btScalar miB = rbBinvMass; bool hasStaticBody = (miA < SIMD_EPSILON) || (miB < SIMD_EPSILON); btScalar miS = miA + miB; btScalar factA, factB; if(miS > btScalar(0.f)) { factA = miB / miS; } else { factA = btScalar(0.5f); } factB = btScalar(1.0f) - factA; btVector3 ax1, p, q; btVector3 ax1A = trA.getBasis().getColumn(0); btVector3 ax1B = trB.getBasis().getColumn(0); if(m_useOffsetForConstraintFrame) { // get the desired direction of slider axis // as weighted sum of X-orthos of frameA and frameB in WCS ax1 = ax1A * factA + ax1B * factB; ax1.normalize(); // construct two orthos to slider axis btPlaneSpace1 (ax1, p, q); } else { // old way - use frameA ax1 = trA.getBasis().getColumn(0); // get 2 orthos to slider axis (Y, Z) p = trA.getBasis().getColumn(1); q = trA.getBasis().getColumn(2); } // make rotations around these orthos equal // the slider axis should be the only unconstrained // rotational axis, the angular velocity of the two bodies perpendicular to // the slider axis should be equal. thus the constraint equations are // p*w1 - p*w2 = 0 // q*w1 - q*w2 = 0 // where p and q are unit vectors normal to the slider axis, and w1 and w2 // are the angular velocity vectors of the two bodies. info->m_J1angularAxis[0] = p[0]; info->m_J1angularAxis[1] = p[1]; info->m_J1angularAxis[2] = p[2]; info->m_J1angularAxis[s+0] = q[0]; info->m_J1angularAxis[s+1] = q[1]; info->m_J1angularAxis[s+2] = q[2]; info->m_J2angularAxis[0] = -p[0]; info->m_J2angularAxis[1] = -p[1]; info->m_J2angularAxis[2] = -p[2]; info->m_J2angularAxis[s+0] = -q[0]; info->m_J2angularAxis[s+1] = -q[1]; info->m_J2angularAxis[s+2] = -q[2]; // compute the right hand side of the constraint equation. set relative // body velocities along p and q to bring the slider back into alignment. // if ax1A,ax1B are the unit length slider axes as computed from bodyA and // bodyB, we need to rotate both bodies along the axis u = (ax1 x ax2). // if "theta" is the angle between ax1 and ax2, we need an angular velocity // along u to cover angle erp*theta in one step : // |angular_velocity| = angle/time = erp*theta / stepsize // = (erp*fps) * theta // angular_velocity = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2| // = (erp*fps) * theta * (ax1 x ax2) / sin(theta) // ...as ax1 and ax2 are unit length. if theta is smallish, // theta ~= sin(theta), so // angular_velocity = (erp*fps) * (ax1 x ax2) // ax1 x ax2 is in the plane space of ax1, so we project the angular // velocity to p and q to find the right hand side. // btScalar k = info->fps * info->erp * getSoftnessOrthoAng(); btScalar currERP = (m_flags & BT_SLIDER_FLAGS_ERP_ORTANG) ? m_softnessOrthoAng : m_softnessOrthoAng * info->erp; btScalar k = info->fps * currERP; btVector3 u = ax1A.cross(ax1B); info->m_constraintError[0] = k * u.dot(p); info->m_constraintError[s] = k * u.dot(q); if(m_flags & BT_SLIDER_FLAGS_CFM_ORTANG) { info->cfm[0] = m_cfmOrthoAng; info->cfm[s] = m_cfmOrthoAng; } int nrow = 1; // last filled row int srow; btScalar limit_err; int limit; int powered; // next two rows. // we want: velA + wA x relA == velB + wB x relB ... but this would // result in three equations, so we project along two orthos to the slider axis btTransform bodyA_trans = transA; btTransform bodyB_trans = transB; nrow++; int s2 = nrow * s; nrow++; int s3 = nrow * s; btVector3 tmpA(0,0,0), tmpB(0,0,0), relA(0,0,0), relB(0,0,0), c(0,0,0); if(m_useOffsetForConstraintFrame) { // get vector from bodyB to frameB in WCS relB = trB.getOrigin() - bodyB_trans.getOrigin(); // get its projection to slider axis btVector3 projB = ax1 * relB.dot(ax1); // get vector directed from bodyB to slider axis (and orthogonal to it) btVector3 orthoB = relB - projB; // same for bodyA relA = trA.getOrigin() - bodyA_trans.getOrigin(); btVector3 projA = ax1 * relA.dot(ax1); btVector3 orthoA = relA - projA; // get desired offset between frames A and B along slider axis btScalar sliderOffs = m_linPos - m_depth[0]; // desired vector from projection of center of bodyA to projection of center of bodyB to slider axis btVector3 totalDist = projA + ax1 * sliderOffs - projB; // get offset vectors relA and relB relA = orthoA + totalDist * factA; relB = orthoB - totalDist * factB; // now choose average ortho to slider axis p = orthoB * factA + orthoA * factB; btScalar len2 = p.length2(); if(len2 > SIMD_EPSILON) { p /= btSqrt(len2); } else { p = trA.getBasis().getColumn(1); } // make one more ortho q = ax1.cross(p); // fill two rows tmpA = relA.cross(p); tmpB = relB.cross(p); for (i=0; i<3; i++) info->m_J1angularAxis[s2+i] = tmpA[i]; for (i=0; i<3; i++) info->m_J2angularAxis[s2+i] = -tmpB[i]; tmpA = relA.cross(q); tmpB = relB.cross(q); if(hasStaticBody && getSolveAngLimit()) { // to make constraint between static and dynamic objects more rigid // remove wA (or wB) from equation if angular limit is hit tmpB *= factB; tmpA *= factA; } for (i=0; i<3; i++) info->m_J1angularAxis[s3+i] = tmpA[i]; for (i=0; i<3; i++) info->m_J2angularAxis[s3+i] = -tmpB[i]; for (i=0; i<3; i++) info->m_J1linearAxis[s2+i] = p[i]; for (i=0; i<3; i++) info->m_J1linearAxis[s3+i] = q[i]; } else { // old way - maybe incorrect if bodies are not on the slider axis // see discussion "Bug in slider constraint" http://bulletphysics.org/Bullet/phpBB3/viewtopic.php?f=9&t=4024&start=0 c = bodyB_trans.getOrigin() - bodyA_trans.getOrigin(); btVector3 tmp = c.cross(p); for (i=0; i<3; i++) info->m_J1angularAxis[s2+i] = factA*tmp[i]; for (i=0; i<3; i++) info->m_J2angularAxis[s2+i] = factB*tmp[i]; tmp = c.cross(q); for (i=0; i<3; i++) info->m_J1angularAxis[s3+i] = factA*tmp[i]; for (i=0; i<3; i++) info->m_J2angularAxis[s3+i] = factB*tmp[i]; for (i=0; i<3; i++) info->m_J1linearAxis[s2+i] = p[i]; for (i=0; i<3; i++) info->m_J1linearAxis[s3+i] = q[i]; } // compute two elements of right hand side // k = info->fps * info->erp * getSoftnessOrthoLin(); currERP = (m_flags & BT_SLIDER_FLAGS_ERP_ORTLIN) ? m_softnessOrthoLin : m_softnessOrthoLin * info->erp; k = info->fps * currERP; btScalar rhs = k * p.dot(ofs); info->m_constraintError[s2] = rhs; rhs = k * q.dot(ofs); info->m_constraintError[s3] = rhs; if(m_flags & BT_SLIDER_FLAGS_CFM_ORTLIN) { info->cfm[s2] = m_cfmOrthoLin; info->cfm[s3] = m_cfmOrthoLin; } // check linear limits limit_err = btScalar(0.0); limit = 0; if(getSolveLinLimit()) { limit_err = getLinDepth() * signFact; limit = (limit_err > btScalar(0.0)) ? 2 : 1; } powered = 0; if(getPoweredLinMotor()) { powered = 1; } // if the slider has joint limits or motor, add in the extra row if (limit || powered) { nrow++; srow = nrow * info->rowskip; info->m_J1linearAxis[srow+0] = ax1[0]; info->m_J1linearAxis[srow+1] = ax1[1]; info->m_J1linearAxis[srow+2] = ax1[2]; // linear torque decoupling step: // // we have to be careful that the linear constraint forces (+/- ax1) applied to the two bodies // do not create a torque couple. in other words, the points that the // constraint force is applied at must lie along the same ax1 axis. // a torque couple will result in limited slider-jointed free // bodies from gaining angular momentum. if(m_useOffsetForConstraintFrame) { // this is needed only when bodyA and bodyB are both dynamic. if(!hasStaticBody) { tmpA = relA.cross(ax1); tmpB = relB.cross(ax1); info->m_J1angularAxis[srow+0] = tmpA[0]; info->m_J1angularAxis[srow+1] = tmpA[1]; info->m_J1angularAxis[srow+2] = tmpA[2]; info->m_J2angularAxis[srow+0] = -tmpB[0]; info->m_J2angularAxis[srow+1] = -tmpB[1]; info->m_J2angularAxis[srow+2] = -tmpB[2]; } } else { // The old way. May be incorrect if bodies are not on the slider axis btVector3 ltd; // Linear Torque Decoupling vector (a torque) ltd = c.cross(ax1); info->m_J1angularAxis[srow+0] = factA*ltd[0]; info->m_J1angularAxis[srow+1] = factA*ltd[1]; info->m_J1angularAxis[srow+2] = factA*ltd[2]; info->m_J2angularAxis[srow+0] = factB*ltd[0]; info->m_J2angularAxis[srow+1] = factB*ltd[1]; info->m_J2angularAxis[srow+2] = factB*ltd[2]; } // right-hand part btScalar lostop = getLowerLinLimit(); btScalar histop = getUpperLinLimit(); if(limit && (lostop == histop)) { // the joint motor is ineffective powered = 0; } info->m_constraintError[srow] = 0.; info->m_lowerLimit[srow] = 0.; info->m_upperLimit[srow] = 0.; currERP = (m_flags & BT_SLIDER_FLAGS_ERP_LIMLIN) ? m_softnessLimLin : info->erp; if(powered) { if(m_flags & BT_SLIDER_FLAGS_CFM_DIRLIN) { info->cfm[srow] = m_cfmDirLin; } btScalar tag_vel = getTargetLinMotorVelocity(); btScalar mot_fact = getMotorFactor(m_linPos, m_lowerLinLimit, m_upperLinLimit, tag_vel, info->fps * currERP); info->m_constraintError[srow] -= signFact * mot_fact * getTargetLinMotorVelocity(); info->m_lowerLimit[srow] += -getMaxLinMotorForce() * info->fps; info->m_upperLimit[srow] += getMaxLinMotorForce() * info->fps; } if(limit) { k = info->fps * currERP; info->m_constraintError[srow] += k * limit_err; if(m_flags & BT_SLIDER_FLAGS_CFM_LIMLIN) { info->cfm[srow] = m_cfmLimLin; } if(lostop == histop) { // limited low and high simultaneously info->m_lowerLimit[srow] = -SIMD_INFINITY; info->m_upperLimit[srow] = SIMD_INFINITY; } else if(limit == 1) { // low limit info->m_lowerLimit[srow] = -SIMD_INFINITY; info->m_upperLimit[srow] = 0; } else { // high limit info->m_lowerLimit[srow] = 0; info->m_upperLimit[srow] = SIMD_INFINITY; } // bounce (we'll use slider parameter abs(1.0 - m_dampingLimLin) for that) btScalar bounce = btFabs(btScalar(1.0) - getDampingLimLin()); if(bounce > btScalar(0.0)) { btScalar vel = linVelA.dot(ax1); vel -= linVelB.dot(ax1); vel *= signFact; // only apply bounce if the velocity is incoming, and if the // resulting c[] exceeds what we already have. if(limit == 1) { // low limit if(vel < 0) { btScalar newc = -bounce * vel; if (newc > info->m_constraintError[srow]) { info->m_constraintError[srow] = newc; } } } else { // high limit - all those computations are reversed if(vel > 0) { btScalar newc = -bounce * vel; if(newc < info->m_constraintError[srow]) { info->m_constraintError[srow] = newc; } } } } info->m_constraintError[srow] *= getSoftnessLimLin(); } // if(limit) } // if linear limit // check angular limits limit_err = btScalar(0.0); limit = 0; if(getSolveAngLimit()) { limit_err = getAngDepth(); limit = (limit_err > btScalar(0.0)) ? 1 : 2; } // if the slider has joint limits, add in the extra row powered = 0; if(getPoweredAngMotor()) { powered = 1; } if(limit || powered) { nrow++; srow = nrow * info->rowskip; info->m_J1angularAxis[srow+0] = ax1[0]; info->m_J1angularAxis[srow+1] = ax1[1]; info->m_J1angularAxis[srow+2] = ax1[2]; info->m_J2angularAxis[srow+0] = -ax1[0]; info->m_J2angularAxis[srow+1] = -ax1[1]; info->m_J2angularAxis[srow+2] = -ax1[2]; btScalar lostop = getLowerAngLimit(); btScalar histop = getUpperAngLimit(); if(limit && (lostop == histop)) { // the joint motor is ineffective powered = 0; } currERP = (m_flags & BT_SLIDER_FLAGS_ERP_LIMANG) ? m_softnessLimAng : info->erp; if(powered) { if(m_flags & BT_SLIDER_FLAGS_CFM_DIRANG) { info->cfm[srow] = m_cfmDirAng; } btScalar mot_fact = getMotorFactor(m_angPos, m_lowerAngLimit, m_upperAngLimit, getTargetAngMotorVelocity(), info->fps * currERP); info->m_constraintError[srow] = mot_fact * getTargetAngMotorVelocity(); info->m_lowerLimit[srow] = -getMaxAngMotorForce() * info->fps; info->m_upperLimit[srow] = getMaxAngMotorForce() * info->fps; } if(limit) { k = info->fps * currERP; info->m_constraintError[srow] += k * limit_err; if(m_flags & BT_SLIDER_FLAGS_CFM_LIMANG) { info->cfm[srow] = m_cfmLimAng; } if(lostop == histop) { // limited low and high simultaneously info->m_lowerLimit[srow] = -SIMD_INFINITY; info->m_upperLimit[srow] = SIMD_INFINITY; } else if(limit == 1) { // low limit info->m_lowerLimit[srow] = 0; info->m_upperLimit[srow] = SIMD_INFINITY; } else { // high limit info->m_lowerLimit[srow] = -SIMD_INFINITY; info->m_upperLimit[srow] = 0; } // bounce (we'll use slider parameter abs(1.0 - m_dampingLimAng) for that) btScalar bounce = btFabs(btScalar(1.0) - getDampingLimAng()); if(bounce > btScalar(0.0)) { btScalar vel = m_rbA.getAngularVelocity().dot(ax1); vel -= m_rbB.getAngularVelocity().dot(ax1); // only apply bounce if the velocity is incoming, and if the // resulting c[] exceeds what we already have. if(limit == 1) { // low limit if(vel < 0) { btScalar newc = -bounce * vel; if(newc > info->m_constraintError[srow]) { info->m_constraintError[srow] = newc; } } } else { // high limit - all those computations are reversed if(vel > 0) { btScalar newc = -bounce * vel; if(newc < info->m_constraintError[srow]) { info->m_constraintError[srow] = newc; } } } } info->m_constraintError[srow] *= getSoftnessLimAng(); } // if(limit) } // if angular limit or powered } ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). ///If no axis is provided, it uses the default axis for this constraint. void btSliderConstraint::setParam(int num, btScalar value, int axis) { switch(num) { case BT_CONSTRAINT_STOP_ERP : if(axis < 1) { m_softnessLimLin = value; m_flags |= BT_SLIDER_FLAGS_ERP_LIMLIN; } else if(axis < 3) { m_softnessOrthoLin = value; m_flags |= BT_SLIDER_FLAGS_ERP_ORTLIN; } else if(axis == 3) { m_softnessLimAng = value; m_flags |= BT_SLIDER_FLAGS_ERP_LIMANG; } else if(axis < 6) { m_softnessOrthoAng = value; m_flags |= BT_SLIDER_FLAGS_ERP_ORTANG; } else { btAssertConstrParams(0); } break; case BT_CONSTRAINT_CFM : if(axis < 1) { m_cfmDirLin = value; m_flags |= BT_SLIDER_FLAGS_CFM_DIRLIN; } else if(axis == 3) { m_cfmDirAng = value; m_flags |= BT_SLIDER_FLAGS_CFM_DIRANG; } else { btAssertConstrParams(0); } break; case BT_CONSTRAINT_STOP_CFM : if(axis < 1) { m_cfmLimLin = value; m_flags |= BT_SLIDER_FLAGS_CFM_LIMLIN; } else if(axis < 3) { m_cfmOrthoLin = value; m_flags |= BT_SLIDER_FLAGS_CFM_ORTLIN; } else if(axis == 3) { m_cfmLimAng = value; m_flags |= BT_SLIDER_FLAGS_CFM_LIMANG; } else if(axis < 6) { m_cfmOrthoAng = value; m_flags |= BT_SLIDER_FLAGS_CFM_ORTANG; } else { btAssertConstrParams(0); } break; } } ///return the local value of parameter btScalar btSliderConstraint::getParam(int num, int axis) const { btScalar retVal(SIMD_INFINITY); switch(num) { case BT_CONSTRAINT_STOP_ERP : if(axis < 1) { btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_LIMLIN); retVal = m_softnessLimLin; } else if(axis < 3) { btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_ORTLIN); retVal = m_softnessOrthoLin; } else if(axis == 3) { btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_LIMANG); retVal = m_softnessLimAng; } else if(axis < 6) { btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_ERP_ORTANG); retVal = m_softnessOrthoAng; } else { btAssertConstrParams(0); } break; case BT_CONSTRAINT_CFM : if(axis < 1) { btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_DIRLIN); retVal = m_cfmDirLin; } else if(axis == 3) { btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_DIRANG); retVal = m_cfmDirAng; } else { btAssertConstrParams(0); } break; case BT_CONSTRAINT_STOP_CFM : if(axis < 1) { btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_LIMLIN); retVal = m_cfmLimLin; } else if(axis < 3) { btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_ORTLIN); retVal = m_cfmOrthoLin; } else if(axis == 3) { btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_LIMANG); retVal = m_cfmLimAng; } else if(axis < 6) { btAssertConstrParams(m_flags & BT_SLIDER_FLAGS_CFM_ORTANG); retVal = m_cfmOrthoAng; } else { btAssertConstrParams(0); } break; } return retVal; } critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btTypedConstraint.h0000644000175000017500000002077111344267705031062 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2010 Erwin Coumans http://continuousphysics.com/Bullet/ 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 TYPED_CONSTRAINT_H #define TYPED_CONSTRAINT_H class btRigidBody; #include "LinearMath/btScalar.h" #include "btSolverConstraint.h" #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" class btSerializer; enum btTypedConstraintType { POINT2POINT_CONSTRAINT_TYPE=MAX_CONTACT_MANIFOLD_TYPE+1, HINGE_CONSTRAINT_TYPE, CONETWIST_CONSTRAINT_TYPE, D6_CONSTRAINT_TYPE, SLIDER_CONSTRAINT_TYPE, CONTACT_CONSTRAINT_TYPE }; enum btConstraintParams { BT_CONSTRAINT_ERP=1, BT_CONSTRAINT_STOP_ERP, BT_CONSTRAINT_CFM, BT_CONSTRAINT_STOP_CFM }; #if 1 #define btAssertConstrParams(_par) btAssert(_par) #else #define btAssertConstrParams(_par) #endif ///TypedConstraint is the baseclass for Bullet constraints and vehicles class btTypedConstraint : public btTypedObject { int m_userConstraintType; int m_userConstraintId; bool m_needsFeedback; btTypedConstraint& operator=(btTypedConstraint& other) { btAssert(0); (void) other; return *this; } protected: btRigidBody& m_rbA; btRigidBody& m_rbB; btScalar m_appliedImpulse; btScalar m_dbgDrawSize; ///internal method used by the constraint solver, don't use them directly btScalar getMotorFactor(btScalar pos, btScalar lowLim, btScalar uppLim, btScalar vel, btScalar timeFact); static btRigidBody& getFixedBody() { static btRigidBody s_fixed(0, 0,0); s_fixed.setMassProps(btScalar(0.),btVector3(btScalar(0.),btScalar(0.),btScalar(0.))); return s_fixed; } public: virtual ~btTypedConstraint() {}; btTypedConstraint(btTypedConstraintType type, btRigidBody& rbA); btTypedConstraint(btTypedConstraintType type, btRigidBody& rbA,btRigidBody& rbB); struct btConstraintInfo1 { int m_numConstraintRows,nub; }; struct btConstraintInfo2 { // integrator parameters: frames per second (1/stepsize), default error // reduction parameter (0..1). btScalar fps,erp; // for the first and second body, pointers to two (linear and angular) // n*3 jacobian sub matrices, stored by rows. these matrices will have // been initialized to 0 on entry. if the second body is zero then the // J2xx pointers may be 0. btScalar *m_J1linearAxis,*m_J1angularAxis,*m_J2linearAxis,*m_J2angularAxis; // elements to jump from one row to the next in J's int rowskip; // right hand sides of the equation J*v = c + cfm * lambda. cfm is the // "constraint force mixing" vector. c is set to zero on entry, cfm is // set to a constant value (typically very small or zero) value on entry. btScalar *m_constraintError,*cfm; // lo and hi limits for variables (set to -/+ infinity on entry). btScalar *m_lowerLimit,*m_upperLimit; // findex vector for variables. see the LCP solver interface for a // description of what this does. this is set to -1 on entry. // note that the returned indexes are relative to the first index of // the constraint. int *findex; // number of solver iterations int m_numIterations; }; ///internal method used by the constraint solver, don't use them directly virtual void buildJacobian() {}; ///internal method used by the constraint solver, don't use them directly virtual void setupSolverConstraint(btConstraintArray& ca, int solverBodyA,int solverBodyB, btScalar timeStep) { (void)ca; (void)solverBodyA; (void)solverBodyB; (void)timeStep; } ///internal method used by the constraint solver, don't use them directly virtual void getInfo1 (btConstraintInfo1* info)=0; ///internal method used by the constraint solver, don't use them directly virtual void getInfo2 (btConstraintInfo2* info)=0; ///internal method used by the constraint solver, don't use them directly void internalSetAppliedImpulse(btScalar appliedImpulse) { m_appliedImpulse = appliedImpulse; } ///internal method used by the constraint solver, don't use them directly btScalar internalGetAppliedImpulse() { return m_appliedImpulse; } ///internal method used by the constraint solver, don't use them directly virtual void solveConstraintObsolete(btRigidBody& bodyA,btRigidBody& bodyB,btScalar timeStep) {}; const btRigidBody& getRigidBodyA() const { return m_rbA; } const btRigidBody& getRigidBodyB() const { return m_rbB; } btRigidBody& getRigidBodyA() { return m_rbA; } btRigidBody& getRigidBodyB() { return m_rbB; } int getUserConstraintType() const { return m_userConstraintType ; } void setUserConstraintType(int userConstraintType) { m_userConstraintType = userConstraintType; }; void setUserConstraintId(int uid) { m_userConstraintId = uid; } int getUserConstraintId() const { return m_userConstraintId; } int getUid() const { return m_userConstraintId; } bool needsFeedback() const { return m_needsFeedback; } ///enableFeedback will allow to read the applied linear and angular impulse ///use getAppliedImpulse, getAppliedLinearImpulse and getAppliedAngularImpulse to read feedback information void enableFeedback(bool needsFeedback) { m_needsFeedback = needsFeedback; } ///getAppliedImpulse is an estimated total applied impulse. ///This feedback could be used to determine breaking constraints or playing sounds. btScalar getAppliedImpulse() const { btAssert(m_needsFeedback); return m_appliedImpulse; } btTypedConstraintType getConstraintType () const { return btTypedConstraintType(m_objectType); } void setDbgDrawSize(btScalar dbgDrawSize) { m_dbgDrawSize = dbgDrawSize; } btScalar getDbgDrawSize() { return m_dbgDrawSize; } ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). ///If no axis is provided, it uses the default axis for this constraint. virtual void setParam(int num, btScalar value, int axis = -1) = 0; ///return the local value of parameter virtual btScalar getParam(int num, int axis = -1) const = 0; virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; }; // returns angle in range [-SIMD_2_PI, SIMD_2_PI], closest to one of the limits // all arguments should be normalized angles (i.e. in range [-SIMD_PI, SIMD_PI]) SIMD_FORCE_INLINE btScalar btAdjustAngleToLimits(btScalar angleInRadians, btScalar angleLowerLimitInRadians, btScalar angleUpperLimitInRadians) { if(angleLowerLimitInRadians >= angleUpperLimitInRadians) { return angleInRadians; } else if(angleInRadians < angleLowerLimitInRadians) { btScalar diffLo = btNormalizeAngle(angleLowerLimitInRadians - angleInRadians); // this is positive btScalar diffHi = btFabs(btNormalizeAngle(angleUpperLimitInRadians - angleInRadians)); return (diffLo < diffHi) ? angleInRadians : (angleInRadians + SIMD_2_PI); } else if(angleInRadians > angleUpperLimitInRadians) { btScalar diffHi = btNormalizeAngle(angleInRadians - angleUpperLimitInRadians); // this is positive btScalar diffLo = btFabs(btNormalizeAngle(angleInRadians - angleLowerLimitInRadians)); return (diffLo < diffHi) ? (angleInRadians - SIMD_2_PI) : angleInRadians; } else { return angleInRadians; } } ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btTypedConstraintData { btRigidBodyData *m_rbA; btRigidBodyData *m_rbB; char *m_name; int m_objectType; int m_userConstraintType; int m_userConstraintId; int m_needsFeedback; float m_appliedImpulse; float m_dbgDrawSize; int m_disableCollisionsBetweenLinkedBodies; char m_pad4[4]; }; SIMD_FORCE_INLINE int btTypedConstraint::calculateSerializeBufferSize() const { return sizeof(btTypedConstraintData); } #endif //TYPED_CONSTRAINT_H critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btSliderConstraint.h0000755000175000017500000003074611344267705031225 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ /* Added by Roman Ponomarev (rponom@gmail.com) April 04, 2008 TODO: - add clamping od accumulated impulse to improve stability - add conversion for ODE constraint solver */ #ifndef SLIDER_CONSTRAINT_H #define SLIDER_CONSTRAINT_H #include "LinearMath/btVector3.h" #include "btJacobianEntry.h" #include "btTypedConstraint.h" class btRigidBody; #define SLIDER_CONSTRAINT_DEF_SOFTNESS (btScalar(1.0)) #define SLIDER_CONSTRAINT_DEF_DAMPING (btScalar(1.0)) #define SLIDER_CONSTRAINT_DEF_RESTITUTION (btScalar(0.7)) #define SLIDER_CONSTRAINT_DEF_CFM (btScalar(0.f)) enum btSliderFlags { BT_SLIDER_FLAGS_CFM_DIRLIN = (1 << 0), BT_SLIDER_FLAGS_ERP_DIRLIN = (1 << 1), BT_SLIDER_FLAGS_CFM_DIRANG = (1 << 2), BT_SLIDER_FLAGS_ERP_DIRANG = (1 << 3), BT_SLIDER_FLAGS_CFM_ORTLIN = (1 << 4), BT_SLIDER_FLAGS_ERP_ORTLIN = (1 << 5), BT_SLIDER_FLAGS_CFM_ORTANG = (1 << 6), BT_SLIDER_FLAGS_ERP_ORTANG = (1 << 7), BT_SLIDER_FLAGS_CFM_LIMLIN = (1 << 8), BT_SLIDER_FLAGS_ERP_LIMLIN = (1 << 9), BT_SLIDER_FLAGS_CFM_LIMANG = (1 << 10), BT_SLIDER_FLAGS_ERP_LIMANG = (1 << 11) }; class btSliderConstraint : public btTypedConstraint { protected: ///for backwards compatibility during the transition to 'getInfo/getInfo2' bool m_useSolveConstraintObsolete; bool m_useOffsetForConstraintFrame; btTransform m_frameInA; btTransform m_frameInB; // use frameA fo define limits, if true bool m_useLinearReferenceFrameA; // linear limits btScalar m_lowerLinLimit; btScalar m_upperLinLimit; // angular limits btScalar m_lowerAngLimit; btScalar m_upperAngLimit; // softness, restitution and damping for different cases // DirLin - moving inside linear limits // LimLin - hitting linear limit // DirAng - moving inside angular limits // LimAng - hitting angular limit // OrthoLin, OrthoAng - against constraint axis btScalar m_softnessDirLin; btScalar m_restitutionDirLin; btScalar m_dampingDirLin; btScalar m_cfmDirLin; btScalar m_softnessDirAng; btScalar m_restitutionDirAng; btScalar m_dampingDirAng; btScalar m_cfmDirAng; btScalar m_softnessLimLin; btScalar m_restitutionLimLin; btScalar m_dampingLimLin; btScalar m_cfmLimLin; btScalar m_softnessLimAng; btScalar m_restitutionLimAng; btScalar m_dampingLimAng; btScalar m_cfmLimAng; btScalar m_softnessOrthoLin; btScalar m_restitutionOrthoLin; btScalar m_dampingOrthoLin; btScalar m_cfmOrthoLin; btScalar m_softnessOrthoAng; btScalar m_restitutionOrthoAng; btScalar m_dampingOrthoAng; btScalar m_cfmOrthoAng; // for interlal use bool m_solveLinLim; bool m_solveAngLim; int m_flags; btJacobianEntry m_jacLin[3]; btScalar m_jacLinDiagABInv[3]; btJacobianEntry m_jacAng[3]; btScalar m_timeStep; btTransform m_calculatedTransformA; btTransform m_calculatedTransformB; btVector3 m_sliderAxis; btVector3 m_realPivotAInW; btVector3 m_realPivotBInW; btVector3 m_projPivotInW; btVector3 m_delta; btVector3 m_depth; btVector3 m_relPosA; btVector3 m_relPosB; btScalar m_linPos; btScalar m_angPos; btScalar m_angDepth; btScalar m_kAngle; bool m_poweredLinMotor; btScalar m_targetLinMotorVelocity; btScalar m_maxLinMotorForce; btScalar m_accumulatedLinMotorImpulse; bool m_poweredAngMotor; btScalar m_targetAngMotorVelocity; btScalar m_maxAngMotorForce; btScalar m_accumulatedAngMotorImpulse; //------------------------ void initParams(); public: // constructors btSliderConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB ,bool useLinearReferenceFrameA); btSliderConstraint(btRigidBody& rbB, const btTransform& frameInB, bool useLinearReferenceFrameA); // overrides virtual void getInfo1 (btConstraintInfo1* info); void getInfo1NonVirtual(btConstraintInfo1* info); virtual void getInfo2 (btConstraintInfo2* info); void getInfo2NonVirtual(btConstraintInfo2* info, const btTransform& transA, const btTransform& transB,const btVector3& linVelA,const btVector3& linVelB, btScalar rbAinvMass,btScalar rbBinvMass); // access const btRigidBody& getRigidBodyA() const { return m_rbA; } const btRigidBody& getRigidBodyB() const { return m_rbB; } const btTransform & getCalculatedTransformA() const { return m_calculatedTransformA; } const btTransform & getCalculatedTransformB() const { return m_calculatedTransformB; } const btTransform & getFrameOffsetA() const { return m_frameInA; } const btTransform & getFrameOffsetB() const { return m_frameInB; } btTransform & getFrameOffsetA() { return m_frameInA; } btTransform & getFrameOffsetB() { return m_frameInB; } btScalar getLowerLinLimit() { return m_lowerLinLimit; } void setLowerLinLimit(btScalar lowerLimit) { m_lowerLinLimit = lowerLimit; } btScalar getUpperLinLimit() { return m_upperLinLimit; } void setUpperLinLimit(btScalar upperLimit) { m_upperLinLimit = upperLimit; } btScalar getLowerAngLimit() { return m_lowerAngLimit; } void setLowerAngLimit(btScalar lowerLimit) { m_lowerAngLimit = btNormalizeAngle(lowerLimit); } btScalar getUpperAngLimit() { return m_upperAngLimit; } void setUpperAngLimit(btScalar upperLimit) { m_upperAngLimit = btNormalizeAngle(upperLimit); } bool getUseLinearReferenceFrameA() { return m_useLinearReferenceFrameA; } btScalar getSoftnessDirLin() { return m_softnessDirLin; } btScalar getRestitutionDirLin() { return m_restitutionDirLin; } btScalar getDampingDirLin() { return m_dampingDirLin ; } btScalar getSoftnessDirAng() { return m_softnessDirAng; } btScalar getRestitutionDirAng() { return m_restitutionDirAng; } btScalar getDampingDirAng() { return m_dampingDirAng; } btScalar getSoftnessLimLin() { return m_softnessLimLin; } btScalar getRestitutionLimLin() { return m_restitutionLimLin; } btScalar getDampingLimLin() { return m_dampingLimLin; } btScalar getSoftnessLimAng() { return m_softnessLimAng; } btScalar getRestitutionLimAng() { return m_restitutionLimAng; } btScalar getDampingLimAng() { return m_dampingLimAng; } btScalar getSoftnessOrthoLin() { return m_softnessOrthoLin; } btScalar getRestitutionOrthoLin() { return m_restitutionOrthoLin; } btScalar getDampingOrthoLin() { return m_dampingOrthoLin; } btScalar getSoftnessOrthoAng() { return m_softnessOrthoAng; } btScalar getRestitutionOrthoAng() { return m_restitutionOrthoAng; } btScalar getDampingOrthoAng() { return m_dampingOrthoAng; } void setSoftnessDirLin(btScalar softnessDirLin) { m_softnessDirLin = softnessDirLin; } void setRestitutionDirLin(btScalar restitutionDirLin) { m_restitutionDirLin = restitutionDirLin; } void setDampingDirLin(btScalar dampingDirLin) { m_dampingDirLin = dampingDirLin; } void setSoftnessDirAng(btScalar softnessDirAng) { m_softnessDirAng = softnessDirAng; } void setRestitutionDirAng(btScalar restitutionDirAng) { m_restitutionDirAng = restitutionDirAng; } void setDampingDirAng(btScalar dampingDirAng) { m_dampingDirAng = dampingDirAng; } void setSoftnessLimLin(btScalar softnessLimLin) { m_softnessLimLin = softnessLimLin; } void setRestitutionLimLin(btScalar restitutionLimLin) { m_restitutionLimLin = restitutionLimLin; } void setDampingLimLin(btScalar dampingLimLin) { m_dampingLimLin = dampingLimLin; } void setSoftnessLimAng(btScalar softnessLimAng) { m_softnessLimAng = softnessLimAng; } void setRestitutionLimAng(btScalar restitutionLimAng) { m_restitutionLimAng = restitutionLimAng; } void setDampingLimAng(btScalar dampingLimAng) { m_dampingLimAng = dampingLimAng; } void setSoftnessOrthoLin(btScalar softnessOrthoLin) { m_softnessOrthoLin = softnessOrthoLin; } void setRestitutionOrthoLin(btScalar restitutionOrthoLin) { m_restitutionOrthoLin = restitutionOrthoLin; } void setDampingOrthoLin(btScalar dampingOrthoLin) { m_dampingOrthoLin = dampingOrthoLin; } void setSoftnessOrthoAng(btScalar softnessOrthoAng) { m_softnessOrthoAng = softnessOrthoAng; } void setRestitutionOrthoAng(btScalar restitutionOrthoAng) { m_restitutionOrthoAng = restitutionOrthoAng; } void setDampingOrthoAng(btScalar dampingOrthoAng) { m_dampingOrthoAng = dampingOrthoAng; } void setPoweredLinMotor(bool onOff) { m_poweredLinMotor = onOff; } bool getPoweredLinMotor() { return m_poweredLinMotor; } void setTargetLinMotorVelocity(btScalar targetLinMotorVelocity) { m_targetLinMotorVelocity = targetLinMotorVelocity; } btScalar getTargetLinMotorVelocity() { return m_targetLinMotorVelocity; } void setMaxLinMotorForce(btScalar maxLinMotorForce) { m_maxLinMotorForce = maxLinMotorForce; } btScalar getMaxLinMotorForce() { return m_maxLinMotorForce; } void setPoweredAngMotor(bool onOff) { m_poweredAngMotor = onOff; } bool getPoweredAngMotor() { return m_poweredAngMotor; } void setTargetAngMotorVelocity(btScalar targetAngMotorVelocity) { m_targetAngMotorVelocity = targetAngMotorVelocity; } btScalar getTargetAngMotorVelocity() { return m_targetAngMotorVelocity; } void setMaxAngMotorForce(btScalar maxAngMotorForce) { m_maxAngMotorForce = maxAngMotorForce; } btScalar getMaxAngMotorForce() { return m_maxAngMotorForce; } btScalar getLinearPos() { return m_linPos; } // access for ODE solver bool getSolveLinLimit() { return m_solveLinLim; } btScalar getLinDepth() { return m_depth[0]; } bool getSolveAngLimit() { return m_solveAngLim; } btScalar getAngDepth() { return m_angDepth; } // shared code used by ODE solver void calculateTransforms(const btTransform& transA,const btTransform& transB); void testLinLimits(); void testAngLimits(); // access for PE Solver btVector3 getAncorInA(); btVector3 getAncorInB(); // access for UseFrameOffset bool getUseFrameOffset() { return m_useOffsetForConstraintFrame; } void setUseFrameOffset(bool frameOffsetOnOff) { m_useOffsetForConstraintFrame = frameOffsetOnOff; } ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). ///If no axis is provided, it uses the default axis for this constraint. virtual void setParam(int num, btScalar value, int axis = -1); ///return the local value of parameter virtual btScalar getParam(int num, int axis = -1) const; virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btSliderConstraintData { btTypedConstraintData m_typeConstraintData; btTransformFloatData m_rbAFrame; // constraint axii. Assumes z is hinge axis. btTransformFloatData m_rbBFrame; float m_linearUpperLimit; float m_linearLowerLimit; float m_angularUpperLimit; float m_angularLowerLimit; int m_useLinearReferenceFrameA; int m_useOffsetForConstraintFrame; }; SIMD_FORCE_INLINE int btSliderConstraint::calculateSerializeBufferSize() const { return sizeof(btSliderConstraintData); } ///fills the dataBuffer and returns the struct name (and 0 on failure) SIMD_FORCE_INLINE const char* btSliderConstraint::serialize(void* dataBuffer, btSerializer* serializer) const { btSliderConstraintData* sliderData = (btSliderConstraintData*) dataBuffer; btTypedConstraint::serialize(&sliderData->m_typeConstraintData,serializer); m_frameInA.serializeFloat(sliderData->m_rbAFrame); m_frameInB.serializeFloat(sliderData->m_rbBFrame); sliderData->m_linearUpperLimit = float(m_upperLinLimit); sliderData->m_linearLowerLimit = float(m_lowerLinLimit); sliderData->m_angularUpperLimit = float(m_upperAngLimit); sliderData->m_angularLowerLimit = float(m_lowerAngLimit); sliderData->m_useLinearReferenceFrameA = m_useLinearReferenceFrameA; sliderData->m_useOffsetForConstraintFrame = m_useOffsetForConstraintFrame; return "btSliderConstraintData"; } #endif //SLIDER_CONSTRAINT_H critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btUniversalConstraint.h0000644000175000017500000000506711337071441031736 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. 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 UNIVERSAL_CONSTRAINT_H #define UNIVERSAL_CONSTRAINT_H #include "LinearMath/btVector3.h" #include "btTypedConstraint.h" #include "btGeneric6DofConstraint.h" /// Constraint similar to ODE Universal Joint /// has 2 rotatioonal degrees of freedom, similar to Euler rotations around Z (axis 1) /// and Y (axis 2) /// Description from ODE manual : /// "Given axis 1 on body 1, and axis 2 on body 2 that is perpendicular to axis 1, it keeps them perpendicular. /// In other words, rotation of the two bodies about the direction perpendicular to the two axes will be equal." class btUniversalConstraint : public btGeneric6DofConstraint { protected: btVector3 m_anchor; btVector3 m_axis1; btVector3 m_axis2; public: // constructor // anchor, axis1 and axis2 are in world coordinate system // axis1 must be orthogonal to axis2 btUniversalConstraint(btRigidBody& rbA, btRigidBody& rbB, btVector3& anchor, btVector3& axis1, btVector3& axis2); // access const btVector3& getAnchor() { return m_calculatedTransformA.getOrigin(); } const btVector3& getAnchor2() { return m_calculatedTransformB.getOrigin(); } const btVector3& getAxis1() { return m_axis1; } const btVector3& getAxis2() { return m_axis2; } btScalar getAngle1() { return getAngle(2); } btScalar getAngle2() { return getAngle(1); } // limits void setUpperLimit(btScalar ang1max, btScalar ang2max) { setAngularUpperLimit(btVector3(0.f, ang1max, ang2max)); } void setLowerLimit(btScalar ang1min, btScalar ang2min) { setAngularLowerLimit(btVector3(0.f, ang1min, ang2min)); } }; #endif // UNIVERSAL_CONSTRAINT_H critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btHinge2Constraint.cpp0000644000175000017500000000610411337071441031426 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. 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 "btHinge2Constraint.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "LinearMath/btTransformUtil.h" // constructor // anchor, axis1 and axis2 are in world coordinate system // axis1 must be orthogonal to axis2 btHinge2Constraint::btHinge2Constraint(btRigidBody& rbA, btRigidBody& rbB, btVector3& anchor, btVector3& axis1, btVector3& axis2) : btGeneric6DofSpringConstraint(rbA, rbB, btTransform::getIdentity(), btTransform::getIdentity(), true), m_anchor(anchor), m_axis1(axis1), m_axis2(axis2) { // build frame basis // 6DOF constraint uses Euler angles and to define limits // it is assumed that rotational order is : // Z - first, allowed limits are (-PI,PI); // new position of Y - second (allowed limits are (-PI/2 + epsilon, PI/2 - epsilon), where epsilon is a small positive number // used to prevent constraint from instability on poles; // new position of X, allowed limits are (-PI,PI); // So to simulate ODE Universal joint we should use parent axis as Z, child axis as Y and limit all other DOFs // Build the frame in world coordinate system first btVector3 zAxis = axis1.normalize(); btVector3 xAxis = axis2.normalize(); btVector3 yAxis = zAxis.cross(xAxis); // we want right coordinate system btTransform frameInW; frameInW.setIdentity(); frameInW.getBasis().setValue( xAxis[0], yAxis[0], zAxis[0], xAxis[1], yAxis[1], zAxis[1], xAxis[2], yAxis[2], zAxis[2]); frameInW.setOrigin(anchor); // now get constraint frame in local coordinate systems m_frameInA = rbA.getCenterOfMassTransform().inverse() * frameInW; m_frameInB = rbB.getCenterOfMassTransform().inverse() * frameInW; // sei limits setLinearLowerLimit(btVector3(0.f, 0.f, -1.f)); setLinearUpperLimit(btVector3(0.f, 0.f, 1.f)); // like front wheels of a car setAngularLowerLimit(btVector3(1.f, 0.f, -SIMD_HALF_PI * 0.5f)); setAngularUpperLimit(btVector3(-1.f, 0.f, SIMD_HALF_PI * 0.5f)); // enable suspension enableSpring(2, true); setStiffness(2, SIMD_PI * SIMD_PI * 4.f); // period 1 sec for 1 kilogramm weel :-) setDamping(2, 0.01f); setEquilibriumPoint(); } critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btConeTwistConstraint.h0000644000175000017500000002215611344267705031713 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library btConeTwistConstraint is Copyright (c) 2007 Starbreeze Studios 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. Written by: Marcus Hennix */ /* Overview: btConeTwistConstraint can be used to simulate ragdoll joints (upper arm, leg etc). It is a fixed translation, 3 degree-of-freedom (DOF) rotational "joint". It divides the 3 rotational DOFs into swing (movement within a cone) and twist. Swing is divided into swing1 and swing2 which can have different limits, giving an elliptical shape. (Note: the cone's base isn't flat, so this ellipse is "embedded" on the surface of a sphere.) In the contraint's frame of reference: twist is along the x-axis, and swing 1 and 2 are along the z and y axes respectively. */ #ifndef CONETWISTCONSTRAINT_H #define CONETWISTCONSTRAINT_H #include "LinearMath/btVector3.h" #include "btJacobianEntry.h" #include "btTypedConstraint.h" class btRigidBody; enum btConeTwistFlags { BT_CONETWIST_FLAGS_LIN_CFM = 1, BT_CONETWIST_FLAGS_LIN_ERP = 2, BT_CONETWIST_FLAGS_ANG_CFM = 4 }; ///btConeTwistConstraint can be used to simulate ragdoll joints (upper arm, leg etc) class btConeTwistConstraint : public btTypedConstraint { #ifdef IN_PARALLELL_SOLVER public: #endif btJacobianEntry m_jac[3]; //3 orthogonal linear constraints btTransform m_rbAFrame; btTransform m_rbBFrame; btScalar m_limitSoftness; btScalar m_biasFactor; btScalar m_relaxationFactor; btScalar m_damping; btScalar m_swingSpan1; btScalar m_swingSpan2; btScalar m_twistSpan; btScalar m_fixThresh; btVector3 m_swingAxis; btVector3 m_twistAxis; btScalar m_kSwing; btScalar m_kTwist; btScalar m_twistLimitSign; btScalar m_swingCorrection; btScalar m_twistCorrection; btScalar m_twistAngle; btScalar m_accSwingLimitImpulse; btScalar m_accTwistLimitImpulse; bool m_angularOnly; bool m_solveTwistLimit; bool m_solveSwingLimit; bool m_useSolveConstraintObsolete; // not yet used... btScalar m_swingLimitRatio; btScalar m_twistLimitRatio; btVector3 m_twistAxisA; // motor bool m_bMotorEnabled; bool m_bNormalizedMotorStrength; btQuaternion m_qTarget; btScalar m_maxMotorImpulse; btVector3 m_accMotorImpulse; // parameters int m_flags; btScalar m_linCFM; btScalar m_linERP; btScalar m_angCFM; protected: void init(); void computeConeLimitInfo(const btQuaternion& qCone, // in btScalar& swingAngle, btVector3& vSwingAxis, btScalar& swingLimit); // all outs void computeTwistLimitInfo(const btQuaternion& qTwist, // in btScalar& twistAngle, btVector3& vTwistAxis); // all outs void adjustSwingAxisToUseEllipseNormal(btVector3& vSwingAxis) const; public: btConeTwistConstraint(btRigidBody& rbA,btRigidBody& rbB,const btTransform& rbAFrame, const btTransform& rbBFrame); btConeTwistConstraint(btRigidBody& rbA,const btTransform& rbAFrame); virtual void buildJacobian(); virtual void getInfo1 (btConstraintInfo1* info); void getInfo1NonVirtual(btConstraintInfo1* info); virtual void getInfo2 (btConstraintInfo2* info); void getInfo2NonVirtual(btConstraintInfo2* info,const btTransform& transA,const btTransform& transB,const btMatrix3x3& invInertiaWorldA,const btMatrix3x3& invInertiaWorldB); virtual void solveConstraintObsolete(btRigidBody& bodyA,btRigidBody& bodyB,btScalar timeStep); void updateRHS(btScalar timeStep); const btRigidBody& getRigidBodyA() const { return m_rbA; } const btRigidBody& getRigidBodyB() const { return m_rbB; } void setAngularOnly(bool angularOnly) { m_angularOnly = angularOnly; } void setLimit(int limitIndex,btScalar limitValue) { switch (limitIndex) { case 3: { m_twistSpan = limitValue; break; } case 4: { m_swingSpan2 = limitValue; break; } case 5: { m_swingSpan1 = limitValue; break; } default: { } }; } // setLimit(), a few notes: // _softness: // 0->1, recommend ~0.8->1. // describes % of limits where movement is free. // beyond this softness %, the limit is gradually enforced until the "hard" (1.0) limit is reached. // _biasFactor: // 0->1?, recommend 0.3 +/-0.3 or so. // strength with which constraint resists zeroth order (angular, not angular velocity) limit violation. // __relaxationFactor: // 0->1, recommend to stay near 1. // the lower the value, the less the constraint will fight velocities which violate the angular limits. void setLimit(btScalar _swingSpan1,btScalar _swingSpan2,btScalar _twistSpan, btScalar _softness = 1.f, btScalar _biasFactor = 0.3f, btScalar _relaxationFactor = 1.0f) { m_swingSpan1 = _swingSpan1; m_swingSpan2 = _swingSpan2; m_twistSpan = _twistSpan; m_limitSoftness = _softness; m_biasFactor = _biasFactor; m_relaxationFactor = _relaxationFactor; } const btTransform& getAFrame() { return m_rbAFrame; }; const btTransform& getBFrame() { return m_rbBFrame; }; inline int getSolveTwistLimit() { return m_solveTwistLimit; } inline int getSolveSwingLimit() { return m_solveTwistLimit; } inline btScalar getTwistLimitSign() { return m_twistLimitSign; } void calcAngleInfo(); void calcAngleInfo2(const btTransform& transA, const btTransform& transB,const btMatrix3x3& invInertiaWorldA,const btMatrix3x3& invInertiaWorldB); inline btScalar getSwingSpan1() { return m_swingSpan1; } inline btScalar getSwingSpan2() { return m_swingSpan2; } inline btScalar getTwistSpan() { return m_twistSpan; } inline btScalar getTwistAngle() { return m_twistAngle; } bool isPastSwingLimit() { return m_solveSwingLimit; } void setDamping(btScalar damping) { m_damping = damping; } void enableMotor(bool b) { m_bMotorEnabled = b; } void setMaxMotorImpulse(btScalar maxMotorImpulse) { m_maxMotorImpulse = maxMotorImpulse; m_bNormalizedMotorStrength = false; } void setMaxMotorImpulseNormalized(btScalar maxMotorImpulse) { m_maxMotorImpulse = maxMotorImpulse; m_bNormalizedMotorStrength = true; } btScalar getFixThresh() { return m_fixThresh; } void setFixThresh(btScalar fixThresh) { m_fixThresh = fixThresh; } // setMotorTarget: // q: the desired rotation of bodyA wrt bodyB. // note: if q violates the joint limits, the internal target is clamped to avoid conflicting impulses (very bad for stability) // note: don't forget to enableMotor() void setMotorTarget(const btQuaternion &q); // same as above, but q is the desired rotation of frameA wrt frameB in constraint space void setMotorTargetInConstraintSpace(const btQuaternion &q); btVector3 GetPointForAngle(btScalar fAngleInRadians, btScalar fLength) const; ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). ///If no axis is provided, it uses the default axis for this constraint. virtual void setParam(int num, btScalar value, int axis = -1); ///return the local value of parameter virtual btScalar getParam(int num, int axis = -1) const; virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btConeTwistConstraintData { btTypedConstraintData m_typeConstraintData; btTransformFloatData m_rbAFrame; btTransformFloatData m_rbBFrame; //limits float m_swingSpan1; float m_swingSpan2; float m_twistSpan; float m_limitSoftness; float m_biasFactor; float m_relaxationFactor; float m_damping; char m_pad[4]; }; SIMD_FORCE_INLINE int btConeTwistConstraint::calculateSerializeBufferSize() const { return sizeof(btConeTwistConstraintData); } ///fills the dataBuffer and returns the struct name (and 0 on failure) SIMD_FORCE_INLINE const char* btConeTwistConstraint::serialize(void* dataBuffer, btSerializer* serializer) const { btConeTwistConstraintData* cone = (btConeTwistConstraintData*) dataBuffer; btTypedConstraint::serialize(&cone->m_typeConstraintData,serializer); m_rbAFrame.serializeFloat(cone->m_rbAFrame); m_rbBFrame.serializeFloat(cone->m_rbBFrame); cone->m_swingSpan1 = float(m_swingSpan1); cone->m_swingSpan2 = float(m_swingSpan2); cone->m_twistSpan = float(m_twistSpan); cone->m_limitSoftness = float(m_limitSoftness); cone->m_biasFactor = float(m_biasFactor); cone->m_relaxationFactor = float(m_relaxationFactor); cone->m_damping = float(m_damping); return "btConeTwistConstraintData"; } #endif //CONETWISTCONSTRAINT_H critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btUniversalConstraint.cpp0000644000175000017500000000566411337071441032274 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. 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 "btUniversalConstraint.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "LinearMath/btTransformUtil.h" #define UNIV_EPS btScalar(0.01f) // constructor // anchor, axis1 and axis2 are in world coordinate system // axis1 must be orthogonal to axis2 btUniversalConstraint::btUniversalConstraint(btRigidBody& rbA, btRigidBody& rbB, btVector3& anchor, btVector3& axis1, btVector3& axis2) : btGeneric6DofConstraint(rbA, rbB, btTransform::getIdentity(), btTransform::getIdentity(), true), m_anchor(anchor), m_axis1(axis1), m_axis2(axis2) { // build frame basis // 6DOF constraint uses Euler angles and to define limits // it is assumed that rotational order is : // Z - first, allowed limits are (-PI,PI); // new position of Y - second (allowed limits are (-PI/2 + epsilon, PI/2 - epsilon), where epsilon is a small positive number // used to prevent constraint from instability on poles; // new position of X, allowed limits are (-PI,PI); // So to simulate ODE Universal joint we should use parent axis as Z, child axis as Y and limit all other DOFs // Build the frame in world coordinate system first btVector3 zAxis = axis1.normalize(); btVector3 yAxis = axis2.normalize(); btVector3 xAxis = yAxis.cross(zAxis); // we want right coordinate system btTransform frameInW; frameInW.setIdentity(); frameInW.getBasis().setValue( xAxis[0], yAxis[0], zAxis[0], xAxis[1], yAxis[1], zAxis[1], xAxis[2], yAxis[2], zAxis[2]); frameInW.setOrigin(anchor); // now get constraint frame in local coordinate systems m_frameInA = rbA.getCenterOfMassTransform().inverse() * frameInW; m_frameInB = rbB.getCenterOfMassTransform().inverse() * frameInW; // sei limits setLinearLowerLimit(btVector3(0., 0., 0.)); setLinearUpperLimit(btVector3(0., 0., 0.)); setAngularLowerLimit(btVector3(0.f, -SIMD_HALF_PI + UNIV_EPS, -SIMD_PI + UNIV_EPS)); setAngularUpperLimit(btVector3(0.f, SIMD_HALF_PI - UNIV_EPS, SIMD_PI - UNIV_EPS)); } critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btContactConstraint.cpp0000644000175000017500000000772311344267705031725 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btContactConstraint.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "LinearMath/btVector3.h" #include "btJacobianEntry.h" #include "btContactSolverInfo.h" #include "LinearMath/btMinMax.h" #include "BulletCollision/NarrowPhaseCollision/btManifoldPoint.h" btContactConstraint::btContactConstraint(btPersistentManifold* contactManifold,btRigidBody& rbA,btRigidBody& rbB) :btTypedConstraint(CONTACT_CONSTRAINT_TYPE,rbA,rbB), m_contactManifold(*contactManifold) { } btContactConstraint::~btContactConstraint() { } void btContactConstraint::setContactManifold(btPersistentManifold* contactManifold) { m_contactManifold = *contactManifold; } void btContactConstraint::getInfo1 (btConstraintInfo1* info) { } void btContactConstraint::getInfo2 (btConstraintInfo2* info) { } void btContactConstraint::buildJacobian() { } #include "btContactConstraint.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "LinearMath/btVector3.h" #include "btJacobianEntry.h" #include "btContactSolverInfo.h" #include "LinearMath/btMinMax.h" #include "BulletCollision/NarrowPhaseCollision/btManifoldPoint.h" #define ASSERT2 btAssert #define USE_INTERNAL_APPLY_IMPULSE 1 //bilateral constraint between two dynamic objects void resolveSingleBilateral(btRigidBody& body1, const btVector3& pos1, btRigidBody& body2, const btVector3& pos2, btScalar distance, const btVector3& normal,btScalar& impulse ,btScalar timeStep) { (void)timeStep; (void)distance; btScalar normalLenSqr = normal.length2(); ASSERT2(btFabs(normalLenSqr) < btScalar(1.1)); if (normalLenSqr > btScalar(1.1)) { impulse = btScalar(0.); return; } btVector3 rel_pos1 = pos1 - body1.getCenterOfMassPosition(); btVector3 rel_pos2 = pos2 - body2.getCenterOfMassPosition(); //this jacobian entry could be re-used for all iterations btVector3 vel1 = body1.getVelocityInLocalPoint(rel_pos1); btVector3 vel2 = body2.getVelocityInLocalPoint(rel_pos2); btVector3 vel = vel1 - vel2; btJacobianEntry jac(body1.getCenterOfMassTransform().getBasis().transpose(), body2.getCenterOfMassTransform().getBasis().transpose(), rel_pos1,rel_pos2,normal,body1.getInvInertiaDiagLocal(),body1.getInvMass(), body2.getInvInertiaDiagLocal(),body2.getInvMass()); btScalar jacDiagAB = jac.getDiagonal(); btScalar jacDiagABInv = btScalar(1.) / jacDiagAB; btScalar rel_vel = jac.getRelativeVelocity( body1.getLinearVelocity(), body1.getCenterOfMassTransform().getBasis().transpose() * body1.getAngularVelocity(), body2.getLinearVelocity(), body2.getCenterOfMassTransform().getBasis().transpose() * body2.getAngularVelocity()); btScalar a; a=jacDiagABInv; rel_vel = normal.dot(vel); //todo: move this into proper structure btScalar contactDamping = btScalar(0.2); #ifdef ONLY_USE_LINEAR_MASS btScalar massTerm = btScalar(1.) / (body1.getInvMass() + body2.getInvMass()); impulse = - contactDamping * rel_vel * massTerm; #else btScalar velocityImpulse = -contactDamping * rel_vel * jacDiagABInv; impulse = velocityImpulse; #endif } critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btHinge2Constraint.h0000644000175000017500000000451311337071441031075 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. 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 HINGE2_CONSTRAINT_H #define HINGE2_CONSTRAINT_H #include "LinearMath/btVector3.h" #include "btTypedConstraint.h" #include "btGeneric6DofSpringConstraint.h" // Constraint similar to ODE Hinge2 Joint // has 3 degrees of frredom: // 2 rotational degrees of freedom, similar to Euler rotations around Z (axis 1) and X (axis 2) // 1 translational (along axis Z) with suspension spring class btHinge2Constraint : public btGeneric6DofSpringConstraint { protected: btVector3 m_anchor; btVector3 m_axis1; btVector3 m_axis2; public: // constructor // anchor, axis1 and axis2 are in world coordinate system // axis1 must be orthogonal to axis2 btHinge2Constraint(btRigidBody& rbA, btRigidBody& rbB, btVector3& anchor, btVector3& axis1, btVector3& axis2); // access const btVector3& getAnchor() { return m_calculatedTransformA.getOrigin(); } const btVector3& getAnchor2() { return m_calculatedTransformB.getOrigin(); } const btVector3& getAxis1() { return m_axis1; } const btVector3& getAxis2() { return m_axis2; } btScalar getAngle1() { return getAngle(2); } btScalar getAngle2() { return getAngle(0); } // limits void setUpperLimit(btScalar ang1max) { setAngularUpperLimit(btVector3(-1.f, 0.f, ang1max)); } void setLowerLimit(btScalar ang1min) { setAngularLowerLimit(btVector3( 1.f, 0.f, ang1min)); } }; #endif // HINGE2_CONSTRAINT_H critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h0000644000175000017500000001142011344267705032151 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 POINT2POINTCONSTRAINT_H #define POINT2POINTCONSTRAINT_H #include "LinearMath/btVector3.h" #include "btJacobianEntry.h" #include "btTypedConstraint.h" class btRigidBody; #ifdef BT_USE_DOUBLE_PRECISION #define btPoint2PointConstraintData btPoint2PointConstraintDoubleData #define btPoint2PointConstraintDataName "btPoint2PointConstraintDoubleData" #else #define btPoint2PointConstraintData btPoint2PointConstraintFloatData #define btPoint2PointConstraintDataName "btPoint2PointConstraintFloatData" #endif //BT_USE_DOUBLE_PRECISION struct btConstraintSetting { btConstraintSetting() : m_tau(btScalar(0.3)), m_damping(btScalar(1.)), m_impulseClamp(btScalar(0.)) { } btScalar m_tau; btScalar m_damping; btScalar m_impulseClamp; }; enum btPoint2PointFlags { BT_P2P_FLAGS_ERP = 1, BT_P2P_FLAGS_CFM = 2 }; /// point to point constraint between two rigidbodies each with a pivotpoint that descibes the 'ballsocket' location in local space ATTRIBUTE_ALIGNED16(class) btPoint2PointConstraint : public btTypedConstraint { #ifdef IN_PARALLELL_SOLVER public: #endif btJacobianEntry m_jac[3]; //3 orthogonal linear constraints btVector3 m_pivotInA; btVector3 m_pivotInB; int m_flags; btScalar m_erp; btScalar m_cfm; public: ///for backwards compatibility during the transition to 'getInfo/getInfo2' bool m_useSolveConstraintObsolete; btConstraintSetting m_setting; btPoint2PointConstraint(btRigidBody& rbA,btRigidBody& rbB, const btVector3& pivotInA,const btVector3& pivotInB); btPoint2PointConstraint(btRigidBody& rbA,const btVector3& pivotInA); virtual void buildJacobian(); virtual void getInfo1 (btConstraintInfo1* info); void getInfo1NonVirtual (btConstraintInfo1* info); virtual void getInfo2 (btConstraintInfo2* info); void getInfo2NonVirtual (btConstraintInfo2* info, const btTransform& body0_trans, const btTransform& body1_trans); void updateRHS(btScalar timeStep); void setPivotA(const btVector3& pivotA) { m_pivotInA = pivotA; } void setPivotB(const btVector3& pivotB) { m_pivotInB = pivotB; } const btVector3& getPivotInA() const { return m_pivotInA; } const btVector3& getPivotInB() const { return m_pivotInB; } ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). ///If no axis is provided, it uses the default axis for this constraint. virtual void setParam(int num, btScalar value, int axis = -1); ///return the local value of parameter virtual btScalar getParam(int num, int axis = -1) const; virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btPoint2PointConstraintFloatData { btTypedConstraintData m_typeConstraintData; btVector3FloatData m_pivotInA; btVector3FloatData m_pivotInB; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btPoint2PointConstraintDoubleData { btTypedConstraintData m_typeConstraintData; btVector3DoubleData m_pivotInA; btVector3DoubleData m_pivotInB; }; SIMD_FORCE_INLINE int btPoint2PointConstraint::calculateSerializeBufferSize() const { return sizeof(btPoint2PointConstraintData); } ///fills the dataBuffer and returns the struct name (and 0 on failure) SIMD_FORCE_INLINE const char* btPoint2PointConstraint::serialize(void* dataBuffer, btSerializer* serializer) const { btPoint2PointConstraintData* p2pData = (btPoint2PointConstraintData*)dataBuffer; btTypedConstraint::serialize(&p2pData->m_typeConstraintData,serializer); m_pivotInA.serialize(p2pData->m_pivotInA); m_pivotInB.serialize(p2pData->m_pivotInB); return btPoint2PointConstraintDataName; } #endif //POINT2POINTCONSTRAINT_H critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btConeTwistConstraint.cpp0000644000175000017500000010601311344267705032241 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library btConeTwistConstraint is Copyright (c) 2007 Starbreeze Studios 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. Written by: Marcus Hennix */ #include "btConeTwistConstraint.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "LinearMath/btTransformUtil.h" #include "LinearMath/btMinMax.h" #include //#define CONETWIST_USE_OBSOLETE_SOLVER true #define CONETWIST_USE_OBSOLETE_SOLVER false #define CONETWIST_DEF_FIX_THRESH btScalar(.05f) SIMD_FORCE_INLINE btScalar computeAngularImpulseDenominator(const btVector3& axis, const btMatrix3x3& invInertiaWorld) { btVector3 vec = axis * invInertiaWorld; return axis.dot(vec); } btConeTwistConstraint::btConeTwistConstraint(btRigidBody& rbA,btRigidBody& rbB, const btTransform& rbAFrame,const btTransform& rbBFrame) :btTypedConstraint(CONETWIST_CONSTRAINT_TYPE, rbA,rbB),m_rbAFrame(rbAFrame),m_rbBFrame(rbBFrame), m_angularOnly(false), m_useSolveConstraintObsolete(CONETWIST_USE_OBSOLETE_SOLVER) { init(); } btConeTwistConstraint::btConeTwistConstraint(btRigidBody& rbA,const btTransform& rbAFrame) :btTypedConstraint(CONETWIST_CONSTRAINT_TYPE,rbA),m_rbAFrame(rbAFrame), m_angularOnly(false), m_useSolveConstraintObsolete(CONETWIST_USE_OBSOLETE_SOLVER) { m_rbBFrame = m_rbAFrame; init(); } void btConeTwistConstraint::init() { m_angularOnly = false; m_solveTwistLimit = false; m_solveSwingLimit = false; m_bMotorEnabled = false; m_maxMotorImpulse = btScalar(-1); setLimit(btScalar(BT_LARGE_FLOAT), btScalar(BT_LARGE_FLOAT), btScalar(BT_LARGE_FLOAT)); m_damping = btScalar(0.01); m_fixThresh = CONETWIST_DEF_FIX_THRESH; m_flags = 0; m_linCFM = btScalar(0.f); m_linERP = btScalar(0.7f); m_angCFM = btScalar(0.f); } void btConeTwistConstraint::getInfo1 (btConstraintInfo1* info) { if (m_useSolveConstraintObsolete) { info->m_numConstraintRows = 0; info->nub = 0; } else { info->m_numConstraintRows = 3; info->nub = 3; calcAngleInfo2(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(),m_rbA.getInvInertiaTensorWorld(),m_rbB.getInvInertiaTensorWorld()); if(m_solveSwingLimit) { info->m_numConstraintRows++; info->nub--; if((m_swingSpan1 < m_fixThresh) && (m_swingSpan2 < m_fixThresh)) { info->m_numConstraintRows++; info->nub--; } } if(m_solveTwistLimit) { info->m_numConstraintRows++; info->nub--; } } } void btConeTwistConstraint::getInfo1NonVirtual (btConstraintInfo1* info) { //always reserve 6 rows: object transform is not available on SPU info->m_numConstraintRows = 6; info->nub = 0; } void btConeTwistConstraint::getInfo2 (btConstraintInfo2* info) { getInfo2NonVirtual(info,m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(),m_rbA.getInvInertiaTensorWorld(),m_rbB.getInvInertiaTensorWorld()); } void btConeTwistConstraint::getInfo2NonVirtual (btConstraintInfo2* info,const btTransform& transA,const btTransform& transB,const btMatrix3x3& invInertiaWorldA,const btMatrix3x3& invInertiaWorldB) { calcAngleInfo2(transA,transB,invInertiaWorldA,invInertiaWorldB); btAssert(!m_useSolveConstraintObsolete); // set jacobian info->m_J1linearAxis[0] = 1; info->m_J1linearAxis[info->rowskip+1] = 1; info->m_J1linearAxis[2*info->rowskip+2] = 1; btVector3 a1 = transA.getBasis() * m_rbAFrame.getOrigin(); { btVector3* angular0 = (btVector3*)(info->m_J1angularAxis); btVector3* angular1 = (btVector3*)(info->m_J1angularAxis+info->rowskip); btVector3* angular2 = (btVector3*)(info->m_J1angularAxis+2*info->rowskip); btVector3 a1neg = -a1; a1neg.getSkewSymmetricMatrix(angular0,angular1,angular2); } btVector3 a2 = transB.getBasis() * m_rbBFrame.getOrigin(); { btVector3* angular0 = (btVector3*)(info->m_J2angularAxis); btVector3* angular1 = (btVector3*)(info->m_J2angularAxis+info->rowskip); btVector3* angular2 = (btVector3*)(info->m_J2angularAxis+2*info->rowskip); a2.getSkewSymmetricMatrix(angular0,angular1,angular2); } // set right hand side btScalar linERP = (m_flags & BT_CONETWIST_FLAGS_LIN_ERP) ? m_linERP : info->erp; btScalar k = info->fps * linERP; int j; for (j=0; j<3; j++) { info->m_constraintError[j*info->rowskip] = k * (a2[j] + transB.getOrigin()[j] - a1[j] - transA.getOrigin()[j]); info->m_lowerLimit[j*info->rowskip] = -SIMD_INFINITY; info->m_upperLimit[j*info->rowskip] = SIMD_INFINITY; if(m_flags & BT_CONETWIST_FLAGS_LIN_CFM) { info->cfm[j*info->rowskip] = m_linCFM; } } int row = 3; int srow = row * info->rowskip; btVector3 ax1; // angular limits if(m_solveSwingLimit) { btScalar *J1 = info->m_J1angularAxis; btScalar *J2 = info->m_J2angularAxis; if((m_swingSpan1 < m_fixThresh) && (m_swingSpan2 < m_fixThresh)) { btTransform trA = transA*m_rbAFrame; btVector3 p = trA.getBasis().getColumn(1); btVector3 q = trA.getBasis().getColumn(2); int srow1 = srow + info->rowskip; J1[srow+0] = p[0]; J1[srow+1] = p[1]; J1[srow+2] = p[2]; J1[srow1+0] = q[0]; J1[srow1+1] = q[1]; J1[srow1+2] = q[2]; J2[srow+0] = -p[0]; J2[srow+1] = -p[1]; J2[srow+2] = -p[2]; J2[srow1+0] = -q[0]; J2[srow1+1] = -q[1]; J2[srow1+2] = -q[2]; btScalar fact = info->fps * m_relaxationFactor; info->m_constraintError[srow] = fact * m_swingAxis.dot(p); info->m_constraintError[srow1] = fact * m_swingAxis.dot(q); info->m_lowerLimit[srow] = -SIMD_INFINITY; info->m_upperLimit[srow] = SIMD_INFINITY; info->m_lowerLimit[srow1] = -SIMD_INFINITY; info->m_upperLimit[srow1] = SIMD_INFINITY; srow = srow1 + info->rowskip; } else { ax1 = m_swingAxis * m_relaxationFactor * m_relaxationFactor; J1[srow+0] = ax1[0]; J1[srow+1] = ax1[1]; J1[srow+2] = ax1[2]; J2[srow+0] = -ax1[0]; J2[srow+1] = -ax1[1]; J2[srow+2] = -ax1[2]; btScalar k = info->fps * m_biasFactor; info->m_constraintError[srow] = k * m_swingCorrection; if(m_flags & BT_CONETWIST_FLAGS_ANG_CFM) { info->cfm[srow] = m_angCFM; } // m_swingCorrection is always positive or 0 info->m_lowerLimit[srow] = 0; info->m_upperLimit[srow] = SIMD_INFINITY; srow += info->rowskip; } } if(m_solveTwistLimit) { ax1 = m_twistAxis * m_relaxationFactor * m_relaxationFactor; btScalar *J1 = info->m_J1angularAxis; btScalar *J2 = info->m_J2angularAxis; J1[srow+0] = ax1[0]; J1[srow+1] = ax1[1]; J1[srow+2] = ax1[2]; J2[srow+0] = -ax1[0]; J2[srow+1] = -ax1[1]; J2[srow+2] = -ax1[2]; btScalar k = info->fps * m_biasFactor; info->m_constraintError[srow] = k * m_twistCorrection; if(m_flags & BT_CONETWIST_FLAGS_ANG_CFM) { info->cfm[srow] = m_angCFM; } if(m_twistSpan > 0.0f) { if(m_twistCorrection > 0.0f) { info->m_lowerLimit[srow] = 0; info->m_upperLimit[srow] = SIMD_INFINITY; } else { info->m_lowerLimit[srow] = -SIMD_INFINITY; info->m_upperLimit[srow] = 0; } } else { info->m_lowerLimit[srow] = -SIMD_INFINITY; info->m_upperLimit[srow] = SIMD_INFINITY; } srow += info->rowskip; } } void btConeTwistConstraint::buildJacobian() { if (m_useSolveConstraintObsolete) { m_appliedImpulse = btScalar(0.); m_accTwistLimitImpulse = btScalar(0.); m_accSwingLimitImpulse = btScalar(0.); m_accMotorImpulse = btVector3(0.,0.,0.); if (!m_angularOnly) { btVector3 pivotAInW = m_rbA.getCenterOfMassTransform()*m_rbAFrame.getOrigin(); btVector3 pivotBInW = m_rbB.getCenterOfMassTransform()*m_rbBFrame.getOrigin(); btVector3 relPos = pivotBInW - pivotAInW; btVector3 normal[3]; if (relPos.length2() > SIMD_EPSILON) { normal[0] = relPos.normalized(); } else { normal[0].setValue(btScalar(1.0),0,0); } btPlaneSpace1(normal[0], normal[1], normal[2]); for (int i=0;i<3;i++) { new (&m_jac[i]) btJacobianEntry( m_rbA.getCenterOfMassTransform().getBasis().transpose(), m_rbB.getCenterOfMassTransform().getBasis().transpose(), pivotAInW - m_rbA.getCenterOfMassPosition(), pivotBInW - m_rbB.getCenterOfMassPosition(), normal[i], m_rbA.getInvInertiaDiagLocal(), m_rbA.getInvMass(), m_rbB.getInvInertiaDiagLocal(), m_rbB.getInvMass()); } } calcAngleInfo2(m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform(),m_rbA.getInvInertiaTensorWorld(),m_rbB.getInvInertiaTensorWorld()); } } void btConeTwistConstraint::solveConstraintObsolete(btRigidBody& bodyA,btRigidBody& bodyB,btScalar timeStep) { #ifndef __SPU__ if (m_useSolveConstraintObsolete) { btVector3 pivotAInW = m_rbA.getCenterOfMassTransform()*m_rbAFrame.getOrigin(); btVector3 pivotBInW = m_rbB.getCenterOfMassTransform()*m_rbBFrame.getOrigin(); btScalar tau = btScalar(0.3); //linear part if (!m_angularOnly) { btVector3 rel_pos1 = pivotAInW - m_rbA.getCenterOfMassPosition(); btVector3 rel_pos2 = pivotBInW - m_rbB.getCenterOfMassPosition(); btVector3 vel1; bodyA.internalGetVelocityInLocalPointObsolete(rel_pos1,vel1); btVector3 vel2; bodyB.internalGetVelocityInLocalPointObsolete(rel_pos2,vel2); btVector3 vel = vel1 - vel2; for (int i=0;i<3;i++) { const btVector3& normal = m_jac[i].m_linearJointAxis; btScalar jacDiagABInv = btScalar(1.) / m_jac[i].getDiagonal(); btScalar rel_vel; rel_vel = normal.dot(vel); //positional error (zeroth order error) btScalar depth = -(pivotAInW - pivotBInW).dot(normal); //this is the error projected on the normal btScalar impulse = depth*tau/timeStep * jacDiagABInv - rel_vel * jacDiagABInv; m_appliedImpulse += impulse; btVector3 ftorqueAxis1 = rel_pos1.cross(normal); btVector3 ftorqueAxis2 = rel_pos2.cross(normal); bodyA.internalApplyImpulse(normal*m_rbA.getInvMass(), m_rbA.getInvInertiaTensorWorld()*ftorqueAxis1,impulse); bodyB.internalApplyImpulse(normal*m_rbB.getInvMass(), m_rbB.getInvInertiaTensorWorld()*ftorqueAxis2,-impulse); } } // apply motor if (m_bMotorEnabled) { // compute current and predicted transforms btTransform trACur = m_rbA.getCenterOfMassTransform(); btTransform trBCur = m_rbB.getCenterOfMassTransform(); btVector3 omegaA; bodyA.internalGetAngularVelocity(omegaA); btVector3 omegaB; bodyB.internalGetAngularVelocity(omegaB); btTransform trAPred; trAPred.setIdentity(); btVector3 zerovec(0,0,0); btTransformUtil::integrateTransform( trACur, zerovec, omegaA, timeStep, trAPred); btTransform trBPred; trBPred.setIdentity(); btTransformUtil::integrateTransform( trBCur, zerovec, omegaB, timeStep, trBPred); // compute desired transforms in world btTransform trPose(m_qTarget); btTransform trABDes = m_rbBFrame * trPose * m_rbAFrame.inverse(); btTransform trADes = trBPred * trABDes; btTransform trBDes = trAPred * trABDes.inverse(); // compute desired omegas in world btVector3 omegaADes, omegaBDes; btTransformUtil::calculateVelocity(trACur, trADes, timeStep, zerovec, omegaADes); btTransformUtil::calculateVelocity(trBCur, trBDes, timeStep, zerovec, omegaBDes); // compute delta omegas btVector3 dOmegaA = omegaADes - omegaA; btVector3 dOmegaB = omegaBDes - omegaB; // compute weighted avg axis of dOmega (weighting based on inertias) btVector3 axisA, axisB; btScalar kAxisAInv = 0, kAxisBInv = 0; if (dOmegaA.length2() > SIMD_EPSILON) { axisA = dOmegaA.normalized(); kAxisAInv = getRigidBodyA().computeAngularImpulseDenominator(axisA); } if (dOmegaB.length2() > SIMD_EPSILON) { axisB = dOmegaB.normalized(); kAxisBInv = getRigidBodyB().computeAngularImpulseDenominator(axisB); } btVector3 avgAxis = kAxisAInv * axisA + kAxisBInv * axisB; static bool bDoTorque = true; if (bDoTorque && avgAxis.length2() > SIMD_EPSILON) { avgAxis.normalize(); kAxisAInv = getRigidBodyA().computeAngularImpulseDenominator(avgAxis); kAxisBInv = getRigidBodyB().computeAngularImpulseDenominator(avgAxis); btScalar kInvCombined = kAxisAInv + kAxisBInv; btVector3 impulse = (kAxisAInv * dOmegaA - kAxisBInv * dOmegaB) / (kInvCombined * kInvCombined); if (m_maxMotorImpulse >= 0) { btScalar fMaxImpulse = m_maxMotorImpulse; if (m_bNormalizedMotorStrength) fMaxImpulse = fMaxImpulse/kAxisAInv; btVector3 newUnclampedAccImpulse = m_accMotorImpulse + impulse; btScalar newUnclampedMag = newUnclampedAccImpulse.length(); if (newUnclampedMag > fMaxImpulse) { newUnclampedAccImpulse.normalize(); newUnclampedAccImpulse *= fMaxImpulse; impulse = newUnclampedAccImpulse - m_accMotorImpulse; } m_accMotorImpulse += impulse; } btScalar impulseMag = impulse.length(); btVector3 impulseAxis = impulse / impulseMag; bodyA.internalApplyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*impulseAxis, impulseMag); bodyB.internalApplyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*impulseAxis, -impulseMag); } } else if (m_damping > SIMD_EPSILON) // no motor: do a little damping { btVector3 angVelA; bodyA.internalGetAngularVelocity(angVelA); btVector3 angVelB; bodyB.internalGetAngularVelocity(angVelB); btVector3 relVel = angVelB - angVelA; if (relVel.length2() > SIMD_EPSILON) { btVector3 relVelAxis = relVel.normalized(); btScalar m_kDamping = btScalar(1.) / (getRigidBodyA().computeAngularImpulseDenominator(relVelAxis) + getRigidBodyB().computeAngularImpulseDenominator(relVelAxis)); btVector3 impulse = m_damping * m_kDamping * relVel; btScalar impulseMag = impulse.length(); btVector3 impulseAxis = impulse / impulseMag; bodyA.internalApplyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*impulseAxis, impulseMag); bodyB.internalApplyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*impulseAxis, -impulseMag); } } // joint limits { ///solve angular part btVector3 angVelA; bodyA.internalGetAngularVelocity(angVelA); btVector3 angVelB; bodyB.internalGetAngularVelocity(angVelB); // solve swing limit if (m_solveSwingLimit) { btScalar amplitude = m_swingLimitRatio * m_swingCorrection*m_biasFactor/timeStep; btScalar relSwingVel = (angVelB - angVelA).dot(m_swingAxis); if (relSwingVel > 0) amplitude += m_swingLimitRatio * relSwingVel * m_relaxationFactor; btScalar impulseMag = amplitude * m_kSwing; // Clamp the accumulated impulse btScalar temp = m_accSwingLimitImpulse; m_accSwingLimitImpulse = btMax(m_accSwingLimitImpulse + impulseMag, btScalar(0.0) ); impulseMag = m_accSwingLimitImpulse - temp; btVector3 impulse = m_swingAxis * impulseMag; // don't let cone response affect twist // (this can happen since body A's twist doesn't match body B's AND we use an elliptical cone limit) { btVector3 impulseTwistCouple = impulse.dot(m_twistAxisA) * m_twistAxisA; btVector3 impulseNoTwistCouple = impulse - impulseTwistCouple; impulse = impulseNoTwistCouple; } impulseMag = impulse.length(); btVector3 noTwistSwingAxis = impulse / impulseMag; bodyA.internalApplyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*noTwistSwingAxis, impulseMag); bodyB.internalApplyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*noTwistSwingAxis, -impulseMag); } // solve twist limit if (m_solveTwistLimit) { btScalar amplitude = m_twistLimitRatio * m_twistCorrection*m_biasFactor/timeStep; btScalar relTwistVel = (angVelB - angVelA).dot( m_twistAxis ); if (relTwistVel > 0) // only damp when moving towards limit (m_twistAxis flipping is important) amplitude += m_twistLimitRatio * relTwistVel * m_relaxationFactor; btScalar impulseMag = amplitude * m_kTwist; // Clamp the accumulated impulse btScalar temp = m_accTwistLimitImpulse; m_accTwistLimitImpulse = btMax(m_accTwistLimitImpulse + impulseMag, btScalar(0.0) ); impulseMag = m_accTwistLimitImpulse - temp; btVector3 impulse = m_twistAxis * impulseMag; bodyA.internalApplyImpulse(btVector3(0,0,0), m_rbA.getInvInertiaTensorWorld()*m_twistAxis,impulseMag); bodyB.internalApplyImpulse(btVector3(0,0,0), m_rbB.getInvInertiaTensorWorld()*m_twistAxis,-impulseMag); } } } #else btAssert(0); #endif //__SPU__ } void btConeTwistConstraint::updateRHS(btScalar timeStep) { (void)timeStep; } #ifndef __SPU__ void btConeTwistConstraint::calcAngleInfo() { m_swingCorrection = btScalar(0.); m_twistLimitSign = btScalar(0.); m_solveTwistLimit = false; m_solveSwingLimit = false; btVector3 b1Axis1,b1Axis2,b1Axis3; btVector3 b2Axis1,b2Axis2; b1Axis1 = getRigidBodyA().getCenterOfMassTransform().getBasis() * this->m_rbAFrame.getBasis().getColumn(0); b2Axis1 = getRigidBodyB().getCenterOfMassTransform().getBasis() * this->m_rbBFrame.getBasis().getColumn(0); btScalar swing1=btScalar(0.),swing2 = btScalar(0.); btScalar swx=btScalar(0.),swy = btScalar(0.); btScalar thresh = btScalar(10.); btScalar fact; // Get Frame into world space if (m_swingSpan1 >= btScalar(0.05f)) { b1Axis2 = getRigidBodyA().getCenterOfMassTransform().getBasis() * this->m_rbAFrame.getBasis().getColumn(1); swx = b2Axis1.dot(b1Axis1); swy = b2Axis1.dot(b1Axis2); swing1 = btAtan2Fast(swy, swx); fact = (swy*swy + swx*swx) * thresh * thresh; fact = fact / (fact + btScalar(1.0)); swing1 *= fact; } if (m_swingSpan2 >= btScalar(0.05f)) { b1Axis3 = getRigidBodyA().getCenterOfMassTransform().getBasis() * this->m_rbAFrame.getBasis().getColumn(2); swx = b2Axis1.dot(b1Axis1); swy = b2Axis1.dot(b1Axis3); swing2 = btAtan2Fast(swy, swx); fact = (swy*swy + swx*swx) * thresh * thresh; fact = fact / (fact + btScalar(1.0)); swing2 *= fact; } btScalar RMaxAngle1Sq = 1.0f / (m_swingSpan1*m_swingSpan1); btScalar RMaxAngle2Sq = 1.0f / (m_swingSpan2*m_swingSpan2); btScalar EllipseAngle = btFabs(swing1*swing1)* RMaxAngle1Sq + btFabs(swing2*swing2) * RMaxAngle2Sq; if (EllipseAngle > 1.0f) { m_swingCorrection = EllipseAngle-1.0f; m_solveSwingLimit = true; // Calculate necessary axis & factors m_swingAxis = b2Axis1.cross(b1Axis2* b2Axis1.dot(b1Axis2) + b1Axis3* b2Axis1.dot(b1Axis3)); m_swingAxis.normalize(); btScalar swingAxisSign = (b2Axis1.dot(b1Axis1) >= 0.0f) ? 1.0f : -1.0f; m_swingAxis *= swingAxisSign; } // Twist limits if (m_twistSpan >= btScalar(0.)) { btVector3 b2Axis2 = getRigidBodyB().getCenterOfMassTransform().getBasis() * this->m_rbBFrame.getBasis().getColumn(1); btQuaternion rotationArc = shortestArcQuat(b2Axis1,b1Axis1); btVector3 TwistRef = quatRotate(rotationArc,b2Axis2); btScalar twist = btAtan2Fast( TwistRef.dot(b1Axis3), TwistRef.dot(b1Axis2) ); m_twistAngle = twist; // btScalar lockedFreeFactor = (m_twistSpan > btScalar(0.05f)) ? m_limitSoftness : btScalar(0.); btScalar lockedFreeFactor = (m_twistSpan > btScalar(0.05f)) ? btScalar(1.0f) : btScalar(0.); if (twist <= -m_twistSpan*lockedFreeFactor) { m_twistCorrection = -(twist + m_twistSpan); m_solveTwistLimit = true; m_twistAxis = (b2Axis1 + b1Axis1) * 0.5f; m_twistAxis.normalize(); m_twistAxis *= -1.0f; } else if (twist > m_twistSpan*lockedFreeFactor) { m_twistCorrection = (twist - m_twistSpan); m_solveTwistLimit = true; m_twistAxis = (b2Axis1 + b1Axis1) * 0.5f; m_twistAxis.normalize(); } } } #endif //__SPU__ static btVector3 vTwist(1,0,0); // twist axis in constraint's space void btConeTwistConstraint::calcAngleInfo2(const btTransform& transA, const btTransform& transB, const btMatrix3x3& invInertiaWorldA,const btMatrix3x3& invInertiaWorldB) { m_swingCorrection = btScalar(0.); m_twistLimitSign = btScalar(0.); m_solveTwistLimit = false; m_solveSwingLimit = false; // compute rotation of A wrt B (in constraint space) if (m_bMotorEnabled && (!m_useSolveConstraintObsolete)) { // it is assumed that setMotorTarget() was alredy called // and motor target m_qTarget is within constraint limits // TODO : split rotation to pure swing and pure twist // compute desired transforms in world btTransform trPose(m_qTarget); btTransform trA = transA * m_rbAFrame; btTransform trB = transB * m_rbBFrame; btTransform trDeltaAB = trB * trPose * trA.inverse(); btQuaternion qDeltaAB = trDeltaAB.getRotation(); btVector3 swingAxis = btVector3(qDeltaAB.x(), qDeltaAB.y(), qDeltaAB.z()); m_swingAxis = swingAxis; m_swingAxis.normalize(); m_swingCorrection = qDeltaAB.getAngle(); if(!btFuzzyZero(m_swingCorrection)) { m_solveSwingLimit = true; } return; } { // compute rotation of A wrt B (in constraint space) btQuaternion qA = transA.getRotation() * m_rbAFrame.getRotation(); btQuaternion qB = transB.getRotation() * m_rbBFrame.getRotation(); btQuaternion qAB = qB.inverse() * qA; // split rotation into cone and twist // (all this is done from B's perspective. Maybe I should be averaging axes...) btVector3 vConeNoTwist = quatRotate(qAB, vTwist); vConeNoTwist.normalize(); btQuaternion qABCone = shortestArcQuat(vTwist, vConeNoTwist); qABCone.normalize(); btQuaternion qABTwist = qABCone.inverse() * qAB; qABTwist.normalize(); if (m_swingSpan1 >= m_fixThresh && m_swingSpan2 >= m_fixThresh) { btScalar swingAngle, swingLimit = 0; btVector3 swingAxis; computeConeLimitInfo(qABCone, swingAngle, swingAxis, swingLimit); if (swingAngle > swingLimit * m_limitSoftness) { m_solveSwingLimit = true; // compute limit ratio: 0->1, where // 0 == beginning of soft limit // 1 == hard/real limit m_swingLimitRatio = 1.f; if (swingAngle < swingLimit && m_limitSoftness < 1.f - SIMD_EPSILON) { m_swingLimitRatio = (swingAngle - swingLimit * m_limitSoftness)/ (swingLimit - swingLimit * m_limitSoftness); } // swing correction tries to get back to soft limit m_swingCorrection = swingAngle - (swingLimit * m_limitSoftness); // adjustment of swing axis (based on ellipse normal) adjustSwingAxisToUseEllipseNormal(swingAxis); // Calculate necessary axis & factors m_swingAxis = quatRotate(qB, -swingAxis); m_twistAxisA.setValue(0,0,0); m_kSwing = btScalar(1.) / (computeAngularImpulseDenominator(m_swingAxis,invInertiaWorldA) + computeAngularImpulseDenominator(m_swingAxis,invInertiaWorldB)); } } else { // you haven't set any limits; // or you're trying to set at least one of the swing limits too small. (if so, do you really want a conetwist constraint?) // anyway, we have either hinge or fixed joint btVector3 ivA = transA.getBasis() * m_rbAFrame.getBasis().getColumn(0); btVector3 jvA = transA.getBasis() * m_rbAFrame.getBasis().getColumn(1); btVector3 kvA = transA.getBasis() * m_rbAFrame.getBasis().getColumn(2); btVector3 ivB = transB.getBasis() * m_rbBFrame.getBasis().getColumn(0); btVector3 target; btScalar x = ivB.dot(ivA); btScalar y = ivB.dot(jvA); btScalar z = ivB.dot(kvA); if((m_swingSpan1 < m_fixThresh) && (m_swingSpan2 < m_fixThresh)) { // fixed. We'll need to add one more row to constraint if((!btFuzzyZero(y)) || (!(btFuzzyZero(z)))) { m_solveSwingLimit = true; m_swingAxis = -ivB.cross(ivA); } } else { if(m_swingSpan1 < m_fixThresh) { // hinge around Y axis if(!(btFuzzyZero(y))) { m_solveSwingLimit = true; if(m_swingSpan2 >= m_fixThresh) { y = btScalar(0.f); btScalar span2 = btAtan2(z, x); if(span2 > m_swingSpan2) { x = btCos(m_swingSpan2); z = btSin(m_swingSpan2); } else if(span2 < -m_swingSpan2) { x = btCos(m_swingSpan2); z = -btSin(m_swingSpan2); } } } } else { // hinge around Z axis if(!btFuzzyZero(z)) { m_solveSwingLimit = true; if(m_swingSpan1 >= m_fixThresh) { z = btScalar(0.f); btScalar span1 = btAtan2(y, x); if(span1 > m_swingSpan1) { x = btCos(m_swingSpan1); y = btSin(m_swingSpan1); } else if(span1 < -m_swingSpan1) { x = btCos(m_swingSpan1); y = -btSin(m_swingSpan1); } } } } target[0] = x * ivA[0] + y * jvA[0] + z * kvA[0]; target[1] = x * ivA[1] + y * jvA[1] + z * kvA[1]; target[2] = x * ivA[2] + y * jvA[2] + z * kvA[2]; target.normalize(); m_swingAxis = -ivB.cross(target); m_swingCorrection = m_swingAxis.length(); m_swingAxis.normalize(); } } if (m_twistSpan >= btScalar(0.f)) { btVector3 twistAxis; computeTwistLimitInfo(qABTwist, m_twistAngle, twistAxis); if (m_twistAngle > m_twistSpan*m_limitSoftness) { m_solveTwistLimit = true; m_twistLimitRatio = 1.f; if (m_twistAngle < m_twistSpan && m_limitSoftness < 1.f - SIMD_EPSILON) { m_twistLimitRatio = (m_twistAngle - m_twistSpan * m_limitSoftness)/ (m_twistSpan - m_twistSpan * m_limitSoftness); } // twist correction tries to get back to soft limit m_twistCorrection = m_twistAngle - (m_twistSpan * m_limitSoftness); m_twistAxis = quatRotate(qB, -twistAxis); m_kTwist = btScalar(1.) / (computeAngularImpulseDenominator(m_twistAxis,invInertiaWorldA) + computeAngularImpulseDenominator(m_twistAxis,invInertiaWorldB)); } if (m_solveSwingLimit) m_twistAxisA = quatRotate(qA, -twistAxis); } else { m_twistAngle = btScalar(0.f); } } } // given a cone rotation in constraint space, (pre: twist must already be removed) // this method computes its corresponding swing angle and axis. // more interestingly, it computes the cone/swing limit (angle) for this cone "pose". void btConeTwistConstraint::computeConeLimitInfo(const btQuaternion& qCone, btScalar& swingAngle, // out btVector3& vSwingAxis, // out btScalar& swingLimit) // out { swingAngle = qCone.getAngle(); if (swingAngle > SIMD_EPSILON) { vSwingAxis = btVector3(qCone.x(), qCone.y(), qCone.z()); vSwingAxis.normalize(); if (fabs(vSwingAxis.x()) > SIMD_EPSILON) { // non-zero twist?! this should never happen. int wtf = 0; wtf = wtf; } // Compute limit for given swing. tricky: // Given a swing axis, we're looking for the intersection with the bounding cone ellipse. // (Since we're dealing with angles, this ellipse is embedded on the surface of a sphere.) // For starters, compute the direction from center to surface of ellipse. // This is just the perpendicular (ie. rotate 2D vector by PI/2) of the swing axis. // (vSwingAxis is the cone rotation (in z,y); change vars and rotate to (x,y) coords.) btScalar xEllipse = vSwingAxis.y(); btScalar yEllipse = -vSwingAxis.z(); // Now, we use the slope of the vector (using x/yEllipse) and find the length // of the line that intersects the ellipse: // x^2 y^2 // --- + --- = 1, where a and b are semi-major axes 2 and 1 respectively (ie. the limits) // a^2 b^2 // Do the math and it should be clear. swingLimit = m_swingSpan1; // if xEllipse == 0, we have a pure vSwingAxis.z rotation: just use swingspan1 if (fabs(xEllipse) > SIMD_EPSILON) { btScalar surfaceSlope2 = (yEllipse*yEllipse)/(xEllipse*xEllipse); btScalar norm = 1 / (m_swingSpan2 * m_swingSpan2); norm += surfaceSlope2 / (m_swingSpan1 * m_swingSpan1); btScalar swingLimit2 = (1 + surfaceSlope2) / norm; swingLimit = sqrt(swingLimit2); } // test! /*swingLimit = m_swingSpan2; if (fabs(vSwingAxis.z()) > SIMD_EPSILON) { btScalar mag_2 = m_swingSpan1*m_swingSpan1 + m_swingSpan2*m_swingSpan2; btScalar sinphi = m_swingSpan2 / sqrt(mag_2); btScalar phi = asin(sinphi); btScalar theta = atan2(fabs(vSwingAxis.y()),fabs(vSwingAxis.z())); btScalar alpha = 3.14159f - theta - phi; btScalar sinalpha = sin(alpha); swingLimit = m_swingSpan1 * sinphi/sinalpha; }*/ } else if (swingAngle < 0) { // this should never happen! int wtf = 0; wtf = wtf; } } btVector3 btConeTwistConstraint::GetPointForAngle(btScalar fAngleInRadians, btScalar fLength) const { // compute x/y in ellipse using cone angle (0 -> 2*PI along surface of cone) btScalar xEllipse = btCos(fAngleInRadians); btScalar yEllipse = btSin(fAngleInRadians); // Use the slope of the vector (using x/yEllipse) and find the length // of the line that intersects the ellipse: // x^2 y^2 // --- + --- = 1, where a and b are semi-major axes 2 and 1 respectively (ie. the limits) // a^2 b^2 // Do the math and it should be clear. float swingLimit = m_swingSpan1; // if xEllipse == 0, just use axis b (1) if (fabs(xEllipse) > SIMD_EPSILON) { btScalar surfaceSlope2 = (yEllipse*yEllipse)/(xEllipse*xEllipse); btScalar norm = 1 / (m_swingSpan2 * m_swingSpan2); norm += surfaceSlope2 / (m_swingSpan1 * m_swingSpan1); btScalar swingLimit2 = (1 + surfaceSlope2) / norm; swingLimit = sqrt(swingLimit2); } // convert into point in constraint space: // note: twist is x-axis, swing 1 and 2 are along the z and y axes respectively btVector3 vSwingAxis(0, xEllipse, -yEllipse); btQuaternion qSwing(vSwingAxis, swingLimit); btVector3 vPointInConstraintSpace(fLength,0,0); return quatRotate(qSwing, vPointInConstraintSpace); } // given a twist rotation in constraint space, (pre: cone must already be removed) // this method computes its corresponding angle and axis. void btConeTwistConstraint::computeTwistLimitInfo(const btQuaternion& qTwist, btScalar& twistAngle, // out btVector3& vTwistAxis) // out { btQuaternion qMinTwist = qTwist; twistAngle = qTwist.getAngle(); if (twistAngle > SIMD_PI) // long way around. flip quat and recalculate. { qMinTwist = operator-(qTwist); twistAngle = qMinTwist.getAngle(); } if (twistAngle < 0) { // this should never happen int wtf = 0; wtf = wtf; } vTwistAxis = btVector3(qMinTwist.x(), qMinTwist.y(), qMinTwist.z()); if (twistAngle > SIMD_EPSILON) vTwistAxis.normalize(); } void btConeTwistConstraint::adjustSwingAxisToUseEllipseNormal(btVector3& vSwingAxis) const { // the swing axis is computed as the "twist-free" cone rotation, // but the cone limit is not circular, but elliptical (if swingspan1 != swingspan2). // so, if we're outside the limits, the closest way back inside the cone isn't // along the vector back to the center. better (and more stable) to use the ellipse normal. // convert swing axis to direction from center to surface of ellipse // (ie. rotate 2D vector by PI/2) btScalar y = -vSwingAxis.z(); btScalar z = vSwingAxis.y(); // do the math... if (fabs(z) > SIMD_EPSILON) // avoid division by 0. and we don't need an update if z == 0. { // compute gradient/normal of ellipse surface at current "point" btScalar grad = y/z; grad *= m_swingSpan2 / m_swingSpan1; // adjust y/z to represent normal at point (instead of vector to point) if (y > 0) y = fabs(grad * z); else y = -fabs(grad * z); // convert ellipse direction back to swing axis vSwingAxis.setZ(-y); vSwingAxis.setY( z); vSwingAxis.normalize(); } } void btConeTwistConstraint::setMotorTarget(const btQuaternion &q) { btTransform trACur = m_rbA.getCenterOfMassTransform(); btTransform trBCur = m_rbB.getCenterOfMassTransform(); btTransform trABCur = trBCur.inverse() * trACur; btQuaternion qABCur = trABCur.getRotation(); btTransform trConstraintCur = (trBCur * m_rbBFrame).inverse() * (trACur * m_rbAFrame); btQuaternion qConstraintCur = trConstraintCur.getRotation(); btQuaternion qConstraint = m_rbBFrame.getRotation().inverse() * q * m_rbAFrame.getRotation(); setMotorTargetInConstraintSpace(qConstraint); } void btConeTwistConstraint::setMotorTargetInConstraintSpace(const btQuaternion &q) { m_qTarget = q; // clamp motor target to within limits { btScalar softness = 1.f;//m_limitSoftness; // split into twist and cone btVector3 vTwisted = quatRotate(m_qTarget, vTwist); btQuaternion qTargetCone = shortestArcQuat(vTwist, vTwisted); qTargetCone.normalize(); btQuaternion qTargetTwist = qTargetCone.inverse() * m_qTarget; qTargetTwist.normalize(); // clamp cone if (m_swingSpan1 >= btScalar(0.05f) && m_swingSpan2 >= btScalar(0.05f)) { btScalar swingAngle, swingLimit; btVector3 swingAxis; computeConeLimitInfo(qTargetCone, swingAngle, swingAxis, swingLimit); if (fabs(swingAngle) > SIMD_EPSILON) { if (swingAngle > swingLimit*softness) swingAngle = swingLimit*softness; else if (swingAngle < -swingLimit*softness) swingAngle = -swingLimit*softness; qTargetCone = btQuaternion(swingAxis, swingAngle); } } // clamp twist if (m_twistSpan >= btScalar(0.05f)) { btScalar twistAngle; btVector3 twistAxis; computeTwistLimitInfo(qTargetTwist, twistAngle, twistAxis); if (fabs(twistAngle) > SIMD_EPSILON) { // eddy todo: limitSoftness used here??? if (twistAngle > m_twistSpan*softness) twistAngle = m_twistSpan*softness; else if (twistAngle < -m_twistSpan*softness) twistAngle = -m_twistSpan*softness; qTargetTwist = btQuaternion(twistAxis, twistAngle); } } m_qTarget = qTargetCone * qTargetTwist; } } ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). ///If no axis is provided, it uses the default axis for this constraint. void btConeTwistConstraint::setParam(int num, btScalar value, int axis) { switch(num) { case BT_CONSTRAINT_ERP : case BT_CONSTRAINT_STOP_ERP : if((axis >= 0) && (axis < 3)) { m_linERP = value; m_flags |= BT_CONETWIST_FLAGS_LIN_ERP; } else { m_biasFactor = value; } break; case BT_CONSTRAINT_CFM : case BT_CONSTRAINT_STOP_CFM : if((axis >= 0) && (axis < 3)) { m_linCFM = value; m_flags |= BT_CONETWIST_FLAGS_LIN_CFM; } else { m_angCFM = value; m_flags |= BT_CONETWIST_FLAGS_ANG_CFM; } break; default: btAssertConstrParams(0); break; } } ///return the local value of parameter btScalar btConeTwistConstraint::getParam(int num, int axis) const { btScalar retVal = 0; switch(num) { case BT_CONSTRAINT_ERP : case BT_CONSTRAINT_STOP_ERP : if((axis >= 0) && (axis < 3)) { btAssertConstrParams(m_flags & BT_CONETWIST_FLAGS_LIN_ERP); retVal = m_linERP; } else if((axis >= 3) && (axis < 6)) { retVal = m_biasFactor; } else { btAssertConstrParams(0); } break; case BT_CONSTRAINT_CFM : case BT_CONSTRAINT_STOP_CFM : if((axis >= 0) && (axis < 3)) { btAssertConstrParams(m_flags & BT_CONETWIST_FLAGS_LIN_CFM); retVal = m_linCFM; } else if((axis >= 3) && (axis < 6)) { btAssertConstrParams(m_flags & BT_CONETWIST_FLAGS_ANG_CFM); retVal = m_angCFM; } else { btAssertConstrParams(0); } break; default : btAssertConstrParams(0); } return retVal; } critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btPoint2PointConstraint.cpp0000644000175000017500000001371411344267705032514 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btPoint2PointConstraint.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include btPoint2PointConstraint::btPoint2PointConstraint(btRigidBody& rbA,btRigidBody& rbB, const btVector3& pivotInA,const btVector3& pivotInB) :btTypedConstraint(POINT2POINT_CONSTRAINT_TYPE,rbA,rbB),m_pivotInA(pivotInA),m_pivotInB(pivotInB), m_flags(0), m_useSolveConstraintObsolete(false) { } btPoint2PointConstraint::btPoint2PointConstraint(btRigidBody& rbA,const btVector3& pivotInA) :btTypedConstraint(POINT2POINT_CONSTRAINT_TYPE,rbA),m_pivotInA(pivotInA),m_pivotInB(rbA.getCenterOfMassTransform()(pivotInA)), m_flags(0), m_useSolveConstraintObsolete(false) { } void btPoint2PointConstraint::buildJacobian() { ///we need it for both methods { m_appliedImpulse = btScalar(0.); btVector3 normal(0,0,0); for (int i=0;i<3;i++) { normal[i] = 1; new (&m_jac[i]) btJacobianEntry( m_rbA.getCenterOfMassTransform().getBasis().transpose(), m_rbB.getCenterOfMassTransform().getBasis().transpose(), m_rbA.getCenterOfMassTransform()*m_pivotInA - m_rbA.getCenterOfMassPosition(), m_rbB.getCenterOfMassTransform()*m_pivotInB - m_rbB.getCenterOfMassPosition(), normal, m_rbA.getInvInertiaDiagLocal(), m_rbA.getInvMass(), m_rbB.getInvInertiaDiagLocal(), m_rbB.getInvMass()); normal[i] = 0; } } } void btPoint2PointConstraint::getInfo1 (btConstraintInfo1* info) { getInfo1NonVirtual(info); } void btPoint2PointConstraint::getInfo1NonVirtual (btConstraintInfo1* info) { if (m_useSolveConstraintObsolete) { info->m_numConstraintRows = 0; info->nub = 0; } else { info->m_numConstraintRows = 3; info->nub = 3; } } void btPoint2PointConstraint::getInfo2 (btConstraintInfo2* info) { getInfo2NonVirtual(info, m_rbA.getCenterOfMassTransform(),m_rbB.getCenterOfMassTransform()); } void btPoint2PointConstraint::getInfo2NonVirtual (btConstraintInfo2* info, const btTransform& body0_trans, const btTransform& body1_trans) { btAssert(!m_useSolveConstraintObsolete); //retrieve matrices // anchor points in global coordinates with respect to body PORs. // set jacobian info->m_J1linearAxis[0] = 1; info->m_J1linearAxis[info->rowskip+1] = 1; info->m_J1linearAxis[2*info->rowskip+2] = 1; btVector3 a1 = body0_trans.getBasis()*getPivotInA(); { btVector3* angular0 = (btVector3*)(info->m_J1angularAxis); btVector3* angular1 = (btVector3*)(info->m_J1angularAxis+info->rowskip); btVector3* angular2 = (btVector3*)(info->m_J1angularAxis+2*info->rowskip); btVector3 a1neg = -a1; a1neg.getSkewSymmetricMatrix(angular0,angular1,angular2); } /*info->m_J2linearAxis[0] = -1; info->m_J2linearAxis[s+1] = -1; info->m_J2linearAxis[2*s+2] = -1; */ btVector3 a2 = body1_trans.getBasis()*getPivotInB(); { btVector3 a2n = -a2; btVector3* angular0 = (btVector3*)(info->m_J2angularAxis); btVector3* angular1 = (btVector3*)(info->m_J2angularAxis+info->rowskip); btVector3* angular2 = (btVector3*)(info->m_J2angularAxis+2*info->rowskip); a2.getSkewSymmetricMatrix(angular0,angular1,angular2); } // set right hand side btScalar currERP = (m_flags & BT_P2P_FLAGS_ERP) ? m_erp : info->erp; btScalar k = info->fps * currERP; int j; for (j=0; j<3; j++) { info->m_constraintError[j*info->rowskip] = k * (a2[j] + body1_trans.getOrigin()[j] - a1[j] - body0_trans.getOrigin()[j]); //printf("info->m_constraintError[%d]=%f\n",j,info->m_constraintError[j]); } if(m_flags & BT_P2P_FLAGS_CFM) { for (j=0; j<3; j++) { info->cfm[j*info->rowskip] = m_cfm; } } btScalar impulseClamp = m_setting.m_impulseClamp;// for (j=0; j<3; j++) { if (m_setting.m_impulseClamp > 0) { info->m_lowerLimit[j*info->rowskip] = -impulseClamp; info->m_upperLimit[j*info->rowskip] = impulseClamp; } } } void btPoint2PointConstraint::updateRHS(btScalar timeStep) { (void)timeStep; } ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). ///If no axis is provided, it uses the default axis for this constraint. void btPoint2PointConstraint::setParam(int num, btScalar value, int axis) { if(axis != -1) { btAssertConstrParams(0); } else { switch(num) { case BT_CONSTRAINT_ERP : case BT_CONSTRAINT_STOP_ERP : m_erp = value; m_flags |= BT_P2P_FLAGS_ERP; break; case BT_CONSTRAINT_CFM : case BT_CONSTRAINT_STOP_CFM : m_cfm = value; m_flags |= BT_P2P_FLAGS_CFM; break; default: btAssertConstrParams(0); } } } ///return the local value of parameter btScalar btPoint2PointConstraint::getParam(int num, int axis) const { btScalar retVal(SIMD_INFINITY); if(axis != -1) { btAssertConstrParams(0); } else { switch(num) { case BT_CONSTRAINT_ERP : case BT_CONSTRAINT_STOP_ERP : btAssertConstrParams(m_flags & BT_P2P_FLAGS_ERP); retVal = m_erp; break; case BT_CONSTRAINT_CFM : case BT_CONSTRAINT_STOP_CFM : btAssertConstrParams(m_flags & BT_P2P_FLAGS_CFM); retVal = m_cfm; break; default: btAssertConstrParams(0); } } return retVal; } critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btSolverBody.h0000644000175000017500000001233211344267705030012 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BT_SOLVER_BODY_H #define BT_SOLVER_BODY_H class btRigidBody; #include "LinearMath/btVector3.h" #include "LinearMath/btMatrix3x3.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "LinearMath/btAlignedAllocator.h" #include "LinearMath/btTransformUtil.h" ///Until we get other contributions, only use SIMD on Windows, when using Visual Studio 2008 or later, and not double precision #ifdef BT_USE_SSE #define USE_SIMD 1 #endif // #ifdef USE_SIMD struct btSimdScalar { SIMD_FORCE_INLINE btSimdScalar() { } SIMD_FORCE_INLINE btSimdScalar(float fl) :m_vec128 (_mm_set1_ps(fl)) { } SIMD_FORCE_INLINE btSimdScalar(__m128 v128) :m_vec128(v128) { } union { __m128 m_vec128; float m_floats[4]; int m_ints[4]; btScalar m_unusedPadding; }; SIMD_FORCE_INLINE __m128 get128() { return m_vec128; } SIMD_FORCE_INLINE const __m128 get128() const { return m_vec128; } SIMD_FORCE_INLINE void set128(__m128 v128) { m_vec128 = v128; } SIMD_FORCE_INLINE operator __m128() { return m_vec128; } SIMD_FORCE_INLINE operator const __m128() const { return m_vec128; } SIMD_FORCE_INLINE operator float() const { return m_floats[0]; } }; ///@brief Return the elementwise product of two btSimdScalar SIMD_FORCE_INLINE btSimdScalar operator*(const btSimdScalar& v1, const btSimdScalar& v2) { return btSimdScalar(_mm_mul_ps(v1.get128(),v2.get128())); } ///@brief Return the elementwise product of two btSimdScalar SIMD_FORCE_INLINE btSimdScalar operator+(const btSimdScalar& v1, const btSimdScalar& v2) { return btSimdScalar(_mm_add_ps(v1.get128(),v2.get128())); } #else #define btSimdScalar btScalar #endif ///The btSolverBody is an internal datastructure for the constraint solver. Only necessary data is packed to increase cache coherence/performance. ATTRIBUTE_ALIGNED64 (struct) btSolverBodyObsolete { BT_DECLARE_ALIGNED_ALLOCATOR(); btVector3 m_deltaLinearVelocity; btVector3 m_deltaAngularVelocity; btVector3 m_angularFactor; btVector3 m_invMass; btRigidBody* m_originalBody; btVector3 m_pushVelocity; btVector3 m_turnVelocity; SIMD_FORCE_INLINE void getVelocityInLocalPointObsolete(const btVector3& rel_pos, btVector3& velocity ) const { if (m_originalBody) velocity = m_originalBody->getLinearVelocity()+m_deltaLinearVelocity + (m_originalBody->getAngularVelocity()+m_deltaAngularVelocity).cross(rel_pos); else velocity.setValue(0,0,0); } SIMD_FORCE_INLINE void getAngularVelocity(btVector3& angVel) const { if (m_originalBody) angVel = m_originalBody->getAngularVelocity()+m_deltaAngularVelocity; else angVel.setValue(0,0,0); } //Optimization for the iterative solver: avoid calculating constant terms involving inertia, normal, relative position SIMD_FORCE_INLINE void applyImpulse(const btVector3& linearComponent, const btVector3& angularComponent,const btScalar impulseMagnitude) { //if (m_invMass) { m_deltaLinearVelocity += linearComponent*impulseMagnitude; m_deltaAngularVelocity += angularComponent*(impulseMagnitude*m_angularFactor); } } SIMD_FORCE_INLINE void internalApplyPushImpulse(const btVector3& linearComponent, const btVector3& angularComponent,btScalar impulseMagnitude) { if (m_originalBody) { m_pushVelocity += linearComponent*impulseMagnitude; m_turnVelocity += angularComponent*(impulseMagnitude*m_angularFactor); } } void writebackVelocity() { if (m_originalBody) { m_originalBody->setLinearVelocity(m_originalBody->getLinearVelocity()+ m_deltaLinearVelocity); m_originalBody->setAngularVelocity(m_originalBody->getAngularVelocity()+m_deltaAngularVelocity); //m_originalBody->setCompanionId(-1); } } void writebackVelocity(btScalar timeStep) { (void) timeStep; if (m_originalBody) { m_originalBody->setLinearVelocity(m_originalBody->getLinearVelocity()+ m_deltaLinearVelocity); m_originalBody->setAngularVelocity(m_originalBody->getAngularVelocity()+m_deltaAngularVelocity); //correct the position/orientation based on push/turn recovery btTransform newTransform; btTransformUtil::integrateTransform(m_originalBody->getWorldTransform(),m_pushVelocity,m_turnVelocity,timeStep,newTransform); m_originalBody->setWorldTransform(newTransform); //m_originalBody->setCompanionId(-1); } } }; #endif //BT_SOLVER_BODY_H ././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.cppcritterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintS0000644000175000017500000014012411344267705033336 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ //#define COMPUTE_IMPULSE_DENOM 1 //It is not necessary (redundant) to refresh contact manifolds, this refresh has been moved to the collision algorithms. #include "btSequentialImpulseConstraintSolver.h" #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "btContactConstraint.h" #include "btSolve2LinearConstraint.h" #include "btContactSolverInfo.h" #include "LinearMath/btIDebugDraw.h" #include "btJacobianEntry.h" #include "LinearMath/btMinMax.h" #include "BulletDynamics/ConstraintSolver/btTypedConstraint.h" #include #include "LinearMath/btStackAlloc.h" #include "LinearMath/btQuickprof.h" #include "btSolverBody.h" #include "btSolverConstraint.h" #include "LinearMath/btAlignedObjectArray.h" #include //for memset int gNumSplitImpulseRecoveries = 0; btSequentialImpulseConstraintSolver::btSequentialImpulseConstraintSolver() :m_btSeed2(0) { } btSequentialImpulseConstraintSolver::~btSequentialImpulseConstraintSolver() { } #ifdef USE_SIMD #include #define vec_splat(x, e) _mm_shuffle_ps(x, x, _MM_SHUFFLE(e,e,e,e)) static inline __m128 _vmathVfDot3( __m128 vec0, __m128 vec1 ) { __m128 result = _mm_mul_ps( vec0, vec1); return _mm_add_ps( vec_splat( result, 0 ), _mm_add_ps( vec_splat( result, 1 ), vec_splat( result, 2 ) ) ); } #endif//USE_SIMD // Project Gauss Seidel or the equivalent Sequential Impulse void btSequentialImpulseConstraintSolver::resolveSingleConstraintRowGenericSIMD(btRigidBody& body1,btRigidBody& body2,const btSolverConstraint& c) { #ifdef USE_SIMD __m128 cpAppliedImp = _mm_set1_ps(c.m_appliedImpulse); __m128 lowerLimit1 = _mm_set1_ps(c.m_lowerLimit); __m128 upperLimit1 = _mm_set1_ps(c.m_upperLimit); __m128 deltaImpulse = _mm_sub_ps(_mm_set1_ps(c.m_rhs), _mm_mul_ps(_mm_set1_ps(c.m_appliedImpulse),_mm_set1_ps(c.m_cfm))); __m128 deltaVel1Dotn = _mm_add_ps(_vmathVfDot3(c.m_contactNormal.mVec128,body1.internalGetDeltaLinearVelocity().mVec128), _vmathVfDot3(c.m_relpos1CrossNormal.mVec128,body1.internalGetDeltaAngularVelocity().mVec128)); __m128 deltaVel2Dotn = _mm_sub_ps(_vmathVfDot3(c.m_relpos2CrossNormal.mVec128,body2.internalGetDeltaAngularVelocity().mVec128),_vmathVfDot3((c.m_contactNormal).mVec128,body2.internalGetDeltaLinearVelocity().mVec128)); deltaImpulse = _mm_sub_ps(deltaImpulse,_mm_mul_ps(deltaVel1Dotn,_mm_set1_ps(c.m_jacDiagABInv))); deltaImpulse = _mm_sub_ps(deltaImpulse,_mm_mul_ps(deltaVel2Dotn,_mm_set1_ps(c.m_jacDiagABInv))); btSimdScalar sum = _mm_add_ps(cpAppliedImp,deltaImpulse); btSimdScalar resultLowerLess,resultUpperLess; resultLowerLess = _mm_cmplt_ps(sum,lowerLimit1); resultUpperLess = _mm_cmplt_ps(sum,upperLimit1); __m128 lowMinApplied = _mm_sub_ps(lowerLimit1,cpAppliedImp); deltaImpulse = _mm_or_ps( _mm_and_ps(resultLowerLess, lowMinApplied), _mm_andnot_ps(resultLowerLess, deltaImpulse) ); c.m_appliedImpulse = _mm_or_ps( _mm_and_ps(resultLowerLess, lowerLimit1), _mm_andnot_ps(resultLowerLess, sum) ); __m128 upperMinApplied = _mm_sub_ps(upperLimit1,cpAppliedImp); deltaImpulse = _mm_or_ps( _mm_and_ps(resultUpperLess, deltaImpulse), _mm_andnot_ps(resultUpperLess, upperMinApplied) ); c.m_appliedImpulse = _mm_or_ps( _mm_and_ps(resultUpperLess, c.m_appliedImpulse), _mm_andnot_ps(resultUpperLess, upperLimit1) ); __m128 linearComponentA = _mm_mul_ps(c.m_contactNormal.mVec128,body1.internalGetInvMass().mVec128); __m128 linearComponentB = _mm_mul_ps((c.m_contactNormal).mVec128,body2.internalGetInvMass().mVec128); __m128 impulseMagnitude = deltaImpulse; body1.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaLinearVelocity().mVec128,_mm_mul_ps(linearComponentA,impulseMagnitude)); body1.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaAngularVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentA.mVec128,impulseMagnitude)); body2.internalGetDeltaLinearVelocity().mVec128 = _mm_sub_ps(body2.internalGetDeltaLinearVelocity().mVec128,_mm_mul_ps(linearComponentB,impulseMagnitude)); body2.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body2.internalGetDeltaAngularVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentB.mVec128,impulseMagnitude)); #else resolveSingleConstraintRowGeneric(body1,body2,c); #endif } // Project Gauss Seidel or the equivalent Sequential Impulse void btSequentialImpulseConstraintSolver::resolveSingleConstraintRowGeneric(btRigidBody& body1,btRigidBody& body2,const btSolverConstraint& c) { btScalar deltaImpulse = c.m_rhs-btScalar(c.m_appliedImpulse)*c.m_cfm; const btScalar deltaVel1Dotn = c.m_contactNormal.dot(body1.internalGetDeltaLinearVelocity()) + c.m_relpos1CrossNormal.dot(body1.internalGetDeltaAngularVelocity()); const btScalar deltaVel2Dotn = -c.m_contactNormal.dot(body2.internalGetDeltaLinearVelocity()) + c.m_relpos2CrossNormal.dot(body2.internalGetDeltaAngularVelocity()); // const btScalar delta_rel_vel = deltaVel1Dotn-deltaVel2Dotn; deltaImpulse -= deltaVel1Dotn*c.m_jacDiagABInv; deltaImpulse -= deltaVel2Dotn*c.m_jacDiagABInv; const btScalar sum = btScalar(c.m_appliedImpulse) + deltaImpulse; if (sum < c.m_lowerLimit) { deltaImpulse = c.m_lowerLimit-c.m_appliedImpulse; c.m_appliedImpulse = c.m_lowerLimit; } else if (sum > c.m_upperLimit) { deltaImpulse = c.m_upperLimit-c.m_appliedImpulse; c.m_appliedImpulse = c.m_upperLimit; } else { c.m_appliedImpulse = sum; } body1.internalApplyImpulse(c.m_contactNormal*body1.internalGetInvMass(),c.m_angularComponentA,deltaImpulse); body2.internalApplyImpulse(-c.m_contactNormal*body2.internalGetInvMass(),c.m_angularComponentB,deltaImpulse); } void btSequentialImpulseConstraintSolver::resolveSingleConstraintRowLowerLimitSIMD(btRigidBody& body1,btRigidBody& body2,const btSolverConstraint& c) { #ifdef USE_SIMD __m128 cpAppliedImp = _mm_set1_ps(c.m_appliedImpulse); __m128 lowerLimit1 = _mm_set1_ps(c.m_lowerLimit); __m128 upperLimit1 = _mm_set1_ps(c.m_upperLimit); __m128 deltaImpulse = _mm_sub_ps(_mm_set1_ps(c.m_rhs), _mm_mul_ps(_mm_set1_ps(c.m_appliedImpulse),_mm_set1_ps(c.m_cfm))); __m128 deltaVel1Dotn = _mm_add_ps(_vmathVfDot3(c.m_contactNormal.mVec128,body1.internalGetDeltaLinearVelocity().mVec128), _vmathVfDot3(c.m_relpos1CrossNormal.mVec128,body1.internalGetDeltaAngularVelocity().mVec128)); __m128 deltaVel2Dotn = _mm_sub_ps(_vmathVfDot3(c.m_relpos2CrossNormal.mVec128,body2.internalGetDeltaAngularVelocity().mVec128),_vmathVfDot3((c.m_contactNormal).mVec128,body2.internalGetDeltaLinearVelocity().mVec128)); deltaImpulse = _mm_sub_ps(deltaImpulse,_mm_mul_ps(deltaVel1Dotn,_mm_set1_ps(c.m_jacDiagABInv))); deltaImpulse = _mm_sub_ps(deltaImpulse,_mm_mul_ps(deltaVel2Dotn,_mm_set1_ps(c.m_jacDiagABInv))); btSimdScalar sum = _mm_add_ps(cpAppliedImp,deltaImpulse); btSimdScalar resultLowerLess,resultUpperLess; resultLowerLess = _mm_cmplt_ps(sum,lowerLimit1); resultUpperLess = _mm_cmplt_ps(sum,upperLimit1); __m128 lowMinApplied = _mm_sub_ps(lowerLimit1,cpAppliedImp); deltaImpulse = _mm_or_ps( _mm_and_ps(resultLowerLess, lowMinApplied), _mm_andnot_ps(resultLowerLess, deltaImpulse) ); c.m_appliedImpulse = _mm_or_ps( _mm_and_ps(resultLowerLess, lowerLimit1), _mm_andnot_ps(resultLowerLess, sum) ); __m128 linearComponentA = _mm_mul_ps(c.m_contactNormal.mVec128,body1.internalGetInvMass().mVec128); __m128 linearComponentB = _mm_mul_ps((c.m_contactNormal).mVec128,body2.internalGetInvMass().mVec128); __m128 impulseMagnitude = deltaImpulse; body1.internalGetDeltaLinearVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaLinearVelocity().mVec128,_mm_mul_ps(linearComponentA,impulseMagnitude)); body1.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body1.internalGetDeltaAngularVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentA.mVec128,impulseMagnitude)); body2.internalGetDeltaLinearVelocity().mVec128 = _mm_sub_ps(body2.internalGetDeltaLinearVelocity().mVec128,_mm_mul_ps(linearComponentB,impulseMagnitude)); body2.internalGetDeltaAngularVelocity().mVec128 = _mm_add_ps(body2.internalGetDeltaAngularVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentB.mVec128,impulseMagnitude)); #else resolveSingleConstraintRowLowerLimit(body1,body2,c); #endif } // Project Gauss Seidel or the equivalent Sequential Impulse void btSequentialImpulseConstraintSolver::resolveSingleConstraintRowLowerLimit(btRigidBody& body1,btRigidBody& body2,const btSolverConstraint& c) { btScalar deltaImpulse = c.m_rhs-btScalar(c.m_appliedImpulse)*c.m_cfm; const btScalar deltaVel1Dotn = c.m_contactNormal.dot(body1.internalGetDeltaLinearVelocity()) + c.m_relpos1CrossNormal.dot(body1.internalGetDeltaAngularVelocity()); const btScalar deltaVel2Dotn = -c.m_contactNormal.dot(body2.internalGetDeltaLinearVelocity()) + c.m_relpos2CrossNormal.dot(body2.internalGetDeltaAngularVelocity()); deltaImpulse -= deltaVel1Dotn*c.m_jacDiagABInv; deltaImpulse -= deltaVel2Dotn*c.m_jacDiagABInv; const btScalar sum = btScalar(c.m_appliedImpulse) + deltaImpulse; if (sum < c.m_lowerLimit) { deltaImpulse = c.m_lowerLimit-c.m_appliedImpulse; c.m_appliedImpulse = c.m_lowerLimit; } else { c.m_appliedImpulse = sum; } body1.internalApplyImpulse(c.m_contactNormal*body1.internalGetInvMass(),c.m_angularComponentA,deltaImpulse); body2.internalApplyImpulse(-c.m_contactNormal*body2.internalGetInvMass(),c.m_angularComponentB,deltaImpulse); } void btSequentialImpulseConstraintSolver::resolveSplitPenetrationImpulseCacheFriendly( btRigidBody& body1, btRigidBody& body2, const btSolverConstraint& c) { if (c.m_rhsPenetration) { gNumSplitImpulseRecoveries++; btScalar deltaImpulse = c.m_rhsPenetration-btScalar(c.m_appliedPushImpulse)*c.m_cfm; const btScalar deltaVel1Dotn = c.m_contactNormal.dot(body1.internalGetPushVelocity()) + c.m_relpos1CrossNormal.dot(body1.internalGetTurnVelocity()); const btScalar deltaVel2Dotn = -c.m_contactNormal.dot(body2.internalGetPushVelocity()) + c.m_relpos2CrossNormal.dot(body2.internalGetTurnVelocity()); deltaImpulse -= deltaVel1Dotn*c.m_jacDiagABInv; deltaImpulse -= deltaVel2Dotn*c.m_jacDiagABInv; const btScalar sum = btScalar(c.m_appliedPushImpulse) + deltaImpulse; if (sum < c.m_lowerLimit) { deltaImpulse = c.m_lowerLimit-c.m_appliedPushImpulse; c.m_appliedPushImpulse = c.m_lowerLimit; } else { c.m_appliedPushImpulse = sum; } body1.internalApplyPushImpulse(c.m_contactNormal*body1.internalGetInvMass(),c.m_angularComponentA,deltaImpulse); body2.internalApplyPushImpulse(-c.m_contactNormal*body2.internalGetInvMass(),c.m_angularComponentB,deltaImpulse); } } void btSequentialImpulseConstraintSolver::resolveSplitPenetrationSIMD(btRigidBody& body1,btRigidBody& body2,const btSolverConstraint& c) { #ifdef USE_SIMD if (!c.m_rhsPenetration) return; gNumSplitImpulseRecoveries++; __m128 cpAppliedImp = _mm_set1_ps(c.m_appliedPushImpulse); __m128 lowerLimit1 = _mm_set1_ps(c.m_lowerLimit); __m128 upperLimit1 = _mm_set1_ps(c.m_upperLimit); __m128 deltaImpulse = _mm_sub_ps(_mm_set1_ps(c.m_rhsPenetration), _mm_mul_ps(_mm_set1_ps(c.m_appliedPushImpulse),_mm_set1_ps(c.m_cfm))); __m128 deltaVel1Dotn = _mm_add_ps(_vmathVfDot3(c.m_contactNormal.mVec128,body1.internalGetPushVelocity().mVec128), _vmathVfDot3(c.m_relpos1CrossNormal.mVec128,body1.internalGetTurnVelocity().mVec128)); __m128 deltaVel2Dotn = _mm_sub_ps(_vmathVfDot3(c.m_relpos2CrossNormal.mVec128,body2.internalGetTurnVelocity().mVec128),_vmathVfDot3((c.m_contactNormal).mVec128,body2.internalGetPushVelocity().mVec128)); deltaImpulse = _mm_sub_ps(deltaImpulse,_mm_mul_ps(deltaVel1Dotn,_mm_set1_ps(c.m_jacDiagABInv))); deltaImpulse = _mm_sub_ps(deltaImpulse,_mm_mul_ps(deltaVel2Dotn,_mm_set1_ps(c.m_jacDiagABInv))); btSimdScalar sum = _mm_add_ps(cpAppliedImp,deltaImpulse); btSimdScalar resultLowerLess,resultUpperLess; resultLowerLess = _mm_cmplt_ps(sum,lowerLimit1); resultUpperLess = _mm_cmplt_ps(sum,upperLimit1); __m128 lowMinApplied = _mm_sub_ps(lowerLimit1,cpAppliedImp); deltaImpulse = _mm_or_ps( _mm_and_ps(resultLowerLess, lowMinApplied), _mm_andnot_ps(resultLowerLess, deltaImpulse) ); c.m_appliedImpulse = _mm_or_ps( _mm_and_ps(resultLowerLess, lowerLimit1), _mm_andnot_ps(resultLowerLess, sum) ); __m128 linearComponentA = _mm_mul_ps(c.m_contactNormal.mVec128,body1.internalGetInvMass().mVec128); __m128 linearComponentB = _mm_mul_ps((c.m_contactNormal).mVec128,body2.internalGetInvMass().mVec128); __m128 impulseMagnitude = deltaImpulse; body1.internalGetPushVelocity().mVec128 = _mm_add_ps(body1.internalGetPushVelocity().mVec128,_mm_mul_ps(linearComponentA,impulseMagnitude)); body1.internalGetTurnVelocity().mVec128 = _mm_add_ps(body1.internalGetTurnVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentA.mVec128,impulseMagnitude)); body2.internalGetPushVelocity().mVec128 = _mm_sub_ps(body2.internalGetPushVelocity().mVec128,_mm_mul_ps(linearComponentB,impulseMagnitude)); body2.internalGetTurnVelocity().mVec128 = _mm_add_ps(body2.internalGetTurnVelocity().mVec128 ,_mm_mul_ps(c.m_angularComponentB.mVec128,impulseMagnitude)); #else resolveSplitPenetrationImpulseCacheFriendly(body1,body2,c); #endif } unsigned long btSequentialImpulseConstraintSolver::btRand2() { m_btSeed2 = (1664525L*m_btSeed2 + 1013904223L) & 0xffffffff; return m_btSeed2; } //See ODE: adam's all-int straightforward(?) dRandInt (0..n-1) int btSequentialImpulseConstraintSolver::btRandInt2 (int n) { // seems good; xor-fold and modulus const unsigned long un = static_cast(n); unsigned long r = btRand2(); // note: probably more aggressive than it needs to be -- might be // able to get away without one or two of the innermost branches. if (un <= 0x00010000UL) { r ^= (r >> 16); if (un <= 0x00000100UL) { r ^= (r >> 8); if (un <= 0x00000010UL) { r ^= (r >> 4); if (un <= 0x00000004UL) { r ^= (r >> 2); if (un <= 0x00000002UL) { r ^= (r >> 1); } } } } } return (int) (r % un); } #if 0 void btSequentialImpulseConstraintSolver::initSolverBody(btSolverBody* solverBody, btCollisionObject* collisionObject) { btRigidBody* rb = collisionObject? btRigidBody::upcast(collisionObject) : 0; solverBody->internalGetDeltaLinearVelocity().setValue(0.f,0.f,0.f); solverBody->internalGetDeltaAngularVelocity().setValue(0.f,0.f,0.f); solverBody->internalGetPushVelocity().setValue(0.f,0.f,0.f); solverBody->internalGetTurnVelocity().setValue(0.f,0.f,0.f); if (rb) { solverBody->internalGetInvMass() = btVector3(rb->getInvMass(),rb->getInvMass(),rb->getInvMass())*rb->getLinearFactor(); solverBody->m_originalBody = rb; solverBody->m_angularFactor = rb->getAngularFactor(); } else { solverBody->internalGetInvMass().setValue(0,0,0); solverBody->m_originalBody = 0; solverBody->m_angularFactor.setValue(1,1,1); } } #endif btScalar btSequentialImpulseConstraintSolver::restitutionCurve(btScalar rel_vel, btScalar restitution) { btScalar rest = restitution * -rel_vel; return rest; } void applyAnisotropicFriction(btCollisionObject* colObj,btVector3& frictionDirection); void applyAnisotropicFriction(btCollisionObject* colObj,btVector3& frictionDirection) { if (colObj && colObj->hasAnisotropicFriction()) { // transform to local coordinates btVector3 loc_lateral = frictionDirection * colObj->getWorldTransform().getBasis(); const btVector3& friction_scaling = colObj->getAnisotropicFriction(); //apply anisotropic friction loc_lateral *= friction_scaling; // ... and transform it back to global coordinates frictionDirection = colObj->getWorldTransform().getBasis() * loc_lateral; } } void btSequentialImpulseConstraintSolver::setupFrictionConstraint(btSolverConstraint& solverConstraint, const btVector3& normalAxis,btRigidBody* solverBodyA,btRigidBody* solverBodyB,btManifoldPoint& cp,const btVector3& rel_pos1,const btVector3& rel_pos2,btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, btScalar desiredVelocity, btScalar cfmSlip) { btRigidBody* body0=btRigidBody::upcast(colObj0); btRigidBody* body1=btRigidBody::upcast(colObj1); solverConstraint.m_contactNormal = normalAxis; solverConstraint.m_solverBodyA = body0 ? body0 : &getFixedBody(); solverConstraint.m_solverBodyB = body1 ? body1 : &getFixedBody(); solverConstraint.m_friction = cp.m_combinedFriction; solverConstraint.m_originalContactPoint = 0; solverConstraint.m_appliedImpulse = 0.f; solverConstraint.m_appliedPushImpulse = 0.f; { btVector3 ftorqueAxis1 = rel_pos1.cross(solverConstraint.m_contactNormal); solverConstraint.m_relpos1CrossNormal = ftorqueAxis1; solverConstraint.m_angularComponentA = body0 ? body0->getInvInertiaTensorWorld()*ftorqueAxis1*body0->getAngularFactor() : btVector3(0,0,0); } { btVector3 ftorqueAxis1 = rel_pos2.cross(-solverConstraint.m_contactNormal); solverConstraint.m_relpos2CrossNormal = ftorqueAxis1; solverConstraint.m_angularComponentB = body1 ? body1->getInvInertiaTensorWorld()*ftorqueAxis1*body1->getAngularFactor() : btVector3(0,0,0); } #ifdef COMPUTE_IMPULSE_DENOM btScalar denom0 = rb0->computeImpulseDenominator(pos1,solverConstraint.m_contactNormal); btScalar denom1 = rb1->computeImpulseDenominator(pos2,solverConstraint.m_contactNormal); #else btVector3 vec; btScalar denom0 = 0.f; btScalar denom1 = 0.f; if (body0) { vec = ( solverConstraint.m_angularComponentA).cross(rel_pos1); denom0 = body0->getInvMass() + normalAxis.dot(vec); } if (body1) { vec = ( -solverConstraint.m_angularComponentB).cross(rel_pos2); denom1 = body1->getInvMass() + normalAxis.dot(vec); } #endif //COMPUTE_IMPULSE_DENOM btScalar denom = relaxation/(denom0+denom1); solverConstraint.m_jacDiagABInv = denom; #ifdef _USE_JACOBIAN solverConstraint.m_jac = btJacobianEntry ( rel_pos1,rel_pos2,solverConstraint.m_contactNormal, body0->getInvInertiaDiagLocal(), body0->getInvMass(), body1->getInvInertiaDiagLocal(), body1->getInvMass()); #endif //_USE_JACOBIAN { btScalar rel_vel; btScalar vel1Dotn = solverConstraint.m_contactNormal.dot(body0?body0->getLinearVelocity():btVector3(0,0,0)) + solverConstraint.m_relpos1CrossNormal.dot(body0?body0->getAngularVelocity():btVector3(0,0,0)); btScalar vel2Dotn = -solverConstraint.m_contactNormal.dot(body1?body1->getLinearVelocity():btVector3(0,0,0)) + solverConstraint.m_relpos2CrossNormal.dot(body1?body1->getAngularVelocity():btVector3(0,0,0)); rel_vel = vel1Dotn+vel2Dotn; // btScalar positionalError = 0.f; btSimdScalar velocityError = desiredVelocity - rel_vel; btSimdScalar velocityImpulse = velocityError * btSimdScalar(solverConstraint.m_jacDiagABInv); solverConstraint.m_rhs = velocityImpulse; solverConstraint.m_cfm = cfmSlip; solverConstraint.m_lowerLimit = 0; solverConstraint.m_upperLimit = 1e10f; } } btSolverConstraint& btSequentialImpulseConstraintSolver::addFrictionConstraint(const btVector3& normalAxis,btRigidBody* solverBodyA,btRigidBody* solverBodyB,int frictionIndex,btManifoldPoint& cp,const btVector3& rel_pos1,const btVector3& rel_pos2,btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, btScalar desiredVelocity, btScalar cfmSlip) { btSolverConstraint& solverConstraint = m_tmpSolverContactFrictionConstraintPool.expandNonInitializing(); solverConstraint.m_frictionIndex = frictionIndex; setupFrictionConstraint(solverConstraint, normalAxis, solverBodyA, solverBodyB, cp, rel_pos1, rel_pos2, colObj0, colObj1, relaxation, desiredVelocity, cfmSlip); return solverConstraint; } int btSequentialImpulseConstraintSolver::getOrInitSolverBody(btCollisionObject& body) { #if 0 int solverBodyIdA = -1; if (body.getCompanionId() >= 0) { //body has already been converted solverBodyIdA = body.getCompanionId(); } else { btRigidBody* rb = btRigidBody::upcast(&body); if (rb && rb->getInvMass()) { solverBodyIdA = m_tmpSolverBodyPool.size(); btSolverBody& solverBody = m_tmpSolverBodyPool.expand(); initSolverBody(&solverBody,&body); body.setCompanionId(solverBodyIdA); } else { return 0;//assume first one is a fixed solver body } } return solverBodyIdA; #endif return 0; } #include void btSequentialImpulseConstraintSolver::setupContactConstraint(btSolverConstraint& solverConstraint, btCollisionObject* colObj0, btCollisionObject* colObj1, btManifoldPoint& cp, const btContactSolverInfo& infoGlobal, btVector3& vel, btScalar& rel_vel, btScalar& relaxation, btVector3& rel_pos1, btVector3& rel_pos2) { btRigidBody* rb0 = btRigidBody::upcast(colObj0); btRigidBody* rb1 = btRigidBody::upcast(colObj1); const btVector3& pos1 = cp.getPositionWorldOnA(); const btVector3& pos2 = cp.getPositionWorldOnB(); // btVector3 rel_pos1 = pos1 - colObj0->getWorldTransform().getOrigin(); // btVector3 rel_pos2 = pos2 - colObj1->getWorldTransform().getOrigin(); rel_pos1 = pos1 - colObj0->getWorldTransform().getOrigin(); rel_pos2 = pos2 - colObj1->getWorldTransform().getOrigin(); relaxation = 1.f; btVector3 torqueAxis0 = rel_pos1.cross(cp.m_normalWorldOnB); solverConstraint.m_angularComponentA = rb0 ? rb0->getInvInertiaTensorWorld()*torqueAxis0*rb0->getAngularFactor() : btVector3(0,0,0); btVector3 torqueAxis1 = rel_pos2.cross(cp.m_normalWorldOnB); solverConstraint.m_angularComponentB = rb1 ? rb1->getInvInertiaTensorWorld()*-torqueAxis1*rb1->getAngularFactor() : btVector3(0,0,0); { #ifdef COMPUTE_IMPULSE_DENOM btScalar denom0 = rb0->computeImpulseDenominator(pos1,cp.m_normalWorldOnB); btScalar denom1 = rb1->computeImpulseDenominator(pos2,cp.m_normalWorldOnB); #else btVector3 vec; btScalar denom0 = 0.f; btScalar denom1 = 0.f; if (rb0) { vec = ( solverConstraint.m_angularComponentA).cross(rel_pos1); denom0 = rb0->getInvMass() + cp.m_normalWorldOnB.dot(vec); } if (rb1) { vec = ( -solverConstraint.m_angularComponentB).cross(rel_pos2); denom1 = rb1->getInvMass() + cp.m_normalWorldOnB.dot(vec); } #endif //COMPUTE_IMPULSE_DENOM btScalar denom = relaxation/(denom0+denom1); solverConstraint.m_jacDiagABInv = denom; } solverConstraint.m_contactNormal = cp.m_normalWorldOnB; solverConstraint.m_relpos1CrossNormal = rel_pos1.cross(cp.m_normalWorldOnB); solverConstraint.m_relpos2CrossNormal = rel_pos2.cross(-cp.m_normalWorldOnB); btVector3 vel1 = rb0 ? rb0->getVelocityInLocalPoint(rel_pos1) : btVector3(0,0,0); btVector3 vel2 = rb1 ? rb1->getVelocityInLocalPoint(rel_pos2) : btVector3(0,0,0); vel = vel1 - vel2; rel_vel = cp.m_normalWorldOnB.dot(vel); btScalar penetration = cp.getDistance()+infoGlobal.m_linearSlop; solverConstraint.m_friction = cp.m_combinedFriction; btScalar restitution = 0.f; if (cp.m_lifeTime>infoGlobal.m_restingContactRestitutionThreshold) { restitution = 0.f; } else { restitution = restitutionCurve(rel_vel, cp.m_combinedRestitution); if (restitution <= btScalar(0.)) { restitution = 0.f; }; } ///warm starting (or zero if disabled) if (infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING) { solverConstraint.m_appliedImpulse = cp.m_appliedImpulse * infoGlobal.m_warmstartingFactor; if (rb0) rb0->internalApplyImpulse(solverConstraint.m_contactNormal*rb0->getInvMass()*rb0->getLinearFactor(),solverConstraint.m_angularComponentA,solverConstraint.m_appliedImpulse); if (rb1) rb1->internalApplyImpulse(solverConstraint.m_contactNormal*rb1->getInvMass()*rb1->getLinearFactor(),-solverConstraint.m_angularComponentB,-solverConstraint.m_appliedImpulse); } else { solverConstraint.m_appliedImpulse = 0.f; } solverConstraint.m_appliedPushImpulse = 0.f; { btScalar rel_vel; btScalar vel1Dotn = solverConstraint.m_contactNormal.dot(rb0?rb0->getLinearVelocity():btVector3(0,0,0)) + solverConstraint.m_relpos1CrossNormal.dot(rb0?rb0->getAngularVelocity():btVector3(0,0,0)); btScalar vel2Dotn = -solverConstraint.m_contactNormal.dot(rb1?rb1->getLinearVelocity():btVector3(0,0,0)) + solverConstraint.m_relpos2CrossNormal.dot(rb1?rb1->getAngularVelocity():btVector3(0,0,0)); rel_vel = vel1Dotn+vel2Dotn; btScalar positionalError = 0.f; positionalError = -penetration * infoGlobal.m_erp/infoGlobal.m_timeStep; btScalar velocityError = restitution - rel_vel;// * damping; btScalar penetrationImpulse = positionalError*solverConstraint.m_jacDiagABInv; btScalar velocityImpulse = velocityError *solverConstraint.m_jacDiagABInv; if (!infoGlobal.m_splitImpulse || (penetration > infoGlobal.m_splitImpulsePenetrationThreshold)) { //combine position and velocity into rhs solverConstraint.m_rhs = penetrationImpulse+velocityImpulse; solverConstraint.m_rhsPenetration = 0.f; } else { //split position and velocity into rhs and m_rhsPenetration solverConstraint.m_rhs = velocityImpulse; solverConstraint.m_rhsPenetration = penetrationImpulse; } solverConstraint.m_cfm = 0.f; solverConstraint.m_lowerLimit = 0; solverConstraint.m_upperLimit = 1e10f; } } void btSequentialImpulseConstraintSolver::setFrictionConstraintImpulse( btSolverConstraint& solverConstraint, btRigidBody* rb0, btRigidBody* rb1, btManifoldPoint& cp, const btContactSolverInfo& infoGlobal) { if (infoGlobal.m_solverMode & SOLVER_USE_FRICTION_WARMSTARTING) { { btSolverConstraint& frictionConstraint1 = m_tmpSolverContactFrictionConstraintPool[solverConstraint.m_frictionIndex]; if (infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING) { frictionConstraint1.m_appliedImpulse = cp.m_appliedImpulseLateral1 * infoGlobal.m_warmstartingFactor; if (rb0) rb0->internalApplyImpulse(frictionConstraint1.m_contactNormal*rb0->getInvMass()*rb0->getLinearFactor(),frictionConstraint1.m_angularComponentA,frictionConstraint1.m_appliedImpulse); if (rb1) rb1->internalApplyImpulse(frictionConstraint1.m_contactNormal*rb1->getInvMass()*rb1->getLinearFactor(),-frictionConstraint1.m_angularComponentB,-frictionConstraint1.m_appliedImpulse); } else { frictionConstraint1.m_appliedImpulse = 0.f; } } if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)) { btSolverConstraint& frictionConstraint2 = m_tmpSolverContactFrictionConstraintPool[solverConstraint.m_frictionIndex+1]; if (infoGlobal.m_solverMode & SOLVER_USE_WARMSTARTING) { frictionConstraint2.m_appliedImpulse = cp.m_appliedImpulseLateral2 * infoGlobal.m_warmstartingFactor; if (rb0) rb0->internalApplyImpulse(frictionConstraint2.m_contactNormal*rb0->getInvMass(),frictionConstraint2.m_angularComponentA,frictionConstraint2.m_appliedImpulse); if (rb1) rb1->internalApplyImpulse(frictionConstraint2.m_contactNormal*rb1->getInvMass(),-frictionConstraint2.m_angularComponentB,-frictionConstraint2.m_appliedImpulse); } else { frictionConstraint2.m_appliedImpulse = 0.f; } } } else { btSolverConstraint& frictionConstraint1 = m_tmpSolverContactFrictionConstraintPool[solverConstraint.m_frictionIndex]; frictionConstraint1.m_appliedImpulse = 0.f; if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)) { btSolverConstraint& frictionConstraint2 = m_tmpSolverContactFrictionConstraintPool[solverConstraint.m_frictionIndex+1]; frictionConstraint2.m_appliedImpulse = 0.f; } } } void btSequentialImpulseConstraintSolver::convertContact(btPersistentManifold* manifold,const btContactSolverInfo& infoGlobal) { btCollisionObject* colObj0=0,*colObj1=0; colObj0 = (btCollisionObject*)manifold->getBody0(); colObj1 = (btCollisionObject*)manifold->getBody1(); btRigidBody* solverBodyA = btRigidBody::upcast(colObj0); btRigidBody* solverBodyB = btRigidBody::upcast(colObj1); ///avoid collision response between two static objects if ((!solverBodyA || !solverBodyA->getInvMass()) && (!solverBodyB || !solverBodyB->getInvMass())) return; for (int j=0;jgetNumContacts();j++) { btManifoldPoint& cp = manifold->getContactPoint(j); if (cp.getDistance() <= manifold->getContactProcessingThreshold()) { btVector3 rel_pos1; btVector3 rel_pos2; btScalar relaxation; btScalar rel_vel; btVector3 vel; int frictionIndex = m_tmpSolverContactConstraintPool.size(); btSolverConstraint& solverConstraint = m_tmpSolverContactConstraintPool.expandNonInitializing(); btRigidBody* rb0 = btRigidBody::upcast(colObj0); btRigidBody* rb1 = btRigidBody::upcast(colObj1); solverConstraint.m_solverBodyA = rb0? rb0 : &getFixedBody(); solverConstraint.m_solverBodyB = rb1? rb1 : &getFixedBody(); solverConstraint.m_originalContactPoint = &cp; setupContactConstraint(solverConstraint, colObj0, colObj1, cp, infoGlobal, vel, rel_vel, relaxation, rel_pos1, rel_pos2); // const btVector3& pos1 = cp.getPositionWorldOnA(); // const btVector3& pos2 = cp.getPositionWorldOnB(); /////setup the friction constraints solverConstraint.m_frictionIndex = m_tmpSolverContactFrictionConstraintPool.size(); if (!(infoGlobal.m_solverMode & SOLVER_ENABLE_FRICTION_DIRECTION_CACHING) || !cp.m_lateralFrictionInitialized) { cp.m_lateralFrictionDir1 = vel - cp.m_normalWorldOnB * rel_vel; btScalar lat_rel_vel = cp.m_lateralFrictionDir1.length2(); if (!(infoGlobal.m_solverMode & SOLVER_DISABLE_VELOCITY_DEPENDENT_FRICTION_DIRECTION) && lat_rel_vel > SIMD_EPSILON) { cp.m_lateralFrictionDir1 /= btSqrt(lat_rel_vel); if((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)) { cp.m_lateralFrictionDir2 = cp.m_lateralFrictionDir1.cross(cp.m_normalWorldOnB); cp.m_lateralFrictionDir2.normalize();//?? applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir2); applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir2); addFrictionConstraint(cp.m_lateralFrictionDir2,solverBodyA,solverBodyB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); } applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir1); applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir1); addFrictionConstraint(cp.m_lateralFrictionDir1,solverBodyA,solverBodyB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); cp.m_lateralFrictionInitialized = true; } else { //re-calculate friction direction every frame, todo: check if this is really needed btPlaneSpace1(cp.m_normalWorldOnB,cp.m_lateralFrictionDir1,cp.m_lateralFrictionDir2); if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)) { applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir2); applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir2); addFrictionConstraint(cp.m_lateralFrictionDir2,solverBodyA,solverBodyB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); } applyAnisotropicFriction(colObj0,cp.m_lateralFrictionDir1); applyAnisotropicFriction(colObj1,cp.m_lateralFrictionDir1); addFrictionConstraint(cp.m_lateralFrictionDir1,solverBodyA,solverBodyB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation); cp.m_lateralFrictionInitialized = true; } } else { addFrictionConstraint(cp.m_lateralFrictionDir1,solverBodyA,solverBodyB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation,cp.m_contactMotion1, cp.m_contactCFM1); if ((infoGlobal.m_solverMode & SOLVER_USE_2_FRICTION_DIRECTIONS)) addFrictionConstraint(cp.m_lateralFrictionDir2,solverBodyA,solverBodyB,frictionIndex,cp,rel_pos1,rel_pos2,colObj0,colObj1, relaxation, cp.m_contactMotion2, cp.m_contactCFM2); } setFrictionConstraintImpulse( solverConstraint, rb0, rb1, cp, infoGlobal); } } } btScalar btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySetup(btCollisionObject** /*bodies */,int /*numBodies */,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer,btStackAlloc* stackAlloc) { BT_PROFILE("solveGroupCacheFriendlySetup"); (void)stackAlloc; (void)debugDrawer; if (!(numConstraints + numManifolds)) { // printf("empty\n"); return 0.f; } if (1) { int j; for (j=0;jbuildJacobian(); } } //btRigidBody* rb0=0,*rb1=0; //if (1) { { int totalNumRows = 0; int i; m_tmpConstraintSizesPool.resize(numConstraints); //calculate the total number of contraint rows for (i=0;igetInfo1(&info1); totalNumRows += info1.m_numConstraintRows; } m_tmpSolverNonContactConstraintPool.resize(totalNumRows); ///setup the btSolverConstraints int currentRow = 0; for (i=0;igetRigidBodyA(); btRigidBody& rbB = constraint->getRigidBodyB(); int j; for ( j=0;jm_contactNormal; info2.m_J1angularAxis = currentConstraintRow->m_relpos1CrossNormal; info2.m_J2linearAxis = 0; info2.m_J2angularAxis = currentConstraintRow->m_relpos2CrossNormal; info2.rowskip = sizeof(btSolverConstraint)/sizeof(btScalar);//check this ///the size of btSolverConstraint needs be a multiple of btScalar btAssert(info2.rowskip*sizeof(btScalar)== sizeof(btSolverConstraint)); info2.m_constraintError = ¤tConstraintRow->m_rhs; currentConstraintRow->m_cfm = infoGlobal.m_globalCfm; info2.cfm = ¤tConstraintRow->m_cfm; info2.m_lowerLimit = ¤tConstraintRow->m_lowerLimit; info2.m_upperLimit = ¤tConstraintRow->m_upperLimit; info2.m_numIterations = infoGlobal.m_numIterations; constraints[i]->getInfo2(&info2); ///finalize the constraint setup for ( j=0;jgetRigidBodyA().getInvInertiaTensorWorld()*ftorqueAxis1*constraint->getRigidBodyA().getAngularFactor(); } { const btVector3& ftorqueAxis2 = solverConstraint.m_relpos2CrossNormal; solverConstraint.m_angularComponentB = constraint->getRigidBodyB().getInvInertiaTensorWorld()*ftorqueAxis2*constraint->getRigidBodyB().getAngularFactor(); } { btVector3 iMJlA = solverConstraint.m_contactNormal*rbA.getInvMass(); btVector3 iMJaA = rbA.getInvInertiaTensorWorld()*solverConstraint.m_relpos1CrossNormal; btVector3 iMJlB = solverConstraint.m_contactNormal*rbB.getInvMass();//sign of normal? btVector3 iMJaB = rbB.getInvInertiaTensorWorld()*solverConstraint.m_relpos2CrossNormal; btScalar sum = iMJlA.dot(solverConstraint.m_contactNormal); sum += iMJaA.dot(solverConstraint.m_relpos1CrossNormal); sum += iMJlB.dot(solverConstraint.m_contactNormal); sum += iMJaB.dot(solverConstraint.m_relpos2CrossNormal); solverConstraint.m_jacDiagABInv = btScalar(1.)/sum; } ///fix rhs ///todo: add force/torque accelerators { btScalar rel_vel; btScalar vel1Dotn = solverConstraint.m_contactNormal.dot(rbA.getLinearVelocity()) + solverConstraint.m_relpos1CrossNormal.dot(rbA.getAngularVelocity()); btScalar vel2Dotn = -solverConstraint.m_contactNormal.dot(rbB.getLinearVelocity()) + solverConstraint.m_relpos2CrossNormal.dot(rbB.getAngularVelocity()); rel_vel = vel1Dotn+vel2Dotn; btScalar restitution = 0.f; btScalar positionalError = solverConstraint.m_rhs;//already filled in by getConstraintInfo2 btScalar velocityError = restitution - rel_vel;// * damping; btScalar penetrationImpulse = positionalError*solverConstraint.m_jacDiagABInv; btScalar velocityImpulse = velocityError *solverConstraint.m_jacDiagABInv; solverConstraint.m_rhs = penetrationImpulse+velocityImpulse; solverConstraint.m_appliedImpulse = 0.f; } } } currentRow+=m_tmpConstraintSizesPool[i].m_numConstraintRows; } } { int i; btPersistentManifold* manifold = 0; // btCollisionObject* colObj0=0,*colObj1=0; for (i=0;isolveConstraintObsolete(constraints[j]->getRigidBodyA(),constraints[j]->getRigidBodyB(),infoGlobal.m_timeStep); } ///solve all contact constraints using SIMD, if available int numPoolConstraints = m_tmpSolverContactConstraintPool.size(); for (j=0;jbtScalar(0)) { solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse); solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse; resolveSingleConstraintRowGenericSIMD(*solveManifold.m_solverBodyA, *solveManifold.m_solverBodyB,solveManifold); } } } else { ///solve all joint constraints for (j=0;jsolveConstraintObsolete(constraints[j]->getRigidBodyA(),constraints[j]->getRigidBodyB(),infoGlobal.m_timeStep); } ///solve all contact constraints int numPoolConstraints = m_tmpSolverContactConstraintPool.size(); for (j=0;jbtScalar(0)) { solveManifold.m_lowerLimit = -(solveManifold.m_friction*totalImpulse); solveManifold.m_upperLimit = solveManifold.m_friction*totalImpulse; resolveSingleConstraintRowGeneric(*solveManifold.m_solverBodyA,*solveManifold.m_solverBodyB,solveManifold); } } } return 0.f; } void btSequentialImpulseConstraintSolver::solveGroupCacheFriendlySplitImpulseIterations(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer,btStackAlloc* stackAlloc) { int iteration; if (infoGlobal.m_splitImpulse) { if (infoGlobal.m_solverMode & SOLVER_SIMD) { for ( iteration = 0;iterationm_appliedImpulse = solveManifold.m_appliedImpulse; if (infoGlobal.m_solverMode & SOLVER_USE_FRICTION_WARMSTARTING) { pt->m_appliedImpulseLateral1 = m_tmpSolverContactFrictionConstraintPool[solveManifold.m_frictionIndex].m_appliedImpulse; pt->m_appliedImpulseLateral2 = m_tmpSolverContactFrictionConstraintPool[solveManifold.m_frictionIndex+1].m_appliedImpulse; } //do a callback here? } numPoolConstraints = m_tmpSolverNonContactConstraintPool.size(); for (j=0;jinternalGetAppliedImpulse(); sum += solverConstr.m_appliedImpulse; constr->internalSetAppliedImpulse(sum); } if (infoGlobal.m_splitImpulse) { for ( i=0;iinternalWritebackVelocity(infoGlobal.m_timeStep); } } else { for ( i=0;iinternalWritebackVelocity(); } } m_tmpSolverContactConstraintPool.resize(0); m_tmpSolverNonContactConstraintPool.resize(0); m_tmpSolverContactFrictionConstraintPool.resize(0); return 0.f; } /// btSequentialImpulseConstraintSolver Sequentially applies impulses btScalar btSequentialImpulseConstraintSolver::solveGroup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer,btStackAlloc* stackAlloc,btDispatcher* /*dispatcher*/) { BT_PROFILE("solveGroup"); //you need to provide at least some bodies btAssert(bodies); btAssert(numBodies); solveGroupCacheFriendlySetup( bodies, numBodies, manifoldPtr, numManifolds,constraints, numConstraints,infoGlobal,debugDrawer, stackAlloc); solveGroupCacheFriendlyIterations(bodies, numBodies, manifoldPtr, numManifolds,constraints, numConstraints,infoGlobal,debugDrawer, stackAlloc); solveGroupCacheFriendlyFinish(bodies, numBodies, manifoldPtr, numManifolds,constraints, numConstraints,infoGlobal,debugDrawer, stackAlloc); return 0.f; } void btSequentialImpulseConstraintSolver::reset() { m_btSeed2 = 0; } critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btHingeConstraint.h0000644000175000017500000002425411344267705031027 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ /* Hinge Constraint by Dirk Gregorius. Limits added by Marcus Hennix at Starbreeze Studios */ #ifndef HINGECONSTRAINT_H #define HINGECONSTRAINT_H #include "LinearMath/btVector3.h" #include "btJacobianEntry.h" #include "btTypedConstraint.h" class btRigidBody; #ifdef BT_USE_DOUBLE_PRECISION #define btHingeConstraintData btHingeConstraintDoubleData #define btHingeConstraintDataName "btHingeConstraintDoubleData" #else #define btHingeConstraintData btHingeConstraintFloatData #define btHingeConstraintDataName "btHingeConstraintFloatData" #endif //BT_USE_DOUBLE_PRECISION enum btHingeFlags { BT_HINGE_FLAGS_CFM_STOP = 1, BT_HINGE_FLAGS_ERP_STOP = 2, BT_HINGE_FLAGS_CFM_NORM = 4 }; /// hinge constraint between two rigidbodies each with a pivotpoint that descibes the axis location in local space /// axis defines the orientation of the hinge axis ATTRIBUTE_ALIGNED16(class) btHingeConstraint : public btTypedConstraint { #ifdef IN_PARALLELL_SOLVER public: #endif btJacobianEntry m_jac[3]; //3 orthogonal linear constraints btJacobianEntry m_jacAng[3]; //2 orthogonal angular constraints+ 1 for limit/motor btTransform m_rbAFrame; // constraint axii. Assumes z is hinge axis. btTransform m_rbBFrame; btScalar m_motorTargetVelocity; btScalar m_maxMotorImpulse; btScalar m_limitSoftness; btScalar m_biasFactor; btScalar m_relaxationFactor; btScalar m_lowerLimit; btScalar m_upperLimit; btScalar m_kHinge; btScalar m_limitSign; btScalar m_correction; btScalar m_accLimitImpulse; btScalar m_hingeAngle; btScalar m_referenceSign; bool m_angularOnly; bool m_enableAngularMotor; bool m_solveLimit; bool m_useSolveConstraintObsolete; bool m_useOffsetForConstraintFrame; bool m_useReferenceFrameA; btScalar m_accMotorImpulse; int m_flags; btScalar m_normalCFM; btScalar m_stopCFM; btScalar m_stopERP; public: btHingeConstraint(btRigidBody& rbA,btRigidBody& rbB, const btVector3& pivotInA,const btVector3& pivotInB, btVector3& axisInA,btVector3& axisInB, bool useReferenceFrameA = false); btHingeConstraint(btRigidBody& rbA,const btVector3& pivotInA,btVector3& axisInA, bool useReferenceFrameA = false); btHingeConstraint(btRigidBody& rbA,btRigidBody& rbB, const btTransform& rbAFrame, const btTransform& rbBFrame, bool useReferenceFrameA = false); btHingeConstraint(btRigidBody& rbA,const btTransform& rbAFrame, bool useReferenceFrameA = false); virtual void buildJacobian(); virtual void getInfo1 (btConstraintInfo1* info); void getInfo1NonVirtual(btConstraintInfo1* info); virtual void getInfo2 (btConstraintInfo2* info); void getInfo2NonVirtual(btConstraintInfo2* info,const btTransform& transA,const btTransform& transB,const btVector3& angVelA,const btVector3& angVelB); void getInfo2Internal(btConstraintInfo2* info,const btTransform& transA,const btTransform& transB,const btVector3& angVelA,const btVector3& angVelB); void getInfo2InternalUsingFrameOffset(btConstraintInfo2* info,const btTransform& transA,const btTransform& transB,const btVector3& angVelA,const btVector3& angVelB); void updateRHS(btScalar timeStep); const btRigidBody& getRigidBodyA() const { return m_rbA; } const btRigidBody& getRigidBodyB() const { return m_rbB; } btRigidBody& getRigidBodyA() { return m_rbA; } btRigidBody& getRigidBodyB() { return m_rbB; } void setAngularOnly(bool angularOnly) { m_angularOnly = angularOnly; } void enableAngularMotor(bool enableMotor,btScalar targetVelocity,btScalar maxMotorImpulse) { m_enableAngularMotor = enableMotor; m_motorTargetVelocity = targetVelocity; m_maxMotorImpulse = maxMotorImpulse; } // extra motor API, including ability to set a target rotation (as opposed to angular velocity) // note: setMotorTarget sets angular velocity under the hood, so you must call it every tick to // maintain a given angular target. void enableMotor(bool enableMotor) { m_enableAngularMotor = enableMotor; } void setMaxMotorImpulse(btScalar maxMotorImpulse) { m_maxMotorImpulse = maxMotorImpulse; } void setMotorTarget(const btQuaternion& qAinB, btScalar dt); // qAinB is rotation of body A wrt body B. void setMotorTarget(btScalar targetAngle, btScalar dt); void setLimit(btScalar low,btScalar high,btScalar _softness = 0.9f, btScalar _biasFactor = 0.3f, btScalar _relaxationFactor = 1.0f) { m_lowerLimit = btNormalizeAngle(low); m_upperLimit = btNormalizeAngle(high); m_limitSoftness = _softness; m_biasFactor = _biasFactor; m_relaxationFactor = _relaxationFactor; } void setAxis(btVector3& axisInA) { btVector3 rbAxisA1, rbAxisA2; btPlaneSpace1(axisInA, rbAxisA1, rbAxisA2); btVector3 pivotInA = m_rbAFrame.getOrigin(); // m_rbAFrame.getOrigin() = pivotInA; m_rbAFrame.getBasis().setValue( rbAxisA1.getX(),rbAxisA2.getX(),axisInA.getX(), rbAxisA1.getY(),rbAxisA2.getY(),axisInA.getY(), rbAxisA1.getZ(),rbAxisA2.getZ(),axisInA.getZ() ); btVector3 axisInB = m_rbA.getCenterOfMassTransform().getBasis() * axisInA; btQuaternion rotationArc = shortestArcQuat(axisInA,axisInB); btVector3 rbAxisB1 = quatRotate(rotationArc,rbAxisA1); btVector3 rbAxisB2 = axisInB.cross(rbAxisB1); m_rbBFrame.getOrigin() = m_rbA.getCenterOfMassTransform()(pivotInA); m_rbBFrame.getBasis().setValue( rbAxisB1.getX(),rbAxisB2.getX(),axisInB.getX(), rbAxisB1.getY(),rbAxisB2.getY(),axisInB.getY(), rbAxisB1.getZ(),rbAxisB2.getZ(),axisInB.getZ() ); } btScalar getLowerLimit() const { return m_lowerLimit; } btScalar getUpperLimit() const { return m_upperLimit; } btScalar getHingeAngle(); btScalar getHingeAngle(const btTransform& transA,const btTransform& transB); void testLimit(const btTransform& transA,const btTransform& transB); const btTransform& getAFrame() const { return m_rbAFrame; }; const btTransform& getBFrame() const { return m_rbBFrame; }; btTransform& getAFrame() { return m_rbAFrame; }; btTransform& getBFrame() { return m_rbBFrame; }; inline int getSolveLimit() { return m_solveLimit; } inline btScalar getLimitSign() { return m_limitSign; } inline bool getAngularOnly() { return m_angularOnly; } inline bool getEnableAngularMotor() { return m_enableAngularMotor; } inline btScalar getMotorTargetVelosity() { return m_motorTargetVelocity; } inline btScalar getMaxMotorImpulse() { return m_maxMotorImpulse; } // access for UseFrameOffset bool getUseFrameOffset() { return m_useOffsetForConstraintFrame; } void setUseFrameOffset(bool frameOffsetOnOff) { m_useOffsetForConstraintFrame = frameOffsetOnOff; } ///override the default global value of a parameter (such as ERP or CFM), optionally provide the axis (0..5). ///If no axis is provided, it uses the default axis for this constraint. virtual void setParam(int num, btScalar value, int axis = -1); ///return the local value of parameter virtual btScalar getParam(int num, int axis = -1) const; virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btHingeConstraintDoubleData { btTypedConstraintData m_typeConstraintData; btTransformDoubleData m_rbAFrame; // constraint axii. Assumes z is hinge axis. btTransformDoubleData m_rbBFrame; int m_useReferenceFrameA; int m_angularOnly; int m_enableAngularMotor; float m_motorTargetVelocity; float m_maxMotorImpulse; float m_lowerLimit; float m_upperLimit; float m_limitSoftness; float m_biasFactor; float m_relaxationFactor; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btHingeConstraintFloatData { btTypedConstraintData m_typeConstraintData; btTransformFloatData m_rbAFrame; // constraint axii. Assumes z is hinge axis. btTransformFloatData m_rbBFrame; int m_useReferenceFrameA; int m_angularOnly; int m_enableAngularMotor; float m_motorTargetVelocity; float m_maxMotorImpulse; float m_lowerLimit; float m_upperLimit; float m_limitSoftness; float m_biasFactor; float m_relaxationFactor; }; SIMD_FORCE_INLINE int btHingeConstraint::calculateSerializeBufferSize() const { return sizeof(btHingeConstraintData); } ///fills the dataBuffer and returns the struct name (and 0 on failure) SIMD_FORCE_INLINE const char* btHingeConstraint::serialize(void* dataBuffer, btSerializer* serializer) const { btHingeConstraintData* hingeData = (btHingeConstraintData*)dataBuffer; btTypedConstraint::serialize(&hingeData->m_typeConstraintData,serializer); m_rbAFrame.serialize(hingeData->m_rbAFrame); m_rbBFrame.serialize(hingeData->m_rbBFrame); hingeData->m_angularOnly = m_angularOnly; hingeData->m_enableAngularMotor = m_enableAngularMotor; hingeData->m_maxMotorImpulse = float(m_maxMotorImpulse); hingeData->m_motorTargetVelocity = float(m_motorTargetVelocity); hingeData->m_useReferenceFrameA = m_useReferenceFrameA; hingeData->m_lowerLimit = float(m_lowerLimit); hingeData->m_upperLimit = float(m_upperLimit); hingeData->m_limitSoftness = float(m_limitSoftness); hingeData->m_biasFactor = float(m_biasFactor); hingeData->m_relaxationFactor = float(m_relaxationFactor); return btHingeConstraintDataName; } #endif //HINGECONSTRAINT_H critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btJacobianEntry.h0000644000175000017500000001250511337071441030444 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 JACOBIAN_ENTRY_H #define JACOBIAN_ENTRY_H #include "LinearMath/btVector3.h" #include "BulletDynamics/Dynamics/btRigidBody.h" //notes: // Another memory optimization would be to store m_1MinvJt in the remaining 3 w components // which makes the btJacobianEntry memory layout 16 bytes // if you only are interested in angular part, just feed massInvA and massInvB zero /// Jacobian entry is an abstraction that allows to describe constraints /// it can be used in combination with a constraint solver /// Can be used to relate the effect of an impulse to the constraint error ATTRIBUTE_ALIGNED16(class) btJacobianEntry { public: btJacobianEntry() {}; //constraint between two different rigidbodies btJacobianEntry( const btMatrix3x3& world2A, const btMatrix3x3& world2B, const btVector3& rel_pos1,const btVector3& rel_pos2, const btVector3& jointAxis, const btVector3& inertiaInvA, const btScalar massInvA, const btVector3& inertiaInvB, const btScalar massInvB) :m_linearJointAxis(jointAxis) { m_aJ = world2A*(rel_pos1.cross(m_linearJointAxis)); m_bJ = world2B*(rel_pos2.cross(-m_linearJointAxis)); m_0MinvJt = inertiaInvA * m_aJ; m_1MinvJt = inertiaInvB * m_bJ; m_Adiag = massInvA + m_0MinvJt.dot(m_aJ) + massInvB + m_1MinvJt.dot(m_bJ); btAssert(m_Adiag > btScalar(0.0)); } //angular constraint between two different rigidbodies btJacobianEntry(const btVector3& jointAxis, const btMatrix3x3& world2A, const btMatrix3x3& world2B, const btVector3& inertiaInvA, const btVector3& inertiaInvB) :m_linearJointAxis(btVector3(btScalar(0.),btScalar(0.),btScalar(0.))) { m_aJ= world2A*jointAxis; m_bJ = world2B*-jointAxis; m_0MinvJt = inertiaInvA * m_aJ; m_1MinvJt = inertiaInvB * m_bJ; m_Adiag = m_0MinvJt.dot(m_aJ) + m_1MinvJt.dot(m_bJ); btAssert(m_Adiag > btScalar(0.0)); } //angular constraint between two different rigidbodies btJacobianEntry(const btVector3& axisInA, const btVector3& axisInB, const btVector3& inertiaInvA, const btVector3& inertiaInvB) : m_linearJointAxis(btVector3(btScalar(0.),btScalar(0.),btScalar(0.))) , m_aJ(axisInA) , m_bJ(-axisInB) { m_0MinvJt = inertiaInvA * m_aJ; m_1MinvJt = inertiaInvB * m_bJ; m_Adiag = m_0MinvJt.dot(m_aJ) + m_1MinvJt.dot(m_bJ); btAssert(m_Adiag > btScalar(0.0)); } //constraint on one rigidbody btJacobianEntry( const btMatrix3x3& world2A, const btVector3& rel_pos1,const btVector3& rel_pos2, const btVector3& jointAxis, const btVector3& inertiaInvA, const btScalar massInvA) :m_linearJointAxis(jointAxis) { m_aJ= world2A*(rel_pos1.cross(jointAxis)); m_bJ = world2A*(rel_pos2.cross(-jointAxis)); m_0MinvJt = inertiaInvA * m_aJ; m_1MinvJt = btVector3(btScalar(0.),btScalar(0.),btScalar(0.)); m_Adiag = massInvA + m_0MinvJt.dot(m_aJ); btAssert(m_Adiag > btScalar(0.0)); } btScalar getDiagonal() const { return m_Adiag; } // for two constraints on the same rigidbody (for example vehicle friction) btScalar getNonDiagonal(const btJacobianEntry& jacB, const btScalar massInvA) const { const btJacobianEntry& jacA = *this; btScalar lin = massInvA * jacA.m_linearJointAxis.dot(jacB.m_linearJointAxis); btScalar ang = jacA.m_0MinvJt.dot(jacB.m_aJ); return lin + ang; } // for two constraints on sharing two same rigidbodies (for example two contact points between two rigidbodies) btScalar getNonDiagonal(const btJacobianEntry& jacB,const btScalar massInvA,const btScalar massInvB) const { const btJacobianEntry& jacA = *this; btVector3 lin = jacA.m_linearJointAxis * jacB.m_linearJointAxis; btVector3 ang0 = jacA.m_0MinvJt * jacB.m_aJ; btVector3 ang1 = jacA.m_1MinvJt * jacB.m_bJ; btVector3 lin0 = massInvA * lin ; btVector3 lin1 = massInvB * lin; btVector3 sum = ang0+ang1+lin0+lin1; return sum[0]+sum[1]+sum[2]; } btScalar getRelativeVelocity(const btVector3& linvelA,const btVector3& angvelA,const btVector3& linvelB,const btVector3& angvelB) { btVector3 linrel = linvelA - linvelB; btVector3 angvela = angvelA * m_aJ; btVector3 angvelb = angvelB * m_bJ; linrel *= m_linearJointAxis; angvela += angvelb; angvela += linrel; btScalar rel_vel2 = angvela[0]+angvela[1]+angvela[2]; return rel_vel2 + SIMD_EPSILON; } //private: btVector3 m_linearJointAxis; btVector3 m_aJ; btVector3 m_bJ; btVector3 m_0MinvJt; btVector3 m_1MinvJt; //Optimization: can be stored in the w/last component of one of the vectors btScalar m_Adiag; }; #endif //JACOBIAN_ENTRY_H ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.cppcritterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.0000644000175000017500000001074411344267705033102 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. 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 "btGeneric6DofSpringConstraint.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "LinearMath/btTransformUtil.h" btGeneric6DofSpringConstraint::btGeneric6DofSpringConstraint(btRigidBody& rbA, btRigidBody& rbB, const btTransform& frameInA, const btTransform& frameInB ,bool useLinearReferenceFrameA) : btGeneric6DofConstraint(rbA, rbB, frameInA, frameInB, useLinearReferenceFrameA) { for(int i = 0; i < 6; i++) { m_springEnabled[i] = false; m_equilibriumPoint[i] = btScalar(0.f); m_springStiffness[i] = btScalar(0.f); m_springDamping[i] = btScalar(1.f); } } void btGeneric6DofSpringConstraint::enableSpring(int index, bool onOff) { btAssert((index >= 0) && (index < 6)); m_springEnabled[index] = onOff; if(index < 3) { m_linearLimits.m_enableMotor[index] = onOff; } else { m_angularLimits[index - 3].m_enableMotor = onOff; } } void btGeneric6DofSpringConstraint::setStiffness(int index, btScalar stiffness) { btAssert((index >= 0) && (index < 6)); m_springStiffness[index] = stiffness; } void btGeneric6DofSpringConstraint::setDamping(int index, btScalar damping) { btAssert((index >= 0) && (index < 6)); m_springDamping[index] = damping; } void btGeneric6DofSpringConstraint::setEquilibriumPoint() { calculateTransforms(); int i; for( i = 0; i < 3; i++) { m_equilibriumPoint[i] = m_calculatedLinearDiff[i]; } for(i = 0; i < 3; i++) { m_equilibriumPoint[i + 3] = m_calculatedAxisAngleDiff[i]; } } void btGeneric6DofSpringConstraint::setEquilibriumPoint(int index) { btAssert((index >= 0) && (index < 6)); calculateTransforms(); if(index < 3) { m_equilibriumPoint[index] = m_calculatedLinearDiff[index]; } else { m_equilibriumPoint[index] = m_calculatedAxisAngleDiff[index - 3]; } } void btGeneric6DofSpringConstraint::internalUpdateSprings(btConstraintInfo2* info) { // it is assumed that calculateTransforms() have been called before this call int i; btVector3 relVel = m_rbB.getLinearVelocity() - m_rbA.getLinearVelocity(); for(i = 0; i < 3; i++) { if(m_springEnabled[i]) { // get current position of constraint btScalar currPos = m_calculatedLinearDiff[i]; // calculate difference btScalar delta = currPos - m_equilibriumPoint[i]; // spring force is (delta * m_stiffness) according to Hooke's Law btScalar force = delta * m_springStiffness[i]; btScalar velFactor = info->fps * m_springDamping[i] / btScalar(info->m_numIterations); m_linearLimits.m_targetVelocity[i] = velFactor * force; m_linearLimits.m_maxMotorForce[i] = btFabs(force) / info->fps; } } for(i = 0; i < 3; i++) { if(m_springEnabled[i + 3]) { // get current position of constraint btScalar currPos = m_calculatedAxisAngleDiff[i]; // calculate difference btScalar delta = currPos - m_equilibriumPoint[i+3]; // spring force is (-delta * m_stiffness) according to Hooke's Law btScalar force = -delta * m_springStiffness[i+3]; btScalar velFactor = info->fps * m_springDamping[i+3] / btScalar(info->m_numIterations); m_angularLimits[i].m_targetVelocity = velFactor * force; m_angularLimits[i].m_maxMotorForce = btFabs(force) / info->fps; } } } void btGeneric6DofSpringConstraint::getInfo2(btConstraintInfo2* info) { // this will be called by constraint solver at the constraint setup stage // set current motor parameters internalUpdateSprings(info); // do the rest of job for constraint setup btGeneric6DofConstraint::getInfo2(info); } ././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.hcritterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintS0000644000175000017500000001522411344267705033340 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 SEQUENTIAL_IMPULSE_CONSTRAINT_SOLVER_H #define SEQUENTIAL_IMPULSE_CONSTRAINT_SOLVER_H #include "btConstraintSolver.h" class btIDebugDraw; #include "btContactConstraint.h" #include "btSolverBody.h" #include "btSolverConstraint.h" #include "btTypedConstraint.h" #include "BulletCollision/NarrowPhaseCollision/btManifoldPoint.h" ///The btSequentialImpulseConstraintSolver is a fast SIMD implementation of the Projected Gauss Seidel (iterative LCP) method. class btSequentialImpulseConstraintSolver : public btConstraintSolver { protected: btConstraintArray m_tmpSolverContactConstraintPool; btConstraintArray m_tmpSolverNonContactConstraintPool; btConstraintArray m_tmpSolverContactFrictionConstraintPool; btAlignedObjectArray m_orderTmpConstraintPool; btAlignedObjectArray m_orderFrictionConstraintPool; btAlignedObjectArray m_tmpConstraintSizesPool; void setupFrictionConstraint( btSolverConstraint& solverConstraint, const btVector3& normalAxis,btRigidBody* solverBodyA,btRigidBody* solverBodyIdB, btManifoldPoint& cp,const btVector3& rel_pos1,const btVector3& rel_pos2, btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, btScalar desiredVelocity=0., btScalar cfmSlip=0.); btSolverConstraint& addFrictionConstraint(const btVector3& normalAxis,btRigidBody* solverBodyA,btRigidBody* solverBodyB,int frictionIndex,btManifoldPoint& cp,const btVector3& rel_pos1,const btVector3& rel_pos2,btCollisionObject* colObj0,btCollisionObject* colObj1, btScalar relaxation, btScalar desiredVelocity=0., btScalar cfmSlip=0.); void setupContactConstraint(btSolverConstraint& solverConstraint, btCollisionObject* colObj0, btCollisionObject* colObj1, btManifoldPoint& cp, const btContactSolverInfo& infoGlobal, btVector3& vel, btScalar& rel_vel, btScalar& relaxation, btVector3& rel_pos1, btVector3& rel_pos2); void setFrictionConstraintImpulse( btSolverConstraint& solverConstraint, btRigidBody* rb0, btRigidBody* rb1, btManifoldPoint& cp, const btContactSolverInfo& infoGlobal); ///m_btSeed2 is used for re-arranging the constraint rows. improves convergence/quality of friction unsigned long m_btSeed2; // void initSolverBody(btSolverBody* solverBody, btCollisionObject* collisionObject); btScalar restitutionCurve(btScalar rel_vel, btScalar restitution); void convertContact(btPersistentManifold* manifold,const btContactSolverInfo& infoGlobal); void resolveSplitPenetrationSIMD( btRigidBody& body1, btRigidBody& body2, const btSolverConstraint& contactConstraint); void resolveSplitPenetrationImpulseCacheFriendly( btRigidBody& body1, btRigidBody& body2, const btSolverConstraint& contactConstraint); //internal method int getOrInitSolverBody(btCollisionObject& body); void resolveSingleConstraintRowGeneric(btRigidBody& body1,btRigidBody& body2,const btSolverConstraint& contactConstraint); void resolveSingleConstraintRowGenericSIMD(btRigidBody& body1,btRigidBody& body2,const btSolverConstraint& contactConstraint); void resolveSingleConstraintRowLowerLimit(btRigidBody& body1,btRigidBody& body2,const btSolverConstraint& contactConstraint); void resolveSingleConstraintRowLowerLimitSIMD(btRigidBody& body1,btRigidBody& body2,const btSolverConstraint& contactConstraint); protected: static btRigidBody& getFixedBody() { static btRigidBody s_fixed(0, 0,0); s_fixed.setMassProps(btScalar(0.),btVector3(btScalar(0.),btScalar(0.),btScalar(0.))); return s_fixed; } virtual void solveGroupCacheFriendlySplitImpulseIterations(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer,btStackAlloc* stackAlloc); virtual btScalar solveGroupCacheFriendlyFinish(btCollisionObject** bodies ,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer,btStackAlloc* stackAlloc); btScalar solveSingleIteration(int iteration, btCollisionObject** bodies ,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer,btStackAlloc* stackAlloc); virtual btScalar solveGroupCacheFriendlySetup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer,btStackAlloc* stackAlloc); virtual btScalar solveGroupCacheFriendlyIterations(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifoldPtr, int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& infoGlobal,btIDebugDraw* debugDrawer,btStackAlloc* stackAlloc); public: btSequentialImpulseConstraintSolver(); virtual ~btSequentialImpulseConstraintSolver(); virtual btScalar solveGroup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifold,int numManifolds,btTypedConstraint** constraints,int numConstraints,const btContactSolverInfo& info, btIDebugDraw* debugDrawer, btStackAlloc* stackAlloc,btDispatcher* dispatcher); ///clear internal cached data and reset random seed virtual void reset(); unsigned long btRand2(); int btRandInt2 (int n); void setRandSeed(unsigned long seed) { m_btSeed2 = seed; } unsigned long getRandSeed() const { return m_btSeed2; } }; #ifndef BT_PREFER_SIMD typedef btSequentialImpulseConstraintSolver btSequentialImpulseConstraintSolverPrefered; #endif #endif //SEQUENTIAL_IMPULSE_CONSTRAINT_SOLVER_H critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btConstraintSolver.h0000644000175000017500000000376011337071441031236 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 CONSTRAINT_SOLVER_H #define CONSTRAINT_SOLVER_H #include "LinearMath/btScalar.h" class btPersistentManifold; class btRigidBody; class btCollisionObject; class btTypedConstraint; struct btContactSolverInfo; struct btBroadphaseProxy; class btIDebugDraw; class btStackAlloc; class btDispatcher; /// btConstraintSolver provides solver interface class btConstraintSolver { public: virtual ~btConstraintSolver() {} virtual void prepareSolve (int /* numBodies */, int /* numManifolds */) {;} ///solve a group of constraints virtual btScalar solveGroup(btCollisionObject** bodies,int numBodies,btPersistentManifold** manifold,int numManifolds,btTypedConstraint** constraints,int numConstraints, const btContactSolverInfo& info,class btIDebugDraw* debugDrawer, btStackAlloc* stackAlloc,btDispatcher* dispatcher) = 0; virtual void allSolved (const btContactSolverInfo& /* info */,class btIDebugDraw* /* debugDrawer */, btStackAlloc* /* stackAlloc */) {;} ///clear internal cached data and reset random seed virtual void reset() = 0; }; #endif //CONSTRAINT_SOLVER_H critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.cpp0000644000175000017500000001704411337071441032624 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btSolve2LinearConstraint.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "LinearMath/btVector3.h" #include "btJacobianEntry.h" void btSolve2LinearConstraint::resolveUnilateralPairConstraint( btRigidBody* body1, btRigidBody* body2, const btMatrix3x3& world2A, const btMatrix3x3& world2B, const btVector3& invInertiaADiag, const btScalar invMassA, const btVector3& linvelA,const btVector3& angvelA, const btVector3& rel_posA1, const btVector3& invInertiaBDiag, const btScalar invMassB, const btVector3& linvelB,const btVector3& angvelB, const btVector3& rel_posA2, btScalar depthA, const btVector3& normalA, const btVector3& rel_posB1,const btVector3& rel_posB2, btScalar depthB, const btVector3& normalB, btScalar& imp0,btScalar& imp1) { (void)linvelA; (void)linvelB; (void)angvelB; (void)angvelA; imp0 = btScalar(0.); imp1 = btScalar(0.); btScalar len = btFabs(normalA.length()) - btScalar(1.); if (btFabs(len) >= SIMD_EPSILON) return; btAssert(len < SIMD_EPSILON); //this jacobian entry could be re-used for all iterations btJacobianEntry jacA(world2A,world2B,rel_posA1,rel_posA2,normalA,invInertiaADiag,invMassA, invInertiaBDiag,invMassB); btJacobianEntry jacB(world2A,world2B,rel_posB1,rel_posB2,normalB,invInertiaADiag,invMassA, invInertiaBDiag,invMassB); //const btScalar vel0 = jacA.getRelativeVelocity(linvelA,angvelA,linvelB,angvelB); //const btScalar vel1 = jacB.getRelativeVelocity(linvelA,angvelA,linvelB,angvelB); const btScalar vel0 = normalA.dot(body1->getVelocityInLocalPoint(rel_posA1)-body2->getVelocityInLocalPoint(rel_posA1)); const btScalar vel1 = normalB.dot(body1->getVelocityInLocalPoint(rel_posB1)-body2->getVelocityInLocalPoint(rel_posB1)); // btScalar penetrationImpulse = (depth*contactTau*timeCorrection) * massTerm;//jacDiagABInv btScalar massTerm = btScalar(1.) / (invMassA + invMassB); // calculate rhs (or error) terms const btScalar dv0 = depthA * m_tau * massTerm - vel0 * m_damping; const btScalar dv1 = depthB * m_tau * massTerm - vel1 * m_damping; // dC/dv * dv = -C // jacobian * impulse = -error // //impulse = jacobianInverse * -error // inverting 2x2 symmetric system (offdiagonal are equal!) // btScalar nonDiag = jacA.getNonDiagonal(jacB,invMassA,invMassB); btScalar invDet = btScalar(1.0) / (jacA.getDiagonal() * jacB.getDiagonal() - nonDiag * nonDiag ); //imp0 = dv0 * jacA.getDiagonal() * invDet + dv1 * -nonDiag * invDet; //imp1 = dv1 * jacB.getDiagonal() * invDet + dv0 * - nonDiag * invDet; imp0 = dv0 * jacA.getDiagonal() * invDet + dv1 * -nonDiag * invDet; imp1 = dv1 * jacB.getDiagonal() * invDet + dv0 * - nonDiag * invDet; //[a b] [d -c] //[c d] inverse = (1 / determinant) * [-b a] where determinant is (ad - bc) //[jA nD] * [imp0] = [dv0] //[nD jB] [imp1] [dv1] } void btSolve2LinearConstraint::resolveBilateralPairConstraint( btRigidBody* body1, btRigidBody* body2, const btMatrix3x3& world2A, const btMatrix3x3& world2B, const btVector3& invInertiaADiag, const btScalar invMassA, const btVector3& linvelA,const btVector3& angvelA, const btVector3& rel_posA1, const btVector3& invInertiaBDiag, const btScalar invMassB, const btVector3& linvelB,const btVector3& angvelB, const btVector3& rel_posA2, btScalar depthA, const btVector3& normalA, const btVector3& rel_posB1,const btVector3& rel_posB2, btScalar depthB, const btVector3& normalB, btScalar& imp0,btScalar& imp1) { (void)linvelA; (void)linvelB; (void)angvelA; (void)angvelB; imp0 = btScalar(0.); imp1 = btScalar(0.); btScalar len = btFabs(normalA.length()) - btScalar(1.); if (btFabs(len) >= SIMD_EPSILON) return; btAssert(len < SIMD_EPSILON); //this jacobian entry could be re-used for all iterations btJacobianEntry jacA(world2A,world2B,rel_posA1,rel_posA2,normalA,invInertiaADiag,invMassA, invInertiaBDiag,invMassB); btJacobianEntry jacB(world2A,world2B,rel_posB1,rel_posB2,normalB,invInertiaADiag,invMassA, invInertiaBDiag,invMassB); //const btScalar vel0 = jacA.getRelativeVelocity(linvelA,angvelA,linvelB,angvelB); //const btScalar vel1 = jacB.getRelativeVelocity(linvelA,angvelA,linvelB,angvelB); const btScalar vel0 = normalA.dot(body1->getVelocityInLocalPoint(rel_posA1)-body2->getVelocityInLocalPoint(rel_posA1)); const btScalar vel1 = normalB.dot(body1->getVelocityInLocalPoint(rel_posB1)-body2->getVelocityInLocalPoint(rel_posB1)); // calculate rhs (or error) terms const btScalar dv0 = depthA * m_tau - vel0 * m_damping; const btScalar dv1 = depthB * m_tau - vel1 * m_damping; // dC/dv * dv = -C // jacobian * impulse = -error // //impulse = jacobianInverse * -error // inverting 2x2 symmetric system (offdiagonal are equal!) // btScalar nonDiag = jacA.getNonDiagonal(jacB,invMassA,invMassB); btScalar invDet = btScalar(1.0) / (jacA.getDiagonal() * jacB.getDiagonal() - nonDiag * nonDiag ); //imp0 = dv0 * jacA.getDiagonal() * invDet + dv1 * -nonDiag * invDet; //imp1 = dv1 * jacB.getDiagonal() * invDet + dv0 * - nonDiag * invDet; imp0 = dv0 * jacA.getDiagonal() * invDet + dv1 * -nonDiag * invDet; imp1 = dv1 * jacB.getDiagonal() * invDet + dv0 * - nonDiag * invDet; //[a b] [d -c] //[c d] inverse = (1 / determinant) * [-b a] where determinant is (ad - bc) //[jA nD] * [imp0] = [dv0] //[nD jB] [imp1] [dv1] if ( imp0 > btScalar(0.0)) { if ( imp1 > btScalar(0.0) ) { //both positive } else { imp1 = btScalar(0.); // now imp0>0 imp1<0 imp0 = dv0 / jacA.getDiagonal(); if ( imp0 > btScalar(0.0) ) { } else { imp0 = btScalar(0.); } } } else { imp0 = btScalar(0.); imp1 = dv1 / jacB.getDiagonal(); if ( imp1 <= btScalar(0.0) ) { imp1 = btScalar(0.); // now imp0>0 imp1<0 imp0 = dv0 / jacA.getDiagonal(); if ( imp0 > btScalar(0.0) ) { } else { imp0 = btScalar(0.); } } else { } } } /* void btSolve2LinearConstraint::resolveAngularConstraint( const btMatrix3x3& invInertiaAWS, const btScalar invMassA, const btVector3& linvelA,const btVector3& angvelA, const btVector3& rel_posA1, const btMatrix3x3& invInertiaBWS, const btScalar invMassB, const btVector3& linvelB,const btVector3& angvelB, const btVector3& rel_posA2, btScalar depthA, const btVector3& normalA, const btVector3& rel_posB1,const btVector3& rel_posB2, btScalar depthB, const btVector3& normalB, btScalar& imp0,btScalar& imp1) { } */ critterding-beta12.1/src/utils/bullet/BulletDynamics/ConstraintSolver/btTypedConstraint.cpp0000644000175000017500000000731311344267705031412 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btTypedConstraint.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "LinearMath/btSerializer.h" #define DEFAULT_DEBUGDRAW_SIZE btScalar(0.3f) btTypedConstraint::btTypedConstraint(btTypedConstraintType type, btRigidBody& rbA) :btTypedObject(type), m_userConstraintType(-1), m_userConstraintId(-1), m_needsFeedback(false), m_rbA(rbA), m_rbB(getFixedBody()), m_appliedImpulse(btScalar(0.)), m_dbgDrawSize(DEFAULT_DEBUGDRAW_SIZE) { } btTypedConstraint::btTypedConstraint(btTypedConstraintType type, btRigidBody& rbA,btRigidBody& rbB) :btTypedObject(type), m_userConstraintType(-1), m_userConstraintId(-1), m_needsFeedback(false), m_rbA(rbA), m_rbB(rbB), m_appliedImpulse(btScalar(0.)), m_dbgDrawSize(DEFAULT_DEBUGDRAW_SIZE) { } btScalar btTypedConstraint::getMotorFactor(btScalar pos, btScalar lowLim, btScalar uppLim, btScalar vel, btScalar timeFact) { if(lowLim > uppLim) { return btScalar(1.0f); } else if(lowLim == uppLim) { return btScalar(0.0f); } btScalar lim_fact = btScalar(1.0f); btScalar delta_max = vel / timeFact; if(delta_max < btScalar(0.0f)) { if((pos >= lowLim) && (pos < (lowLim - delta_max))) { lim_fact = (lowLim - pos) / delta_max; } else if(pos < lowLim) { lim_fact = btScalar(0.0f); } else { lim_fact = btScalar(1.0f); } } else if(delta_max > btScalar(0.0f)) { if((pos <= uppLim) && (pos > (uppLim - delta_max))) { lim_fact = (uppLim - pos) / delta_max; } else if(pos > uppLim) { lim_fact = btScalar(0.0f); } else { lim_fact = btScalar(1.0f); } } else { lim_fact = btScalar(0.0f); } return lim_fact; } ///fills the dataBuffer and returns the struct name (and 0 on failure) const char* btTypedConstraint::serialize(void* dataBuffer, btSerializer* serializer) const { btTypedConstraintData* tcd = (btTypedConstraintData*) dataBuffer; tcd->m_rbA = (btRigidBodyData*)serializer->getUniquePointer(&m_rbA); tcd->m_rbB = (btRigidBodyData*)serializer->getUniquePointer(&m_rbB); char* name = (char*) serializer->findNameForPointer(this); tcd->m_name = (char*)serializer->getUniquePointer(name); if (tcd->m_name) { serializer->serializeName(name); } tcd->m_objectType = m_objectType; tcd->m_needsFeedback = m_needsFeedback; tcd->m_userConstraintId =m_userConstraintId; tcd->m_userConstraintType =m_userConstraintType; tcd->m_appliedImpulse = float(m_appliedImpulse); tcd->m_dbgDrawSize = float(m_dbgDrawSize ); tcd->m_disableCollisionsBetweenLinkedBodies = false; int i; for (i=0;im_disableCollisionsBetweenLinkedBodies = true; for (i=0;im_disableCollisionsBetweenLinkedBodies = true; return "btTypedConstraintData"; } critterding-beta12.1/src/utils/bullet/BulletDynamics/Vehicle/0000755000175000017500000000000011347266042023256 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletDynamics/Vehicle/btWheelInfo.cpp0000644000175000017500000000345511337071441026173 0ustar bobkebobke/* * Copyright (c) 2005 Erwin Coumans http://continuousphysics.com/Bullet/ * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies. * Erwin Coumans makes no representations about the suitability * of this software for any purpose. * It is provided "as is" without express or implied warranty. */ #include "btWheelInfo.h" #include "BulletDynamics/Dynamics/btRigidBody.h" // for pointvelocity btScalar btWheelInfo::getSuspensionRestLength() const { return m_suspensionRestLength1; } void btWheelInfo::updateWheel(const btRigidBody& chassis,RaycastInfo& raycastInfo) { (void)raycastInfo; if (m_raycastInfo.m_isInContact) { btScalar project= m_raycastInfo.m_contactNormalWS.dot( m_raycastInfo.m_wheelDirectionWS ); btVector3 chassis_velocity_at_contactPoint; btVector3 relpos = m_raycastInfo.m_contactPointWS - chassis.getCenterOfMassPosition(); chassis_velocity_at_contactPoint = chassis.getVelocityInLocalPoint( relpos ); btScalar projVel = m_raycastInfo.m_contactNormalWS.dot( chassis_velocity_at_contactPoint ); if ( project >= btScalar(-0.1)) { m_suspensionRelativeVelocity = btScalar(0.0); m_clippedInvContactDotSuspension = btScalar(1.0) / btScalar(0.1); } else { btScalar inv = btScalar(-1.) / project; m_suspensionRelativeVelocity = projVel * inv; m_clippedInvContactDotSuspension = inv; } } else // Not in contact : position wheel in a nice (rest length) position { m_raycastInfo.m_suspensionLength = this->getSuspensionRestLength(); m_suspensionRelativeVelocity = btScalar(0.0); m_raycastInfo.m_contactNormalWS = -m_raycastInfo.m_wheelDirectionWS; m_clippedInvContactDotSuspension = btScalar(1.0); } } critterding-beta12.1/src/utils/bullet/BulletDynamics/Vehicle/btRaycastVehicle.cpp0000644000175000017500000005074511344267705027235 0ustar bobkebobke/* * Copyright (c) 2005 Erwin Coumans http://continuousphysics.com/Bullet/ * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies. * Erwin Coumans makes no representations about the suitability * of this software for any purpose. * It is provided "as is" without express or implied warranty. */ #include "LinearMath/btVector3.h" #include "btRaycastVehicle.h" #include "BulletDynamics/ConstraintSolver/btSolve2LinearConstraint.h" #include "BulletDynamics/ConstraintSolver/btJacobianEntry.h" #include "LinearMath/btQuaternion.h" #include "BulletDynamics/Dynamics/btDynamicsWorld.h" #include "btVehicleRaycaster.h" #include "btWheelInfo.h" #include "LinearMath/btMinMax.h" #include "LinearMath/btIDebugDraw.h" #include "BulletDynamics/ConstraintSolver/btContactConstraint.h" btRaycastVehicle::btRaycastVehicle(const btVehicleTuning& tuning,btRigidBody* chassis, btVehicleRaycaster* raycaster ) :m_vehicleRaycaster(raycaster), m_pitchControl(btScalar(0.)) { m_chassisBody = chassis; m_indexRightAxis = 0; m_indexUpAxis = 2; m_indexForwardAxis = 1; defaultInit(tuning); } void btRaycastVehicle::defaultInit(const btVehicleTuning& tuning) { (void)tuning; m_currentVehicleSpeedKmHour = btScalar(0.); m_steeringValue = btScalar(0.); } btRaycastVehicle::~btRaycastVehicle() { } // // basically most of the code is general for 2 or 4 wheel vehicles, but some of it needs to be reviewed // btWheelInfo& btRaycastVehicle::addWheel( const btVector3& connectionPointCS, const btVector3& wheelDirectionCS0,const btVector3& wheelAxleCS, btScalar suspensionRestLength, btScalar wheelRadius,const btVehicleTuning& tuning, bool isFrontWheel) { btWheelInfoConstructionInfo ci; ci.m_chassisConnectionCS = connectionPointCS; ci.m_wheelDirectionCS = wheelDirectionCS0; ci.m_wheelAxleCS = wheelAxleCS; ci.m_suspensionRestLength = suspensionRestLength; ci.m_wheelRadius = wheelRadius; ci.m_suspensionStiffness = tuning.m_suspensionStiffness; ci.m_wheelsDampingCompression = tuning.m_suspensionCompression; ci.m_wheelsDampingRelaxation = tuning.m_suspensionDamping; ci.m_frictionSlip = tuning.m_frictionSlip; ci.m_bIsFrontWheel = isFrontWheel; ci.m_maxSuspensionTravelCm = tuning.m_maxSuspensionTravelCm; ci.m_maxSuspensionForce = tuning.m_maxSuspensionForce; m_wheelInfo.push_back( btWheelInfo(ci)); btWheelInfo& wheel = m_wheelInfo[getNumWheels()-1]; updateWheelTransformsWS( wheel , false ); updateWheelTransform(getNumWheels()-1,false); return wheel; } const btTransform& btRaycastVehicle::getWheelTransformWS( int wheelIndex ) const { btAssert(wheelIndex < getNumWheels()); const btWheelInfo& wheel = m_wheelInfo[wheelIndex]; return wheel.m_worldTransform; } void btRaycastVehicle::updateWheelTransform( int wheelIndex , bool interpolatedTransform) { btWheelInfo& wheel = m_wheelInfo[ wheelIndex ]; updateWheelTransformsWS(wheel,interpolatedTransform); btVector3 up = -wheel.m_raycastInfo.m_wheelDirectionWS; const btVector3& right = wheel.m_raycastInfo.m_wheelAxleWS; btVector3 fwd = up.cross(right); fwd = fwd.normalize(); // up = right.cross(fwd); // up.normalize(); //rotate around steering over de wheelAxleWS btScalar steering = wheel.m_steering; btQuaternion steeringOrn(up,steering);//wheel.m_steering); btMatrix3x3 steeringMat(steeringOrn); btQuaternion rotatingOrn(right,-wheel.m_rotation); btMatrix3x3 rotatingMat(rotatingOrn); btMatrix3x3 basis2( right[0],fwd[0],up[0], right[1],fwd[1],up[1], right[2],fwd[2],up[2] ); wheel.m_worldTransform.setBasis(steeringMat * rotatingMat * basis2); wheel.m_worldTransform.setOrigin( wheel.m_raycastInfo.m_hardPointWS + wheel.m_raycastInfo.m_wheelDirectionWS * wheel.m_raycastInfo.m_suspensionLength ); } void btRaycastVehicle::resetSuspension() { int i; for (i=0;igetMotionState())) { getRigidBody()->getMotionState()->getWorldTransform(chassisTrans); } wheel.m_raycastInfo.m_hardPointWS = chassisTrans( wheel.m_chassisConnectionPointCS ); wheel.m_raycastInfo.m_wheelDirectionWS = chassisTrans.getBasis() * wheel.m_wheelDirectionCS ; wheel.m_raycastInfo.m_wheelAxleWS = chassisTrans.getBasis() * wheel.m_wheelAxleCS; } btScalar btRaycastVehicle::rayCast(btWheelInfo& wheel) { updateWheelTransformsWS( wheel,false); btScalar depth = -1; btScalar raylen = wheel.getSuspensionRestLength()+wheel.m_wheelsRadius; btVector3 rayvector = wheel.m_raycastInfo.m_wheelDirectionWS * (raylen); const btVector3& source = wheel.m_raycastInfo.m_hardPointWS; wheel.m_raycastInfo.m_contactPointWS = source + rayvector; const btVector3& target = wheel.m_raycastInfo.m_contactPointWS; btScalar param = btScalar(0.); btVehicleRaycaster::btVehicleRaycasterResult rayResults; btAssert(m_vehicleRaycaster); void* object = m_vehicleRaycaster->castRay(source,target,rayResults); wheel.m_raycastInfo.m_groundObject = 0; if (object) { param = rayResults.m_distFraction; depth = raylen * rayResults.m_distFraction; wheel.m_raycastInfo.m_contactNormalWS = rayResults.m_hitNormalInWorld; wheel.m_raycastInfo.m_isInContact = true; wheel.m_raycastInfo.m_groundObject = &getFixedBody();///@todo for driving on dynamic/movable objects!; //wheel.m_raycastInfo.m_groundObject = object; btScalar hitDistance = param*raylen; wheel.m_raycastInfo.m_suspensionLength = hitDistance - wheel.m_wheelsRadius; //clamp on max suspension travel btScalar minSuspensionLength = wheel.getSuspensionRestLength() - wheel.m_maxSuspensionTravelCm*btScalar(0.01); btScalar maxSuspensionLength = wheel.getSuspensionRestLength()+ wheel.m_maxSuspensionTravelCm*btScalar(0.01); if (wheel.m_raycastInfo.m_suspensionLength < minSuspensionLength) { wheel.m_raycastInfo.m_suspensionLength = minSuspensionLength; } if (wheel.m_raycastInfo.m_suspensionLength > maxSuspensionLength) { wheel.m_raycastInfo.m_suspensionLength = maxSuspensionLength; } wheel.m_raycastInfo.m_contactPointWS = rayResults.m_hitPointInWorld; btScalar denominator= wheel.m_raycastInfo.m_contactNormalWS.dot( wheel.m_raycastInfo.m_wheelDirectionWS ); btVector3 chassis_velocity_at_contactPoint; btVector3 relpos = wheel.m_raycastInfo.m_contactPointWS-getRigidBody()->getCenterOfMassPosition(); chassis_velocity_at_contactPoint = getRigidBody()->getVelocityInLocalPoint(relpos); btScalar projVel = wheel.m_raycastInfo.m_contactNormalWS.dot( chassis_velocity_at_contactPoint ); if ( denominator >= btScalar(-0.1)) { wheel.m_suspensionRelativeVelocity = btScalar(0.0); wheel.m_clippedInvContactDotSuspension = btScalar(1.0) / btScalar(0.1); } else { btScalar inv = btScalar(-1.) / denominator; wheel.m_suspensionRelativeVelocity = projVel * inv; wheel.m_clippedInvContactDotSuspension = inv; } } else { //put wheel info as in rest position wheel.m_raycastInfo.m_suspensionLength = wheel.getSuspensionRestLength(); wheel.m_suspensionRelativeVelocity = btScalar(0.0); wheel.m_raycastInfo.m_contactNormalWS = - wheel.m_raycastInfo.m_wheelDirectionWS; wheel.m_clippedInvContactDotSuspension = btScalar(1.0); } return depth; } const btTransform& btRaycastVehicle::getChassisWorldTransform() const { /*if (getRigidBody()->getMotionState()) { btTransform chassisWorldTrans; getRigidBody()->getMotionState()->getWorldTransform(chassisWorldTrans); return chassisWorldTrans; } */ return getRigidBody()->getCenterOfMassTransform(); } void btRaycastVehicle::updateVehicle( btScalar step ) { { for (int i=0;igetLinearVelocity().length(); const btTransform& chassisTrans = getChassisWorldTransform(); btVector3 forwardW ( chassisTrans.getBasis()[0][m_indexForwardAxis], chassisTrans.getBasis()[1][m_indexForwardAxis], chassisTrans.getBasis()[2][m_indexForwardAxis]); if (forwardW.dot(getRigidBody()->getLinearVelocity()) < btScalar(0.)) { m_currentVehicleSpeedKmHour *= btScalar(-1.); } // // simulate suspension // int i=0; for (i=0;i wheel.m_maxSuspensionForce) { suspensionForce = wheel.m_maxSuspensionForce; } btVector3 impulse = wheel.m_raycastInfo.m_contactNormalWS * suspensionForce * step; btVector3 relpos = wheel.m_raycastInfo.m_contactPointWS - getRigidBody()->getCenterOfMassPosition(); getRigidBody()->applyImpulse(impulse, relpos); } updateFriction( step); for (i=0;igetCenterOfMassPosition(); btVector3 vel = getRigidBody()->getVelocityInLocalPoint( relpos ); if (wheel.m_raycastInfo.m_isInContact) { const btTransform& chassisWorldTransform = getChassisWorldTransform(); btVector3 fwd ( chassisWorldTransform.getBasis()[0][m_indexForwardAxis], chassisWorldTransform.getBasis()[1][m_indexForwardAxis], chassisWorldTransform.getBasis()[2][m_indexForwardAxis]); btScalar proj = fwd.dot(wheel.m_raycastInfo.m_contactNormalWS); fwd -= wheel.m_raycastInfo.m_contactNormalWS * proj; btScalar proj2 = fwd.dot(vel); wheel.m_deltaRotation = (proj2 * step) / (wheel.m_wheelsRadius); wheel.m_rotation += wheel.m_deltaRotation; } else { wheel.m_rotation += wheel.m_deltaRotation; } wheel.m_deltaRotation *= btScalar(0.99);//damping of rotation when not in contact } } void btRaycastVehicle::setSteeringValue(btScalar steering,int wheel) { btAssert(wheel>=0 && wheel < getNumWheels()); btWheelInfo& wheelInfo = getWheelInfo(wheel); wheelInfo.m_steering = steering; } btScalar btRaycastVehicle::getSteeringValue(int wheel) const { return getWheelInfo(wheel).m_steering; } void btRaycastVehicle::applyEngineForce(btScalar force, int wheel) { btAssert(wheel>=0 && wheel < getNumWheels()); btWheelInfo& wheelInfo = getWheelInfo(wheel); wheelInfo.m_engineForce = force; } const btWheelInfo& btRaycastVehicle::getWheelInfo(int index) const { btAssert((index >= 0) && (index < getNumWheels())); return m_wheelInfo[index]; } btWheelInfo& btRaycastVehicle::getWheelInfo(int index) { btAssert((index >= 0) && (index < getNumWheels())); return m_wheelInfo[index]; } void btRaycastVehicle::setBrake(btScalar brake,int wheelIndex) { btAssert((wheelIndex >= 0) && (wheelIndex < getNumWheels())); getWheelInfo(wheelIndex).m_brake = brake; } void btRaycastVehicle::updateSuspension(btScalar deltaTime) { (void)deltaTime; btScalar chassisMass = btScalar(1.) / m_chassisBody->getInvMass(); for (int w_it=0; w_itcomputeImpulseDenominator(frictionPosWorld,frictionDirectionWorld); btScalar denom1 = body1->computeImpulseDenominator(frictionPosWorld,frictionDirectionWorld); btScalar relaxation = 1.f; m_jacDiagABInv = relaxation/(denom0+denom1); } }; btScalar calcRollingFriction(btWheelContactPoint& contactPoint); btScalar calcRollingFriction(btWheelContactPoint& contactPoint) { btScalar j1=0.f; const btVector3& contactPosWorld = contactPoint.m_frictionPositionWorld; btVector3 rel_pos1 = contactPosWorld - contactPoint.m_body0->getCenterOfMassPosition(); btVector3 rel_pos2 = contactPosWorld - contactPoint.m_body1->getCenterOfMassPosition(); btScalar maxImpulse = contactPoint.m_maxImpulse; btVector3 vel1 = contactPoint.m_body0->getVelocityInLocalPoint(rel_pos1); btVector3 vel2 = contactPoint.m_body1->getVelocityInLocalPoint(rel_pos2); btVector3 vel = vel1 - vel2; btScalar vrel = contactPoint.m_frictionDirectionWorld.dot(vel); // calculate j that moves us to zero relative velocity j1 = -vrel * contactPoint.m_jacDiagABInv; btSetMin(j1, maxImpulse); btSetMax(j1, -maxImpulse); return j1; } btScalar sideFrictionStiffness2 = btScalar(1.0); void btRaycastVehicle::updateFriction(btScalar timeStep) { //calculate the impulse, so that the wheels don't move sidewards int numWheel = getNumWheels(); if (!numWheel) return; m_forwardWS.resize(numWheel); m_axle.resize(numWheel); m_forwardImpulse.resize(numWheel); m_sideImpulse.resize(numWheel); int numWheelsOnGround = 0; //collapse all those loops into one! for (int i=0;i maximpSquared) { sliding = true; btScalar factor = maximp / btSqrt(impulseSquared); m_wheelInfo[wheel].m_skidInfo *= factor; } } } } if (sliding) { for (int wheel = 0;wheel < getNumWheels(); wheel++) { if (m_sideImpulse[wheel] != btScalar(0.)) { if (m_wheelInfo[wheel].m_skidInfo< btScalar(1.)) { m_forwardImpulse[wheel] *= m_wheelInfo[wheel].m_skidInfo; m_sideImpulse[wheel] *= m_wheelInfo[wheel].m_skidInfo; } } } } // apply the impulses { for (int wheel = 0;wheelgetCenterOfMassPosition(); if (m_forwardImpulse[wheel] != btScalar(0.)) { m_chassisBody->applyImpulse(m_forwardWS[wheel]*(m_forwardImpulse[wheel]),rel_pos); } if (m_sideImpulse[wheel] != btScalar(0.)) { class btRigidBody* groundObject = (class btRigidBody*) m_wheelInfo[wheel].m_raycastInfo.m_groundObject; btVector3 rel_pos2 = wheelInfo.m_raycastInfo.m_contactPointWS - groundObject->getCenterOfMassPosition(); btVector3 sideImp = m_axle[wheel] * m_sideImpulse[wheel]; rel_pos[m_indexUpAxis] *= wheelInfo.m_rollInfluence; m_chassisBody->applyImpulse(sideImp,rel_pos); //apply friction impulse on the ground groundObject->applyImpulse(-sideImp,rel_pos2); } } } } void btRaycastVehicle::debugDraw(btIDebugDraw* debugDrawer) { for (int v=0;vgetNumWheels();v++) { btVector3 wheelColor(0,1,1); if (getWheelInfo(v).m_raycastInfo.m_isInContact) { wheelColor.setValue(0,0,1); } else { wheelColor.setValue(1,0,1); } btVector3 wheelPosWS = getWheelInfo(v).m_worldTransform.getOrigin(); btVector3 axle = btVector3( getWheelInfo(v).m_worldTransform.getBasis()[0][getRightAxis()], getWheelInfo(v).m_worldTransform.getBasis()[1][getRightAxis()], getWheelInfo(v).m_worldTransform.getBasis()[2][getRightAxis()]); //debug wheels (cylinders) debugDrawer->drawLine(wheelPosWS,wheelPosWS+axle,wheelColor); debugDrawer->drawLine(wheelPosWS,getWheelInfo(v).m_raycastInfo.m_contactPointWS,wheelColor); } } void* btDefaultVehicleRaycaster::castRay(const btVector3& from,const btVector3& to, btVehicleRaycasterResult& result) { // RayResultCallback& resultCallback; btCollisionWorld::ClosestRayResultCallback rayCallback(from,to); m_dynamicsWorld->rayTest(from, to, rayCallback); if (rayCallback.hasHit()) { btRigidBody* body = btRigidBody::upcast(rayCallback.m_collisionObject); if (body && body->hasContactResponse()) { result.m_hitPointInWorld = rayCallback.m_hitPointWorld; result.m_hitNormalInWorld = rayCallback.m_hitNormalWorld; result.m_hitNormalInWorld.normalize(); result.m_distFraction = rayCallback.m_closestHitFraction; return body; } } return 0; } critterding-beta12.1/src/utils/bullet/BulletDynamics/Vehicle/btRaycastVehicle.h0000644000175000017500000001336511344267705026677 0ustar bobkebobke/* * Copyright (c) 2005 Erwin Coumans http://continuousphysics.com/Bullet/ * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies. * Erwin Coumans makes no representations about the suitability * of this software for any purpose. * It is provided "as is" without express or implied warranty. */ #ifndef RAYCASTVEHICLE_H #define RAYCASTVEHICLE_H #include "BulletDynamics/Dynamics/btRigidBody.h" #include "BulletDynamics/ConstraintSolver/btTypedConstraint.h" #include "btVehicleRaycaster.h" class btDynamicsWorld; #include "LinearMath/btAlignedObjectArray.h" #include "btWheelInfo.h" #include "BulletDynamics/Dynamics/btActionInterface.h" class btVehicleTuning; ///rayCast vehicle, very special constraint that turn a rigidbody into a vehicle. class btRaycastVehicle : public btActionInterface { btAlignedObjectArray m_forwardWS; btAlignedObjectArray m_axle; btAlignedObjectArray m_forwardImpulse; btAlignedObjectArray m_sideImpulse; ///backwards compatibility int m_userConstraintType; int m_userConstraintId; public: class btVehicleTuning { public: btVehicleTuning() :m_suspensionStiffness(btScalar(5.88)), m_suspensionCompression(btScalar(0.83)), m_suspensionDamping(btScalar(0.88)), m_maxSuspensionTravelCm(btScalar(500.)), m_frictionSlip(btScalar(10.5)), m_maxSuspensionForce(btScalar(6000.)) { } btScalar m_suspensionStiffness; btScalar m_suspensionCompression; btScalar m_suspensionDamping; btScalar m_maxSuspensionTravelCm; btScalar m_frictionSlip; btScalar m_maxSuspensionForce; }; private: btScalar m_tau; btScalar m_damping; btVehicleRaycaster* m_vehicleRaycaster; btScalar m_pitchControl; btScalar m_steeringValue; btScalar m_currentVehicleSpeedKmHour; btRigidBody* m_chassisBody; int m_indexRightAxis; int m_indexUpAxis; int m_indexForwardAxis; void defaultInit(const btVehicleTuning& tuning); public: //constructor to create a car from an existing rigidbody btRaycastVehicle(const btVehicleTuning& tuning,btRigidBody* chassis, btVehicleRaycaster* raycaster ); virtual ~btRaycastVehicle() ; ///btActionInterface interface virtual void updateAction( btCollisionWorld* collisionWorld, btScalar step) { (void) collisionWorld; updateVehicle(step); } ///btActionInterface interface void debugDraw(btIDebugDraw* debugDrawer); const btTransform& getChassisWorldTransform() const; btScalar rayCast(btWheelInfo& wheel); virtual void updateVehicle(btScalar step); void resetSuspension(); btScalar getSteeringValue(int wheel) const; void setSteeringValue(btScalar steering,int wheel); void applyEngineForce(btScalar force, int wheel); const btTransform& getWheelTransformWS( int wheelIndex ) const; void updateWheelTransform( int wheelIndex, bool interpolatedTransform = true ); void setRaycastWheelInfo( int wheelIndex , bool isInContact, const btVector3& hitPoint, const btVector3& hitNormal,btScalar depth); btWheelInfo& addWheel( const btVector3& connectionPointCS0, const btVector3& wheelDirectionCS0,const btVector3& wheelAxleCS,btScalar suspensionRestLength,btScalar wheelRadius,const btVehicleTuning& tuning, bool isFrontWheel); inline int getNumWheels() const { return int (m_wheelInfo.size()); } btAlignedObjectArray m_wheelInfo; const btWheelInfo& getWheelInfo(int index) const; btWheelInfo& getWheelInfo(int index); void updateWheelTransformsWS(btWheelInfo& wheel , bool interpolatedTransform = true); void setBrake(btScalar brake,int wheelIndex); void setPitchControl(btScalar pitch) { m_pitchControl = pitch; } void updateSuspension(btScalar deltaTime); virtual void updateFriction(btScalar timeStep); inline btRigidBody* getRigidBody() { return m_chassisBody; } const btRigidBody* getRigidBody() const { return m_chassisBody; } inline int getRightAxis() const { return m_indexRightAxis; } inline int getUpAxis() const { return m_indexUpAxis; } inline int getForwardAxis() const { return m_indexForwardAxis; } ///Worldspace forward vector btVector3 getForwardVector() const { const btTransform& chassisTrans = getChassisWorldTransform(); btVector3 forwardW ( chassisTrans.getBasis()[0][m_indexForwardAxis], chassisTrans.getBasis()[1][m_indexForwardAxis], chassisTrans.getBasis()[2][m_indexForwardAxis]); return forwardW; } ///Velocity of vehicle (positive if velocity vector has same direction as foward vector) btScalar getCurrentSpeedKmHour() const { return m_currentVehicleSpeedKmHour; } virtual void setCoordinateSystem(int rightIndex,int upIndex,int forwardIndex) { m_indexRightAxis = rightIndex; m_indexUpAxis = upIndex; m_indexForwardAxis = forwardIndex; } ///backwards compatibility int getUserConstraintType() const { return m_userConstraintType ; } void setUserConstraintType(int userConstraintType) { m_userConstraintType = userConstraintType; }; void setUserConstraintId(int uid) { m_userConstraintId = uid; } int getUserConstraintId() const { return m_userConstraintId; } }; class btDefaultVehicleRaycaster : public btVehicleRaycaster { btDynamicsWorld* m_dynamicsWorld; public: btDefaultVehicleRaycaster(btDynamicsWorld* world) :m_dynamicsWorld(world) { } virtual void* castRay(const btVector3& from,const btVector3& to, btVehicleRaycasterResult& result); }; #endif //RAYCASTVEHICLE_H critterding-beta12.1/src/utils/bullet/BulletDynamics/Vehicle/btVehicleRaycaster.h0000644000175000017500000000201411337071441027203 0ustar bobkebobke/* * Copyright (c) 2005 Erwin Coumans http://continuousphysics.com/Bullet/ * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies. * Erwin Coumans makes no representations about the suitability * of this software for any purpose. * It is provided "as is" without express or implied warranty. */ #ifndef VEHICLE_RAYCASTER_H #define VEHICLE_RAYCASTER_H #include "LinearMath/btVector3.h" /// btVehicleRaycaster is provides interface for between vehicle simulation and raycasting struct btVehicleRaycaster { virtual ~btVehicleRaycaster() { } struct btVehicleRaycasterResult { btVehicleRaycasterResult() :m_distFraction(btScalar(-1.)){}; btVector3 m_hitPointInWorld; btVector3 m_hitNormalInWorld; btScalar m_distFraction; }; virtual void* castRay(const btVector3& from,const btVector3& to, btVehicleRaycasterResult& result) = 0; }; #endif //VEHICLE_RAYCASTER_H critterding-beta12.1/src/utils/bullet/BulletDynamics/Vehicle/btWheelInfo.h0000644000175000017500000000653011344267705025645 0ustar bobkebobke/* * Copyright (c) 2005 Erwin Coumans http://continuousphysics.com/Bullet/ * * Permission to use, copy, modify, distribute and sell this software * and its documentation for any purpose is hereby granted without fee, * provided that the above copyright notice appear in all copies. * Erwin Coumans makes no representations about the suitability * of this software for any purpose. * It is provided "as is" without express or implied warranty. */ #ifndef WHEEL_INFO_H #define WHEEL_INFO_H #include "LinearMath/btVector3.h" #include "LinearMath/btTransform.h" class btRigidBody; struct btWheelInfoConstructionInfo { btVector3 m_chassisConnectionCS; btVector3 m_wheelDirectionCS; btVector3 m_wheelAxleCS; btScalar m_suspensionRestLength; btScalar m_maxSuspensionTravelCm; btScalar m_wheelRadius; btScalar m_suspensionStiffness; btScalar m_wheelsDampingCompression; btScalar m_wheelsDampingRelaxation; btScalar m_frictionSlip; btScalar m_maxSuspensionForce; bool m_bIsFrontWheel; }; /// btWheelInfo contains information per wheel about friction and suspension. struct btWheelInfo { struct RaycastInfo { //set by raycaster btVector3 m_contactNormalWS;//contactnormal btVector3 m_contactPointWS;//raycast hitpoint btScalar m_suspensionLength; btVector3 m_hardPointWS;//raycast starting point btVector3 m_wheelDirectionWS; //direction in worldspace btVector3 m_wheelAxleWS; // axle in worldspace bool m_isInContact; void* m_groundObject; //could be general void* ptr }; RaycastInfo m_raycastInfo; btTransform m_worldTransform; btVector3 m_chassisConnectionPointCS; //const btVector3 m_wheelDirectionCS;//const btVector3 m_wheelAxleCS; // const or modified by steering btScalar m_suspensionRestLength1;//const btScalar m_maxSuspensionTravelCm; btScalar getSuspensionRestLength() const; btScalar m_wheelsRadius;//const btScalar m_suspensionStiffness;//const btScalar m_wheelsDampingCompression;//const btScalar m_wheelsDampingRelaxation;//const btScalar m_frictionSlip; btScalar m_steering; btScalar m_rotation; btScalar m_deltaRotation; btScalar m_rollInfluence; btScalar m_maxSuspensionForce; btScalar m_engineForce; btScalar m_brake; bool m_bIsFrontWheel; void* m_clientInfo;//can be used to store pointer to sync transforms... btWheelInfo(btWheelInfoConstructionInfo& ci) { m_suspensionRestLength1 = ci.m_suspensionRestLength; m_maxSuspensionTravelCm = ci.m_maxSuspensionTravelCm; m_wheelsRadius = ci.m_wheelRadius; m_suspensionStiffness = ci.m_suspensionStiffness; m_wheelsDampingCompression = ci.m_wheelsDampingCompression; m_wheelsDampingRelaxation = ci.m_wheelsDampingRelaxation; m_chassisConnectionPointCS = ci.m_chassisConnectionCS; m_wheelDirectionCS = ci.m_wheelDirectionCS; m_wheelAxleCS = ci.m_wheelAxleCS; m_frictionSlip = ci.m_frictionSlip; m_steering = btScalar(0.); m_engineForce = btScalar(0.); m_rotation = btScalar(0.); m_deltaRotation = btScalar(0.); m_brake = btScalar(0.); m_rollInfluence = btScalar(0.1); m_bIsFrontWheel = ci.m_bIsFrontWheel; m_maxSuspensionForce = ci.m_maxSuspensionForce; } void updateWheel(const btRigidBody& chassis,RaycastInfo& raycastInfo); btScalar m_clippedInvContactDotSuspension; btScalar m_suspensionRelativeVelocity; //calculated by suspension btScalar m_wheelsSuspensionForce; btScalar m_skidInfo; }; #endif //WHEEL_INFO_H critterding-beta12.1/src/utils/bullet/BulletDynamics/CMakeLists.txt0000644000175000017500000000734211337071441024441 0ustar bobkebobkeINCLUDE_DIRECTORIES( ${BULLET_PHYSICS_SOURCE_DIR}/src } ) SET(BulletDynamics_SRCS Character/btKinematicCharacterController.cpp ConstraintSolver/btConeTwistConstraint.cpp ConstraintSolver/btContactConstraint.cpp ConstraintSolver/btGeneric6DofConstraint.cpp ConstraintSolver/btGeneric6DofSpringConstraint.cpp ConstraintSolver/btHinge2Constraint.cpp ConstraintSolver/btHingeConstraint.cpp ConstraintSolver/btPoint2PointConstraint.cpp ConstraintSolver/btSequentialImpulseConstraintSolver.cpp ConstraintSolver/btSliderConstraint.cpp ConstraintSolver/btSolve2LinearConstraint.cpp ConstraintSolver/btTypedConstraint.cpp ConstraintSolver/btUniversalConstraint.cpp Dynamics/btContinuousDynamicsWorld.cpp Dynamics/btDiscreteDynamicsWorld.cpp Dynamics/btRigidBody.cpp Dynamics/btSimpleDynamicsWorld.cpp Dynamics/Bullet-C-API.cpp Vehicle/btRaycastVehicle.cpp Vehicle/btWheelInfo.cpp ) SET(Root_HDRS ../btBulletDynamicsCommon.h ../btBulletCollisionCommon.h ) SET(ConstraintSolver_HDRS ConstraintSolver/btConeTwistConstraint.h ConstraintSolver/btConstraintSolver.h ConstraintSolver/btContactConstraint.h ConstraintSolver/btContactSolverInfo.h ConstraintSolver/btGeneric6DofConstraint.h ConstraintSolver/btGeneric6DofSpringConstraint.h ConstraintSolver/btHinge2Constraint.h ConstraintSolver/btHingeConstraint.h ConstraintSolver/btJacobianEntry.h ConstraintSolver/btPoint2PointConstraint.h ConstraintSolver/btSequentialImpulseConstraintSolver.h ConstraintSolver/btSliderConstraint.h ConstraintSolver/btSolve2LinearConstraint.h ConstraintSolver/btSolverBody.h ConstraintSolver/btSolverConstraint.h ConstraintSolver/btTypedConstraint.h ConstraintSolver/btUniversalConstraint.h ) SET(Dynamics_HDRS Dynamics/btActionInterface.h Dynamics/btContinuousDynamicsWorld.h Dynamics/btDiscreteDynamicsWorld.h Dynamics/btDynamicsWorld.h Dynamics/btSimpleDynamicsWorld.h Dynamics/btRigidBody.h ) SET(Vehicle_HDRS Vehicle/btRaycastVehicle.h Vehicle/btVehicleRaycaster.h Vehicle/btWheelInfo.h ) SET(Character_HDRS Character/btCharacterControllerInterface.h Character/btKinematicCharacterController.h ) SET(BulletDynamics_HDRS ${Root_HDRS} ${ConstraintSolver_HDRS} ${Dynamics_HDRS} ${Vehicle_HDRS} ${Character_HDRS} ) ADD_LIBRARY(BulletDynamics ${BulletDynamics_SRCS} ${BulletDynamics_HDRS}) SET_TARGET_PROPERTIES(BulletDynamics PROPERTIES VERSION ${BULLET_VERSION}) SET_TARGET_PROPERTIES(BulletDynamics PROPERTIES SOVERSION ${BULLET_VERSION}) IF (BUILD_SHARED_LIBS) TARGET_LINK_LIBRARIES(BulletDynamics BulletCollision LinearMath) ENDIF (BUILD_SHARED_LIBS) IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) INSTALL(TARGETS BulletDynamics DESTINATION .) ELSE (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) INSTALL(TARGETS BulletDynamics DESTINATION lib) INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DESTINATION include FILES_MATCHING PATTERN "*.h") INSTALL(FILES ../btBulletDynamicsCommon.h DESTINATION include/BulletDynamics) ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) SET_TARGET_PROPERTIES(BulletDynamics PROPERTIES FRAMEWORK true) SET_TARGET_PROPERTIES(BulletDynamics PROPERTIES PUBLIC_HEADER "${Root_HDRS}") # Have to list out sub-directories manually: SET_PROPERTY(SOURCE ${ConstraintSolver_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/ConstraintSolver) SET_PROPERTY(SOURCE ${Dynamics_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/Dynamics) SET_PROPERTY(SOURCE ${Vehicle_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/Vehicle) SET_PROPERTY(SOURCE ${Character_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/Character) ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) critterding-beta12.1/src/utils/bullet/btBulletCollisionCommon.h0000644000175000017500000000647111344267705023747 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BULLET_COLLISION_COMMON_H #define BULLET_COLLISION_COMMON_H ///Common headerfile includes for Bullet Collision Detection ///Bullet's btCollisionWorld and btCollisionObject definitions #include "BulletCollision/CollisionDispatch/btCollisionWorld.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" ///Collision Shapes #include "BulletCollision/CollisionShapes/btBoxShape.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" #include "BulletCollision/CollisionShapes/btCapsuleShape.h" #include "BulletCollision/CollisionShapes/btCylinderShape.h" #include "BulletCollision/CollisionShapes/btConeShape.h" #include "BulletCollision/CollisionShapes/btStaticPlaneShape.h" #include "BulletCollision/CollisionShapes/btConvexHullShape.h" #include "BulletCollision/CollisionShapes/btTriangleMesh.h" #include "BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h" #include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" #include "BulletCollision/CollisionShapes/btTriangleMeshShape.h" #include "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h" #include "BulletCollision/CollisionShapes/btCompoundShape.h" #include "BulletCollision/CollisionShapes/btTetrahedronShape.h" #include "BulletCollision/CollisionShapes/btEmptyShape.h" #include "BulletCollision/CollisionShapes/btMultiSphereShape.h" #include "BulletCollision/CollisionShapes/btUniformScalingShape.h" ///Narrowphase Collision Detector #include "BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h" //btSphereBoxCollisionAlgorithm is broken, use gjk for now //#include "BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h" ///Dispatching and generation of collision pairs (broadphase) #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h" #include "BulletCollision/BroadphaseCollision/btAxisSweep3.h" #include "BulletCollision/BroadphaseCollision/btMultiSapBroadphase.h" #include "BulletCollision/BroadphaseCollision/btDbvtBroadphase.h" ///Math library & Utils #include "LinearMath/btQuaternion.h" #include "LinearMath/btTransform.h" #include "LinearMath/btDefaultMotionState.h" #include "LinearMath/btQuickprof.h" #include "LinearMath/btIDebugDraw.h" #include "LinearMath/btSerializer.h" #endif //BULLET_COLLISION_COMMON_H critterding-beta12.1/src/utils/bullet/Bullet-C-Api.h0000644000175000017500000001606411337071441021252 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ /* Draft high-level generic physics C-API. For low-level access, use the physics SDK native API's. Work in progress, functionality will be added on demand. If possible, use the richer Bullet C++ API, by including "btBulletDynamicsCommon.h" */ #ifndef BULLET_C_API_H #define BULLET_C_API_H #define PL_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name #ifdef BT_USE_DOUBLE_PRECISION typedef double plReal; #else typedef float plReal; #endif typedef plReal plVector3[3]; typedef plReal plQuaternion[4]; #ifdef __cplusplus extern "C" { #endif /** Particular physics SDK (C-API) */ PL_DECLARE_HANDLE(plPhysicsSdkHandle); /** Dynamics world, belonging to some physics SDK (C-API)*/ PL_DECLARE_HANDLE(plDynamicsWorldHandle); /** Rigid Body that can be part of a Dynamics World (C-API)*/ PL_DECLARE_HANDLE(plRigidBodyHandle); /** Collision Shape/Geometry, property of a Rigid Body (C-API)*/ PL_DECLARE_HANDLE(plCollisionShapeHandle); /** Constraint for Rigid Bodies (C-API)*/ PL_DECLARE_HANDLE(plConstraintHandle); /** Triangle Mesh interface (C-API)*/ PL_DECLARE_HANDLE(plMeshInterfaceHandle); /** Broadphase Scene/Proxy Handles (C-API)*/ PL_DECLARE_HANDLE(plCollisionBroadphaseHandle); PL_DECLARE_HANDLE(plBroadphaseProxyHandle); PL_DECLARE_HANDLE(plCollisionWorldHandle); /** Create and Delete a Physics SDK */ extern plPhysicsSdkHandle plNewBulletSdk(); //this could be also another sdk, like ODE, PhysX etc. extern void plDeletePhysicsSdk(plPhysicsSdkHandle physicsSdk); /** Collision World, not strictly necessary, you can also just create a Dynamics World with Rigid Bodies which internally manages the Collision World with Collision Objects */ typedef void(*btBroadphaseCallback)(void* clientData, void* object1,void* object2); extern plCollisionBroadphaseHandle plCreateSapBroadphase(btBroadphaseCallback beginCallback,btBroadphaseCallback endCallback); extern void plDestroyBroadphase(plCollisionBroadphaseHandle bp); extern plBroadphaseProxyHandle plCreateProxy(plCollisionBroadphaseHandle bp, void* clientData, plReal minX,plReal minY,plReal minZ, plReal maxX,plReal maxY, plReal maxZ); extern void plDestroyProxy(plCollisionBroadphaseHandle bp, plBroadphaseProxyHandle proxyHandle); extern void plSetBoundingBox(plBroadphaseProxyHandle proxyHandle, plReal minX,plReal minY,plReal minZ, plReal maxX,plReal maxY, plReal maxZ); /* todo: add pair cache support with queries like add/remove/find pair */ extern plCollisionWorldHandle plCreateCollisionWorld(plPhysicsSdkHandle physicsSdk); /* todo: add/remove objects */ /* Dynamics World */ extern plDynamicsWorldHandle plCreateDynamicsWorld(plPhysicsSdkHandle physicsSdk); extern void plDeleteDynamicsWorld(plDynamicsWorldHandle world); extern void plStepSimulation(plDynamicsWorldHandle, plReal timeStep); extern void plAddRigidBody(plDynamicsWorldHandle world, plRigidBodyHandle object); extern void plRemoveRigidBody(plDynamicsWorldHandle world, plRigidBodyHandle object); /* Rigid Body */ extern plRigidBodyHandle plCreateRigidBody( void* user_data, float mass, plCollisionShapeHandle cshape ); extern void plDeleteRigidBody(plRigidBodyHandle body); /* Collision Shape definition */ extern plCollisionShapeHandle plNewSphereShape(plReal radius); extern plCollisionShapeHandle plNewBoxShape(plReal x, plReal y, plReal z); extern plCollisionShapeHandle plNewCapsuleShape(plReal radius, plReal height); extern plCollisionShapeHandle plNewConeShape(plReal radius, plReal height); extern plCollisionShapeHandle plNewCylinderShape(plReal radius, plReal height); extern plCollisionShapeHandle plNewCompoundShape(); extern void plAddChildShape(plCollisionShapeHandle compoundShape,plCollisionShapeHandle childShape, plVector3 childPos,plQuaternion childOrn); extern void plDeleteShape(plCollisionShapeHandle shape); /* Convex Meshes */ extern plCollisionShapeHandle plNewConvexHullShape(); extern void plAddVertex(plCollisionShapeHandle convexHull, plReal x,plReal y,plReal z); /* Concave static triangle meshes */ extern plMeshInterfaceHandle plNewMeshInterface(); extern void plAddTriangle(plMeshInterfaceHandle meshHandle, plVector3 v0,plVector3 v1,plVector3 v2); extern plCollisionShapeHandle plNewStaticTriangleMeshShape(plMeshInterfaceHandle); extern void plSetScaling(plCollisionShapeHandle shape, plVector3 scaling); /* SOLID has Response Callback/Table/Management */ /* PhysX has Triggers, User Callbacks and filtering */ /* ODE has the typedef void dNearCallback (void *data, dGeomID o1, dGeomID o2); */ /* typedef void plUpdatedPositionCallback(void* userData, plRigidBodyHandle rbHandle, plVector3 pos); */ /* typedef void plUpdatedOrientationCallback(void* userData, plRigidBodyHandle rbHandle, plQuaternion orientation); */ /* get world transform */ extern void plGetOpenGLMatrix(plRigidBodyHandle object, plReal* matrix); extern void plGetPosition(plRigidBodyHandle object,plVector3 position); extern void plGetOrientation(plRigidBodyHandle object,plQuaternion orientation); /* set world transform (position/orientation) */ extern void plSetPosition(plRigidBodyHandle object, const plVector3 position); extern void plSetOrientation(plRigidBodyHandle object, const plQuaternion orientation); extern void plSetEuler(plReal yaw,plReal pitch,plReal roll, plQuaternion orient); extern void plSetOpenGLMatrix(plRigidBodyHandle object, plReal* matrix); typedef struct plRayCastResult { plRigidBodyHandle m_body; plCollisionShapeHandle m_shape; plVector3 m_positionWorld; plVector3 m_normalWorld; } plRayCastResult; extern int plRayCast(plDynamicsWorldHandle world, const plVector3 rayStart, const plVector3 rayEnd, plRayCastResult res); /* Sweep API */ /* extern plRigidBodyHandle plObjectCast(plDynamicsWorldHandle world, const plVector3 rayStart, const plVector3 rayEnd, plVector3 hitpoint, plVector3 normal); */ /* Continuous Collision Detection API */ // needed for source/blender/blenkernel/intern/collision.c double plNearestPoints(float p1[3], float p2[3], float p3[3], float q1[3], float q2[3], float q3[3], float *pa, float *pb, float normal[3]); #ifdef __cplusplus } #endif #endif //BULLET_C_API_H critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/0000755000175000017500000000000011347266042022663 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuSampleTask/0000755000175000017500000000000011347266042025417 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuSampleTask/SpuSampleTask.cpp0000644000175000017500000001374311337073000030654 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library, Copyright (c) 2007 Erwin Coumans 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 "SpuSampleTask.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "../PlatformDefinitions.h" #include "../SpuFakeDma.h" #include "LinearMath/btMinMax.h" #ifdef __SPU__ #include #else #include #define spu_printf printf #endif #define MAX_NUM_BODIES 8192 struct SampleTask_LocalStoreMemory { ATTRIBUTE_ALIGNED16(char gLocalRigidBody [sizeof(btRigidBody)+16]); ATTRIBUTE_ALIGNED16(void* gPointerArray[MAX_NUM_BODIES]); }; //-- MAIN METHOD void processSampleTask(void* userPtr, void* lsMemory) { // BT_PROFILE("processSampleTask"); SampleTask_LocalStoreMemory* localMemory = (SampleTask_LocalStoreMemory*)lsMemory; SpuSampleTaskDesc* taskDescPtr = (SpuSampleTaskDesc*)userPtr; SpuSampleTaskDesc& taskDesc = *taskDescPtr; switch (taskDesc.m_sampleCommand) { case CMD_SAMPLE_INTEGRATE_BODIES: { btTransform predictedTrans; btCollisionObject** eaPtr = (btCollisionObject**)taskDesc.m_mainMemoryPtr; int batchSize = taskDesc.m_sampleValue; if (batchSize>MAX_NUM_BODIES) { spu_printf("SPU Error: exceed number of bodies, see MAX_NUM_BODIES in SpuSampleTask.cpp\n"); break; } int dmaArraySize = batchSize*sizeof(void*); uint64_t ppuArrayAddress = reinterpret_cast(eaPtr); // spu_printf("array location is at %llx, batchSize = %d, DMA size = %d\n",ppuArrayAddress,batchSize,dmaArraySize); if (dmaArraySize>=16) { cellDmaLargeGet((void*)&localMemory->gPointerArray[0], ppuArrayAddress , dmaArraySize, DMA_TAG(1), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(1)); } else { stallingUnalignedDmaSmallGet((void*)&localMemory->gPointerArray[0], ppuArrayAddress , dmaArraySize); } for ( int i=0;igLocalRigidBody[0]; void* shortAdd = localMemory->gPointerArray[i]; uint64_t ppuRigidBodyAddress = reinterpret_cast(shortAdd); // spu_printf("cellDmaGet at CMD_SAMPLE_INTEGRATE_BODIES from %llx to %llx\n",ppuRigidBodyAddress,localPtr); int dmaBodySize = sizeof(btRigidBody); cellDmaGet((void*)localPtr, ppuRigidBodyAddress , dmaBodySize, DMA_TAG(1), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(1)); float timeStep = 1.f/60.f; btRigidBody* body = (btRigidBody*) localPtr;//btRigidBody::upcast(colObj); if (body) { if (body->isActive() && (!body->isStaticOrKinematicObject())) { body->predictIntegratedTransform(timeStep, predictedTrans); body->proceedToTransform( predictedTrans); void* ptr = (void*)localPtr; // spu_printf("cellDmaLargePut from %llx to LS %llx\n",ptr,ppuRigidBodyAddress); cellDmaLargePut(ptr, ppuRigidBodyAddress , dmaBodySize, DMA_TAG(1), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(1)); } } } break; } case CMD_SAMPLE_PREDICT_MOTION_BODIES: { btTransform predictedTrans; btCollisionObject** eaPtr = (btCollisionObject**)taskDesc.m_mainMemoryPtr; int batchSize = taskDesc.m_sampleValue; int dmaArraySize = batchSize*sizeof(void*); if (batchSize>MAX_NUM_BODIES) { spu_printf("SPU Error: exceed number of bodies, see MAX_NUM_BODIES in SpuSampleTask.cpp\n"); break; } uint64_t ppuArrayAddress = reinterpret_cast(eaPtr); // spu_printf("array location is at %llx, batchSize = %d, DMA size = %d\n",ppuArrayAddress,batchSize,dmaArraySize); if (dmaArraySize>=16) { cellDmaLargeGet((void*)&localMemory->gPointerArray[0], ppuArrayAddress , dmaArraySize, DMA_TAG(1), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(1)); } else { stallingUnalignedDmaSmallGet((void*)&localMemory->gPointerArray[0], ppuArrayAddress , dmaArraySize); } for ( int i=0;igLocalRigidBody[0]; void* shortAdd = localMemory->gPointerArray[i]; uint64_t ppuRigidBodyAddress = reinterpret_cast(shortAdd); // spu_printf("cellDmaGet at CMD_SAMPLE_INTEGRATE_BODIES from %llx to %llx\n",ppuRigidBodyAddress,localPtr); int dmaBodySize = sizeof(btRigidBody); cellDmaGet((void*)localPtr, ppuRigidBodyAddress , dmaBodySize, DMA_TAG(1), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(1)); float timeStep = 1.f/60.f; btRigidBody* body = (btRigidBody*) localPtr;//btRigidBody::upcast(colObj); if (body) { if (!body->isStaticOrKinematicObject()) { if (body->isActive()) { body->integrateVelocities( timeStep); //damping body->applyDamping(timeStep); body->predictIntegratedTransform(timeStep,body->getInterpolationWorldTransform()); void* ptr = (void*)localPtr; cellDmaLargePut(ptr, ppuRigidBodyAddress , dmaBodySize, DMA_TAG(1), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(1)); } } } } break; } default: { } }; } #if defined(__CELLOS_LV2__) || defined (LIBSPE2) ATTRIBUTE_ALIGNED16(SampleTask_LocalStoreMemory gLocalStoreMemory); void* createSampleLocalStoreMemory() { return &gLocalStoreMemory; } #else void* createSampleLocalStoreMemory() { return new SampleTask_LocalStoreMemory; }; #endif critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuSampleTask/readme.txt0000644000175000017500000000005611337073000027403 0ustar bobkebobkeEmpty placeholder for future Libspe2 SPU task critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuSampleTask/SpuSampleTask.h0000644000175000017500000000301411337073000030307 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library, Copyright (c) 2007 Erwin Coumans 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 SPU_SAMPLE_TASK_H #define SPU_SAMPLE_TASK_H #include "../PlatformDefinitions.h" #include "LinearMath/btScalar.h" #include "LinearMath/btVector3.h" #include "LinearMath/btMatrix3x3.h" #include "LinearMath/btAlignedAllocator.h" enum { CMD_SAMPLE_INTEGRATE_BODIES = 1, CMD_SAMPLE_PREDICT_MOTION_BODIES }; ATTRIBUTE_ALIGNED16(struct) SpuSampleTaskDesc { BT_DECLARE_ALIGNED_ALLOCATOR(); uint32_t m_sampleCommand; uint32_t m_taskId; uint64_t m_mainMemoryPtr; int m_sampleValue; }; void processSampleTask(void* userPtr, void* lsMemory); void* createSampleLocalStoreMemory(); #endif //SPU_SAMPLE_TASK_H critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/btGpuDefines.h0000644000175000017500000001257011337073000025405 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org Copyright (C) 2006, 2009 Sony Computer Entertainment Inc. 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. */ // definitions for "GPU on CPU" code #ifndef BT_GPU_DEFINES_H #define BT_GPU_DEFINES_H typedef unsigned int uint; struct int2 { int x, y; }; struct uint2 { unsigned int x, y; }; struct int3 { int x, y, z; }; struct uint3 { unsigned int x, y, z; }; struct float4 { float x, y, z, w; }; struct float3 { float x, y, z; }; #define BT_GPU___device__ inline #define BT_GPU___devdata__ #define BT_GPU___constant__ #define BT_GPU_max(a, b) ((a) > (b) ? (a) : (b)) #define BT_GPU_min(a, b) ((a) < (b) ? (a) : (b)) #define BT_GPU_params s3DGridBroadphaseParams #define BT_GPU___mul24(a, b) ((a)*(b)) #define BT_GPU___global__ inline #define BT_GPU___shared__ static #define BT_GPU___syncthreads() #define CUDART_PI_F SIMD_PI static inline uint2 bt3dGrid_make_uint2(unsigned int x, unsigned int y) { uint2 t; t.x = x; t.y = y; return t; } #define BT_GPU_make_uint2(x, y) bt3dGrid_make_uint2(x, y) static inline int3 bt3dGrid_make_int3(int x, int y, int z) { int3 t; t.x = x; t.y = y; t.z = z; return t; } #define BT_GPU_make_int3(x, y, z) bt3dGrid_make_int3(x, y, z) static inline float3 bt3dGrid_make_float3(float x, float y, float z) { float3 t; t.x = x; t.y = y; t.z = z; return t; } #define BT_GPU_make_float3(x, y, z) bt3dGrid_make_float3(x, y, z) static inline float3 bt3dGrid_make_float34(float4 f) { float3 t; t.x = f.x; t.y = f.y; t.z = f.z; return t; } #define BT_GPU_make_float34(f) bt3dGrid_make_float34(f) static inline float3 bt3dGrid_make_float31(float f) { float3 t; t.x = t.y = t.z = f; return t; } #define BT_GPU_make_float31(x) bt3dGrid_make_float31(x) static inline float4 bt3dGrid_make_float42(float3 v, float f) { float4 t; t.x = v.x; t.y = v.y; t.z = v.z; t.w = f; return t; } #define BT_GPU_make_float42(a, b) bt3dGrid_make_float42(a, b) static inline float4 bt3dGrid_make_float44(float a, float b, float c, float d) { float4 t; t.x = a; t.y = b; t.z = c; t.w = d; return t; } #define BT_GPU_make_float44(a, b, c, d) bt3dGrid_make_float44(a, b, c, d) inline int3 operator+(int3 a, int3 b) { return bt3dGrid_make_int3(a.x + b.x, a.y + b.y, a.z + b.z); } inline float4 operator+(const float4& a, const float4& b) { float4 r; r.x = a.x+b.x; r.y = a.y+b.y; r.z = a.z+b.z; r.w = a.w+b.w; return r; } inline float4 operator*(const float4& a, float fact) { float4 r; r.x = a.x*fact; r.y = a.y*fact; r.z = a.z*fact; r.w = a.w*fact; return r; } inline float4 operator*(float fact, float4& a) { return (a * fact); } inline float4& operator*=(float4& a, float fact) { a = fact * a; return a; } inline float4& operator+=(float4& a, const float4& b) { a = a + b; return a; } inline float3 operator+(const float3& a, const float3& b) { float3 r; r.x = a.x+b.x; r.y = a.y+b.y; r.z = a.z+b.z; return r; } inline float3 operator-(const float3& a, const float3& b) { float3 r; r.x = a.x-b.x; r.y = a.y-b.y; r.z = a.z-b.z; return r; } static inline float bt3dGrid_dot(float3& a, float3& b) { return a.x*b.x+a.y*b.y+a.z*b.z; } #define BT_GPU_dot(a,b) bt3dGrid_dot(a,b) static inline float bt3dGrid_dot4(float4& a, float4& b) { return a.x*b.x+a.y*b.y+a.z*b.z+a.w*b.w; } #define BT_GPU_dot4(a,b) bt3dGrid_dot4(a,b) static inline float3 bt3dGrid_cross(const float3& a, const float3& b) { float3 r; r.x = a.y*b.z-a.z*b.y; r.y = -a.x*b.z+a.z*b.x; r.z = a.x*b.y-a.y*b.x; return r; } #define BT_GPU_cross(a,b) bt3dGrid_cross(a,b) inline float3 operator*(const float3& a, float fact) { float3 r; r.x = a.x*fact; r.y = a.y*fact; r.z = a.z*fact; return r; } inline float3& operator+=(float3& a, const float3& b) { a = a + b; return a; } inline float3& operator-=(float3& a, const float3& b) { a = a - b; return a; } inline float3& operator*=(float3& a, float fact) { a = a * fact; return a; } inline float3 operator-(const float3& v) { float3 r; r.x = -v.x; r.y = -v.y; r.z = -v.z; return r; } #define BT_GPU_FETCH(a, b) a[b] #define BT_GPU_FETCH4(a, b) a[b] #define BT_GPU_PREF(func) btGpu_##func #define BT_GPU_SAFE_CALL(func) func #define BT_GPU_Memset memset #define BT_GPU_MemcpyToSymbol(a, b, c) memcpy(a, b, c) #define BT_GPU_BindTexture(a, b, c, d) #define BT_GPU_UnbindTexture(a) static uint2 s_blockIdx, s_blockDim, s_threadIdx; #define BT_GPU_blockIdx s_blockIdx #define BT_GPU_blockDim s_blockDim #define BT_GPU_threadIdx s_threadIdx #define BT_GPU_EXECKERNEL(numb, numt, kfunc, args) {s_blockDim.x=numt;for(int nb=0;nb m_activeSpuStatus; btAlignedObjectArray m_completeHandles; public: struct SequentialThreadConstructionInfo { SequentialThreadConstructionInfo (char* uniqueName, SequentialThreadFunc userThreadFunc, SequentiallsMemorySetupFunc lsMemoryFunc ) :m_uniqueName(uniqueName), m_userThreadFunc(userThreadFunc), m_lsMemoryFunc(lsMemoryFunc) { } char* m_uniqueName; SequentialThreadFunc m_userThreadFunc; SequentiallsMemorySetupFunc m_lsMemoryFunc; }; SequentialThreadSupport(SequentialThreadConstructionInfo& threadConstructionInfo); virtual ~SequentialThreadSupport(); void startThreads(SequentialThreadConstructionInfo& threadInfo); ///send messages to SPUs virtual void sendRequest(uint32_t uiCommand, ppu_address_t uiArgument0, uint32_t uiArgument1); ///check for messages from SPUs virtual void waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1); ///start the spus (can be called at the beginning of each frame, to make sure that the right SPU program is loaded) virtual void startSPU(); ///tell the task scheduler we are done with the SPU tasks virtual void stopSPU(); virtual void setNumTasks(int numTasks); virtual int getNumTasks() const { return 1; } }; #endif //SEQUENTIAL_THREAD_SUPPORT_H critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/Makefile.original0000644000175000017500000001746011337073000026123 0ustar bobkebobke__ARCH_BITS__ := 32 # define macros NARROWPHASEDIR=./SpuNarrowPhaseCollisionTask SPU_TASKFILE=$(NARROWPHASEDIR)/SpuGatheringCollisionTask IBM_CELLSDK_VERSION := $(shell if [ -d /opt/cell ]; then echo "3.0"; fi) ifeq ("$(IBM_CELLSDK_VERSION)","3.0") CELL_TOP ?= /opt/cell/sdk CELL_SYSROOT := /opt/cell/sysroot else CELL_TOP ?= /opt/ibm/cell-sdk/prototype CELL_SYSROOT := $(CELL_TOP)/sysroot endif USE_CCACHE=ccache RM=rm -f OUTDIR=./out DEBUGFLAG=-DNDEBUG LIBOUTDIR=../../lib/ibmsdk COLLISIONDIR=../../src/BulletCollision MATHDIR=../../src/LinearMath ARCHITECTUREFLAG=-m$(__ARCH_BITS__) ifeq "$(__ARCH_BITS__)" "64" SPU_DEFFLAGS= -DUSE_LIBSPE2 -D__SPU__ -DUSE_ADDR64 else SPU_DEFFLAGS= -DUSE_LIBSPE2 -D__SPU__ endif SPU_DEFFLAGS+=-DUSE_PE_BOX_BOX SPU_GCC=$(USE_CCACHE) /usr/bin/spu-gcc SPU_INCLUDEDIR= -Ivectormath/scalar/cpp -I. -I$(CELL_SYSROOT)/usr/spu/include -I../../src -I$(NARROWPHASEDIR) #SPU_CFLAGS= $(DEBUGFLAG) -W -Wall -Winline -Os -c -include spu_intrinsics.h -include stdbool.h SPU_CFLAGS= $(DEBUGFLAG) -W -Wall -Winline -O3 -mbranch-hints -fomit-frame-pointer -ftree-vectorize -finline-functions -ftree-vect-loop-version -ftree-loop-optimize -ffast-math -fno-rtti -fno-exceptions -c -include spu_intrinsics.h -include stdbool.h SPU_LFLAGS= -Wl,-N SPU_LIBRARIES=-lstdc++ SPU_EMBED=/usr/bin/ppu-embedspu SPU_AR=/usr/bin/ar SYMBOLNAME=spu_program ifeq "$(__ARCH_BITS__)" "64" PPU_DEFFLAGS= -DUSE_LIBSPE2 -DUSE_ADDR64 PPU_GCC=$(USE_CCACHE) /usr/bin/ppu-gcc else PPU_DEFFLAGS= -DUSE_LIBSPE2 PPU_GCC=$(USE_CCACHE) /usr/bin/ppu32-gcc endif PPU_CFLAGS= $(ARCHITECTUREFLAG) $(DEBUGFLAG) -W -Wall -Winline -O3 -c -mabi=altivec -maltivec -include altivec.h -include stdbool.h PPU_INCLUDEDIR= -I. -I$(CELL_SYSROOT)/usr/include -I../../src -I$(NARROWPHASEDIR) PPU_LFLAGS= $(ARCHITECTUREFLAG) -Wl,-m,elf$(__ARCH_BITS__)ppc PPU_LIBRARIES= -lstdc++ -lsupc++ -lgcc -lgcov -lspe2 -lpthread -L../../lib/ibmsdk -lbulletcollision -lbulletdynamics -lbulletmath -L$(CELL_SYSROOT)/usr/lib$(__ARCH_BITS__) -R$(CELL_SYSROOT)/usr/lib PPU_AR=/usr/bin/ar MakeOut : # rm -f -R $(OUTDIR) ; mkdir $(OUTDIR) @echo "usage: make spu, make ppu, make all, or make clean" # SPU SpuTaskFile : MakeOut $(SPU_GCC) $(SPU_DEFFLAGS) $(SPU_CFLAGS) $(SPU_INCLUDEDIR) -o $(OUTDIR)/SpuTaskFile.o $(SPU_TASKFILE).cpp boxBoxDistance : MakeOut $(SPU_GCC) $(SPU_DEFFLAGS) $(SPU_CFLAGS) $(SPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $(NARROWPHASEDIR)/$@.cpp SpuFakeDma : MakeOut $(SPU_GCC) $(SPU_DEFFLAGS) $(SPU_CFLAGS) $(SPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $@.cpp SpuContactManifoldCollisionAlgorithm_spu : MakeOut $(SPU_GCC) $(SPU_DEFFLAGS) $(SPU_CFLAGS) $(SPU_INCLUDEDIR) -o $(OUTDIR)/$@.o SpuContactManifoldCollisionAlgorithm.cpp SpuCollisionShapes : MakeOut $(SPU_GCC) $(SPU_DEFFLAGS) $(SPU_CFLAGS) $(SPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $(NARROWPHASEDIR)/$@.cpp SpuContactResult : MakeOut $(SPU_GCC) $(SPU_DEFFLAGS) $(SPU_CFLAGS) $(SPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $(NARROWPHASEDIR)/$@.cpp #SpuGatheringCollisionTask : MakeOut # $(SPU_GCC) $(SPU_DEFFLAGS) $(SPU_CFLAGS) $(SPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $(NARROWPHASEDIR)/$@.cpp SpuGjkPairDetector: MakeOut $(SPU_GCC) $(SPU_DEFFLAGS) $(SPU_CFLAGS) $(SPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $(NARROWPHASEDIR)/$@.cpp SpuMinkowskiPenetrationDepthSolver : MakeOut $(SPU_GCC) $(SPU_DEFFLAGS) $(SPU_CFLAGS) $(SPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $(NARROWPHASEDIR)/$@.cpp SpuVoronoiSimplexSolver : MakeOut $(SPU_GCC) $(SPU_DEFFLAGS) $(SPU_CFLAGS) $(SPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $(NARROWPHASEDIR)/$@.cpp #SpuLibspe2Support_spu : MakeOut # $(SPU_GCC) $(SPU_DEFFLAGS) $(SPU_CFLAGS) $(SPU_INCLUDEDIR) -o $(OUTDIR)/$@.o SpuLibspe2Support.cpp ## SPU-Bullet btPersistentManifold : MakeOut $(SPU_GCC) $(SPU_DEFFLAGS) $(SPU_CFLAGS) $(SPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $(COLLISIONDIR)/NarrowPhaseCollision/$@.cpp btOptimizedBvh : MakeOut $(SPU_GCC) $(SPU_DEFFLAGS) $(SPU_CFLAGS) $(SPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $(COLLISIONDIR)/CollisionShapes/$@.cpp btCollisionObject : MakeOut $(SPU_GCC) $(SPU_DEFFLAGS) $(SPU_CFLAGS) $(SPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $(COLLISIONDIR)/CollisionDispatch/$@.cpp btTriangleCallback : MakeOut $(SPU_GCC) $(SPU_DEFFLAGS) $(SPU_CFLAGS) $(SPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $(COLLISIONDIR)/CollisionShapes/$@.cpp btTriangleIndexVertexArray : MakeOut $(SPU_GCC) $(SPU_DEFFLAGS) $(SPU_CFLAGS) $(SPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $(COLLISIONDIR)/CollisionShapes/$@.cpp btStridingMeshInterface : MakeOut $(SPU_GCC) $(SPU_DEFFLAGS) $(SPU_CFLAGS) $(SPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $(COLLISIONDIR)/CollisionShapes/$@.cpp btAlignedAllocator : MakeOut $(SPU_GCC) $(SPU_DEFFLAGS) $(SPU_CFLAGS) $(SPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $(MATHDIR)/$@.cpp # PPU SpuGatheringCollisionDispatcher : MakeOut $(PPU_GCC) $(PPU_DEFFLAGS) $(PPU_CFLAGS) $(PPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $@.cpp SequentialThreadSupport: MakeOut $(PPU_GCC) $(PPU_DEFFLAGS) $(PPU_CFLAGS) $(PPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $@.cpp SpuLibspe2Support: MakeOut $(PPU_GCC) $(PPU_DEFFLAGS) $(PPU_CFLAGS) $(PPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $@.cpp btThreadSupportInterface: MakeOut $(PPU_GCC) $(PPU_DEFFLAGS) $(PPU_CFLAGS) $(PPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $@.cpp SpuCollisionTaskProcess : MakeOut $(PPU_GCC) $(PPU_DEFFLAGS) $(PPU_CFLAGS) $(PPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $@.cpp SpuContactManifoldCollisionAlgorithm : MakeOut $(PPU_GCC) $(PPU_DEFFLAGS) $(PPU_CFLAGS) $(PPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $@.cpp SpuSampleTaskProcess : MakeOut $(PPU_GCC) $(PPU_DEFFLAGS) $(PPU_CFLAGS) $(PPU_INCLUDEDIR) -o $(OUTDIR)/$@.o $@.cpp spu : boxBoxDistance SpuFakeDma SpuContactManifoldCollisionAlgorithm_spu SpuContactResult SpuTaskFile \ SpuGjkPairDetector SpuMinkowskiPenetrationDepthSolver SpuVoronoiSimplexSolver SpuCollisionShapes \ btPersistentManifold btOptimizedBvh btCollisionObject btTriangleCallback btTriangleIndexVertexArray \ btStridingMeshInterface btAlignedAllocator $(SPU_GCC) -o $(OUTDIR)/spuCollision.elf \ $(OUTDIR)/SpuTaskFile.o \ $(OUTDIR)/SpuFakeDma.o \ $(OUTDIR)/boxBoxDistance.o \ $(OUTDIR)/SpuContactManifoldCollisionAlgorithm_spu.o \ $(OUTDIR)/SpuContactResult.o \ $(OUTDIR)/SpuCollisionShapes.o \ $(OUTDIR)/SpuGjkPairDetector.o \ $(OUTDIR)/SpuMinkowskiPenetrationDepthSolver.o \ $(OUTDIR)/SpuVoronoiSimplexSolver.o \ $(OUTDIR)/btPersistentManifold.o \ $(OUTDIR)/btTriangleCallback.o \ $(OUTDIR)/btTriangleIndexVertexArray.o \ $(OUTDIR)/btStridingMeshInterface.o \ $(OUTDIR)/btAlignedAllocator.o \ $(SPU_LFLAGS) $(SPU_LIBRARIES) spu-embed : spu $(SPU_EMBED) $(ARCHITECTUREFLAG) $(SYMBOLNAME) $(OUTDIR)/spuCollision.elf $(OUTDIR)/$@.o $(SPU_AR) -qcs $(LIBOUTDIR)/libspu.a $(OUTDIR)/$@.o ppu : SpuGatheringCollisionDispatcher SpuCollisionTaskProcess btThreadSupportInterface \ SpuLibspe2Support SpuContactManifoldCollisionAlgorithm SpuSampleTaskProcess $(PPU_AR) -qcs $(LIBOUTDIR)/bulletmultithreaded.a \ $(OUTDIR)/SpuCollisionTaskProcess.o \ $(OUTDIR)/SpuSampleTaskProcess.o \ $(OUTDIR)/SpuGatheringCollisionDispatcher.o \ $(OUTDIR)/SpuLibspe2Support.o \ $(OUTDIR)/btThreadSupportInterface.o \ $(OUTDIR)/SpuContactManifoldCollisionAlgorithm.o all : spu-embed ppu clean: $(RM) $(OUTDIR)/* ; $(RM) $(LIBOUTDIR)/libspu.a ; $(RM) $(LIBOUTDIR)/bulletmultithreaded.a critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuGatheringCollisionDispatcher.cpp0000644000175000017500000001773111337073000031650 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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 "SpuGatheringCollisionDispatcher.h" #include "SpuCollisionTaskProcess.h" #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" #include "BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h" #include "SpuContactManifoldCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionShapes/btCollisionShape.h" #include "LinearMath/btQuickprof.h" SpuGatheringCollisionDispatcher::SpuGatheringCollisionDispatcher(class btThreadSupportInterface* threadInterface, unsigned int maxNumOutstandingTasks,btCollisionConfiguration* collisionConfiguration) :btCollisionDispatcher(collisionConfiguration), m_spuCollisionTaskProcess(0), m_threadInterface(threadInterface), m_maxNumOutstandingTasks(maxNumOutstandingTasks) { } bool SpuGatheringCollisionDispatcher::supportsDispatchPairOnSpu(int proxyType0,int proxyType1) { bool supported0 = ( (proxyType0 == BOX_SHAPE_PROXYTYPE) || (proxyType0 == TRIANGLE_SHAPE_PROXYTYPE) || (proxyType0 == SPHERE_SHAPE_PROXYTYPE) || (proxyType0 == CAPSULE_SHAPE_PROXYTYPE) || (proxyType0 == CYLINDER_SHAPE_PROXYTYPE) || // (proxyType0 == CONE_SHAPE_PROXYTYPE) || (proxyType0 == TRIANGLE_MESH_SHAPE_PROXYTYPE) || (proxyType0 == CONVEX_HULL_SHAPE_PROXYTYPE)|| (proxyType0 == COMPOUND_SHAPE_PROXYTYPE) ); bool supported1 = ( (proxyType1 == BOX_SHAPE_PROXYTYPE) || (proxyType1 == TRIANGLE_SHAPE_PROXYTYPE) || (proxyType1 == SPHERE_SHAPE_PROXYTYPE) || (proxyType1 == CAPSULE_SHAPE_PROXYTYPE) || (proxyType1 == CYLINDER_SHAPE_PROXYTYPE) || // (proxyType1 == CONE_SHAPE_PROXYTYPE) || (proxyType1 == TRIANGLE_MESH_SHAPE_PROXYTYPE) || (proxyType1 == CONVEX_HULL_SHAPE_PROXYTYPE) || (proxyType1 == COMPOUND_SHAPE_PROXYTYPE) ); return supported0 && supported1; } SpuGatheringCollisionDispatcher::~SpuGatheringCollisionDispatcher() { if (m_spuCollisionTaskProcess) delete m_spuCollisionTaskProcess; } #include "stdio.h" ///interface for iterating all overlapping collision pairs, no matter how those pairs are stored (array, set, map etc) ///this is useful for the collision dispatcher. class btSpuCollisionPairCallback : public btOverlapCallback { const btDispatcherInfo& m_dispatchInfo; SpuGatheringCollisionDispatcher* m_dispatcher; public: btSpuCollisionPairCallback(const btDispatcherInfo& dispatchInfo, SpuGatheringCollisionDispatcher* dispatcher) :m_dispatchInfo(dispatchInfo), m_dispatcher(dispatcher) { } virtual bool processOverlap(btBroadphasePair& collisionPair) { //PPU version //(*m_dispatcher->getNearCallback())(collisionPair,*m_dispatcher,m_dispatchInfo); //only support discrete collision detection for now, we could fallback on PPU/unoptimized version for TOI/CCD btAssert(m_dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE); //by default, Bullet will use this near callback { ///userInfo is used to determine if the SPU has to handle this case or not (skip PPU tasks) if (!collisionPair.m_internalTmpValue) { collisionPair.m_internalTmpValue = 1; } if (!collisionPair.m_algorithm) { btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject; btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject; btCollisionAlgorithmConstructionInfo ci; ci.m_dispatcher1 = m_dispatcher; ci.m_manifold = 0; if (m_dispatcher->needsCollision(colObj0,colObj1)) { int proxyType0 = colObj0->getCollisionShape()->getShapeType(); int proxyType1 = colObj1->getCollisionShape()->getShapeType(); if (m_dispatcher->supportsDispatchPairOnSpu(proxyType0,proxyType1)) { int so = sizeof(SpuContactManifoldCollisionAlgorithm); #ifdef ALLOCATE_SEPARATELY void* mem = btAlignedAlloc(so,16);//m_dispatcher->allocateCollisionAlgorithm(so); #else void* mem = m_dispatcher->allocateCollisionAlgorithm(so); #endif collisionPair.m_algorithm = new(mem) SpuContactManifoldCollisionAlgorithm(ci,colObj0,colObj1); collisionPair.m_internalTmpValue = 2; } else { collisionPair.m_algorithm = m_dispatcher->findAlgorithm(colObj0,colObj1); collisionPair.m_internalTmpValue = 3; } } } } return false; } }; void SpuGatheringCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo, btDispatcher* dispatcher) { if (dispatchInfo.m_enableSPU) { m_maxNumOutstandingTasks = m_threadInterface->getNumTasks(); { BT_PROFILE("processAllOverlappingPairs"); if (!m_spuCollisionTaskProcess) m_spuCollisionTaskProcess = new SpuCollisionTaskProcess(m_threadInterface,m_maxNumOutstandingTasks); m_spuCollisionTaskProcess->setNumTasks(m_maxNumOutstandingTasks); // printf("m_maxNumOutstandingTasks =%d\n",m_maxNumOutstandingTasks); m_spuCollisionTaskProcess->initialize2(dispatchInfo.m_useEpa); ///modified version of btCollisionDispatcher::dispatchAllCollisionPairs: { btSpuCollisionPairCallback collisionCallback(dispatchInfo,this); pairCache->processAllOverlappingPairs(&collisionCallback,dispatcher); } } //send one big batch int numTotalPairs = pairCache->getNumOverlappingPairs(); btBroadphasePair* pairPtr = pairCache->getOverlappingPairArrayPtr(); int i; { BT_PROFILE("addWorkToTask"); for (i=0;iaddWorkToTask(pairPtr,i,endIndex); i = endIndex; } } { BT_PROFILE("PPU fallback"); //handle PPU fallback pairs for (i=0;im_clientObject; btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject; if (dispatcher->needsCollision(colObj0,colObj1)) { btManifoldResult contactPointResult(colObj0,colObj1); if (dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE) { //discrete collision detection query collisionPair.m_algorithm->processCollision(colObj0,colObj1,dispatchInfo,&contactPointResult); } else { //continuous collision detection query, time of impact (toi) btScalar toi = collisionPair.m_algorithm->calculateTimeOfImpact(colObj0,colObj1,dispatchInfo,&contactPointResult); if (dispatchInfo.m_timeOfImpact > toi) dispatchInfo.m_timeOfImpact = toi; } } } } } } { BT_PROFILE("flush2"); //make sure all SPU work is done m_spuCollisionTaskProcess->flush2(); } } else { ///PPU fallback ///!Need to make sure to clear all 'algorithms' when switching between SPU and PPU btCollisionDispatcher::dispatchAllCollisionPairs(pairCache,dispatchInfo,dispatcher); } } critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuGatheringCollisionDispatcher.h0000644000175000017500000000512711337073000031311 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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 SPU_GATHERING_COLLISION__DISPATCHER_H #define SPU_GATHERING_COLLISION__DISPATCHER_H #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" ///Tuning value to optimized SPU utilization ///Too small value means Task overhead is large compared to computation (too fine granularity) ///Too big value might render some SPUs are idle, while a few other SPUs are doing all work. //#define SPU_BATCHSIZE_BROADPHASE_PAIRS 8 //#define SPU_BATCHSIZE_BROADPHASE_PAIRS 16 #define SPU_BATCHSIZE_BROADPHASE_PAIRS 64 //#define SPU_BATCHSIZE_BROADPHASE_PAIRS 128 //#define SPU_BATCHSIZE_BROADPHASE_PAIRS 256 //#define SPU_BATCHSIZE_BROADPHASE_PAIRS 1024 class SpuCollisionTaskProcess; ///SpuGatheringCollisionDispatcher can use SPU to gather and calculate collision detection ///Time of Impact, Closest Points and Penetration Depth. class SpuGatheringCollisionDispatcher : public btCollisionDispatcher { SpuCollisionTaskProcess* m_spuCollisionTaskProcess; protected: class btThreadSupportInterface* m_threadInterface; unsigned int m_maxNumOutstandingTasks; public: //can be used by SPU collision algorithms SpuCollisionTaskProcess* getSpuCollisionTaskProcess() { return m_spuCollisionTaskProcess; } SpuGatheringCollisionDispatcher (class btThreadSupportInterface* threadInterface, unsigned int maxNumOutstandingTasks,btCollisionConfiguration* collisionConfiguration); virtual ~SpuGatheringCollisionDispatcher(); bool supportsDispatchPairOnSpu(int proxyType0,int proxyType1); virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher) ; }; #endif //SPU_GATHERING_COLLISION__DISPATCHER_H critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/PosixThreadSupport.h0000644000175000017500000000705711337073000026661 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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 "LinearMath/btScalar.h" #include "PlatformDefinitions.h" #ifdef USE_PTHREADS //platform specific defines are defined in PlatformDefinitions.h #include #include #ifndef POSIX_THREAD_SUPPORT_H #define POSIX_THREAD_SUPPORT_H #include "LinearMath/btAlignedObjectArray.h" #include "btThreadSupportInterface.h" typedef void (*PosixThreadFunc)(void* userPtr,void* lsMemory); typedef void* (*PosixlsMemorySetupFunc)(); // PosixThreadSupport helps to initialize/shutdown libspe2, start/stop SPU tasks and communication class PosixThreadSupport : public btThreadSupportInterface { public: typedef enum sStatus { STATUS_BUSY, STATUS_READY, STATUS_FINISHED } Status; // placeholder, until libspe2 support is there struct btSpuStatus { uint32_t m_taskId; uint32_t m_commandId; uint32_t m_status; PosixThreadFunc m_userThreadFunc; void* m_userPtr; //for taskDesc etc void* m_lsMemory; //initialized using PosixLocalStoreMemorySetupFunc pthread_t thread; sem_t* startSemaphore; unsigned long threadUsed; }; private: btAlignedObjectArray m_activeSpuStatus; public: ///Setup and initialize SPU/CELL/Libspe2 struct ThreadConstructionInfo { ThreadConstructionInfo(char* uniqueName, PosixThreadFunc userThreadFunc, PosixlsMemorySetupFunc lsMemoryFunc, int numThreads=1, int threadStackSize=65535 ) :m_uniqueName(uniqueName), m_userThreadFunc(userThreadFunc), m_lsMemoryFunc(lsMemoryFunc), m_numThreads(numThreads), m_threadStackSize(threadStackSize) { } char* m_uniqueName; PosixThreadFunc m_userThreadFunc; PosixlsMemorySetupFunc m_lsMemoryFunc; int m_numThreads; int m_threadStackSize; }; PosixThreadSupport(ThreadConstructionInfo& threadConstructionInfo); ///cleanup/shutdown Libspe2 virtual ~PosixThreadSupport(); void startThreads(ThreadConstructionInfo& threadInfo); ///send messages to SPUs virtual void sendRequest(uint32_t uiCommand, ppu_address_t uiArgument0, uint32_t uiArgument1); ///check for messages from SPUs virtual void waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1); ///start the spus (can be called at the beginning of each frame, to make sure that the right SPU program is loaded) virtual void startSPU(); ///tell the task scheduler we are done with the SPU tasks virtual void stopSPU(); virtual void setNumTasks(int numTasks) {} virtual int getNumTasks() const { return m_activeSpuStatus.size(); } }; #endif // POSIX_THREAD_SUPPORT_H #endif // USE_PTHREADS critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuCollisionTaskProcess.cpp0000644000175000017500000001577011337073000030173 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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. */ //#define DEBUG_SPU_TASK_SCHEDULING 1 //class OptimizedBvhNode; #include "SpuCollisionTaskProcess.h" void SpuCollisionTaskProcess::setNumTasks(int maxNumTasks) { if (m_maxNumOutstandingTasks != maxNumTasks) { m_maxNumOutstandingTasks = maxNumTasks; m_taskBusy.resize(m_maxNumOutstandingTasks); m_spuGatherTaskDesc.resize(m_maxNumOutstandingTasks); for (int i = 0; i < m_taskBusy.size(); i++) { m_taskBusy[i] = false; } ///re-allocate task memory buffers if (m_workUnitTaskBuffers != 0) { btAlignedFree(m_workUnitTaskBuffers); } m_workUnitTaskBuffers = (unsigned char *)btAlignedAlloc(MIDPHASE_WORKUNIT_TASK_SIZE*m_maxNumOutstandingTasks, 128); m_workUnitTaskBuffers = (unsigned char *)btAlignedAlloc(MIDPHASE_WORKUNIT_TASK_SIZE*6, 128); } } SpuCollisionTaskProcess::SpuCollisionTaskProcess(class btThreadSupportInterface* threadInterface, unsigned int maxNumOutstandingTasks) :m_threadInterface(threadInterface), m_maxNumOutstandingTasks(0) { m_workUnitTaskBuffers = (unsigned char *)0; setNumTasks(maxNumOutstandingTasks); m_numBusyTasks = 0; m_currentTask = 0; m_currentPage = 0; m_currentPageEntry = 0; #ifdef DEBUG_SpuCollisionTaskProcess m_initialized = false; #endif m_threadInterface->startSPU(); //printf("sizeof vec_float4: %d\n", sizeof(vec_float4)); printf("sizeof SpuGatherAndProcessWorkUnitInput: %d\n", sizeof(SpuGatherAndProcessWorkUnitInput)); } SpuCollisionTaskProcess::~SpuCollisionTaskProcess() { if (m_workUnitTaskBuffers != 0) { btAlignedFree(m_workUnitTaskBuffers); m_workUnitTaskBuffers = 0; } m_threadInterface->stopSPU(); } void SpuCollisionTaskProcess::initialize2(bool useEpa) { #ifdef DEBUG_SPU_TASK_SCHEDULING printf("SpuCollisionTaskProcess::initialize()\n"); #endif //DEBUG_SPU_TASK_SCHEDULING for (int i = 0; i < int (m_maxNumOutstandingTasks); i++) { m_taskBusy[i] = false; } m_numBusyTasks = 0; m_currentTask = 0; m_currentPage = 0; m_currentPageEntry = 0; m_useEpa = useEpa; #ifdef DEBUG_SpuCollisionTaskProcess m_initialized = true; btAssert(MIDPHASE_NUM_WORKUNITS_PER_TASK*sizeof(SpuGatherAndProcessWorkUnitInput) <= MIDPHASE_WORKUNIT_TASK_SIZE); #endif } void SpuCollisionTaskProcess::issueTask2() { #ifdef DEBUG_SPU_TASK_SCHEDULING printf("SpuCollisionTaskProcess::issueTask (m_currentTask= %d\n)", m_currentTask); #endif //DEBUG_SPU_TASK_SCHEDULING m_taskBusy[m_currentTask] = true; m_numBusyTasks++; SpuGatherAndProcessPairsTaskDesc& taskDesc = m_spuGatherTaskDesc[m_currentTask]; taskDesc.m_useEpa = m_useEpa; { // send task description in event message // no error checking here... // but, currently, event queue can be no larger than NUM_WORKUNIT_TASKS. taskDesc.m_inPairPtr = reinterpret_cast(MIDPHASE_TASK_PTR(m_currentTask)); taskDesc.taskId = m_currentTask; taskDesc.numPages = m_currentPage+1; taskDesc.numOnLastPage = m_currentPageEntry; } m_threadInterface->sendRequest(CMD_GATHER_AND_PROCESS_PAIRLIST, (ppu_address_t) &taskDesc,m_currentTask); // if all tasks busy, wait for spu event to clear the task. if (m_numBusyTasks >= m_maxNumOutstandingTasks) { unsigned int taskId; unsigned int outputSize; for (int i=0;i=0); m_threadInterface->waitForResponse(&taskId, &outputSize); // printf("issueTask taskId %d completed, numBusy=%d\n",taskId,m_numBusyTasks); //printf("PPU: after issue, received event: %u %d\n", taskId, outputSize); //postProcess(taskId, outputSize); m_taskBusy[taskId] = false; m_numBusyTasks--; } } void SpuCollisionTaskProcess::addWorkToTask(void* pairArrayPtr,int startIndex,int endIndex) { #ifdef DEBUG_SPU_TASK_SCHEDULING printf("#"); #endif //DEBUG_SPU_TASK_SCHEDULING #ifdef DEBUG_SpuCollisionTaskProcess btAssert(m_initialized); btAssert(m_workUnitTaskBuffers); #endif bool batch = true; if (batch) { if (m_currentPageEntry == MIDPHASE_NUM_WORKUNITS_PER_PAGE) { if (m_currentPage == MIDPHASE_NUM_WORKUNIT_PAGES-1) { // task buffer is full, issue current task. // if all task buffers busy, this waits until SPU is done. issueTask2(); // find new task buffer for (unsigned int i = 0; i < m_maxNumOutstandingTasks; i++) { if (!m_taskBusy[i]) { m_currentTask = i; //init the task data break; } } m_currentPage = 0; } else { m_currentPage++; } m_currentPageEntry = 0; } } { SpuGatherAndProcessWorkUnitInput &wuInput = *(reinterpret_cast (MIDPHASE_ENTRY_PTR(m_currentTask, m_currentPage, m_currentPageEntry))); wuInput.m_pairArrayPtr = reinterpret_cast(pairArrayPtr); wuInput.m_startIndex = startIndex; wuInput.m_endIndex = endIndex; m_currentPageEntry++; if (!batch) { issueTask2(); // find new task buffer for (unsigned int i = 0; i < m_maxNumOutstandingTasks; i++) { if (!m_taskBusy[i]) { m_currentTask = i; //init the task data break; } } m_currentPage = 0; m_currentPageEntry =0; } } } void SpuCollisionTaskProcess::flush2() { #ifdef DEBUG_SPU_TASK_SCHEDULING printf("\nSpuCollisionTaskProcess::flush()\n"); #endif //DEBUG_SPU_TASK_SCHEDULING // if there's a partially filled task buffer, submit that task if (m_currentPage > 0 || m_currentPageEntry > 0) { issueTask2(); } // all tasks are issued, wait for all tasks to be complete while(m_numBusyTasks > 0) { // Consolidating SPU code unsigned int taskId=-1; unsigned int outputSize; for (int i=0;i=0); { // SPURS support. m_threadInterface->waitForResponse(&taskId, &outputSize); } // printf("flush2 taskId %d completed, numBusy =%d \n",taskId,m_numBusyTasks); //printf("PPU: flushing, received event: %u %d\n", taskId, outputSize); //postProcess(taskId, outputSize); m_taskBusy[taskId] = false; m_numBusyTasks--; } } critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/btThreadSupportInterface.cpp0000644000175000017500000000201411337073000030324 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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 "btThreadSupportInterface.h" btThreadSupportInterface::~btThreadSupportInterface() { } critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/vectormath/0000755000175000017500000000000011347266042025037 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/vectormath/scalar/0000755000175000017500000000000011347266042026304 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/vectormath/scalar/cpp/0000755000175000017500000000000011347266042027066 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/vectormath/scalar/cpp/mat_aos.h0000644000175000017500000013217211337073000030655 0ustar bobkebobke/* Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Sony Computer Entertainment Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _VECTORMATH_MAT_AOS_CPP_H #define _VECTORMATH_MAT_AOS_CPP_H namespace Vectormath { namespace Aos { //----------------------------------------------------------------------------- // Constants #define _VECTORMATH_PI_OVER_2 1.570796327f //----------------------------------------------------------------------------- // Definitions inline Matrix3::Matrix3( const Matrix3 & mat ) { mCol0 = mat.mCol0; mCol1 = mat.mCol1; mCol2 = mat.mCol2; } inline Matrix3::Matrix3( float scalar ) { mCol0 = Vector3( scalar ); mCol1 = Vector3( scalar ); mCol2 = Vector3( scalar ); } inline Matrix3::Matrix3( const Quat & unitQuat ) { float qx, qy, qz, qw, qx2, qy2, qz2, qxqx2, qyqy2, qzqz2, qxqy2, qyqz2, qzqw2, qxqz2, qyqw2, qxqw2; qx = unitQuat.getX(); qy = unitQuat.getY(); qz = unitQuat.getZ(); qw = unitQuat.getW(); qx2 = ( qx + qx ); qy2 = ( qy + qy ); qz2 = ( qz + qz ); qxqx2 = ( qx * qx2 ); qxqy2 = ( qx * qy2 ); qxqz2 = ( qx * qz2 ); qxqw2 = ( qw * qx2 ); qyqy2 = ( qy * qy2 ); qyqz2 = ( qy * qz2 ); qyqw2 = ( qw * qy2 ); qzqz2 = ( qz * qz2 ); qzqw2 = ( qw * qz2 ); mCol0 = Vector3( ( ( 1.0f - qyqy2 ) - qzqz2 ), ( qxqy2 + qzqw2 ), ( qxqz2 - qyqw2 ) ); mCol1 = Vector3( ( qxqy2 - qzqw2 ), ( ( 1.0f - qxqx2 ) - qzqz2 ), ( qyqz2 + qxqw2 ) ); mCol2 = Vector3( ( qxqz2 + qyqw2 ), ( qyqz2 - qxqw2 ), ( ( 1.0f - qxqx2 ) - qyqy2 ) ); } inline Matrix3::Matrix3( const Vector3 & _col0, const Vector3 & _col1, const Vector3 & _col2 ) { mCol0 = _col0; mCol1 = _col1; mCol2 = _col2; } inline Matrix3 & Matrix3::setCol0( const Vector3 & _col0 ) { mCol0 = _col0; return *this; } inline Matrix3 & Matrix3::setCol1( const Vector3 & _col1 ) { mCol1 = _col1; return *this; } inline Matrix3 & Matrix3::setCol2( const Vector3 & _col2 ) { mCol2 = _col2; return *this; } inline Matrix3 & Matrix3::setCol( int col, const Vector3 & vec ) { *(&mCol0 + col) = vec; return *this; } inline Matrix3 & Matrix3::setRow( int row, const Vector3 & vec ) { mCol0.setElem( row, vec.getElem( 0 ) ); mCol1.setElem( row, vec.getElem( 1 ) ); mCol2.setElem( row, vec.getElem( 2 ) ); return *this; } inline Matrix3 & Matrix3::setElem( int col, int row, float val ) { Vector3 tmpV3_0; tmpV3_0 = this->getCol( col ); tmpV3_0.setElem( row, val ); this->setCol( col, tmpV3_0 ); return *this; } inline float Matrix3::getElem( int col, int row ) const { return this->getCol( col ).getElem( row ); } inline const Vector3 Matrix3::getCol0( ) const { return mCol0; } inline const Vector3 Matrix3::getCol1( ) const { return mCol1; } inline const Vector3 Matrix3::getCol2( ) const { return mCol2; } inline const Vector3 Matrix3::getCol( int col ) const { return *(&mCol0 + col); } inline const Vector3 Matrix3::getRow( int row ) const { return Vector3( mCol0.getElem( row ), mCol1.getElem( row ), mCol2.getElem( row ) ); } inline Vector3 & Matrix3::operator []( int col ) { return *(&mCol0 + col); } inline const Vector3 Matrix3::operator []( int col ) const { return *(&mCol0 + col); } inline Matrix3 & Matrix3::operator =( const Matrix3 & mat ) { mCol0 = mat.mCol0; mCol1 = mat.mCol1; mCol2 = mat.mCol2; return *this; } inline const Matrix3 transpose( const Matrix3 & mat ) { return Matrix3( Vector3( mat.getCol0().getX(), mat.getCol1().getX(), mat.getCol2().getX() ), Vector3( mat.getCol0().getY(), mat.getCol1().getY(), mat.getCol2().getY() ), Vector3( mat.getCol0().getZ(), mat.getCol1().getZ(), mat.getCol2().getZ() ) ); } inline const Matrix3 inverse( const Matrix3 & mat ) { Vector3 tmp0, tmp1, tmp2; float detinv; tmp0 = cross( mat.getCol1(), mat.getCol2() ); tmp1 = cross( mat.getCol2(), mat.getCol0() ); tmp2 = cross( mat.getCol0(), mat.getCol1() ); detinv = ( 1.0f / dot( mat.getCol2(), tmp2 ) ); return Matrix3( Vector3( ( tmp0.getX() * detinv ), ( tmp1.getX() * detinv ), ( tmp2.getX() * detinv ) ), Vector3( ( tmp0.getY() * detinv ), ( tmp1.getY() * detinv ), ( tmp2.getY() * detinv ) ), Vector3( ( tmp0.getZ() * detinv ), ( tmp1.getZ() * detinv ), ( tmp2.getZ() * detinv ) ) ); } inline float determinant( const Matrix3 & mat ) { return dot( mat.getCol2(), cross( mat.getCol0(), mat.getCol1() ) ); } inline const Matrix3 Matrix3::operator +( const Matrix3 & mat ) const { return Matrix3( ( mCol0 + mat.mCol0 ), ( mCol1 + mat.mCol1 ), ( mCol2 + mat.mCol2 ) ); } inline const Matrix3 Matrix3::operator -( const Matrix3 & mat ) const { return Matrix3( ( mCol0 - mat.mCol0 ), ( mCol1 - mat.mCol1 ), ( mCol2 - mat.mCol2 ) ); } inline Matrix3 & Matrix3::operator +=( const Matrix3 & mat ) { *this = *this + mat; return *this; } inline Matrix3 & Matrix3::operator -=( const Matrix3 & mat ) { *this = *this - mat; return *this; } inline const Matrix3 Matrix3::operator -( ) const { return Matrix3( ( -mCol0 ), ( -mCol1 ), ( -mCol2 ) ); } inline const Matrix3 absPerElem( const Matrix3 & mat ) { return Matrix3( absPerElem( mat.getCol0() ), absPerElem( mat.getCol1() ), absPerElem( mat.getCol2() ) ); } inline const Matrix3 Matrix3::operator *( float scalar ) const { return Matrix3( ( mCol0 * scalar ), ( mCol1 * scalar ), ( mCol2 * scalar ) ); } inline Matrix3 & Matrix3::operator *=( float scalar ) { *this = *this * scalar; return *this; } inline const Matrix3 operator *( float scalar, const Matrix3 & mat ) { return mat * scalar; } inline const Vector3 Matrix3::operator *( const Vector3 & vec ) const { return Vector3( ( ( ( mCol0.getX() * vec.getX() ) + ( mCol1.getX() * vec.getY() ) ) + ( mCol2.getX() * vec.getZ() ) ), ( ( ( mCol0.getY() * vec.getX() ) + ( mCol1.getY() * vec.getY() ) ) + ( mCol2.getY() * vec.getZ() ) ), ( ( ( mCol0.getZ() * vec.getX() ) + ( mCol1.getZ() * vec.getY() ) ) + ( mCol2.getZ() * vec.getZ() ) ) ); } inline const Matrix3 Matrix3::operator *( const Matrix3 & mat ) const { return Matrix3( ( *this * mat.mCol0 ), ( *this * mat.mCol1 ), ( *this * mat.mCol2 ) ); } inline Matrix3 & Matrix3::operator *=( const Matrix3 & mat ) { *this = *this * mat; return *this; } inline const Matrix3 mulPerElem( const Matrix3 & mat0, const Matrix3 & mat1 ) { return Matrix3( mulPerElem( mat0.getCol0(), mat1.getCol0() ), mulPerElem( mat0.getCol1(), mat1.getCol1() ), mulPerElem( mat0.getCol2(), mat1.getCol2() ) ); } inline const Matrix3 Matrix3::identity( ) { return Matrix3( Vector3::xAxis( ), Vector3::yAxis( ), Vector3::zAxis( ) ); } inline const Matrix3 Matrix3::rotationX( float radians ) { float s, c; s = sinf( radians ); c = cosf( radians ); return Matrix3( Vector3::xAxis( ), Vector3( 0.0f, c, s ), Vector3( 0.0f, -s, c ) ); } inline const Matrix3 Matrix3::rotationY( float radians ) { float s, c; s = sinf( radians ); c = cosf( radians ); return Matrix3( Vector3( c, 0.0f, -s ), Vector3::yAxis( ), Vector3( s, 0.0f, c ) ); } inline const Matrix3 Matrix3::rotationZ( float radians ) { float s, c; s = sinf( radians ); c = cosf( radians ); return Matrix3( Vector3( c, s, 0.0f ), Vector3( -s, c, 0.0f ), Vector3::zAxis( ) ); } inline const Matrix3 Matrix3::rotationZYX( const Vector3 & radiansXYZ ) { float sX, cX, sY, cY, sZ, cZ, tmp0, tmp1; sX = sinf( radiansXYZ.getX() ); cX = cosf( radiansXYZ.getX() ); sY = sinf( radiansXYZ.getY() ); cY = cosf( radiansXYZ.getY() ); sZ = sinf( radiansXYZ.getZ() ); cZ = cosf( radiansXYZ.getZ() ); tmp0 = ( cZ * sY ); tmp1 = ( sZ * sY ); return Matrix3( Vector3( ( cZ * cY ), ( sZ * cY ), -sY ), Vector3( ( ( tmp0 * sX ) - ( sZ * cX ) ), ( ( tmp1 * sX ) + ( cZ * cX ) ), ( cY * sX ) ), Vector3( ( ( tmp0 * cX ) + ( sZ * sX ) ), ( ( tmp1 * cX ) - ( cZ * sX ) ), ( cY * cX ) ) ); } inline const Matrix3 Matrix3::rotation( float radians, const Vector3 & unitVec ) { float x, y, z, s, c, oneMinusC, xy, yz, zx; s = sinf( radians ); c = cosf( radians ); x = unitVec.getX(); y = unitVec.getY(); z = unitVec.getZ(); xy = ( x * y ); yz = ( y * z ); zx = ( z * x ); oneMinusC = ( 1.0f - c ); return Matrix3( Vector3( ( ( ( x * x ) * oneMinusC ) + c ), ( ( xy * oneMinusC ) + ( z * s ) ), ( ( zx * oneMinusC ) - ( y * s ) ) ), Vector3( ( ( xy * oneMinusC ) - ( z * s ) ), ( ( ( y * y ) * oneMinusC ) + c ), ( ( yz * oneMinusC ) + ( x * s ) ) ), Vector3( ( ( zx * oneMinusC ) + ( y * s ) ), ( ( yz * oneMinusC ) - ( x * s ) ), ( ( ( z * z ) * oneMinusC ) + c ) ) ); } inline const Matrix3 Matrix3::rotation( const Quat & unitQuat ) { return Matrix3( unitQuat ); } inline const Matrix3 Matrix3::scale( const Vector3 & scaleVec ) { return Matrix3( Vector3( scaleVec.getX(), 0.0f, 0.0f ), Vector3( 0.0f, scaleVec.getY(), 0.0f ), Vector3( 0.0f, 0.0f, scaleVec.getZ() ) ); } inline const Matrix3 appendScale( const Matrix3 & mat, const Vector3 & scaleVec ) { return Matrix3( ( mat.getCol0() * scaleVec.getX( ) ), ( mat.getCol1() * scaleVec.getY( ) ), ( mat.getCol2() * scaleVec.getZ( ) ) ); } inline const Matrix3 prependScale( const Vector3 & scaleVec, const Matrix3 & mat ) { return Matrix3( mulPerElem( mat.getCol0(), scaleVec ), mulPerElem( mat.getCol1(), scaleVec ), mulPerElem( mat.getCol2(), scaleVec ) ); } inline const Matrix3 select( const Matrix3 & mat0, const Matrix3 & mat1, bool select1 ) { return Matrix3( select( mat0.getCol0(), mat1.getCol0(), select1 ), select( mat0.getCol1(), mat1.getCol1(), select1 ), select( mat0.getCol2(), mat1.getCol2(), select1 ) ); } #ifdef _VECTORMATH_DEBUG inline void print( const Matrix3 & mat ) { print( mat.getRow( 0 ) ); print( mat.getRow( 1 ) ); print( mat.getRow( 2 ) ); } inline void print( const Matrix3 & mat, const char * name ) { printf("%s:\n", name); print( mat ); } #endif inline Matrix4::Matrix4( const Matrix4 & mat ) { mCol0 = mat.mCol0; mCol1 = mat.mCol1; mCol2 = mat.mCol2; mCol3 = mat.mCol3; } inline Matrix4::Matrix4( float scalar ) { mCol0 = Vector4( scalar ); mCol1 = Vector4( scalar ); mCol2 = Vector4( scalar ); mCol3 = Vector4( scalar ); } inline Matrix4::Matrix4( const Transform3 & mat ) { mCol0 = Vector4( mat.getCol0(), 0.0f ); mCol1 = Vector4( mat.getCol1(), 0.0f ); mCol2 = Vector4( mat.getCol2(), 0.0f ); mCol3 = Vector4( mat.getCol3(), 1.0f ); } inline Matrix4::Matrix4( const Vector4 & _col0, const Vector4 & _col1, const Vector4 & _col2, const Vector4 & _col3 ) { mCol0 = _col0; mCol1 = _col1; mCol2 = _col2; mCol3 = _col3; } inline Matrix4::Matrix4( const Matrix3 & mat, const Vector3 & translateVec ) { mCol0 = Vector4( mat.getCol0(), 0.0f ); mCol1 = Vector4( mat.getCol1(), 0.0f ); mCol2 = Vector4( mat.getCol2(), 0.0f ); mCol3 = Vector4( translateVec, 1.0f ); } inline Matrix4::Matrix4( const Quat & unitQuat, const Vector3 & translateVec ) { Matrix3 mat; mat = Matrix3( unitQuat ); mCol0 = Vector4( mat.getCol0(), 0.0f ); mCol1 = Vector4( mat.getCol1(), 0.0f ); mCol2 = Vector4( mat.getCol2(), 0.0f ); mCol3 = Vector4( translateVec, 1.0f ); } inline Matrix4 & Matrix4::setCol0( const Vector4 & _col0 ) { mCol0 = _col0; return *this; } inline Matrix4 & Matrix4::setCol1( const Vector4 & _col1 ) { mCol1 = _col1; return *this; } inline Matrix4 & Matrix4::setCol2( const Vector4 & _col2 ) { mCol2 = _col2; return *this; } inline Matrix4 & Matrix4::setCol3( const Vector4 & _col3 ) { mCol3 = _col3; return *this; } inline Matrix4 & Matrix4::setCol( int col, const Vector4 & vec ) { *(&mCol0 + col) = vec; return *this; } inline Matrix4 & Matrix4::setRow( int row, const Vector4 & vec ) { mCol0.setElem( row, vec.getElem( 0 ) ); mCol1.setElem( row, vec.getElem( 1 ) ); mCol2.setElem( row, vec.getElem( 2 ) ); mCol3.setElem( row, vec.getElem( 3 ) ); return *this; } inline Matrix4 & Matrix4::setElem( int col, int row, float val ) { Vector4 tmpV3_0; tmpV3_0 = this->getCol( col ); tmpV3_0.setElem( row, val ); this->setCol( col, tmpV3_0 ); return *this; } inline float Matrix4::getElem( int col, int row ) const { return this->getCol( col ).getElem( row ); } inline const Vector4 Matrix4::getCol0( ) const { return mCol0; } inline const Vector4 Matrix4::getCol1( ) const { return mCol1; } inline const Vector4 Matrix4::getCol2( ) const { return mCol2; } inline const Vector4 Matrix4::getCol3( ) const { return mCol3; } inline const Vector4 Matrix4::getCol( int col ) const { return *(&mCol0 + col); } inline const Vector4 Matrix4::getRow( int row ) const { return Vector4( mCol0.getElem( row ), mCol1.getElem( row ), mCol2.getElem( row ), mCol3.getElem( row ) ); } inline Vector4 & Matrix4::operator []( int col ) { return *(&mCol0 + col); } inline const Vector4 Matrix4::operator []( int col ) const { return *(&mCol0 + col); } inline Matrix4 & Matrix4::operator =( const Matrix4 & mat ) { mCol0 = mat.mCol0; mCol1 = mat.mCol1; mCol2 = mat.mCol2; mCol3 = mat.mCol3; return *this; } inline const Matrix4 transpose( const Matrix4 & mat ) { return Matrix4( Vector4( mat.getCol0().getX(), mat.getCol1().getX(), mat.getCol2().getX(), mat.getCol3().getX() ), Vector4( mat.getCol0().getY(), mat.getCol1().getY(), mat.getCol2().getY(), mat.getCol3().getY() ), Vector4( mat.getCol0().getZ(), mat.getCol1().getZ(), mat.getCol2().getZ(), mat.getCol3().getZ() ), Vector4( mat.getCol0().getW(), mat.getCol1().getW(), mat.getCol2().getW(), mat.getCol3().getW() ) ); } inline const Matrix4 inverse( const Matrix4 & mat ) { Vector4 res0, res1, res2, res3; float mA, mB, mC, mD, mE, mF, mG, mH, mI, mJ, mK, mL, mM, mN, mO, mP, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, detInv; mA = mat.getCol0().getX(); mB = mat.getCol0().getY(); mC = mat.getCol0().getZ(); mD = mat.getCol0().getW(); mE = mat.getCol1().getX(); mF = mat.getCol1().getY(); mG = mat.getCol1().getZ(); mH = mat.getCol1().getW(); mI = mat.getCol2().getX(); mJ = mat.getCol2().getY(); mK = mat.getCol2().getZ(); mL = mat.getCol2().getW(); mM = mat.getCol3().getX(); mN = mat.getCol3().getY(); mO = mat.getCol3().getZ(); mP = mat.getCol3().getW(); tmp0 = ( ( mK * mD ) - ( mC * mL ) ); tmp1 = ( ( mO * mH ) - ( mG * mP ) ); tmp2 = ( ( mB * mK ) - ( mJ * mC ) ); tmp3 = ( ( mF * mO ) - ( mN * mG ) ); tmp4 = ( ( mJ * mD ) - ( mB * mL ) ); tmp5 = ( ( mN * mH ) - ( mF * mP ) ); res0.setX( ( ( ( mJ * tmp1 ) - ( mL * tmp3 ) ) - ( mK * tmp5 ) ) ); res0.setY( ( ( ( mN * tmp0 ) - ( mP * tmp2 ) ) - ( mO * tmp4 ) ) ); res0.setZ( ( ( ( mD * tmp3 ) + ( mC * tmp5 ) ) - ( mB * tmp1 ) ) ); res0.setW( ( ( ( mH * tmp2 ) + ( mG * tmp4 ) ) - ( mF * tmp0 ) ) ); detInv = ( 1.0f / ( ( ( ( mA * res0.getX() ) + ( mE * res0.getY() ) ) + ( mI * res0.getZ() ) ) + ( mM * res0.getW() ) ) ); res1.setX( ( mI * tmp1 ) ); res1.setY( ( mM * tmp0 ) ); res1.setZ( ( mA * tmp1 ) ); res1.setW( ( mE * tmp0 ) ); res3.setX( ( mI * tmp3 ) ); res3.setY( ( mM * tmp2 ) ); res3.setZ( ( mA * tmp3 ) ); res3.setW( ( mE * tmp2 ) ); res2.setX( ( mI * tmp5 ) ); res2.setY( ( mM * tmp4 ) ); res2.setZ( ( mA * tmp5 ) ); res2.setW( ( mE * tmp4 ) ); tmp0 = ( ( mI * mB ) - ( mA * mJ ) ); tmp1 = ( ( mM * mF ) - ( mE * mN ) ); tmp2 = ( ( mI * mD ) - ( mA * mL ) ); tmp3 = ( ( mM * mH ) - ( mE * mP ) ); tmp4 = ( ( mI * mC ) - ( mA * mK ) ); tmp5 = ( ( mM * mG ) - ( mE * mO ) ); res2.setX( ( ( ( mL * tmp1 ) - ( mJ * tmp3 ) ) + res2.getX() ) ); res2.setY( ( ( ( mP * tmp0 ) - ( mN * tmp2 ) ) + res2.getY() ) ); res2.setZ( ( ( ( mB * tmp3 ) - ( mD * tmp1 ) ) - res2.getZ() ) ); res2.setW( ( ( ( mF * tmp2 ) - ( mH * tmp0 ) ) - res2.getW() ) ); res3.setX( ( ( ( mJ * tmp5 ) - ( mK * tmp1 ) ) + res3.getX() ) ); res3.setY( ( ( ( mN * tmp4 ) - ( mO * tmp0 ) ) + res3.getY() ) ); res3.setZ( ( ( ( mC * tmp1 ) - ( mB * tmp5 ) ) - res3.getZ() ) ); res3.setW( ( ( ( mG * tmp0 ) - ( mF * tmp4 ) ) - res3.getW() ) ); res1.setX( ( ( ( mK * tmp3 ) - ( mL * tmp5 ) ) - res1.getX() ) ); res1.setY( ( ( ( mO * tmp2 ) - ( mP * tmp4 ) ) - res1.getY() ) ); res1.setZ( ( ( ( mD * tmp5 ) - ( mC * tmp3 ) ) + res1.getZ() ) ); res1.setW( ( ( ( mH * tmp4 ) - ( mG * tmp2 ) ) + res1.getW() ) ); return Matrix4( ( res0 * detInv ), ( res1 * detInv ), ( res2 * detInv ), ( res3 * detInv ) ); } inline const Matrix4 affineInverse( const Matrix4 & mat ) { Transform3 affineMat; affineMat.setCol0( mat.getCol0().getXYZ( ) ); affineMat.setCol1( mat.getCol1().getXYZ( ) ); affineMat.setCol2( mat.getCol2().getXYZ( ) ); affineMat.setCol3( mat.getCol3().getXYZ( ) ); return Matrix4( inverse( affineMat ) ); } inline const Matrix4 orthoInverse( const Matrix4 & mat ) { Transform3 affineMat; affineMat.setCol0( mat.getCol0().getXYZ( ) ); affineMat.setCol1( mat.getCol1().getXYZ( ) ); affineMat.setCol2( mat.getCol2().getXYZ( ) ); affineMat.setCol3( mat.getCol3().getXYZ( ) ); return Matrix4( orthoInverse( affineMat ) ); } inline float determinant( const Matrix4 & mat ) { float dx, dy, dz, dw, mA, mB, mC, mD, mE, mF, mG, mH, mI, mJ, mK, mL, mM, mN, mO, mP, tmp0, tmp1, tmp2, tmp3, tmp4, tmp5; mA = mat.getCol0().getX(); mB = mat.getCol0().getY(); mC = mat.getCol0().getZ(); mD = mat.getCol0().getW(); mE = mat.getCol1().getX(); mF = mat.getCol1().getY(); mG = mat.getCol1().getZ(); mH = mat.getCol1().getW(); mI = mat.getCol2().getX(); mJ = mat.getCol2().getY(); mK = mat.getCol2().getZ(); mL = mat.getCol2().getW(); mM = mat.getCol3().getX(); mN = mat.getCol3().getY(); mO = mat.getCol3().getZ(); mP = mat.getCol3().getW(); tmp0 = ( ( mK * mD ) - ( mC * mL ) ); tmp1 = ( ( mO * mH ) - ( mG * mP ) ); tmp2 = ( ( mB * mK ) - ( mJ * mC ) ); tmp3 = ( ( mF * mO ) - ( mN * mG ) ); tmp4 = ( ( mJ * mD ) - ( mB * mL ) ); tmp5 = ( ( mN * mH ) - ( mF * mP ) ); dx = ( ( ( mJ * tmp1 ) - ( mL * tmp3 ) ) - ( mK * tmp5 ) ); dy = ( ( ( mN * tmp0 ) - ( mP * tmp2 ) ) - ( mO * tmp4 ) ); dz = ( ( ( mD * tmp3 ) + ( mC * tmp5 ) ) - ( mB * tmp1 ) ); dw = ( ( ( mH * tmp2 ) + ( mG * tmp4 ) ) - ( mF * tmp0 ) ); return ( ( ( ( mA * dx ) + ( mE * dy ) ) + ( mI * dz ) ) + ( mM * dw ) ); } inline const Matrix4 Matrix4::operator +( const Matrix4 & mat ) const { return Matrix4( ( mCol0 + mat.mCol0 ), ( mCol1 + mat.mCol1 ), ( mCol2 + mat.mCol2 ), ( mCol3 + mat.mCol3 ) ); } inline const Matrix4 Matrix4::operator -( const Matrix4 & mat ) const { return Matrix4( ( mCol0 - mat.mCol0 ), ( mCol1 - mat.mCol1 ), ( mCol2 - mat.mCol2 ), ( mCol3 - mat.mCol3 ) ); } inline Matrix4 & Matrix4::operator +=( const Matrix4 & mat ) { *this = *this + mat; return *this; } inline Matrix4 & Matrix4::operator -=( const Matrix4 & mat ) { *this = *this - mat; return *this; } inline const Matrix4 Matrix4::operator -( ) const { return Matrix4( ( -mCol0 ), ( -mCol1 ), ( -mCol2 ), ( -mCol3 ) ); } inline const Matrix4 absPerElem( const Matrix4 & mat ) { return Matrix4( absPerElem( mat.getCol0() ), absPerElem( mat.getCol1() ), absPerElem( mat.getCol2() ), absPerElem( mat.getCol3() ) ); } inline const Matrix4 Matrix4::operator *( float scalar ) const { return Matrix4( ( mCol0 * scalar ), ( mCol1 * scalar ), ( mCol2 * scalar ), ( mCol3 * scalar ) ); } inline Matrix4 & Matrix4::operator *=( float scalar ) { *this = *this * scalar; return *this; } inline const Matrix4 operator *( float scalar, const Matrix4 & mat ) { return mat * scalar; } inline const Vector4 Matrix4::operator *( const Vector4 & vec ) const { return Vector4( ( ( ( ( mCol0.getX() * vec.getX() ) + ( mCol1.getX() * vec.getY() ) ) + ( mCol2.getX() * vec.getZ() ) ) + ( mCol3.getX() * vec.getW() ) ), ( ( ( ( mCol0.getY() * vec.getX() ) + ( mCol1.getY() * vec.getY() ) ) + ( mCol2.getY() * vec.getZ() ) ) + ( mCol3.getY() * vec.getW() ) ), ( ( ( ( mCol0.getZ() * vec.getX() ) + ( mCol1.getZ() * vec.getY() ) ) + ( mCol2.getZ() * vec.getZ() ) ) + ( mCol3.getZ() * vec.getW() ) ), ( ( ( ( mCol0.getW() * vec.getX() ) + ( mCol1.getW() * vec.getY() ) ) + ( mCol2.getW() * vec.getZ() ) ) + ( mCol3.getW() * vec.getW() ) ) ); } inline const Vector4 Matrix4::operator *( const Vector3 & vec ) const { return Vector4( ( ( ( mCol0.getX() * vec.getX() ) + ( mCol1.getX() * vec.getY() ) ) + ( mCol2.getX() * vec.getZ() ) ), ( ( ( mCol0.getY() * vec.getX() ) + ( mCol1.getY() * vec.getY() ) ) + ( mCol2.getY() * vec.getZ() ) ), ( ( ( mCol0.getZ() * vec.getX() ) + ( mCol1.getZ() * vec.getY() ) ) + ( mCol2.getZ() * vec.getZ() ) ), ( ( ( mCol0.getW() * vec.getX() ) + ( mCol1.getW() * vec.getY() ) ) + ( mCol2.getW() * vec.getZ() ) ) ); } inline const Vector4 Matrix4::operator *( const Point3 & pnt ) const { return Vector4( ( ( ( ( mCol0.getX() * pnt.getX() ) + ( mCol1.getX() * pnt.getY() ) ) + ( mCol2.getX() * pnt.getZ() ) ) + mCol3.getX() ), ( ( ( ( mCol0.getY() * pnt.getX() ) + ( mCol1.getY() * pnt.getY() ) ) + ( mCol2.getY() * pnt.getZ() ) ) + mCol3.getY() ), ( ( ( ( mCol0.getZ() * pnt.getX() ) + ( mCol1.getZ() * pnt.getY() ) ) + ( mCol2.getZ() * pnt.getZ() ) ) + mCol3.getZ() ), ( ( ( ( mCol0.getW() * pnt.getX() ) + ( mCol1.getW() * pnt.getY() ) ) + ( mCol2.getW() * pnt.getZ() ) ) + mCol3.getW() ) ); } inline const Matrix4 Matrix4::operator *( const Matrix4 & mat ) const { return Matrix4( ( *this * mat.mCol0 ), ( *this * mat.mCol1 ), ( *this * mat.mCol2 ), ( *this * mat.mCol3 ) ); } inline Matrix4 & Matrix4::operator *=( const Matrix4 & mat ) { *this = *this * mat; return *this; } inline const Matrix4 Matrix4::operator *( const Transform3 & tfrm ) const { return Matrix4( ( *this * tfrm.getCol0() ), ( *this * tfrm.getCol1() ), ( *this * tfrm.getCol2() ), ( *this * Point3( tfrm.getCol3() ) ) ); } inline Matrix4 & Matrix4::operator *=( const Transform3 & tfrm ) { *this = *this * tfrm; return *this; } inline const Matrix4 mulPerElem( const Matrix4 & mat0, const Matrix4 & mat1 ) { return Matrix4( mulPerElem( mat0.getCol0(), mat1.getCol0() ), mulPerElem( mat0.getCol1(), mat1.getCol1() ), mulPerElem( mat0.getCol2(), mat1.getCol2() ), mulPerElem( mat0.getCol3(), mat1.getCol3() ) ); } inline const Matrix4 Matrix4::identity( ) { return Matrix4( Vector4::xAxis( ), Vector4::yAxis( ), Vector4::zAxis( ), Vector4::wAxis( ) ); } inline Matrix4 & Matrix4::setUpper3x3( const Matrix3 & mat3 ) { mCol0.setXYZ( mat3.getCol0() ); mCol1.setXYZ( mat3.getCol1() ); mCol2.setXYZ( mat3.getCol2() ); return *this; } inline const Matrix3 Matrix4::getUpper3x3( ) const { return Matrix3( mCol0.getXYZ( ), mCol1.getXYZ( ), mCol2.getXYZ( ) ); } inline Matrix4 & Matrix4::setTranslation( const Vector3 & translateVec ) { mCol3.setXYZ( translateVec ); return *this; } inline const Vector3 Matrix4::getTranslation( ) const { return mCol3.getXYZ( ); } inline const Matrix4 Matrix4::rotationX( float radians ) { float s, c; s = sinf( radians ); c = cosf( radians ); return Matrix4( Vector4::xAxis( ), Vector4( 0.0f, c, s, 0.0f ), Vector4( 0.0f, -s, c, 0.0f ), Vector4::wAxis( ) ); } inline const Matrix4 Matrix4::rotationY( float radians ) { float s, c; s = sinf( radians ); c = cosf( radians ); return Matrix4( Vector4( c, 0.0f, -s, 0.0f ), Vector4::yAxis( ), Vector4( s, 0.0f, c, 0.0f ), Vector4::wAxis( ) ); } inline const Matrix4 Matrix4::rotationZ( float radians ) { float s, c; s = sinf( radians ); c = cosf( radians ); return Matrix4( Vector4( c, s, 0.0f, 0.0f ), Vector4( -s, c, 0.0f, 0.0f ), Vector4::zAxis( ), Vector4::wAxis( ) ); } inline const Matrix4 Matrix4::rotationZYX( const Vector3 & radiansXYZ ) { float sX, cX, sY, cY, sZ, cZ, tmp0, tmp1; sX = sinf( radiansXYZ.getX() ); cX = cosf( radiansXYZ.getX() ); sY = sinf( radiansXYZ.getY() ); cY = cosf( radiansXYZ.getY() ); sZ = sinf( radiansXYZ.getZ() ); cZ = cosf( radiansXYZ.getZ() ); tmp0 = ( cZ * sY ); tmp1 = ( sZ * sY ); return Matrix4( Vector4( ( cZ * cY ), ( sZ * cY ), -sY, 0.0f ), Vector4( ( ( tmp0 * sX ) - ( sZ * cX ) ), ( ( tmp1 * sX ) + ( cZ * cX ) ), ( cY * sX ), 0.0f ), Vector4( ( ( tmp0 * cX ) + ( sZ * sX ) ), ( ( tmp1 * cX ) - ( cZ * sX ) ), ( cY * cX ), 0.0f ), Vector4::wAxis( ) ); } inline const Matrix4 Matrix4::rotation( float radians, const Vector3 & unitVec ) { float x, y, z, s, c, oneMinusC, xy, yz, zx; s = sinf( radians ); c = cosf( radians ); x = unitVec.getX(); y = unitVec.getY(); z = unitVec.getZ(); xy = ( x * y ); yz = ( y * z ); zx = ( z * x ); oneMinusC = ( 1.0f - c ); return Matrix4( Vector4( ( ( ( x * x ) * oneMinusC ) + c ), ( ( xy * oneMinusC ) + ( z * s ) ), ( ( zx * oneMinusC ) - ( y * s ) ), 0.0f ), Vector4( ( ( xy * oneMinusC ) - ( z * s ) ), ( ( ( y * y ) * oneMinusC ) + c ), ( ( yz * oneMinusC ) + ( x * s ) ), 0.0f ), Vector4( ( ( zx * oneMinusC ) + ( y * s ) ), ( ( yz * oneMinusC ) - ( x * s ) ), ( ( ( z * z ) * oneMinusC ) + c ), 0.0f ), Vector4::wAxis( ) ); } inline const Matrix4 Matrix4::rotation( const Quat & unitQuat ) { return Matrix4( Transform3::rotation( unitQuat ) ); } inline const Matrix4 Matrix4::scale( const Vector3 & scaleVec ) { return Matrix4( Vector4( scaleVec.getX(), 0.0f, 0.0f, 0.0f ), Vector4( 0.0f, scaleVec.getY(), 0.0f, 0.0f ), Vector4( 0.0f, 0.0f, scaleVec.getZ(), 0.0f ), Vector4::wAxis( ) ); } inline const Matrix4 appendScale( const Matrix4 & mat, const Vector3 & scaleVec ) { return Matrix4( ( mat.getCol0() * scaleVec.getX( ) ), ( mat.getCol1() * scaleVec.getY( ) ), ( mat.getCol2() * scaleVec.getZ( ) ), mat.getCol3() ); } inline const Matrix4 prependScale( const Vector3 & scaleVec, const Matrix4 & mat ) { Vector4 scale4; scale4 = Vector4( scaleVec, 1.0f ); return Matrix4( mulPerElem( mat.getCol0(), scale4 ), mulPerElem( mat.getCol1(), scale4 ), mulPerElem( mat.getCol2(), scale4 ), mulPerElem( mat.getCol3(), scale4 ) ); } inline const Matrix4 Matrix4::translation( const Vector3 & translateVec ) { return Matrix4( Vector4::xAxis( ), Vector4::yAxis( ), Vector4::zAxis( ), Vector4( translateVec, 1.0f ) ); } inline const Matrix4 Matrix4::lookAt( const Point3 & eyePos, const Point3 & lookAtPos, const Vector3 & upVec ) { Matrix4 m4EyeFrame; Vector3 v3X, v3Y, v3Z; v3Y = normalize( upVec ); v3Z = normalize( ( eyePos - lookAtPos ) ); v3X = normalize( cross( v3Y, v3Z ) ); v3Y = cross( v3Z, v3X ); m4EyeFrame = Matrix4( Vector4( v3X ), Vector4( v3Y ), Vector4( v3Z ), Vector4( eyePos ) ); return orthoInverse( m4EyeFrame ); } inline const Matrix4 Matrix4::perspective( float fovyRadians, float aspect, float zNear, float zFar ) { float f, rangeInv; f = tanf( ( (float)( _VECTORMATH_PI_OVER_2 ) - ( 0.5f * fovyRadians ) ) ); rangeInv = ( 1.0f / ( zNear - zFar ) ); return Matrix4( Vector4( ( f / aspect ), 0.0f, 0.0f, 0.0f ), Vector4( 0.0f, f, 0.0f, 0.0f ), Vector4( 0.0f, 0.0f, ( ( zNear + zFar ) * rangeInv ), -1.0f ), Vector4( 0.0f, 0.0f, ( ( ( zNear * zFar ) * rangeInv ) * 2.0f ), 0.0f ) ); } inline const Matrix4 Matrix4::frustum( float left, float right, float bottom, float top, float zNear, float zFar ) { float sum_rl, sum_tb, sum_nf, inv_rl, inv_tb, inv_nf, n2; sum_rl = ( right + left ); sum_tb = ( top + bottom ); sum_nf = ( zNear + zFar ); inv_rl = ( 1.0f / ( right - left ) ); inv_tb = ( 1.0f / ( top - bottom ) ); inv_nf = ( 1.0f / ( zNear - zFar ) ); n2 = ( zNear + zNear ); return Matrix4( Vector4( ( n2 * inv_rl ), 0.0f, 0.0f, 0.0f ), Vector4( 0.0f, ( n2 * inv_tb ), 0.0f, 0.0f ), Vector4( ( sum_rl * inv_rl ), ( sum_tb * inv_tb ), ( sum_nf * inv_nf ), -1.0f ), Vector4( 0.0f, 0.0f, ( ( n2 * inv_nf ) * zFar ), 0.0f ) ); } inline const Matrix4 Matrix4::orthographic( float left, float right, float bottom, float top, float zNear, float zFar ) { float sum_rl, sum_tb, sum_nf, inv_rl, inv_tb, inv_nf; sum_rl = ( right + left ); sum_tb = ( top + bottom ); sum_nf = ( zNear + zFar ); inv_rl = ( 1.0f / ( right - left ) ); inv_tb = ( 1.0f / ( top - bottom ) ); inv_nf = ( 1.0f / ( zNear - zFar ) ); return Matrix4( Vector4( ( inv_rl + inv_rl ), 0.0f, 0.0f, 0.0f ), Vector4( 0.0f, ( inv_tb + inv_tb ), 0.0f, 0.0f ), Vector4( 0.0f, 0.0f, ( inv_nf + inv_nf ), 0.0f ), Vector4( ( -sum_rl * inv_rl ), ( -sum_tb * inv_tb ), ( sum_nf * inv_nf ), 1.0f ) ); } inline const Matrix4 select( const Matrix4 & mat0, const Matrix4 & mat1, bool select1 ) { return Matrix4( select( mat0.getCol0(), mat1.getCol0(), select1 ), select( mat0.getCol1(), mat1.getCol1(), select1 ), select( mat0.getCol2(), mat1.getCol2(), select1 ), select( mat0.getCol3(), mat1.getCol3(), select1 ) ); } #ifdef _VECTORMATH_DEBUG inline void print( const Matrix4 & mat ) { print( mat.getRow( 0 ) ); print( mat.getRow( 1 ) ); print( mat.getRow( 2 ) ); print( mat.getRow( 3 ) ); } inline void print( const Matrix4 & mat, const char * name ) { printf("%s:\n", name); print( mat ); } #endif inline Transform3::Transform3( const Transform3 & tfrm ) { mCol0 = tfrm.mCol0; mCol1 = tfrm.mCol1; mCol2 = tfrm.mCol2; mCol3 = tfrm.mCol3; } inline Transform3::Transform3( float scalar ) { mCol0 = Vector3( scalar ); mCol1 = Vector3( scalar ); mCol2 = Vector3( scalar ); mCol3 = Vector3( scalar ); } inline Transform3::Transform3( const Vector3 & _col0, const Vector3 & _col1, const Vector3 & _col2, const Vector3 & _col3 ) { mCol0 = _col0; mCol1 = _col1; mCol2 = _col2; mCol3 = _col3; } inline Transform3::Transform3( const Matrix3 & tfrm, const Vector3 & translateVec ) { this->setUpper3x3( tfrm ); this->setTranslation( translateVec ); } inline Transform3::Transform3( const Quat & unitQuat, const Vector3 & translateVec ) { this->setUpper3x3( Matrix3( unitQuat ) ); this->setTranslation( translateVec ); } inline Transform3 & Transform3::setCol0( const Vector3 & _col0 ) { mCol0 = _col0; return *this; } inline Transform3 & Transform3::setCol1( const Vector3 & _col1 ) { mCol1 = _col1; return *this; } inline Transform3 & Transform3::setCol2( const Vector3 & _col2 ) { mCol2 = _col2; return *this; } inline Transform3 & Transform3::setCol3( const Vector3 & _col3 ) { mCol3 = _col3; return *this; } inline Transform3 & Transform3::setCol( int col, const Vector3 & vec ) { *(&mCol0 + col) = vec; return *this; } inline Transform3 & Transform3::setRow( int row, const Vector4 & vec ) { mCol0.setElem( row, vec.getElem( 0 ) ); mCol1.setElem( row, vec.getElem( 1 ) ); mCol2.setElem( row, vec.getElem( 2 ) ); mCol3.setElem( row, vec.getElem( 3 ) ); return *this; } inline Transform3 & Transform3::setElem( int col, int row, float val ) { Vector3 tmpV3_0; tmpV3_0 = this->getCol( col ); tmpV3_0.setElem( row, val ); this->setCol( col, tmpV3_0 ); return *this; } inline float Transform3::getElem( int col, int row ) const { return this->getCol( col ).getElem( row ); } inline const Vector3 Transform3::getCol0( ) const { return mCol0; } inline const Vector3 Transform3::getCol1( ) const { return mCol1; } inline const Vector3 Transform3::getCol2( ) const { return mCol2; } inline const Vector3 Transform3::getCol3( ) const { return mCol3; } inline const Vector3 Transform3::getCol( int col ) const { return *(&mCol0 + col); } inline const Vector4 Transform3::getRow( int row ) const { return Vector4( mCol0.getElem( row ), mCol1.getElem( row ), mCol2.getElem( row ), mCol3.getElem( row ) ); } inline Vector3 & Transform3::operator []( int col ) { return *(&mCol0 + col); } inline const Vector3 Transform3::operator []( int col ) const { return *(&mCol0 + col); } inline Transform3 & Transform3::operator =( const Transform3 & tfrm ) { mCol0 = tfrm.mCol0; mCol1 = tfrm.mCol1; mCol2 = tfrm.mCol2; mCol3 = tfrm.mCol3; return *this; } inline const Transform3 inverse( const Transform3 & tfrm ) { Vector3 tmp0, tmp1, tmp2, inv0, inv1, inv2; float detinv; tmp0 = cross( tfrm.getCol1(), tfrm.getCol2() ); tmp1 = cross( tfrm.getCol2(), tfrm.getCol0() ); tmp2 = cross( tfrm.getCol0(), tfrm.getCol1() ); detinv = ( 1.0f / dot( tfrm.getCol2(), tmp2 ) ); inv0 = Vector3( ( tmp0.getX() * detinv ), ( tmp1.getX() * detinv ), ( tmp2.getX() * detinv ) ); inv1 = Vector3( ( tmp0.getY() * detinv ), ( tmp1.getY() * detinv ), ( tmp2.getY() * detinv ) ); inv2 = Vector3( ( tmp0.getZ() * detinv ), ( tmp1.getZ() * detinv ), ( tmp2.getZ() * detinv ) ); return Transform3( inv0, inv1, inv2, Vector3( ( -( ( inv0 * tfrm.getCol3().getX() ) + ( ( inv1 * tfrm.getCol3().getY() ) + ( inv2 * tfrm.getCol3().getZ() ) ) ) ) ) ); } inline const Transform3 orthoInverse( const Transform3 & tfrm ) { Vector3 inv0, inv1, inv2; inv0 = Vector3( tfrm.getCol0().getX(), tfrm.getCol1().getX(), tfrm.getCol2().getX() ); inv1 = Vector3( tfrm.getCol0().getY(), tfrm.getCol1().getY(), tfrm.getCol2().getY() ); inv2 = Vector3( tfrm.getCol0().getZ(), tfrm.getCol1().getZ(), tfrm.getCol2().getZ() ); return Transform3( inv0, inv1, inv2, Vector3( ( -( ( inv0 * tfrm.getCol3().getX() ) + ( ( inv1 * tfrm.getCol3().getY() ) + ( inv2 * tfrm.getCol3().getZ() ) ) ) ) ) ); } inline const Transform3 absPerElem( const Transform3 & tfrm ) { return Transform3( absPerElem( tfrm.getCol0() ), absPerElem( tfrm.getCol1() ), absPerElem( tfrm.getCol2() ), absPerElem( tfrm.getCol3() ) ); } inline const Vector3 Transform3::operator *( const Vector3 & vec ) const { return Vector3( ( ( ( mCol0.getX() * vec.getX() ) + ( mCol1.getX() * vec.getY() ) ) + ( mCol2.getX() * vec.getZ() ) ), ( ( ( mCol0.getY() * vec.getX() ) + ( mCol1.getY() * vec.getY() ) ) + ( mCol2.getY() * vec.getZ() ) ), ( ( ( mCol0.getZ() * vec.getX() ) + ( mCol1.getZ() * vec.getY() ) ) + ( mCol2.getZ() * vec.getZ() ) ) ); } inline const Point3 Transform3::operator *( const Point3 & pnt ) const { return Point3( ( ( ( ( mCol0.getX() * pnt.getX() ) + ( mCol1.getX() * pnt.getY() ) ) + ( mCol2.getX() * pnt.getZ() ) ) + mCol3.getX() ), ( ( ( ( mCol0.getY() * pnt.getX() ) + ( mCol1.getY() * pnt.getY() ) ) + ( mCol2.getY() * pnt.getZ() ) ) + mCol3.getY() ), ( ( ( ( mCol0.getZ() * pnt.getX() ) + ( mCol1.getZ() * pnt.getY() ) ) + ( mCol2.getZ() * pnt.getZ() ) ) + mCol3.getZ() ) ); } inline const Transform3 Transform3::operator *( const Transform3 & tfrm ) const { return Transform3( ( *this * tfrm.mCol0 ), ( *this * tfrm.mCol1 ), ( *this * tfrm.mCol2 ), Vector3( ( *this * Point3( tfrm.mCol3 ) ) ) ); } inline Transform3 & Transform3::operator *=( const Transform3 & tfrm ) { *this = *this * tfrm; return *this; } inline const Transform3 mulPerElem( const Transform3 & tfrm0, const Transform3 & tfrm1 ) { return Transform3( mulPerElem( tfrm0.getCol0(), tfrm1.getCol0() ), mulPerElem( tfrm0.getCol1(), tfrm1.getCol1() ), mulPerElem( tfrm0.getCol2(), tfrm1.getCol2() ), mulPerElem( tfrm0.getCol3(), tfrm1.getCol3() ) ); } inline const Transform3 Transform3::identity( ) { return Transform3( Vector3::xAxis( ), Vector3::yAxis( ), Vector3::zAxis( ), Vector3( 0.0f ) ); } inline Transform3 & Transform3::setUpper3x3( const Matrix3 & tfrm ) { mCol0 = tfrm.getCol0(); mCol1 = tfrm.getCol1(); mCol2 = tfrm.getCol2(); return *this; } inline const Matrix3 Transform3::getUpper3x3( ) const { return Matrix3( mCol0, mCol1, mCol2 ); } inline Transform3 & Transform3::setTranslation( const Vector3 & translateVec ) { mCol3 = translateVec; return *this; } inline const Vector3 Transform3::getTranslation( ) const { return mCol3; } inline const Transform3 Transform3::rotationX( float radians ) { float s, c; s = sinf( radians ); c = cosf( radians ); return Transform3( Vector3::xAxis( ), Vector3( 0.0f, c, s ), Vector3( 0.0f, -s, c ), Vector3( 0.0f ) ); } inline const Transform3 Transform3::rotationY( float radians ) { float s, c; s = sinf( radians ); c = cosf( radians ); return Transform3( Vector3( c, 0.0f, -s ), Vector3::yAxis( ), Vector3( s, 0.0f, c ), Vector3( 0.0f ) ); } inline const Transform3 Transform3::rotationZ( float radians ) { float s, c; s = sinf( radians ); c = cosf( radians ); return Transform3( Vector3( c, s, 0.0f ), Vector3( -s, c, 0.0f ), Vector3::zAxis( ), Vector3( 0.0f ) ); } inline const Transform3 Transform3::rotationZYX( const Vector3 & radiansXYZ ) { float sX, cX, sY, cY, sZ, cZ, tmp0, tmp1; sX = sinf( radiansXYZ.getX() ); cX = cosf( radiansXYZ.getX() ); sY = sinf( radiansXYZ.getY() ); cY = cosf( radiansXYZ.getY() ); sZ = sinf( radiansXYZ.getZ() ); cZ = cosf( radiansXYZ.getZ() ); tmp0 = ( cZ * sY ); tmp1 = ( sZ * sY ); return Transform3( Vector3( ( cZ * cY ), ( sZ * cY ), -sY ), Vector3( ( ( tmp0 * sX ) - ( sZ * cX ) ), ( ( tmp1 * sX ) + ( cZ * cX ) ), ( cY * sX ) ), Vector3( ( ( tmp0 * cX ) + ( sZ * sX ) ), ( ( tmp1 * cX ) - ( cZ * sX ) ), ( cY * cX ) ), Vector3( 0.0f ) ); } inline const Transform3 Transform3::rotation( float radians, const Vector3 & unitVec ) { return Transform3( Matrix3::rotation( radians, unitVec ), Vector3( 0.0f ) ); } inline const Transform3 Transform3::rotation( const Quat & unitQuat ) { return Transform3( Matrix3( unitQuat ), Vector3( 0.0f ) ); } inline const Transform3 Transform3::scale( const Vector3 & scaleVec ) { return Transform3( Vector3( scaleVec.getX(), 0.0f, 0.0f ), Vector3( 0.0f, scaleVec.getY(), 0.0f ), Vector3( 0.0f, 0.0f, scaleVec.getZ() ), Vector3( 0.0f ) ); } inline const Transform3 appendScale( const Transform3 & tfrm, const Vector3 & scaleVec ) { return Transform3( ( tfrm.getCol0() * scaleVec.getX( ) ), ( tfrm.getCol1() * scaleVec.getY( ) ), ( tfrm.getCol2() * scaleVec.getZ( ) ), tfrm.getCol3() ); } inline const Transform3 prependScale( const Vector3 & scaleVec, const Transform3 & tfrm ) { return Transform3( mulPerElem( tfrm.getCol0(), scaleVec ), mulPerElem( tfrm.getCol1(), scaleVec ), mulPerElem( tfrm.getCol2(), scaleVec ), mulPerElem( tfrm.getCol3(), scaleVec ) ); } inline const Transform3 Transform3::translation( const Vector3 & translateVec ) { return Transform3( Vector3::xAxis( ), Vector3::yAxis( ), Vector3::zAxis( ), translateVec ); } inline const Transform3 select( const Transform3 & tfrm0, const Transform3 & tfrm1, bool select1 ) { return Transform3( select( tfrm0.getCol0(), tfrm1.getCol0(), select1 ), select( tfrm0.getCol1(), tfrm1.getCol1(), select1 ), select( tfrm0.getCol2(), tfrm1.getCol2(), select1 ), select( tfrm0.getCol3(), tfrm1.getCol3(), select1 ) ); } #ifdef _VECTORMATH_DEBUG inline void print( const Transform3 & tfrm ) { print( tfrm.getRow( 0 ) ); print( tfrm.getRow( 1 ) ); print( tfrm.getRow( 2 ) ); } inline void print( const Transform3 & tfrm, const char * name ) { printf("%s:\n", name); print( tfrm ); } #endif inline Quat::Quat( const Matrix3 & tfrm ) { float trace, radicand, scale, xx, yx, zx, xy, yy, zy, xz, yz, zz, tmpx, tmpy, tmpz, tmpw, qx, qy, qz, qw; int negTrace, ZgtX, ZgtY, YgtX; int largestXorY, largestYorZ, largestZorX; xx = tfrm.getCol0().getX(); yx = tfrm.getCol0().getY(); zx = tfrm.getCol0().getZ(); xy = tfrm.getCol1().getX(); yy = tfrm.getCol1().getY(); zy = tfrm.getCol1().getZ(); xz = tfrm.getCol2().getX(); yz = tfrm.getCol2().getY(); zz = tfrm.getCol2().getZ(); trace = ( ( xx + yy ) + zz ); negTrace = ( trace < 0.0f ); ZgtX = zz > xx; ZgtY = zz > yy; YgtX = yy > xx; largestXorY = ( !ZgtX || !ZgtY ) && negTrace; largestYorZ = ( YgtX || ZgtX ) && negTrace; largestZorX = ( ZgtY || !YgtX ) && negTrace; if ( largestXorY ) { zz = -zz; xy = -xy; } if ( largestYorZ ) { xx = -xx; yz = -yz; } if ( largestZorX ) { yy = -yy; zx = -zx; } radicand = ( ( ( xx + yy ) + zz ) + 1.0f ); scale = ( 0.5f * ( 1.0f / sqrtf( radicand ) ) ); tmpx = ( ( zy - yz ) * scale ); tmpy = ( ( xz - zx ) * scale ); tmpz = ( ( yx - xy ) * scale ); tmpw = ( radicand * scale ); qx = tmpx; qy = tmpy; qz = tmpz; qw = tmpw; if ( largestXorY ) { qx = tmpw; qy = tmpz; qz = tmpy; qw = tmpx; } if ( largestYorZ ) { tmpx = qx; tmpz = qz; qx = qy; qy = tmpx; qz = qw; qw = tmpz; } mX = qx; mY = qy; mZ = qz; mW = qw; } inline const Matrix3 outer( const Vector3 & tfrm0, const Vector3 & tfrm1 ) { return Matrix3( ( tfrm0 * tfrm1.getX( ) ), ( tfrm0 * tfrm1.getY( ) ), ( tfrm0 * tfrm1.getZ( ) ) ); } inline const Matrix4 outer( const Vector4 & tfrm0, const Vector4 & tfrm1 ) { return Matrix4( ( tfrm0 * tfrm1.getX( ) ), ( tfrm0 * tfrm1.getY( ) ), ( tfrm0 * tfrm1.getZ( ) ), ( tfrm0 * tfrm1.getW( ) ) ); } inline const Vector3 rowMul( const Vector3 & vec, const Matrix3 & mat ) { return Vector3( ( ( ( vec.getX() * mat.getCol0().getX() ) + ( vec.getY() * mat.getCol0().getY() ) ) + ( vec.getZ() * mat.getCol0().getZ() ) ), ( ( ( vec.getX() * mat.getCol1().getX() ) + ( vec.getY() * mat.getCol1().getY() ) ) + ( vec.getZ() * mat.getCol1().getZ() ) ), ( ( ( vec.getX() * mat.getCol2().getX() ) + ( vec.getY() * mat.getCol2().getY() ) ) + ( vec.getZ() * mat.getCol2().getZ() ) ) ); } inline const Matrix3 crossMatrix( const Vector3 & vec ) { return Matrix3( Vector3( 0.0f, vec.getZ(), -vec.getY() ), Vector3( -vec.getZ(), 0.0f, vec.getX() ), Vector3( vec.getY(), -vec.getX(), 0.0f ) ); } inline const Matrix3 crossMatrixMul( const Vector3 & vec, const Matrix3 & mat ) { return Matrix3( cross( vec, mat.getCol0() ), cross( vec, mat.getCol1() ), cross( vec, mat.getCol2() ) ); } } // namespace Aos } // namespace Vectormath #endif critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/vectormath/scalar/cpp/vectormath_aos.h0000644000175000017500000014576011337073000032257 0ustar bobkebobke/* Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Sony Computer Entertainment Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _VECTORMATH_AOS_CPP_SCALAR_H #define _VECTORMATH_AOS_CPP_SCALAR_H #include #ifdef _VECTORMATH_DEBUG #include #endif namespace Vectormath { namespace Aos { //----------------------------------------------------------------------------- // Forward Declarations // class Vector3; class Vector4; class Point3; class Quat; class Matrix3; class Matrix4; class Transform3; // A 3-D vector in array-of-structures format // class Vector3 { float mX; float mY; float mZ; #ifndef __GNUC__ float d; #endif public: // Default constructor; does no initialization // inline Vector3( ) { }; // Copy a 3-D vector // inline Vector3( const Vector3 & vec ); // Construct a 3-D vector from x, y, and z elements // inline Vector3( float x, float y, float z ); // Copy elements from a 3-D point into a 3-D vector // explicit inline Vector3( const Point3 & pnt ); // Set all elements of a 3-D vector to the same scalar value // explicit inline Vector3( float scalar ); // Assign one 3-D vector to another // inline Vector3 & operator =( const Vector3 & vec ); // Set the x element of a 3-D vector // inline Vector3 & setX( float x ); // Set the y element of a 3-D vector // inline Vector3 & setY( float y ); // Set the z element of a 3-D vector // inline Vector3 & setZ( float z ); // Get the x element of a 3-D vector // inline float getX( ) const; // Get the y element of a 3-D vector // inline float getY( ) const; // Get the z element of a 3-D vector // inline float getZ( ) const; // Set an x, y, or z element of a 3-D vector by index // inline Vector3 & setElem( int idx, float value ); // Get an x, y, or z element of a 3-D vector by index // inline float getElem( int idx ) const; // Subscripting operator to set or get an element // inline float & operator []( int idx ); // Subscripting operator to get an element // inline float operator []( int idx ) const; // Add two 3-D vectors // inline const Vector3 operator +( const Vector3 & vec ) const; // Subtract a 3-D vector from another 3-D vector // inline const Vector3 operator -( const Vector3 & vec ) const; // Add a 3-D vector to a 3-D point // inline const Point3 operator +( const Point3 & pnt ) const; // Multiply a 3-D vector by a scalar // inline const Vector3 operator *( float scalar ) const; // Divide a 3-D vector by a scalar // inline const Vector3 operator /( float scalar ) const; // Perform compound assignment and addition with a 3-D vector // inline Vector3 & operator +=( const Vector3 & vec ); // Perform compound assignment and subtraction by a 3-D vector // inline Vector3 & operator -=( const Vector3 & vec ); // Perform compound assignment and multiplication by a scalar // inline Vector3 & operator *=( float scalar ); // Perform compound assignment and division by a scalar // inline Vector3 & operator /=( float scalar ); // Negate all elements of a 3-D vector // inline const Vector3 operator -( ) const; // Construct x axis // static inline const Vector3 xAxis( ); // Construct y axis // static inline const Vector3 yAxis( ); // Construct z axis // static inline const Vector3 zAxis( ); } #ifdef __GNUC__ __attribute__ ((aligned(16))) #endif ; // Multiply a 3-D vector by a scalar // inline const Vector3 operator *( float scalar, const Vector3 & vec ); // Multiply two 3-D vectors per element // inline const Vector3 mulPerElem( const Vector3 & vec0, const Vector3 & vec1 ); // Divide two 3-D vectors per element // NOTE: // Floating-point behavior matches standard library function divf4. // inline const Vector3 divPerElem( const Vector3 & vec0, const Vector3 & vec1 ); // Compute the reciprocal of a 3-D vector per element // NOTE: // Floating-point behavior matches standard library function recipf4. // inline const Vector3 recipPerElem( const Vector3 & vec ); // Compute the square root of a 3-D vector per element // NOTE: // Floating-point behavior matches standard library function sqrtf4. // inline const Vector3 sqrtPerElem( const Vector3 & vec ); // Compute the reciprocal square root of a 3-D vector per element // NOTE: // Floating-point behavior matches standard library function rsqrtf4. // inline const Vector3 rsqrtPerElem( const Vector3 & vec ); // Compute the absolute value of a 3-D vector per element // inline const Vector3 absPerElem( const Vector3 & vec ); // Copy sign from one 3-D vector to another, per element // inline const Vector3 copySignPerElem( const Vector3 & vec0, const Vector3 & vec1 ); // Maximum of two 3-D vectors per element // inline const Vector3 maxPerElem( const Vector3 & vec0, const Vector3 & vec1 ); // Minimum of two 3-D vectors per element // inline const Vector3 minPerElem( const Vector3 & vec0, const Vector3 & vec1 ); // Maximum element of a 3-D vector // inline float maxElem( const Vector3 & vec ); // Minimum element of a 3-D vector // inline float minElem( const Vector3 & vec ); // Compute the sum of all elements of a 3-D vector // inline float sum( const Vector3 & vec ); // Compute the dot product of two 3-D vectors // inline float dot( const Vector3 & vec0, const Vector3 & vec1 ); // Compute the square of the length of a 3-D vector // inline float lengthSqr( const Vector3 & vec ); // Compute the length of a 3-D vector // inline float length( const Vector3 & vec ); // Normalize a 3-D vector // NOTE: // The result is unpredictable when all elements of vec are at or near zero. // inline const Vector3 normalize( const Vector3 & vec ); // Compute cross product of two 3-D vectors // inline const Vector3 cross( const Vector3 & vec0, const Vector3 & vec1 ); // Outer product of two 3-D vectors // inline const Matrix3 outer( const Vector3 & vec0, const Vector3 & vec1 ); // Pre-multiply a row vector by a 3x3 matrix // inline const Vector3 rowMul( const Vector3 & vec, const Matrix3 & mat ); // Cross-product matrix of a 3-D vector // inline const Matrix3 crossMatrix( const Vector3 & vec ); // Create cross-product matrix and multiply // NOTE: // Faster than separately creating a cross-product matrix and multiplying. // inline const Matrix3 crossMatrixMul( const Vector3 & vec, const Matrix3 & mat ); // Linear interpolation between two 3-D vectors // NOTE: // Does not clamp t between 0 and 1. // inline const Vector3 lerp( float t, const Vector3 & vec0, const Vector3 & vec1 ); // Spherical linear interpolation between two 3-D vectors // NOTE: // The result is unpredictable if the vectors point in opposite directions. // Does not clamp t between 0 and 1. // inline const Vector3 slerp( float t, const Vector3 & unitVec0, const Vector3 & unitVec1 ); // Conditionally select between two 3-D vectors // inline const Vector3 select( const Vector3 & vec0, const Vector3 & vec1, bool select1 ); #ifdef _VECTORMATH_DEBUG // Print a 3-D vector // NOTE: // Function is only defined when _VECTORMATH_DEBUG is defined. // inline void print( const Vector3 & vec ); // Print a 3-D vector and an associated string identifier // NOTE: // Function is only defined when _VECTORMATH_DEBUG is defined. // inline void print( const Vector3 & vec, const char * name ); #endif // A 4-D vector in array-of-structures format // class Vector4 { float mX; float mY; float mZ; float mW; public: // Default constructor; does no initialization // inline Vector4( ) { }; // Copy a 4-D vector // inline Vector4( const Vector4 & vec ); // Construct a 4-D vector from x, y, z, and w elements // inline Vector4( float x, float y, float z, float w ); // Construct a 4-D vector from a 3-D vector and a scalar // inline Vector4( const Vector3 & xyz, float w ); // Copy x, y, and z from a 3-D vector into a 4-D vector, and set w to 0 // explicit inline Vector4( const Vector3 & vec ); // Copy x, y, and z from a 3-D point into a 4-D vector, and set w to 1 // explicit inline Vector4( const Point3 & pnt ); // Copy elements from a quaternion into a 4-D vector // explicit inline Vector4( const Quat & quat ); // Set all elements of a 4-D vector to the same scalar value // explicit inline Vector4( float scalar ); // Assign one 4-D vector to another // inline Vector4 & operator =( const Vector4 & vec ); // Set the x, y, and z elements of a 4-D vector // NOTE: // This function does not change the w element. // inline Vector4 & setXYZ( const Vector3 & vec ); // Get the x, y, and z elements of a 4-D vector // inline const Vector3 getXYZ( ) const; // Set the x element of a 4-D vector // inline Vector4 & setX( float x ); // Set the y element of a 4-D vector // inline Vector4 & setY( float y ); // Set the z element of a 4-D vector // inline Vector4 & setZ( float z ); // Set the w element of a 4-D vector // inline Vector4 & setW( float w ); // Get the x element of a 4-D vector // inline float getX( ) const; // Get the y element of a 4-D vector // inline float getY( ) const; // Get the z element of a 4-D vector // inline float getZ( ) const; // Get the w element of a 4-D vector // inline float getW( ) const; // Set an x, y, z, or w element of a 4-D vector by index // inline Vector4 & setElem( int idx, float value ); // Get an x, y, z, or w element of a 4-D vector by index // inline float getElem( int idx ) const; // Subscripting operator to set or get an element // inline float & operator []( int idx ); // Subscripting operator to get an element // inline float operator []( int idx ) const; // Add two 4-D vectors // inline const Vector4 operator +( const Vector4 & vec ) const; // Subtract a 4-D vector from another 4-D vector // inline const Vector4 operator -( const Vector4 & vec ) const; // Multiply a 4-D vector by a scalar // inline const Vector4 operator *( float scalar ) const; // Divide a 4-D vector by a scalar // inline const Vector4 operator /( float scalar ) const; // Perform compound assignment and addition with a 4-D vector // inline Vector4 & operator +=( const Vector4 & vec ); // Perform compound assignment and subtraction by a 4-D vector // inline Vector4 & operator -=( const Vector4 & vec ); // Perform compound assignment and multiplication by a scalar // inline Vector4 & operator *=( float scalar ); // Perform compound assignment and division by a scalar // inline Vector4 & operator /=( float scalar ); // Negate all elements of a 4-D vector // inline const Vector4 operator -( ) const; // Construct x axis // static inline const Vector4 xAxis( ); // Construct y axis // static inline const Vector4 yAxis( ); // Construct z axis // static inline const Vector4 zAxis( ); // Construct w axis // static inline const Vector4 wAxis( ); } #ifdef __GNUC__ __attribute__ ((aligned(16))) #endif ; // Multiply a 4-D vector by a scalar // inline const Vector4 operator *( float scalar, const Vector4 & vec ); // Multiply two 4-D vectors per element // inline const Vector4 mulPerElem( const Vector4 & vec0, const Vector4 & vec1 ); // Divide two 4-D vectors per element // NOTE: // Floating-point behavior matches standard library function divf4. // inline const Vector4 divPerElem( const Vector4 & vec0, const Vector4 & vec1 ); // Compute the reciprocal of a 4-D vector per element // NOTE: // Floating-point behavior matches standard library function recipf4. // inline const Vector4 recipPerElem( const Vector4 & vec ); // Compute the square root of a 4-D vector per element // NOTE: // Floating-point behavior matches standard library function sqrtf4. // inline const Vector4 sqrtPerElem( const Vector4 & vec ); // Compute the reciprocal square root of a 4-D vector per element // NOTE: // Floating-point behavior matches standard library function rsqrtf4. // inline const Vector4 rsqrtPerElem( const Vector4 & vec ); // Compute the absolute value of a 4-D vector per element // inline const Vector4 absPerElem( const Vector4 & vec ); // Copy sign from one 4-D vector to another, per element // inline const Vector4 copySignPerElem( const Vector4 & vec0, const Vector4 & vec1 ); // Maximum of two 4-D vectors per element // inline const Vector4 maxPerElem( const Vector4 & vec0, const Vector4 & vec1 ); // Minimum of two 4-D vectors per element // inline const Vector4 minPerElem( const Vector4 & vec0, const Vector4 & vec1 ); // Maximum element of a 4-D vector // inline float maxElem( const Vector4 & vec ); // Minimum element of a 4-D vector // inline float minElem( const Vector4 & vec ); // Compute the sum of all elements of a 4-D vector // inline float sum( const Vector4 & vec ); // Compute the dot product of two 4-D vectors // inline float dot( const Vector4 & vec0, const Vector4 & vec1 ); // Compute the square of the length of a 4-D vector // inline float lengthSqr( const Vector4 & vec ); // Compute the length of a 4-D vector // inline float length( const Vector4 & vec ); // Normalize a 4-D vector // NOTE: // The result is unpredictable when all elements of vec are at or near zero. // inline const Vector4 normalize( const Vector4 & vec ); // Outer product of two 4-D vectors // inline const Matrix4 outer( const Vector4 & vec0, const Vector4 & vec1 ); // Linear interpolation between two 4-D vectors // NOTE: // Does not clamp t between 0 and 1. // inline const Vector4 lerp( float t, const Vector4 & vec0, const Vector4 & vec1 ); // Spherical linear interpolation between two 4-D vectors // NOTE: // The result is unpredictable if the vectors point in opposite directions. // Does not clamp t between 0 and 1. // inline const Vector4 slerp( float t, const Vector4 & unitVec0, const Vector4 & unitVec1 ); // Conditionally select between two 4-D vectors // inline const Vector4 select( const Vector4 & vec0, const Vector4 & vec1, bool select1 ); #ifdef _VECTORMATH_DEBUG // Print a 4-D vector // NOTE: // Function is only defined when _VECTORMATH_DEBUG is defined. // inline void print( const Vector4 & vec ); // Print a 4-D vector and an associated string identifier // NOTE: // Function is only defined when _VECTORMATH_DEBUG is defined. // inline void print( const Vector4 & vec, const char * name ); #endif // A 3-D point in array-of-structures format // class Point3 { float mX; float mY; float mZ; #ifndef __GNUC__ float d; #endif public: // Default constructor; does no initialization // inline Point3( ) { }; // Copy a 3-D point // inline Point3( const Point3 & pnt ); // Construct a 3-D point from x, y, and z elements // inline Point3( float x, float y, float z ); // Copy elements from a 3-D vector into a 3-D point // explicit inline Point3( const Vector3 & vec ); // Set all elements of a 3-D point to the same scalar value // explicit inline Point3( float scalar ); // Assign one 3-D point to another // inline Point3 & operator =( const Point3 & pnt ); // Set the x element of a 3-D point // inline Point3 & setX( float x ); // Set the y element of a 3-D point // inline Point3 & setY( float y ); // Set the z element of a 3-D point // inline Point3 & setZ( float z ); // Get the x element of a 3-D point // inline float getX( ) const; // Get the y element of a 3-D point // inline float getY( ) const; // Get the z element of a 3-D point // inline float getZ( ) const; // Set an x, y, or z element of a 3-D point by index // inline Point3 & setElem( int idx, float value ); // Get an x, y, or z element of a 3-D point by index // inline float getElem( int idx ) const; // Subscripting operator to set or get an element // inline float & operator []( int idx ); // Subscripting operator to get an element // inline float operator []( int idx ) const; // Subtract a 3-D point from another 3-D point // inline const Vector3 operator -( const Point3 & pnt ) const; // Add a 3-D point to a 3-D vector // inline const Point3 operator +( const Vector3 & vec ) const; // Subtract a 3-D vector from a 3-D point // inline const Point3 operator -( const Vector3 & vec ) const; // Perform compound assignment and addition with a 3-D vector // inline Point3 & operator +=( const Vector3 & vec ); // Perform compound assignment and subtraction by a 3-D vector // inline Point3 & operator -=( const Vector3 & vec ); } #ifdef __GNUC__ __attribute__ ((aligned(16))) #endif ; // Multiply two 3-D points per element // inline const Point3 mulPerElem( const Point3 & pnt0, const Point3 & pnt1 ); // Divide two 3-D points per element // NOTE: // Floating-point behavior matches standard library function divf4. // inline const Point3 divPerElem( const Point3 & pnt0, const Point3 & pnt1 ); // Compute the reciprocal of a 3-D point per element // NOTE: // Floating-point behavior matches standard library function recipf4. // inline const Point3 recipPerElem( const Point3 & pnt ); // Compute the square root of a 3-D point per element // NOTE: // Floating-point behavior matches standard library function sqrtf4. // inline const Point3 sqrtPerElem( const Point3 & pnt ); // Compute the reciprocal square root of a 3-D point per element // NOTE: // Floating-point behavior matches standard library function rsqrtf4. // inline const Point3 rsqrtPerElem( const Point3 & pnt ); // Compute the absolute value of a 3-D point per element // inline const Point3 absPerElem( const Point3 & pnt ); // Copy sign from one 3-D point to another, per element // inline const Point3 copySignPerElem( const Point3 & pnt0, const Point3 & pnt1 ); // Maximum of two 3-D points per element // inline const Point3 maxPerElem( const Point3 & pnt0, const Point3 & pnt1 ); // Minimum of two 3-D points per element // inline const Point3 minPerElem( const Point3 & pnt0, const Point3 & pnt1 ); // Maximum element of a 3-D point // inline float maxElem( const Point3 & pnt ); // Minimum element of a 3-D point // inline float minElem( const Point3 & pnt ); // Compute the sum of all elements of a 3-D point // inline float sum( const Point3 & pnt ); // Apply uniform scale to a 3-D point // inline const Point3 scale( const Point3 & pnt, float scaleVal ); // Apply non-uniform scale to a 3-D point // inline const Point3 scale( const Point3 & pnt, const Vector3 & scaleVec ); // Scalar projection of a 3-D point on a unit-length 3-D vector // inline float projection( const Point3 & pnt, const Vector3 & unitVec ); // Compute the square of the distance of a 3-D point from the coordinate-system origin // inline float distSqrFromOrigin( const Point3 & pnt ); // Compute the distance of a 3-D point from the coordinate-system origin // inline float distFromOrigin( const Point3 & pnt ); // Compute the square of the distance between two 3-D points // inline float distSqr( const Point3 & pnt0, const Point3 & pnt1 ); // Compute the distance between two 3-D points // inline float dist( const Point3 & pnt0, const Point3 & pnt1 ); // Linear interpolation between two 3-D points // NOTE: // Does not clamp t between 0 and 1. // inline const Point3 lerp( float t, const Point3 & pnt0, const Point3 & pnt1 ); // Conditionally select between two 3-D points // inline const Point3 select( const Point3 & pnt0, const Point3 & pnt1, bool select1 ); #ifdef _VECTORMATH_DEBUG // Print a 3-D point // NOTE: // Function is only defined when _VECTORMATH_DEBUG is defined. // inline void print( const Point3 & pnt ); // Print a 3-D point and an associated string identifier // NOTE: // Function is only defined when _VECTORMATH_DEBUG is defined. // inline void print( const Point3 & pnt, const char * name ); #endif // A quaternion in array-of-structures format // class Quat { float mX; float mY; float mZ; float mW; public: // Default constructor; does no initialization // inline Quat( ) { }; // Copy a quaternion // inline Quat( const Quat & quat ); // Construct a quaternion from x, y, z, and w elements // inline Quat( float x, float y, float z, float w ); // Construct a quaternion from a 3-D vector and a scalar // inline Quat( const Vector3 & xyz, float w ); // Copy elements from a 4-D vector into a quaternion // explicit inline Quat( const Vector4 & vec ); // Convert a rotation matrix to a unit-length quaternion // explicit inline Quat( const Matrix3 & rotMat ); // Set all elements of a quaternion to the same scalar value // explicit inline Quat( float scalar ); // Assign one quaternion to another // inline Quat & operator =( const Quat & quat ); // Set the x, y, and z elements of a quaternion // NOTE: // This function does not change the w element. // inline Quat & setXYZ( const Vector3 & vec ); // Get the x, y, and z elements of a quaternion // inline const Vector3 getXYZ( ) const; // Set the x element of a quaternion // inline Quat & setX( float x ); // Set the y element of a quaternion // inline Quat & setY( float y ); // Set the z element of a quaternion // inline Quat & setZ( float z ); // Set the w element of a quaternion // inline Quat & setW( float w ); // Get the x element of a quaternion // inline float getX( ) const; // Get the y element of a quaternion // inline float getY( ) const; // Get the z element of a quaternion // inline float getZ( ) const; // Get the w element of a quaternion // inline float getW( ) const; // Set an x, y, z, or w element of a quaternion by index // inline Quat & setElem( int idx, float value ); // Get an x, y, z, or w element of a quaternion by index // inline float getElem( int idx ) const; // Subscripting operator to set or get an element // inline float & operator []( int idx ); // Subscripting operator to get an element // inline float operator []( int idx ) const; // Add two quaternions // inline const Quat operator +( const Quat & quat ) const; // Subtract a quaternion from another quaternion // inline const Quat operator -( const Quat & quat ) const; // Multiply two quaternions // inline const Quat operator *( const Quat & quat ) const; // Multiply a quaternion by a scalar // inline const Quat operator *( float scalar ) const; // Divide a quaternion by a scalar // inline const Quat operator /( float scalar ) const; // Perform compound assignment and addition with a quaternion // inline Quat & operator +=( const Quat & quat ); // Perform compound assignment and subtraction by a quaternion // inline Quat & operator -=( const Quat & quat ); // Perform compound assignment and multiplication by a quaternion // inline Quat & operator *=( const Quat & quat ); // Perform compound assignment and multiplication by a scalar // inline Quat & operator *=( float scalar ); // Perform compound assignment and division by a scalar // inline Quat & operator /=( float scalar ); // Negate all elements of a quaternion // inline const Quat operator -( ) const; // Construct an identity quaternion // static inline const Quat identity( ); // Construct a quaternion to rotate between two unit-length 3-D vectors // NOTE: // The result is unpredictable if unitVec0 and unitVec1 point in opposite directions. // static inline const Quat rotation( const Vector3 & unitVec0, const Vector3 & unitVec1 ); // Construct a quaternion to rotate around a unit-length 3-D vector // static inline const Quat rotation( float radians, const Vector3 & unitVec ); // Construct a quaternion to rotate around the x axis // static inline const Quat rotationX( float radians ); // Construct a quaternion to rotate around the y axis // static inline const Quat rotationY( float radians ); // Construct a quaternion to rotate around the z axis // static inline const Quat rotationZ( float radians ); } #ifdef __GNUC__ __attribute__ ((aligned(16))) #endif ; // Multiply a quaternion by a scalar // inline const Quat operator *( float scalar, const Quat & quat ); // Compute the conjugate of a quaternion // inline const Quat conj( const Quat & quat ); // Use a unit-length quaternion to rotate a 3-D vector // inline const Vector3 rotate( const Quat & unitQuat, const Vector3 & vec ); // Compute the dot product of two quaternions // inline float dot( const Quat & quat0, const Quat & quat1 ); // Compute the norm of a quaternion // inline float norm( const Quat & quat ); // Compute the length of a quaternion // inline float length( const Quat & quat ); // Normalize a quaternion // NOTE: // The result is unpredictable when all elements of quat are at or near zero. // inline const Quat normalize( const Quat & quat ); // Linear interpolation between two quaternions // NOTE: // Does not clamp t between 0 and 1. // inline const Quat lerp( float t, const Quat & quat0, const Quat & quat1 ); // Spherical linear interpolation between two quaternions // NOTE: // Interpolates along the shortest path between orientations. // Does not clamp t between 0 and 1. // inline const Quat slerp( float t, const Quat & unitQuat0, const Quat & unitQuat1 ); // Spherical quadrangle interpolation // inline const Quat squad( float t, const Quat & unitQuat0, const Quat & unitQuat1, const Quat & unitQuat2, const Quat & unitQuat3 ); // Conditionally select between two quaternions // inline const Quat select( const Quat & quat0, const Quat & quat1, bool select1 ); #ifdef _VECTORMATH_DEBUG // Print a quaternion // NOTE: // Function is only defined when _VECTORMATH_DEBUG is defined. // inline void print( const Quat & quat ); // Print a quaternion and an associated string identifier // NOTE: // Function is only defined when _VECTORMATH_DEBUG is defined. // inline void print( const Quat & quat, const char * name ); #endif // A 3x3 matrix in array-of-structures format // class Matrix3 { Vector3 mCol0; Vector3 mCol1; Vector3 mCol2; public: // Default constructor; does no initialization // inline Matrix3( ) { }; // Copy a 3x3 matrix // inline Matrix3( const Matrix3 & mat ); // Construct a 3x3 matrix containing the specified columns // inline Matrix3( const Vector3 & col0, const Vector3 & col1, const Vector3 & col2 ); // Construct a 3x3 rotation matrix from a unit-length quaternion // explicit inline Matrix3( const Quat & unitQuat ); // Set all elements of a 3x3 matrix to the same scalar value // explicit inline Matrix3( float scalar ); // Assign one 3x3 matrix to another // inline Matrix3 & operator =( const Matrix3 & mat ); // Set column 0 of a 3x3 matrix // inline Matrix3 & setCol0( const Vector3 & col0 ); // Set column 1 of a 3x3 matrix // inline Matrix3 & setCol1( const Vector3 & col1 ); // Set column 2 of a 3x3 matrix // inline Matrix3 & setCol2( const Vector3 & col2 ); // Get column 0 of a 3x3 matrix // inline const Vector3 getCol0( ) const; // Get column 1 of a 3x3 matrix // inline const Vector3 getCol1( ) const; // Get column 2 of a 3x3 matrix // inline const Vector3 getCol2( ) const; // Set the column of a 3x3 matrix referred to by the specified index // inline Matrix3 & setCol( int col, const Vector3 & vec ); // Set the row of a 3x3 matrix referred to by the specified index // inline Matrix3 & setRow( int row, const Vector3 & vec ); // Get the column of a 3x3 matrix referred to by the specified index // inline const Vector3 getCol( int col ) const; // Get the row of a 3x3 matrix referred to by the specified index // inline const Vector3 getRow( int row ) const; // Subscripting operator to set or get a column // inline Vector3 & operator []( int col ); // Subscripting operator to get a column // inline const Vector3 operator []( int col ) const; // Set the element of a 3x3 matrix referred to by column and row indices // inline Matrix3 & setElem( int col, int row, float val ); // Get the element of a 3x3 matrix referred to by column and row indices // inline float getElem( int col, int row ) const; // Add two 3x3 matrices // inline const Matrix3 operator +( const Matrix3 & mat ) const; // Subtract a 3x3 matrix from another 3x3 matrix // inline const Matrix3 operator -( const Matrix3 & mat ) const; // Negate all elements of a 3x3 matrix // inline const Matrix3 operator -( ) const; // Multiply a 3x3 matrix by a scalar // inline const Matrix3 operator *( float scalar ) const; // Multiply a 3x3 matrix by a 3-D vector // inline const Vector3 operator *( const Vector3 & vec ) const; // Multiply two 3x3 matrices // inline const Matrix3 operator *( const Matrix3 & mat ) const; // Perform compound assignment and addition with a 3x3 matrix // inline Matrix3 & operator +=( const Matrix3 & mat ); // Perform compound assignment and subtraction by a 3x3 matrix // inline Matrix3 & operator -=( const Matrix3 & mat ); // Perform compound assignment and multiplication by a scalar // inline Matrix3 & operator *=( float scalar ); // Perform compound assignment and multiplication by a 3x3 matrix // inline Matrix3 & operator *=( const Matrix3 & mat ); // Construct an identity 3x3 matrix // static inline const Matrix3 identity( ); // Construct a 3x3 matrix to rotate around the x axis // static inline const Matrix3 rotationX( float radians ); // Construct a 3x3 matrix to rotate around the y axis // static inline const Matrix3 rotationY( float radians ); // Construct a 3x3 matrix to rotate around the z axis // static inline const Matrix3 rotationZ( float radians ); // Construct a 3x3 matrix to rotate around the x, y, and z axes // static inline const Matrix3 rotationZYX( const Vector3 & radiansXYZ ); // Construct a 3x3 matrix to rotate around a unit-length 3-D vector // static inline const Matrix3 rotation( float radians, const Vector3 & unitVec ); // Construct a rotation matrix from a unit-length quaternion // static inline const Matrix3 rotation( const Quat & unitQuat ); // Construct a 3x3 matrix to perform scaling // static inline const Matrix3 scale( const Vector3 & scaleVec ); }; // Multiply a 3x3 matrix by a scalar // inline const Matrix3 operator *( float scalar, const Matrix3 & mat ); // Append (post-multiply) a scale transformation to a 3x3 matrix // NOTE: // Faster than creating and multiplying a scale transformation matrix. // inline const Matrix3 appendScale( const Matrix3 & mat, const Vector3 & scaleVec ); // Prepend (pre-multiply) a scale transformation to a 3x3 matrix // NOTE: // Faster than creating and multiplying a scale transformation matrix. // inline const Matrix3 prependScale( const Vector3 & scaleVec, const Matrix3 & mat ); // Multiply two 3x3 matrices per element // inline const Matrix3 mulPerElem( const Matrix3 & mat0, const Matrix3 & mat1 ); // Compute the absolute value of a 3x3 matrix per element // inline const Matrix3 absPerElem( const Matrix3 & mat ); // Transpose of a 3x3 matrix // inline const Matrix3 transpose( const Matrix3 & mat ); // Compute the inverse of a 3x3 matrix // NOTE: // Result is unpredictable when the determinant of mat is equal to or near 0. // inline const Matrix3 inverse( const Matrix3 & mat ); // Determinant of a 3x3 matrix // inline float determinant( const Matrix3 & mat ); // Conditionally select between two 3x3 matrices // inline const Matrix3 select( const Matrix3 & mat0, const Matrix3 & mat1, bool select1 ); #ifdef _VECTORMATH_DEBUG // Print a 3x3 matrix // NOTE: // Function is only defined when _VECTORMATH_DEBUG is defined. // inline void print( const Matrix3 & mat ); // Print a 3x3 matrix and an associated string identifier // NOTE: // Function is only defined when _VECTORMATH_DEBUG is defined. // inline void print( const Matrix3 & mat, const char * name ); #endif // A 4x4 matrix in array-of-structures format // class Matrix4 { Vector4 mCol0; Vector4 mCol1; Vector4 mCol2; Vector4 mCol3; public: // Default constructor; does no initialization // inline Matrix4( ) { }; // Copy a 4x4 matrix // inline Matrix4( const Matrix4 & mat ); // Construct a 4x4 matrix containing the specified columns // inline Matrix4( const Vector4 & col0, const Vector4 & col1, const Vector4 & col2, const Vector4 & col3 ); // Construct a 4x4 matrix from a 3x4 transformation matrix // explicit inline Matrix4( const Transform3 & mat ); // Construct a 4x4 matrix from a 3x3 matrix and a 3-D vector // inline Matrix4( const Matrix3 & mat, const Vector3 & translateVec ); // Construct a 4x4 matrix from a unit-length quaternion and a 3-D vector // inline Matrix4( const Quat & unitQuat, const Vector3 & translateVec ); // Set all elements of a 4x4 matrix to the same scalar value // explicit inline Matrix4( float scalar ); // Assign one 4x4 matrix to another // inline Matrix4 & operator =( const Matrix4 & mat ); // Set the upper-left 3x3 submatrix // NOTE: // This function does not change the bottom row elements. // inline Matrix4 & setUpper3x3( const Matrix3 & mat3 ); // Get the upper-left 3x3 submatrix of a 4x4 matrix // inline const Matrix3 getUpper3x3( ) const; // Set translation component // NOTE: // This function does not change the bottom row elements. // inline Matrix4 & setTranslation( const Vector3 & translateVec ); // Get the translation component of a 4x4 matrix // inline const Vector3 getTranslation( ) const; // Set column 0 of a 4x4 matrix // inline Matrix4 & setCol0( const Vector4 & col0 ); // Set column 1 of a 4x4 matrix // inline Matrix4 & setCol1( const Vector4 & col1 ); // Set column 2 of a 4x4 matrix // inline Matrix4 & setCol2( const Vector4 & col2 ); // Set column 3 of a 4x4 matrix // inline Matrix4 & setCol3( const Vector4 & col3 ); // Get column 0 of a 4x4 matrix // inline const Vector4 getCol0( ) const; // Get column 1 of a 4x4 matrix // inline const Vector4 getCol1( ) const; // Get column 2 of a 4x4 matrix // inline const Vector4 getCol2( ) const; // Get column 3 of a 4x4 matrix // inline const Vector4 getCol3( ) const; // Set the column of a 4x4 matrix referred to by the specified index // inline Matrix4 & setCol( int col, const Vector4 & vec ); // Set the row of a 4x4 matrix referred to by the specified index // inline Matrix4 & setRow( int row, const Vector4 & vec ); // Get the column of a 4x4 matrix referred to by the specified index // inline const Vector4 getCol( int col ) const; // Get the row of a 4x4 matrix referred to by the specified index // inline const Vector4 getRow( int row ) const; // Subscripting operator to set or get a column // inline Vector4 & operator []( int col ); // Subscripting operator to get a column // inline const Vector4 operator []( int col ) const; // Set the element of a 4x4 matrix referred to by column and row indices // inline Matrix4 & setElem( int col, int row, float val ); // Get the element of a 4x4 matrix referred to by column and row indices // inline float getElem( int col, int row ) const; // Add two 4x4 matrices // inline const Matrix4 operator +( const Matrix4 & mat ) const; // Subtract a 4x4 matrix from another 4x4 matrix // inline const Matrix4 operator -( const Matrix4 & mat ) const; // Negate all elements of a 4x4 matrix // inline const Matrix4 operator -( ) const; // Multiply a 4x4 matrix by a scalar // inline const Matrix4 operator *( float scalar ) const; // Multiply a 4x4 matrix by a 4-D vector // inline const Vector4 operator *( const Vector4 & vec ) const; // Multiply a 4x4 matrix by a 3-D vector // inline const Vector4 operator *( const Vector3 & vec ) const; // Multiply a 4x4 matrix by a 3-D point // inline const Vector4 operator *( const Point3 & pnt ) const; // Multiply two 4x4 matrices // inline const Matrix4 operator *( const Matrix4 & mat ) const; // Multiply a 4x4 matrix by a 3x4 transformation matrix // inline const Matrix4 operator *( const Transform3 & tfrm ) const; // Perform compound assignment and addition with a 4x4 matrix // inline Matrix4 & operator +=( const Matrix4 & mat ); // Perform compound assignment and subtraction by a 4x4 matrix // inline Matrix4 & operator -=( const Matrix4 & mat ); // Perform compound assignment and multiplication by a scalar // inline Matrix4 & operator *=( float scalar ); // Perform compound assignment and multiplication by a 4x4 matrix // inline Matrix4 & operator *=( const Matrix4 & mat ); // Perform compound assignment and multiplication by a 3x4 transformation matrix // inline Matrix4 & operator *=( const Transform3 & tfrm ); // Construct an identity 4x4 matrix // static inline const Matrix4 identity( ); // Construct a 4x4 matrix to rotate around the x axis // static inline const Matrix4 rotationX( float radians ); // Construct a 4x4 matrix to rotate around the y axis // static inline const Matrix4 rotationY( float radians ); // Construct a 4x4 matrix to rotate around the z axis // static inline const Matrix4 rotationZ( float radians ); // Construct a 4x4 matrix to rotate around the x, y, and z axes // static inline const Matrix4 rotationZYX( const Vector3 & radiansXYZ ); // Construct a 4x4 matrix to rotate around a unit-length 3-D vector // static inline const Matrix4 rotation( float radians, const Vector3 & unitVec ); // Construct a rotation matrix from a unit-length quaternion // static inline const Matrix4 rotation( const Quat & unitQuat ); // Construct a 4x4 matrix to perform scaling // static inline const Matrix4 scale( const Vector3 & scaleVec ); // Construct a 4x4 matrix to perform translation // static inline const Matrix4 translation( const Vector3 & translateVec ); // Construct viewing matrix based on eye position, position looked at, and up direction // static inline const Matrix4 lookAt( const Point3 & eyePos, const Point3 & lookAtPos, const Vector3 & upVec ); // Construct a perspective projection matrix // static inline const Matrix4 perspective( float fovyRadians, float aspect, float zNear, float zFar ); // Construct a perspective projection matrix based on frustum // static inline const Matrix4 frustum( float left, float right, float bottom, float top, float zNear, float zFar ); // Construct an orthographic projection matrix // static inline const Matrix4 orthographic( float left, float right, float bottom, float top, float zNear, float zFar ); }; // Multiply a 4x4 matrix by a scalar // inline const Matrix4 operator *( float scalar, const Matrix4 & mat ); // Append (post-multiply) a scale transformation to a 4x4 matrix // NOTE: // Faster than creating and multiplying a scale transformation matrix. // inline const Matrix4 appendScale( const Matrix4 & mat, const Vector3 & scaleVec ); // Prepend (pre-multiply) a scale transformation to a 4x4 matrix // NOTE: // Faster than creating and multiplying a scale transformation matrix. // inline const Matrix4 prependScale( const Vector3 & scaleVec, const Matrix4 & mat ); // Multiply two 4x4 matrices per element // inline const Matrix4 mulPerElem( const Matrix4 & mat0, const Matrix4 & mat1 ); // Compute the absolute value of a 4x4 matrix per element // inline const Matrix4 absPerElem( const Matrix4 & mat ); // Transpose of a 4x4 matrix // inline const Matrix4 transpose( const Matrix4 & mat ); // Compute the inverse of a 4x4 matrix // NOTE: // Result is unpredictable when the determinant of mat is equal to or near 0. // inline const Matrix4 inverse( const Matrix4 & mat ); // Compute the inverse of a 4x4 matrix, which is expected to be an affine matrix // NOTE: // This can be used to achieve better performance than a general inverse when the specified 4x4 matrix meets the given restrictions. The result is unpredictable when the determinant of mat is equal to or near 0. // inline const Matrix4 affineInverse( const Matrix4 & mat ); // Compute the inverse of a 4x4 matrix, which is expected to be an affine matrix with an orthogonal upper-left 3x3 submatrix // NOTE: // This can be used to achieve better performance than a general inverse when the specified 4x4 matrix meets the given restrictions. // inline const Matrix4 orthoInverse( const Matrix4 & mat ); // Determinant of a 4x4 matrix // inline float determinant( const Matrix4 & mat ); // Conditionally select between two 4x4 matrices // inline const Matrix4 select( const Matrix4 & mat0, const Matrix4 & mat1, bool select1 ); #ifdef _VECTORMATH_DEBUG // Print a 4x4 matrix // NOTE: // Function is only defined when _VECTORMATH_DEBUG is defined. // inline void print( const Matrix4 & mat ); // Print a 4x4 matrix and an associated string identifier // NOTE: // Function is only defined when _VECTORMATH_DEBUG is defined. // inline void print( const Matrix4 & mat, const char * name ); #endif // A 3x4 transformation matrix in array-of-structures format // class Transform3 { Vector3 mCol0; Vector3 mCol1; Vector3 mCol2; Vector3 mCol3; public: // Default constructor; does no initialization // inline Transform3( ) { }; // Copy a 3x4 transformation matrix // inline Transform3( const Transform3 & tfrm ); // Construct a 3x4 transformation matrix containing the specified columns // inline Transform3( const Vector3 & col0, const Vector3 & col1, const Vector3 & col2, const Vector3 & col3 ); // Construct a 3x4 transformation matrix from a 3x3 matrix and a 3-D vector // inline Transform3( const Matrix3 & tfrm, const Vector3 & translateVec ); // Construct a 3x4 transformation matrix from a unit-length quaternion and a 3-D vector // inline Transform3( const Quat & unitQuat, const Vector3 & translateVec ); // Set all elements of a 3x4 transformation matrix to the same scalar value // explicit inline Transform3( float scalar ); // Assign one 3x4 transformation matrix to another // inline Transform3 & operator =( const Transform3 & tfrm ); // Set the upper-left 3x3 submatrix // inline Transform3 & setUpper3x3( const Matrix3 & mat3 ); // Get the upper-left 3x3 submatrix of a 3x4 transformation matrix // inline const Matrix3 getUpper3x3( ) const; // Set translation component // inline Transform3 & setTranslation( const Vector3 & translateVec ); // Get the translation component of a 3x4 transformation matrix // inline const Vector3 getTranslation( ) const; // Set column 0 of a 3x4 transformation matrix // inline Transform3 & setCol0( const Vector3 & col0 ); // Set column 1 of a 3x4 transformation matrix // inline Transform3 & setCol1( const Vector3 & col1 ); // Set column 2 of a 3x4 transformation matrix // inline Transform3 & setCol2( const Vector3 & col2 ); // Set column 3 of a 3x4 transformation matrix // inline Transform3 & setCol3( const Vector3 & col3 ); // Get column 0 of a 3x4 transformation matrix // inline const Vector3 getCol0( ) const; // Get column 1 of a 3x4 transformation matrix // inline const Vector3 getCol1( ) const; // Get column 2 of a 3x4 transformation matrix // inline const Vector3 getCol2( ) const; // Get column 3 of a 3x4 transformation matrix // inline const Vector3 getCol3( ) const; // Set the column of a 3x4 transformation matrix referred to by the specified index // inline Transform3 & setCol( int col, const Vector3 & vec ); // Set the row of a 3x4 transformation matrix referred to by the specified index // inline Transform3 & setRow( int row, const Vector4 & vec ); // Get the column of a 3x4 transformation matrix referred to by the specified index // inline const Vector3 getCol( int col ) const; // Get the row of a 3x4 transformation matrix referred to by the specified index // inline const Vector4 getRow( int row ) const; // Subscripting operator to set or get a column // inline Vector3 & operator []( int col ); // Subscripting operator to get a column // inline const Vector3 operator []( int col ) const; // Set the element of a 3x4 transformation matrix referred to by column and row indices // inline Transform3 & setElem( int col, int row, float val ); // Get the element of a 3x4 transformation matrix referred to by column and row indices // inline float getElem( int col, int row ) const; // Multiply a 3x4 transformation matrix by a 3-D vector // inline const Vector3 operator *( const Vector3 & vec ) const; // Multiply a 3x4 transformation matrix by a 3-D point // inline const Point3 operator *( const Point3 & pnt ) const; // Multiply two 3x4 transformation matrices // inline const Transform3 operator *( const Transform3 & tfrm ) const; // Perform compound assignment and multiplication by a 3x4 transformation matrix // inline Transform3 & operator *=( const Transform3 & tfrm ); // Construct an identity 3x4 transformation matrix // static inline const Transform3 identity( ); // Construct a 3x4 transformation matrix to rotate around the x axis // static inline const Transform3 rotationX( float radians ); // Construct a 3x4 transformation matrix to rotate around the y axis // static inline const Transform3 rotationY( float radians ); // Construct a 3x4 transformation matrix to rotate around the z axis // static inline const Transform3 rotationZ( float radians ); // Construct a 3x4 transformation matrix to rotate around the x, y, and z axes // static inline const Transform3 rotationZYX( const Vector3 & radiansXYZ ); // Construct a 3x4 transformation matrix to rotate around a unit-length 3-D vector // static inline const Transform3 rotation( float radians, const Vector3 & unitVec ); // Construct a rotation matrix from a unit-length quaternion // static inline const Transform3 rotation( const Quat & unitQuat ); // Construct a 3x4 transformation matrix to perform scaling // static inline const Transform3 scale( const Vector3 & scaleVec ); // Construct a 3x4 transformation matrix to perform translation // static inline const Transform3 translation( const Vector3 & translateVec ); }; // Append (post-multiply) a scale transformation to a 3x4 transformation matrix // NOTE: // Faster than creating and multiplying a scale transformation matrix. // inline const Transform3 appendScale( const Transform3 & tfrm, const Vector3 & scaleVec ); // Prepend (pre-multiply) a scale transformation to a 3x4 transformation matrix // NOTE: // Faster than creating and multiplying a scale transformation matrix. // inline const Transform3 prependScale( const Vector3 & scaleVec, const Transform3 & tfrm ); // Multiply two 3x4 transformation matrices per element // inline const Transform3 mulPerElem( const Transform3 & tfrm0, const Transform3 & tfrm1 ); // Compute the absolute value of a 3x4 transformation matrix per element // inline const Transform3 absPerElem( const Transform3 & tfrm ); // Inverse of a 3x4 transformation matrix // NOTE: // Result is unpredictable when the determinant of the left 3x3 submatrix is equal to or near 0. // inline const Transform3 inverse( const Transform3 & tfrm ); // Compute the inverse of a 3x4 transformation matrix, expected to have an orthogonal upper-left 3x3 submatrix // NOTE: // This can be used to achieve better performance than a general inverse when the specified 3x4 transformation matrix meets the given restrictions. // inline const Transform3 orthoInverse( const Transform3 & tfrm ); // Conditionally select between two 3x4 transformation matrices // inline const Transform3 select( const Transform3 & tfrm0, const Transform3 & tfrm1, bool select1 ); #ifdef _VECTORMATH_DEBUG // Print a 3x4 transformation matrix // NOTE: // Function is only defined when _VECTORMATH_DEBUG is defined. // inline void print( const Transform3 & tfrm ); // Print a 3x4 transformation matrix and an associated string identifier // NOTE: // Function is only defined when _VECTORMATH_DEBUG is defined. // inline void print( const Transform3 & tfrm, const char * name ); #endif } // namespace Aos } // namespace Vectormath #include "vec_aos.h" #include "quat_aos.h" #include "mat_aos.h" #endif critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/vectormath/scalar/cpp/quat_aos.h0000644000175000017500000002507511337073000031051 0ustar bobkebobke/* Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Sony Computer Entertainment Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _VECTORMATH_QUAT_AOS_CPP_H #define _VECTORMATH_QUAT_AOS_CPP_H //----------------------------------------------------------------------------- // Definitions #ifndef _VECTORMATH_INTERNAL_FUNCTIONS #define _VECTORMATH_INTERNAL_FUNCTIONS #endif namespace Vectormath { namespace Aos { inline Quat::Quat( const Quat & quat ) { mX = quat.mX; mY = quat.mY; mZ = quat.mZ; mW = quat.mW; } inline Quat::Quat( float _x, float _y, float _z, float _w ) { mX = _x; mY = _y; mZ = _z; mW = _w; } inline Quat::Quat( const Vector3 & xyz, float _w ) { this->setXYZ( xyz ); this->setW( _w ); } inline Quat::Quat( const Vector4 & vec ) { mX = vec.getX(); mY = vec.getY(); mZ = vec.getZ(); mW = vec.getW(); } inline Quat::Quat( float scalar ) { mX = scalar; mY = scalar; mZ = scalar; mW = scalar; } inline const Quat Quat::identity( ) { return Quat( 0.0f, 0.0f, 0.0f, 1.0f ); } inline const Quat lerp( float t, const Quat & quat0, const Quat & quat1 ) { return ( quat0 + ( ( quat1 - quat0 ) * t ) ); } inline const Quat slerp( float t, const Quat & unitQuat0, const Quat & unitQuat1 ) { Quat start; float recipSinAngle, scale0, scale1, cosAngle, angle; cosAngle = dot( unitQuat0, unitQuat1 ); if ( cosAngle < 0.0f ) { cosAngle = -cosAngle; start = ( -unitQuat0 ); } else { start = unitQuat0; } if ( cosAngle < _VECTORMATH_SLERP_TOL ) { angle = acosf( cosAngle ); recipSinAngle = ( 1.0f / sinf( angle ) ); scale0 = ( sinf( ( ( 1.0f - t ) * angle ) ) * recipSinAngle ); scale1 = ( sinf( ( t * angle ) ) * recipSinAngle ); } else { scale0 = ( 1.0f - t ); scale1 = t; } return ( ( start * scale0 ) + ( unitQuat1 * scale1 ) ); } inline const Quat squad( float t, const Quat & unitQuat0, const Quat & unitQuat1, const Quat & unitQuat2, const Quat & unitQuat3 ) { Quat tmp0, tmp1; tmp0 = slerp( t, unitQuat0, unitQuat3 ); tmp1 = slerp( t, unitQuat1, unitQuat2 ); return slerp( ( ( 2.0f * t ) * ( 1.0f - t ) ), tmp0, tmp1 ); } inline Quat & Quat::operator =( const Quat & quat ) { mX = quat.mX; mY = quat.mY; mZ = quat.mZ; mW = quat.mW; return *this; } inline Quat & Quat::setXYZ( const Vector3 & vec ) { mX = vec.getX(); mY = vec.getY(); mZ = vec.getZ(); return *this; } inline const Vector3 Quat::getXYZ( ) const { return Vector3( mX, mY, mZ ); } inline Quat & Quat::setX( float _x ) { mX = _x; return *this; } inline float Quat::getX( ) const { return mX; } inline Quat & Quat::setY( float _y ) { mY = _y; return *this; } inline float Quat::getY( ) const { return mY; } inline Quat & Quat::setZ( float _z ) { mZ = _z; return *this; } inline float Quat::getZ( ) const { return mZ; } inline Quat & Quat::setW( float _w ) { mW = _w; return *this; } inline float Quat::getW( ) const { return mW; } inline Quat & Quat::setElem( int idx, float value ) { *(&mX + idx) = value; return *this; } inline float Quat::getElem( int idx ) const { return *(&mX + idx); } inline float & Quat::operator []( int idx ) { return *(&mX + idx); } inline float Quat::operator []( int idx ) const { return *(&mX + idx); } inline const Quat Quat::operator +( const Quat & quat ) const { return Quat( ( mX + quat.mX ), ( mY + quat.mY ), ( mZ + quat.mZ ), ( mW + quat.mW ) ); } inline const Quat Quat::operator -( const Quat & quat ) const { return Quat( ( mX - quat.mX ), ( mY - quat.mY ), ( mZ - quat.mZ ), ( mW - quat.mW ) ); } inline const Quat Quat::operator *( float scalar ) const { return Quat( ( mX * scalar ), ( mY * scalar ), ( mZ * scalar ), ( mW * scalar ) ); } inline Quat & Quat::operator +=( const Quat & quat ) { *this = *this + quat; return *this; } inline Quat & Quat::operator -=( const Quat & quat ) { *this = *this - quat; return *this; } inline Quat & Quat::operator *=( float scalar ) { *this = *this * scalar; return *this; } inline const Quat Quat::operator /( float scalar ) const { return Quat( ( mX / scalar ), ( mY / scalar ), ( mZ / scalar ), ( mW / scalar ) ); } inline Quat & Quat::operator /=( float scalar ) { *this = *this / scalar; return *this; } inline const Quat Quat::operator -( ) const { return Quat( -mX, -mY, -mZ, -mW ); } inline const Quat operator *( float scalar, const Quat & quat ) { return quat * scalar; } inline float dot( const Quat & quat0, const Quat & quat1 ) { float result; result = ( quat0.getX() * quat1.getX() ); result = ( result + ( quat0.getY() * quat1.getY() ) ); result = ( result + ( quat0.getZ() * quat1.getZ() ) ); result = ( result + ( quat0.getW() * quat1.getW() ) ); return result; } inline float norm( const Quat & quat ) { float result; result = ( quat.getX() * quat.getX() ); result = ( result + ( quat.getY() * quat.getY() ) ); result = ( result + ( quat.getZ() * quat.getZ() ) ); result = ( result + ( quat.getW() * quat.getW() ) ); return result; } inline float length( const Quat & quat ) { return sqrtf( norm( quat ) ); } inline const Quat normalize( const Quat & quat ) { float lenSqr, lenInv; lenSqr = norm( quat ); lenInv = ( 1.0f / sqrtf( lenSqr ) ); return Quat( ( quat.getX() * lenInv ), ( quat.getY() * lenInv ), ( quat.getZ() * lenInv ), ( quat.getW() * lenInv ) ); } inline const Quat Quat::rotation( const Vector3 & unitVec0, const Vector3 & unitVec1 ) { float cosHalfAngleX2, recipCosHalfAngleX2; cosHalfAngleX2 = sqrtf( ( 2.0f * ( 1.0f + dot( unitVec0, unitVec1 ) ) ) ); recipCosHalfAngleX2 = ( 1.0f / cosHalfAngleX2 ); return Quat( ( cross( unitVec0, unitVec1 ) * recipCosHalfAngleX2 ), ( cosHalfAngleX2 * 0.5f ) ); } inline const Quat Quat::rotation( float radians, const Vector3 & unitVec ) { float s, c, angle; angle = ( radians * 0.5f ); s = sinf( angle ); c = cosf( angle ); return Quat( ( unitVec * s ), c ); } inline const Quat Quat::rotationX( float radians ) { float s, c, angle; angle = ( radians * 0.5f ); s = sinf( angle ); c = cosf( angle ); return Quat( s, 0.0f, 0.0f, c ); } inline const Quat Quat::rotationY( float radians ) { float s, c, angle; angle = ( radians * 0.5f ); s = sinf( angle ); c = cosf( angle ); return Quat( 0.0f, s, 0.0f, c ); } inline const Quat Quat::rotationZ( float radians ) { float s, c, angle; angle = ( radians * 0.5f ); s = sinf( angle ); c = cosf( angle ); return Quat( 0.0f, 0.0f, s, c ); } inline const Quat Quat::operator *( const Quat & quat ) const { return Quat( ( ( ( ( mW * quat.mX ) + ( mX * quat.mW ) ) + ( mY * quat.mZ ) ) - ( mZ * quat.mY ) ), ( ( ( ( mW * quat.mY ) + ( mY * quat.mW ) ) + ( mZ * quat.mX ) ) - ( mX * quat.mZ ) ), ( ( ( ( mW * quat.mZ ) + ( mZ * quat.mW ) ) + ( mX * quat.mY ) ) - ( mY * quat.mX ) ), ( ( ( ( mW * quat.mW ) - ( mX * quat.mX ) ) - ( mY * quat.mY ) ) - ( mZ * quat.mZ ) ) ); } inline Quat & Quat::operator *=( const Quat & quat ) { *this = *this * quat; return *this; } inline const Vector3 rotate( const Quat & quat, const Vector3 & vec ) { float tmpX, tmpY, tmpZ, tmpW; tmpX = ( ( ( quat.getW() * vec.getX() ) + ( quat.getY() * vec.getZ() ) ) - ( quat.getZ() * vec.getY() ) ); tmpY = ( ( ( quat.getW() * vec.getY() ) + ( quat.getZ() * vec.getX() ) ) - ( quat.getX() * vec.getZ() ) ); tmpZ = ( ( ( quat.getW() * vec.getZ() ) + ( quat.getX() * vec.getY() ) ) - ( quat.getY() * vec.getX() ) ); tmpW = ( ( ( quat.getX() * vec.getX() ) + ( quat.getY() * vec.getY() ) ) + ( quat.getZ() * vec.getZ() ) ); return Vector3( ( ( ( ( tmpW * quat.getX() ) + ( tmpX * quat.getW() ) ) - ( tmpY * quat.getZ() ) ) + ( tmpZ * quat.getY() ) ), ( ( ( ( tmpW * quat.getY() ) + ( tmpY * quat.getW() ) ) - ( tmpZ * quat.getX() ) ) + ( tmpX * quat.getZ() ) ), ( ( ( ( tmpW * quat.getZ() ) + ( tmpZ * quat.getW() ) ) - ( tmpX * quat.getY() ) ) + ( tmpY * quat.getX() ) ) ); } inline const Quat conj( const Quat & quat ) { return Quat( -quat.getX(), -quat.getY(), -quat.getZ(), quat.getW() ); } inline const Quat select( const Quat & quat0, const Quat & quat1, bool select1 ) { return Quat( ( select1 )? quat1.getX() : quat0.getX(), ( select1 )? quat1.getY() : quat0.getY(), ( select1 )? quat1.getZ() : quat0.getZ(), ( select1 )? quat1.getW() : quat0.getW() ); } #ifdef _VECTORMATH_DEBUG inline void print( const Quat & quat ) { printf( "( %f %f %f %f )\n", quat.getX(), quat.getY(), quat.getZ(), quat.getW() ); } inline void print( const Quat & quat, const char * name ) { printf( "%s: ( %f %f %f %f )\n", name, quat.getX(), quat.getY(), quat.getZ(), quat.getW() ); } #endif } // namespace Aos } // namespace Vectormath #endif critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/vectormath/scalar/cpp/vec_aos.h0000644000175000017500000006321111337073000030646 0ustar bobkebobke/* Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Sony Computer Entertainment Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef _VECTORMATH_VEC_AOS_CPP_H #define _VECTORMATH_VEC_AOS_CPP_H //----------------------------------------------------------------------------- // Constants #define _VECTORMATH_SLERP_TOL 0.999f //----------------------------------------------------------------------------- // Definitions #ifndef _VECTORMATH_INTERNAL_FUNCTIONS #define _VECTORMATH_INTERNAL_FUNCTIONS #endif namespace Vectormath { namespace Aos { inline Vector3::Vector3( const Vector3 & vec ) { mX = vec.mX; mY = vec.mY; mZ = vec.mZ; } inline Vector3::Vector3( float _x, float _y, float _z ) { mX = _x; mY = _y; mZ = _z; } inline Vector3::Vector3( const Point3 & pnt ) { mX = pnt.getX(); mY = pnt.getY(); mZ = pnt.getZ(); } inline Vector3::Vector3( float scalar ) { mX = scalar; mY = scalar; mZ = scalar; } inline const Vector3 Vector3::xAxis( ) { return Vector3( 1.0f, 0.0f, 0.0f ); } inline const Vector3 Vector3::yAxis( ) { return Vector3( 0.0f, 1.0f, 0.0f ); } inline const Vector3 Vector3::zAxis( ) { return Vector3( 0.0f, 0.0f, 1.0f ); } inline const Vector3 lerp( float t, const Vector3 & vec0, const Vector3 & vec1 ) { return ( vec0 + ( ( vec1 - vec0 ) * t ) ); } inline const Vector3 slerp( float t, const Vector3 & unitVec0, const Vector3 & unitVec1 ) { float recipSinAngle, scale0, scale1, cosAngle, angle; cosAngle = dot( unitVec0, unitVec1 ); if ( cosAngle < _VECTORMATH_SLERP_TOL ) { angle = acosf( cosAngle ); recipSinAngle = ( 1.0f / sinf( angle ) ); scale0 = ( sinf( ( ( 1.0f - t ) * angle ) ) * recipSinAngle ); scale1 = ( sinf( ( t * angle ) ) * recipSinAngle ); } else { scale0 = ( 1.0f - t ); scale1 = t; } return ( ( unitVec0 * scale0 ) + ( unitVec1 * scale1 ) ); } inline Vector3 & Vector3::operator =( const Vector3 & vec ) { mX = vec.mX; mY = vec.mY; mZ = vec.mZ; return *this; } inline Vector3 & Vector3::setX( float _x ) { mX = _x; return *this; } inline float Vector3::getX( ) const { return mX; } inline Vector3 & Vector3::setY( float _y ) { mY = _y; return *this; } inline float Vector3::getY( ) const { return mY; } inline Vector3 & Vector3::setZ( float _z ) { mZ = _z; return *this; } inline float Vector3::getZ( ) const { return mZ; } inline Vector3 & Vector3::setElem( int idx, float value ) { *(&mX + idx) = value; return *this; } inline float Vector3::getElem( int idx ) const { return *(&mX + idx); } inline float & Vector3::operator []( int idx ) { return *(&mX + idx); } inline float Vector3::operator []( int idx ) const { return *(&mX + idx); } inline const Vector3 Vector3::operator +( const Vector3 & vec ) const { return Vector3( ( mX + vec.mX ), ( mY + vec.mY ), ( mZ + vec.mZ ) ); } inline const Vector3 Vector3::operator -( const Vector3 & vec ) const { return Vector3( ( mX - vec.mX ), ( mY - vec.mY ), ( mZ - vec.mZ ) ); } inline const Point3 Vector3::operator +( const Point3 & pnt ) const { return Point3( ( mX + pnt.getX() ), ( mY + pnt.getY() ), ( mZ + pnt.getZ() ) ); } inline const Vector3 Vector3::operator *( float scalar ) const { return Vector3( ( mX * scalar ), ( mY * scalar ), ( mZ * scalar ) ); } inline Vector3 & Vector3::operator +=( const Vector3 & vec ) { *this = *this + vec; return *this; } inline Vector3 & Vector3::operator -=( const Vector3 & vec ) { *this = *this - vec; return *this; } inline Vector3 & Vector3::operator *=( float scalar ) { *this = *this * scalar; return *this; } inline const Vector3 Vector3::operator /( float scalar ) const { return Vector3( ( mX / scalar ), ( mY / scalar ), ( mZ / scalar ) ); } inline Vector3 & Vector3::operator /=( float scalar ) { *this = *this / scalar; return *this; } inline const Vector3 Vector3::operator -( ) const { return Vector3( -mX, -mY, -mZ ); } inline const Vector3 operator *( float scalar, const Vector3 & vec ) { return vec * scalar; } inline const Vector3 mulPerElem( const Vector3 & vec0, const Vector3 & vec1 ) { return Vector3( ( vec0.getX() * vec1.getX() ), ( vec0.getY() * vec1.getY() ), ( vec0.getZ() * vec1.getZ() ) ); } inline const Vector3 divPerElem( const Vector3 & vec0, const Vector3 & vec1 ) { return Vector3( ( vec0.getX() / vec1.getX() ), ( vec0.getY() / vec1.getY() ), ( vec0.getZ() / vec1.getZ() ) ); } inline const Vector3 recipPerElem( const Vector3 & vec ) { return Vector3( ( 1.0f / vec.getX() ), ( 1.0f / vec.getY() ), ( 1.0f / vec.getZ() ) ); } inline const Vector3 sqrtPerElem( const Vector3 & vec ) { return Vector3( sqrtf( vec.getX() ), sqrtf( vec.getY() ), sqrtf( vec.getZ() ) ); } inline const Vector3 rsqrtPerElem( const Vector3 & vec ) { return Vector3( ( 1.0f / sqrtf( vec.getX() ) ), ( 1.0f / sqrtf( vec.getY() ) ), ( 1.0f / sqrtf( vec.getZ() ) ) ); } inline const Vector3 absPerElem( const Vector3 & vec ) { return Vector3( fabsf( vec.getX() ), fabsf( vec.getY() ), fabsf( vec.getZ() ) ); } inline const Vector3 copySignPerElem( const Vector3 & vec0, const Vector3 & vec1 ) { return Vector3( ( vec1.getX() < 0.0f )? -fabsf( vec0.getX() ) : fabsf( vec0.getX() ), ( vec1.getY() < 0.0f )? -fabsf( vec0.getY() ) : fabsf( vec0.getY() ), ( vec1.getZ() < 0.0f )? -fabsf( vec0.getZ() ) : fabsf( vec0.getZ() ) ); } inline const Vector3 maxPerElem( const Vector3 & vec0, const Vector3 & vec1 ) { return Vector3( (vec0.getX() > vec1.getX())? vec0.getX() : vec1.getX(), (vec0.getY() > vec1.getY())? vec0.getY() : vec1.getY(), (vec0.getZ() > vec1.getZ())? vec0.getZ() : vec1.getZ() ); } inline float maxElem( const Vector3 & vec ) { float result; result = (vec.getX() > vec.getY())? vec.getX() : vec.getY(); result = (vec.getZ() > result)? vec.getZ() : result; return result; } inline const Vector3 minPerElem( const Vector3 & vec0, const Vector3 & vec1 ) { return Vector3( (vec0.getX() < vec1.getX())? vec0.getX() : vec1.getX(), (vec0.getY() < vec1.getY())? vec0.getY() : vec1.getY(), (vec0.getZ() < vec1.getZ())? vec0.getZ() : vec1.getZ() ); } inline float minElem( const Vector3 & vec ) { float result; result = (vec.getX() < vec.getY())? vec.getX() : vec.getY(); result = (vec.getZ() < result)? vec.getZ() : result; return result; } inline float sum( const Vector3 & vec ) { float result; result = ( vec.getX() + vec.getY() ); result = ( result + vec.getZ() ); return result; } inline float dot( const Vector3 & vec0, const Vector3 & vec1 ) { float result; result = ( vec0.getX() * vec1.getX() ); result = ( result + ( vec0.getY() * vec1.getY() ) ); result = ( result + ( vec0.getZ() * vec1.getZ() ) ); return result; } inline float lengthSqr( const Vector3 & vec ) { float result; result = ( vec.getX() * vec.getX() ); result = ( result + ( vec.getY() * vec.getY() ) ); result = ( result + ( vec.getZ() * vec.getZ() ) ); return result; } inline float length( const Vector3 & vec ) { return sqrtf( lengthSqr( vec ) ); } inline const Vector3 normalize( const Vector3 & vec ) { float lenSqr, lenInv; lenSqr = lengthSqr( vec ); lenInv = ( 1.0f / sqrtf( lenSqr ) ); return Vector3( ( vec.getX() * lenInv ), ( vec.getY() * lenInv ), ( vec.getZ() * lenInv ) ); } inline const Vector3 cross( const Vector3 & vec0, const Vector3 & vec1 ) { return Vector3( ( ( vec0.getY() * vec1.getZ() ) - ( vec0.getZ() * vec1.getY() ) ), ( ( vec0.getZ() * vec1.getX() ) - ( vec0.getX() * vec1.getZ() ) ), ( ( vec0.getX() * vec1.getY() ) - ( vec0.getY() * vec1.getX() ) ) ); } inline const Vector3 select( const Vector3 & vec0, const Vector3 & vec1, bool select1 ) { return Vector3( ( select1 )? vec1.getX() : vec0.getX(), ( select1 )? vec1.getY() : vec0.getY(), ( select1 )? vec1.getZ() : vec0.getZ() ); } #ifdef _VECTORMATH_DEBUG inline void print( const Vector3 & vec ) { printf( "( %f %f %f )\n", vec.getX(), vec.getY(), vec.getZ() ); } inline void print( const Vector3 & vec, const char * name ) { printf( "%s: ( %f %f %f )\n", name, vec.getX(), vec.getY(), vec.getZ() ); } #endif inline Vector4::Vector4( const Vector4 & vec ) { mX = vec.mX; mY = vec.mY; mZ = vec.mZ; mW = vec.mW; } inline Vector4::Vector4( float _x, float _y, float _z, float _w ) { mX = _x; mY = _y; mZ = _z; mW = _w; } inline Vector4::Vector4( const Vector3 & xyz, float _w ) { this->setXYZ( xyz ); this->setW( _w ); } inline Vector4::Vector4( const Vector3 & vec ) { mX = vec.getX(); mY = vec.getY(); mZ = vec.getZ(); mW = 0.0f; } inline Vector4::Vector4( const Point3 & pnt ) { mX = pnt.getX(); mY = pnt.getY(); mZ = pnt.getZ(); mW = 1.0f; } inline Vector4::Vector4( const Quat & quat ) { mX = quat.getX(); mY = quat.getY(); mZ = quat.getZ(); mW = quat.getW(); } inline Vector4::Vector4( float scalar ) { mX = scalar; mY = scalar; mZ = scalar; mW = scalar; } inline const Vector4 Vector4::xAxis( ) { return Vector4( 1.0f, 0.0f, 0.0f, 0.0f ); } inline const Vector4 Vector4::yAxis( ) { return Vector4( 0.0f, 1.0f, 0.0f, 0.0f ); } inline const Vector4 Vector4::zAxis( ) { return Vector4( 0.0f, 0.0f, 1.0f, 0.0f ); } inline const Vector4 Vector4::wAxis( ) { return Vector4( 0.0f, 0.0f, 0.0f, 1.0f ); } inline const Vector4 lerp( float t, const Vector4 & vec0, const Vector4 & vec1 ) { return ( vec0 + ( ( vec1 - vec0 ) * t ) ); } inline const Vector4 slerp( float t, const Vector4 & unitVec0, const Vector4 & unitVec1 ) { float recipSinAngle, scale0, scale1, cosAngle, angle; cosAngle = dot( unitVec0, unitVec1 ); if ( cosAngle < _VECTORMATH_SLERP_TOL ) { angle = acosf( cosAngle ); recipSinAngle = ( 1.0f / sinf( angle ) ); scale0 = ( sinf( ( ( 1.0f - t ) * angle ) ) * recipSinAngle ); scale1 = ( sinf( ( t * angle ) ) * recipSinAngle ); } else { scale0 = ( 1.0f - t ); scale1 = t; } return ( ( unitVec0 * scale0 ) + ( unitVec1 * scale1 ) ); } inline Vector4 & Vector4::operator =( const Vector4 & vec ) { mX = vec.mX; mY = vec.mY; mZ = vec.mZ; mW = vec.mW; return *this; } inline Vector4 & Vector4::setXYZ( const Vector3 & vec ) { mX = vec.getX(); mY = vec.getY(); mZ = vec.getZ(); return *this; } inline const Vector3 Vector4::getXYZ( ) const { return Vector3( mX, mY, mZ ); } inline Vector4 & Vector4::setX( float _x ) { mX = _x; return *this; } inline float Vector4::getX( ) const { return mX; } inline Vector4 & Vector4::setY( float _y ) { mY = _y; return *this; } inline float Vector4::getY( ) const { return mY; } inline Vector4 & Vector4::setZ( float _z ) { mZ = _z; return *this; } inline float Vector4::getZ( ) const { return mZ; } inline Vector4 & Vector4::setW( float _w ) { mW = _w; return *this; } inline float Vector4::getW( ) const { return mW; } inline Vector4 & Vector4::setElem( int idx, float value ) { *(&mX + idx) = value; return *this; } inline float Vector4::getElem( int idx ) const { return *(&mX + idx); } inline float & Vector4::operator []( int idx ) { return *(&mX + idx); } inline float Vector4::operator []( int idx ) const { return *(&mX + idx); } inline const Vector4 Vector4::operator +( const Vector4 & vec ) const { return Vector4( ( mX + vec.mX ), ( mY + vec.mY ), ( mZ + vec.mZ ), ( mW + vec.mW ) ); } inline const Vector4 Vector4::operator -( const Vector4 & vec ) const { return Vector4( ( mX - vec.mX ), ( mY - vec.mY ), ( mZ - vec.mZ ), ( mW - vec.mW ) ); } inline const Vector4 Vector4::operator *( float scalar ) const { return Vector4( ( mX * scalar ), ( mY * scalar ), ( mZ * scalar ), ( mW * scalar ) ); } inline Vector4 & Vector4::operator +=( const Vector4 & vec ) { *this = *this + vec; return *this; } inline Vector4 & Vector4::operator -=( const Vector4 & vec ) { *this = *this - vec; return *this; } inline Vector4 & Vector4::operator *=( float scalar ) { *this = *this * scalar; return *this; } inline const Vector4 Vector4::operator /( float scalar ) const { return Vector4( ( mX / scalar ), ( mY / scalar ), ( mZ / scalar ), ( mW / scalar ) ); } inline Vector4 & Vector4::operator /=( float scalar ) { *this = *this / scalar; return *this; } inline const Vector4 Vector4::operator -( ) const { return Vector4( -mX, -mY, -mZ, -mW ); } inline const Vector4 operator *( float scalar, const Vector4 & vec ) { return vec * scalar; } inline const Vector4 mulPerElem( const Vector4 & vec0, const Vector4 & vec1 ) { return Vector4( ( vec0.getX() * vec1.getX() ), ( vec0.getY() * vec1.getY() ), ( vec0.getZ() * vec1.getZ() ), ( vec0.getW() * vec1.getW() ) ); } inline const Vector4 divPerElem( const Vector4 & vec0, const Vector4 & vec1 ) { return Vector4( ( vec0.getX() / vec1.getX() ), ( vec0.getY() / vec1.getY() ), ( vec0.getZ() / vec1.getZ() ), ( vec0.getW() / vec1.getW() ) ); } inline const Vector4 recipPerElem( const Vector4 & vec ) { return Vector4( ( 1.0f / vec.getX() ), ( 1.0f / vec.getY() ), ( 1.0f / vec.getZ() ), ( 1.0f / vec.getW() ) ); } inline const Vector4 sqrtPerElem( const Vector4 & vec ) { return Vector4( sqrtf( vec.getX() ), sqrtf( vec.getY() ), sqrtf( vec.getZ() ), sqrtf( vec.getW() ) ); } inline const Vector4 rsqrtPerElem( const Vector4 & vec ) { return Vector4( ( 1.0f / sqrtf( vec.getX() ) ), ( 1.0f / sqrtf( vec.getY() ) ), ( 1.0f / sqrtf( vec.getZ() ) ), ( 1.0f / sqrtf( vec.getW() ) ) ); } inline const Vector4 absPerElem( const Vector4 & vec ) { return Vector4( fabsf( vec.getX() ), fabsf( vec.getY() ), fabsf( vec.getZ() ), fabsf( vec.getW() ) ); } inline const Vector4 copySignPerElem( const Vector4 & vec0, const Vector4 & vec1 ) { return Vector4( ( vec1.getX() < 0.0f )? -fabsf( vec0.getX() ) : fabsf( vec0.getX() ), ( vec1.getY() < 0.0f )? -fabsf( vec0.getY() ) : fabsf( vec0.getY() ), ( vec1.getZ() < 0.0f )? -fabsf( vec0.getZ() ) : fabsf( vec0.getZ() ), ( vec1.getW() < 0.0f )? -fabsf( vec0.getW() ) : fabsf( vec0.getW() ) ); } inline const Vector4 maxPerElem( const Vector4 & vec0, const Vector4 & vec1 ) { return Vector4( (vec0.getX() > vec1.getX())? vec0.getX() : vec1.getX(), (vec0.getY() > vec1.getY())? vec0.getY() : vec1.getY(), (vec0.getZ() > vec1.getZ())? vec0.getZ() : vec1.getZ(), (vec0.getW() > vec1.getW())? vec0.getW() : vec1.getW() ); } inline float maxElem( const Vector4 & vec ) { float result; result = (vec.getX() > vec.getY())? vec.getX() : vec.getY(); result = (vec.getZ() > result)? vec.getZ() : result; result = (vec.getW() > result)? vec.getW() : result; return result; } inline const Vector4 minPerElem( const Vector4 & vec0, const Vector4 & vec1 ) { return Vector4( (vec0.getX() < vec1.getX())? vec0.getX() : vec1.getX(), (vec0.getY() < vec1.getY())? vec0.getY() : vec1.getY(), (vec0.getZ() < vec1.getZ())? vec0.getZ() : vec1.getZ(), (vec0.getW() < vec1.getW())? vec0.getW() : vec1.getW() ); } inline float minElem( const Vector4 & vec ) { float result; result = (vec.getX() < vec.getY())? vec.getX() : vec.getY(); result = (vec.getZ() < result)? vec.getZ() : result; result = (vec.getW() < result)? vec.getW() : result; return result; } inline float sum( const Vector4 & vec ) { float result; result = ( vec.getX() + vec.getY() ); result = ( result + vec.getZ() ); result = ( result + vec.getW() ); return result; } inline float dot( const Vector4 & vec0, const Vector4 & vec1 ) { float result; result = ( vec0.getX() * vec1.getX() ); result = ( result + ( vec0.getY() * vec1.getY() ) ); result = ( result + ( vec0.getZ() * vec1.getZ() ) ); result = ( result + ( vec0.getW() * vec1.getW() ) ); return result; } inline float lengthSqr( const Vector4 & vec ) { float result; result = ( vec.getX() * vec.getX() ); result = ( result + ( vec.getY() * vec.getY() ) ); result = ( result + ( vec.getZ() * vec.getZ() ) ); result = ( result + ( vec.getW() * vec.getW() ) ); return result; } inline float length( const Vector4 & vec ) { return sqrtf( lengthSqr( vec ) ); } inline const Vector4 normalize( const Vector4 & vec ) { float lenSqr, lenInv; lenSqr = lengthSqr( vec ); lenInv = ( 1.0f / sqrtf( lenSqr ) ); return Vector4( ( vec.getX() * lenInv ), ( vec.getY() * lenInv ), ( vec.getZ() * lenInv ), ( vec.getW() * lenInv ) ); } inline const Vector4 select( const Vector4 & vec0, const Vector4 & vec1, bool select1 ) { return Vector4( ( select1 )? vec1.getX() : vec0.getX(), ( select1 )? vec1.getY() : vec0.getY(), ( select1 )? vec1.getZ() : vec0.getZ(), ( select1 )? vec1.getW() : vec0.getW() ); } #ifdef _VECTORMATH_DEBUG inline void print( const Vector4 & vec ) { printf( "( %f %f %f %f )\n", vec.getX(), vec.getY(), vec.getZ(), vec.getW() ); } inline void print( const Vector4 & vec, const char * name ) { printf( "%s: ( %f %f %f %f )\n", name, vec.getX(), vec.getY(), vec.getZ(), vec.getW() ); } #endif inline Point3::Point3( const Point3 & pnt ) { mX = pnt.mX; mY = pnt.mY; mZ = pnt.mZ; } inline Point3::Point3( float _x, float _y, float _z ) { mX = _x; mY = _y; mZ = _z; } inline Point3::Point3( const Vector3 & vec ) { mX = vec.getX(); mY = vec.getY(); mZ = vec.getZ(); } inline Point3::Point3( float scalar ) { mX = scalar; mY = scalar; mZ = scalar; } inline const Point3 lerp( float t, const Point3 & pnt0, const Point3 & pnt1 ) { return ( pnt0 + ( ( pnt1 - pnt0 ) * t ) ); } inline Point3 & Point3::operator =( const Point3 & pnt ) { mX = pnt.mX; mY = pnt.mY; mZ = pnt.mZ; return *this; } inline Point3 & Point3::setX( float _x ) { mX = _x; return *this; } inline float Point3::getX( ) const { return mX; } inline Point3 & Point3::setY( float _y ) { mY = _y; return *this; } inline float Point3::getY( ) const { return mY; } inline Point3 & Point3::setZ( float _z ) { mZ = _z; return *this; } inline float Point3::getZ( ) const { return mZ; } inline Point3 & Point3::setElem( int idx, float value ) { *(&mX + idx) = value; return *this; } inline float Point3::getElem( int idx ) const { return *(&mX + idx); } inline float & Point3::operator []( int idx ) { return *(&mX + idx); } inline float Point3::operator []( int idx ) const { return *(&mX + idx); } inline const Vector3 Point3::operator -( const Point3 & pnt ) const { return Vector3( ( mX - pnt.mX ), ( mY - pnt.mY ), ( mZ - pnt.mZ ) ); } inline const Point3 Point3::operator +( const Vector3 & vec ) const { return Point3( ( mX + vec.getX() ), ( mY + vec.getY() ), ( mZ + vec.getZ() ) ); } inline const Point3 Point3::operator -( const Vector3 & vec ) const { return Point3( ( mX - vec.getX() ), ( mY - vec.getY() ), ( mZ - vec.getZ() ) ); } inline Point3 & Point3::operator +=( const Vector3 & vec ) { *this = *this + vec; return *this; } inline Point3 & Point3::operator -=( const Vector3 & vec ) { *this = *this - vec; return *this; } inline const Point3 mulPerElem( const Point3 & pnt0, const Point3 & pnt1 ) { return Point3( ( pnt0.getX() * pnt1.getX() ), ( pnt0.getY() * pnt1.getY() ), ( pnt0.getZ() * pnt1.getZ() ) ); } inline const Point3 divPerElem( const Point3 & pnt0, const Point3 & pnt1 ) { return Point3( ( pnt0.getX() / pnt1.getX() ), ( pnt0.getY() / pnt1.getY() ), ( pnt0.getZ() / pnt1.getZ() ) ); } inline const Point3 recipPerElem( const Point3 & pnt ) { return Point3( ( 1.0f / pnt.getX() ), ( 1.0f / pnt.getY() ), ( 1.0f / pnt.getZ() ) ); } inline const Point3 sqrtPerElem( const Point3 & pnt ) { return Point3( sqrtf( pnt.getX() ), sqrtf( pnt.getY() ), sqrtf( pnt.getZ() ) ); } inline const Point3 rsqrtPerElem( const Point3 & pnt ) { return Point3( ( 1.0f / sqrtf( pnt.getX() ) ), ( 1.0f / sqrtf( pnt.getY() ) ), ( 1.0f / sqrtf( pnt.getZ() ) ) ); } inline const Point3 absPerElem( const Point3 & pnt ) { return Point3( fabsf( pnt.getX() ), fabsf( pnt.getY() ), fabsf( pnt.getZ() ) ); } inline const Point3 copySignPerElem( const Point3 & pnt0, const Point3 & pnt1 ) { return Point3( ( pnt1.getX() < 0.0f )? -fabsf( pnt0.getX() ) : fabsf( pnt0.getX() ), ( pnt1.getY() < 0.0f )? -fabsf( pnt0.getY() ) : fabsf( pnt0.getY() ), ( pnt1.getZ() < 0.0f )? -fabsf( pnt0.getZ() ) : fabsf( pnt0.getZ() ) ); } inline const Point3 maxPerElem( const Point3 & pnt0, const Point3 & pnt1 ) { return Point3( (pnt0.getX() > pnt1.getX())? pnt0.getX() : pnt1.getX(), (pnt0.getY() > pnt1.getY())? pnt0.getY() : pnt1.getY(), (pnt0.getZ() > pnt1.getZ())? pnt0.getZ() : pnt1.getZ() ); } inline float maxElem( const Point3 & pnt ) { float result; result = (pnt.getX() > pnt.getY())? pnt.getX() : pnt.getY(); result = (pnt.getZ() > result)? pnt.getZ() : result; return result; } inline const Point3 minPerElem( const Point3 & pnt0, const Point3 & pnt1 ) { return Point3( (pnt0.getX() < pnt1.getX())? pnt0.getX() : pnt1.getX(), (pnt0.getY() < pnt1.getY())? pnt0.getY() : pnt1.getY(), (pnt0.getZ() < pnt1.getZ())? pnt0.getZ() : pnt1.getZ() ); } inline float minElem( const Point3 & pnt ) { float result; result = (pnt.getX() < pnt.getY())? pnt.getX() : pnt.getY(); result = (pnt.getZ() < result)? pnt.getZ() : result; return result; } inline float sum( const Point3 & pnt ) { float result; result = ( pnt.getX() + pnt.getY() ); result = ( result + pnt.getZ() ); return result; } inline const Point3 scale( const Point3 & pnt, float scaleVal ) { return mulPerElem( pnt, Point3( scaleVal ) ); } inline const Point3 scale( const Point3 & pnt, const Vector3 & scaleVec ) { return mulPerElem( pnt, Point3( scaleVec ) ); } inline float projection( const Point3 & pnt, const Vector3 & unitVec ) { float result; result = ( pnt.getX() * unitVec.getX() ); result = ( result + ( pnt.getY() * unitVec.getY() ) ); result = ( result + ( pnt.getZ() * unitVec.getZ() ) ); return result; } inline float distSqrFromOrigin( const Point3 & pnt ) { return lengthSqr( Vector3( pnt ) ); } inline float distFromOrigin( const Point3 & pnt ) { return length( Vector3( pnt ) ); } inline float distSqr( const Point3 & pnt0, const Point3 & pnt1 ) { return lengthSqr( ( pnt1 - pnt0 ) ); } inline float dist( const Point3 & pnt0, const Point3 & pnt1 ) { return length( ( pnt1 - pnt0 ) ); } inline const Point3 select( const Point3 & pnt0, const Point3 & pnt1, bool select1 ) { return Point3( ( select1 )? pnt1.getX() : pnt0.getX(), ( select1 )? pnt1.getY() : pnt0.getY(), ( select1 )? pnt1.getZ() : pnt0.getZ() ); } #ifdef _VECTORMATH_DEBUG inline void print( const Point3 & pnt ) { printf( "( %f %f %f )\n", pnt.getX(), pnt.getY(), pnt.getZ() ); } inline void print( const Point3 & pnt, const char * name ) { printf( "%s: ( %f %f %f )\n", name, pnt.getX(), pnt.getY(), pnt.getZ() ); } #endif } // namespace Aos } // namespace Vectormath #endif critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/btGpu3DGridBroadphase.h0000644000175000017500000001325111337073000027072 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org Copyright (C) 2006, 2009 Sony Computer Entertainment Inc. 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 BTGPU3DGRIDBROADPHASE_H #define BTGPU3DGRIDBROADPHASE_H //---------------------------------------------------------------------------------------- #include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h" #include "btGpu3DGridBroadphaseSharedTypes.h" //---------------------------------------------------------------------------------------- ///The btGpu3DGridBroadphase uses GPU-style code compiled for CPU to compute overlapping pairs class btGpu3DGridBroadphase : public btSimpleBroadphase { protected: bool m_bInitialized; unsigned int m_numBodies; unsigned int m_numCells; unsigned int m_maxPairsPerBody; btScalar m_cellFactorAABB; unsigned int m_maxBodiesPerCell; bt3DGridBroadphaseParams m_params; btScalar m_maxRadius; // CPU data unsigned int* m_hBodiesHash; unsigned int* m_hCellStart; unsigned int* m_hPairBuffStartCurr; bt3DGrid3F1U* m_hAABB; unsigned int* m_hPairBuff; unsigned int* m_hPairScan; unsigned int* m_hPairOut; // large proxies int m_numLargeHandles; int m_maxLargeHandles; int m_LastLargeHandleIndex; btSimpleBroadphaseProxy* m_pLargeHandles; void* m_pLargeHandlesRawPtr; int m_firstFreeLargeHandle; int allocLargeHandle() { btAssert(m_numLargeHandles < m_maxLargeHandles); int freeLargeHandle = m_firstFreeLargeHandle; m_firstFreeLargeHandle = m_pLargeHandles[freeLargeHandle].GetNextFree(); m_numLargeHandles++; if(freeLargeHandle > m_LastLargeHandleIndex) { m_LastLargeHandleIndex = freeLargeHandle; } return freeLargeHandle; } void freeLargeHandle(btSimpleBroadphaseProxy* proxy) { int handle = int(proxy - m_pLargeHandles); btAssert((handle >= 0) && (handle < m_maxHandles)); if(handle == m_LastLargeHandleIndex) { m_LastLargeHandleIndex--; } proxy->SetNextFree(m_firstFreeLargeHandle); m_firstFreeLargeHandle = handle; proxy->m_clientObject = 0; m_numLargeHandles--; } bool isLargeProxy(const btVector3& aabbMin, const btVector3& aabbMax); bool isLargeProxy(btBroadphaseProxy* proxy); // debug unsigned int m_numPairsAdded; unsigned int m_numPairsRemoved; unsigned int m_numOverflows; // public: btGpu3DGridBroadphase(const btVector3& worldAabbMin,const btVector3& worldAabbMax, int gridSizeX, int gridSizeY, int gridSizeZ, int maxSmallProxies, int maxLargeProxies, int maxPairsPerBody, int maxBodiesPerCell = 8, btScalar cellFactorAABB = btScalar(1.0f)); btGpu3DGridBroadphase( btOverlappingPairCache* overlappingPairCache, const btVector3& worldAabbMin,const btVector3& worldAabbMax, int gridSizeX, int gridSizeY, int gridSizeZ, int maxSmallProxies, int maxLargeProxies, int maxPairsPerBody, int maxBodiesPerCell = 8, btScalar cellFactorAABB = btScalar(1.0f)); virtual ~btGpu3DGridBroadphase(); virtual void calculateOverlappingPairs(btDispatcher* dispatcher); virtual btBroadphaseProxy* createProxy(const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy); virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback); virtual void resetPool(btDispatcher* dispatcher); protected: void _initialize( const btVector3& worldAabbMin,const btVector3& worldAabbMax, int gridSizeX, int gridSizeY, int gridSizeZ, int maxSmallProxies, int maxLargeProxies, int maxPairsPerBody, int maxBodiesPerCell = 8, btScalar cellFactorAABB = btScalar(1.0f)); void _finalize(); void addPairsToCache(btDispatcher* dispatcher); void addLarge2LargePairsToCache(btDispatcher* dispatcher); // overrides for CPU version virtual void setParameters(bt3DGridBroadphaseParams* hostParams); virtual void prepareAABB(); virtual void calcHashAABB(); virtual void sortHash(); virtual void findCellStart(); virtual void findOverlappingPairs(); virtual void findPairsLarge(); virtual void computePairCacheChanges(); virtual void scanOverlappingPairBuff(); virtual void squeezeOverlappingPairBuff(); }; //---------------------------------------------------------------------------------------- #endif //BTGPU3DGRIDBROADPHASE_H //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/Win32ThreadSupport.cpp0000644000175000017500000001571211337073000027011 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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 "Win32ThreadSupport.h" #ifdef USE_WIN32_THREADING #include #include "SpuCollisionTaskProcess.h" #include "SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h" ///The number of threads should be equal to the number of available cores ///@todo: each worker should be linked to a single core, using SetThreadIdealProcessor. ///Win32ThreadSupport helps to initialize/shutdown libspe2, start/stop SPU tasks and communication ///Setup and initialize SPU/CELL/Libspe2 Win32ThreadSupport::Win32ThreadSupport(const Win32ThreadConstructionInfo & threadConstructionInfo) { m_maxNumTasks = threadConstructionInfo.m_numThreads; startThreads(threadConstructionInfo); } ///cleanup/shutdown Libspe2 Win32ThreadSupport::~Win32ThreadSupport() { stopSPU(); } #include DWORD WINAPI Thread_no_1( LPVOID lpParam ) { Win32ThreadSupport::btSpuStatus* status = (Win32ThreadSupport::btSpuStatus*)lpParam; while (1) { WaitForSingleObject(status->m_eventStartHandle,INFINITE); void* userPtr = status->m_userPtr; if (userPtr) { btAssert(status->m_status); status->m_userThreadFunc(userPtr,status->m_lsMemory); status->m_status = 2; SetEvent(status->m_eventCompletetHandle); } else { //exit Thread status->m_status = 3; SetEvent(status->m_eventCompletetHandle); printf("Thread with taskId %i with handle %p exiting\n",status->m_taskId, status->m_threadHandle); break; } } printf("Thread TERMINATED\n"); return 0; } ///send messages to SPUs void Win32ThreadSupport::sendRequest(uint32_t uiCommand, ppu_address_t uiArgument0, uint32_t taskId) { /// gMidphaseSPU.sendRequest(CMD_GATHER_AND_PROCESS_PAIRLIST, (ppu_address_t) &taskDesc); ///we should spawn an SPU task here, and in 'waitForResponse' it should wait for response of the (one of) the first tasks that finished switch (uiCommand) { case CMD_GATHER_AND_PROCESS_PAIRLIST: { //#define SINGLE_THREADED 1 #ifdef SINGLE_THREADED btSpuStatus& spuStatus = m_activeSpuStatus[0]; spuStatus.m_userPtr=(void*)uiArgument0; spuStatus.m_userThreadFunc(spuStatus.m_userPtr,spuStatus.m_lsMemory); HANDLE handle =0; #else btSpuStatus& spuStatus = m_activeSpuStatus[taskId]; btAssert(taskId>=0); btAssert(int(taskId) 1); spuStatus.m_status = 0; ///need to find an active spu btAssert(last>=0); #else last=0; btSpuStatus& spuStatus = m_activeSpuStatus[last]; #endif //SINGLE_THREADED *puiArgument0 = spuStatus.m_taskId; *puiArgument1 = spuStatus.m_status; } void Win32ThreadSupport::startThreads(const Win32ThreadConstructionInfo& threadConstructionInfo) { m_activeSpuStatus.resize(threadConstructionInfo.m_numThreads); m_completeHandles.resize(threadConstructionInfo.m_numThreads); m_maxNumTasks = threadConstructionInfo.m_numThreads; for (int i=0;i0) { WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE); } spuStatus.m_userPtr = 0; SetEvent(spuStatus.m_eventStartHandle); WaitForSingleObject(spuStatus.m_eventCompletetHandle, INFINITE); CloseHandle(spuStatus.m_eventCompletetHandle); CloseHandle(spuStatus.m_eventStartHandle); CloseHandle(spuStatus.m_threadHandle); } m_activeSpuStatus.clear(); m_completeHandles.clear(); } #endif //USE_WIN32_THREADING critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/Jamfile0000644000175000017500000000113611337073000024143 0ustar bobkebobkeSubDir TOP src BulletMultiThreaded ; #IncludeDir src/BulletMultiThreaded ; Library bulletmultithreaded : [ Wildcard . : *.h *.cpp ] [ Wildcard MiniCLTask : *.h *.cpp ] [ Wildcard SpuNarrowPhaseCollisionTask : *.h *.cpp ] : noinstall ; CFlags bulletmultithreaded : [ FIncludes $(TOP)/src/BulletMultiThreaded ] [ FIncludes $(TOP)/src/BulletMultiThreaded/vectormath/scalar/cpp ] ; LibDepends bulletmultithreaded : ; MsvcIncDirs bulletmultithreaded : "../../src/BulletMultiThreaded" "../../src/BulletMultiThreaded/vectormath/scalar/cpp" ; InstallHeader [ Wildcard *.h ] : bulletmultithreaded ; critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuFakeDma.h0000644000175000017500000002160111337073000025001 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 FAKE_DMA_H #define FAKE_DMA_H #include "PlatformDefinitions.h" #include "LinearMath/btScalar.h" #ifdef __SPU__ #ifndef USE_LIBSPE2 #include #include #define DMA_TAG(xfer) (xfer + 1) #define DMA_MASK(xfer) (1 << DMA_TAG(xfer)) #else // !USE_LIBSPE2 #define DMA_TAG(xfer) (xfer + 1) #define DMA_MASK(xfer) (1 << DMA_TAG(xfer)) #include #define DEBUG_DMA #ifdef DEBUG_DMA #define dUASSERT(a,b) if (!(a)) { printf(b);} #define uintsize ppu_address_t #define cellDmaLargeGet(ls, ea, size, tag, tid, rid) if ( (((uintsize)ls%16) != ((uintsize)ea%16)) || ((((uintsize)ea%16) || ((uintsize)ls%16)) && (( ((uintsize)ls%16) != ((uintsize)size%16) ) || ( ((uintsize)ea%16) != ((uintsize)size%16) ) ) ) || ( ((uintsize)size%16) && ((uintsize)size!=1) && ((uintsize)size!=2) && ((uintsize)size!=4) && ((uintsize)size!=8) ) || (size >= 16384) || !(uintsize)ls || !(uintsize)ea) { \ dUASSERT( (((uintsize)ea % 16) == 0) || (size < 16), "XDR Address not aligned: "); \ dUASSERT( (((uintsize)ls % 16) == 0) || (size < 16), "LS Address not aligned: "); \ dUASSERT( ((((uintsize)ls % size) == 0) && (((uintsize)ea % size) == 0)) || (size > 16), "Not naturally aligned: "); \ dUASSERT((size == 1) || (size == 2) || (size == 4) || (size == 8) || ((size % 16) == 0), "size not a multiple of 16byte: "); \ dUASSERT(size < 16384, "size too big: "); \ dUASSERT( ((uintsize)ea%16)==((uintsize)ls%16), "wrong Quadword alignment of LS and EA: "); \ dUASSERT(ea != 0, "Nullpointer EA: "); dUASSERT(ls != 0, "Nullpointer LS: ");\ printf("GET %s:%d from: 0x%x, to: 0x%x - %d bytes\n", __FILE__, __LINE__, (unsigned int)ea,(unsigned int)ls,(unsigned int)size);\ } \ mfc_get(ls, ea, size, tag, tid, rid) #define cellDmaGet(ls, ea, size, tag, tid, rid) if ( (((uintsize)ls%16) != ((uintsize)ea%16)) || ((((uintsize)ea%16) || ((uintsize)ls%16)) && (( ((uintsize)ls%16) != ((uintsize)size%16) ) || ( ((uintsize)ea%16) != ((uintsize)size%16) ) ) ) || ( ((uintsize)size%16) && ((uintsize)size!=1) && ((uintsize)size!=2) && ((uintsize)size!=4) && ((uintsize)size!=8) ) || (size >= 16384) || !(uintsize)ls || !(uintsize)ea) { \ dUASSERT( (((uintsize)ea % 16) == 0) || (size < 16), "XDR Address not aligned: "); \ dUASSERT( (((uintsize)ls % 16) == 0) || (size < 16), "LS Address not aligned: "); \ dUASSERT( ((((uintsize)ls % size) == 0) && (((uintsize)ea % size) == 0)) || (size > 16), "Not naturally aligned: "); \ dUASSERT((size == 1) || (size == 2) || (size == 4) || (size == 8) || ((size % 16) == 0), "size not a multiple of 16byte: "); \ dUASSERT(size < 16384, "size too big: "); \ dUASSERT( ((uintsize)ea%16)==((uintsize)ls%16), "wrong Quadword alignment of LS and EA: "); \ dUASSERT(ea != 0, "Nullpointer EA: "); dUASSERT(ls != 0, "Nullpointer LS: ");\ printf("GET %s:%d from: 0x%x, to: 0x%x - %d bytes\n", __FILE__, __LINE__, (unsigned int)ea,(unsigned int)ls,(unsigned int)size);\ } \ mfc_get(ls, ea, size, tag, tid, rid) #define cellDmaLargePut(ls, ea, size, tag, tid, rid) if ( (((uintsize)ls%16) != ((uintsize)ea%16)) || ((((uintsize)ea%16) || ((uintsize)ls%16)) && (( ((uintsize)ls%16) != ((uintsize)size%16) ) || ( ((uintsize)ea%16) != ((uintsize)size%16) ) ) ) || ( ((uintsize)size%16) && ((uintsize)size!=1) && ((uintsize)size!=2) && ((uintsize)size!=4) && ((uintsize)size!=8) ) || (size >= 16384) || !(uintsize)ls || !(uintsize)ea) { \ dUASSERT( (((uintsize)ea % 16) == 0) || (size < 16), "XDR Address not aligned: "); \ dUASSERT( (((uintsize)ls % 16) == 0) || (size < 16), "LS Address not aligned: "); \ dUASSERT( ((((uintsize)ls % size) == 0) && (((uintsize)ea % size) == 0)) || (size > 16), "Not naturally aligned: "); \ dUASSERT((size == 1) || (size == 2) || (size == 4) || (size == 8) || ((size % 16) == 0), "size not a multiple of 16byte: "); \ dUASSERT(size < 16384, "size too big: "); \ dUASSERT( ((uintsize)ea%16)==((uintsize)ls%16), "wrong Quadword alignment of LS and EA: "); \ dUASSERT(ea != 0, "Nullpointer EA: "); dUASSERT(ls != 0, "Nullpointer LS: ");\ printf("PUT %s:%d from: 0x%x, to: 0x%x - %d bytes\n", __FILE__, __LINE__, (unsigned int)ls,(unsigned int)ea,(unsigned int)size); \ } \ mfc_put(ls, ea, size, tag, tid, rid) #define cellDmaSmallGet(ls, ea, size, tag, tid, rid) if ( (((uintsize)ls%16) != ((uintsize)ea%16)) || ((((uintsize)ea%16) || ((uintsize)ls%16)) && (( ((uintsize)ls%16) != ((uintsize)size%16) ) || ( ((uintsize)ea%16) != ((uintsize)size%16) ) ) ) || ( ((uintsize)size%16) && ((uintsize)size!=1) && ((uintsize)size!=2) && ((uintsize)size!=4) && ((uintsize)size!=8) ) || (size >= 16384) || !(uintsize)ls || !(uintsize)ea) { \ dUASSERT( (((uintsize)ea % 16) == 0) || (size < 16), "XDR Address not aligned: "); \ dUASSERT( (((uintsize)ls % 16) == 0) || (size < 16), "LS Address not aligned: "); \ dUASSERT( ((((uintsize)ls % size) == 0) && (((uintsize)ea % size) == 0)) || (size > 16), "Not naturally aligned: "); \ dUASSERT((size == 1) || (size == 2) || (size == 4) || (size == 8) || ((size % 16) == 0), "size not a multiple of 16byte: "); \ dUASSERT(size < 16384, "size too big: "); \ dUASSERT( ((uintsize)ea%16)==((uintsize)ls%16), "wrong Quadword alignment of LS and EA: "); \ dUASSERT(ea != 0, "Nullpointer EA: "); dUASSERT(ls != 0, "Nullpointer LS: ");\ printf("GET %s:%d from: 0x%x, to: 0x%x - %d bytes\n", __FILE__, __LINE__, (unsigned int)ea,(unsigned int)ls,(unsigned int)size);\ } \ mfc_get(ls, ea, size, tag, tid, rid) #define cellDmaWaitTagStatusAll(ignore) mfc_write_tag_mask(ignore) ; mfc_read_tag_status_all() #else #define cellDmaLargeGet(ls, ea, size, tag, tid, rid) mfc_get(ls, ea, size, tag, tid, rid) #define cellDmaGet(ls, ea, size, tag, tid, rid) mfc_get(ls, ea, size, tag, tid, rid) #define cellDmaLargePut(ls, ea, size, tag, tid, rid) mfc_put(ls, ea, size, tag, tid, rid) #define cellDmaSmallGet(ls, ea, size, tag, tid, rid) mfc_get(ls, ea, size, tag, tid, rid) #define cellDmaWaitTagStatusAll(ignore) mfc_write_tag_mask(ignore) ; mfc_read_tag_status_all() #endif // DEBUG_DMA #endif // USE_LIBSPE2 #else // !__SPU__ //Simulate DMA using memcpy or direct access on non-CELL platforms that don't have DMAs and SPUs (Win32, Mac, Linux etc) //Potential to add networked simulation using this interface #define DMA_TAG(a) (a) #define DMA_MASK(a) (a) /// cellDmaLargeGet Win32 replacements for Cell DMA to allow simulating most of the SPU code (just memcpy) int cellDmaLargeGet(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid); int cellDmaGet(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid); /// cellDmaLargePut Win32 replacements for Cell DMA to allow simulating most of the SPU code (just memcpy) int cellDmaLargePut(const void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid); /// cellDmaWaitTagStatusAll Win32 replacements for Cell DMA to allow simulating most of the SPU code (just memcpy) void cellDmaWaitTagStatusAll(int ignore); #endif //__CELLOS_LV2__ ///stallingUnalignedDmaSmallGet internally uses DMA_TAG(1) int stallingUnalignedDmaSmallGet(void *ls, uint64_t ea, uint32_t size); void* cellDmaLargeGetReadOnly(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid); void* cellDmaGetReadOnly(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid); void* cellDmaSmallGetReadOnly(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid); #endif //FAKE_DMA_H critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SequentialThreadSupport.cpp0000644000175000017500000000564011337073000030220 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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 "SequentialThreadSupport.h" #include "SpuCollisionTaskProcess.h" #include "SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h" SequentialThreadSupport::SequentialThreadSupport(SequentialThreadConstructionInfo& threadConstructionInfo) { startThreads(threadConstructionInfo); } ///cleanup/shutdown Libspe2 SequentialThreadSupport::~SequentialThreadSupport() { stopSPU(); } #include ///send messages to SPUs void SequentialThreadSupport::sendRequest(uint32_t uiCommand, ppu_address_t uiArgument0, uint32_t taskId) { switch (uiCommand) { case CMD_GATHER_AND_PROCESS_PAIRLIST: { btSpuStatus& spuStatus = m_activeSpuStatus[0]; spuStatus.m_userPtr=(void*)uiArgument0; spuStatus.m_userThreadFunc(spuStatus.m_userPtr,spuStatus.m_lsMemory); } break; default: { ///not implemented btAssert(0 && "Not implemented"); } }; } ///check for messages from SPUs void SequentialThreadSupport::waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1) { btAssert(m_activeSpuStatus.size()); btSpuStatus& spuStatus = m_activeSpuStatus[0]; *puiArgument0 = spuStatus.m_taskId; *puiArgument1 = spuStatus.m_status; } void SequentialThreadSupport::startThreads(SequentialThreadConstructionInfo& threadConstructionInfo) { m_activeSpuStatus.resize(1); printf("STS: Not starting any threads\n"); btSpuStatus& spuStatus = m_activeSpuStatus[0]; spuStatus.m_userPtr = 0; spuStatus.m_taskId = 0; spuStatus.m_commandId = 0; spuStatus.m_status = 0; spuStatus.m_lsMemory = threadConstructionInfo.m_lsMemoryFunc(); spuStatus.m_userThreadFunc = threadConstructionInfo.m_userThreadFunc; printf("STS: Created local store at %p for task %s\n", spuStatus.m_lsMemory, threadConstructionInfo.m_uniqueName); } void SequentialThreadSupport::startSPU() { } void SequentialThreadSupport::stopSPU() { m_activeSpuStatus.clear(); } void SequentialThreadSupport::setNumTasks(int numTasks) { printf("SequentialThreadSupport::setNumTasks(%d) is not implemented and has no effect\n",numTasks); } critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/MiniCLTaskScheduler.h0000644000175000017500000001160211337073000026616 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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 MINICL_TASK_SCHEDULER_H #define MINICL_TASK_SCHEDULER_H #include #include "PlatformDefinitions.h" #include #include "LinearMath/btAlignedObjectArray.h" #include "MiniCLTask/MiniCLTask.h" //just add your commands here, try to keep them globally unique for debugging purposes #define CMD_SAMPLE_TASK_COMMAND 10 /// MiniCLTaskScheduler handles SPU processing of collision pairs. /// When PPU issues a task, it will look for completed task buffers /// PPU will do postprocessing, dependent on workunit output (not likely) class MiniCLTaskScheduler { // track task buffers that are being used, and total busy tasks btAlignedObjectArray m_taskBusy; btAlignedObjectArray m_spuSampleTaskDesc; int m_numBusyTasks; // the current task and the current entry to insert a new work unit int m_currentTask; bool m_initialized; void postProcess(int taskId, int outputSize); class btThreadSupportInterface* m_threadInterface; int m_maxNumOutstandingTasks; public: MiniCLTaskScheduler(btThreadSupportInterface* threadInterface, int maxNumOutstandingTasks); ~MiniCLTaskScheduler(); ///call initialize in the beginning of the frame, before addCollisionPairToTask void initialize(); void issueTask(int firstWorkUnit, int lastWorkUnit,int kernelProgramId,char* argData,int* argSizes); ///call flush to submit potential outstanding work to SPUs and wait for all involved SPUs to be finished void flush(); class btThreadSupportInterface* getThreadSupportInterface() { return m_threadInterface; } int findProgramCommandIdByName(const char* programName) const { return CMD_MINICL_ADDVECTOR;//hardcoded temp value, todo: implement multi-program support } int getMaxNumOutstandingTasks() const { return m_maxNumOutstandingTasks; } }; struct MiniCLKernel { MiniCLTaskScheduler* m_scheduler; int m_kernelProgramCommandId; char m_argData[MINI_CL_MAX_ARG][MINICL_MAX_ARGLENGTH]; int m_argSizes[MINI_CL_MAX_ARG]; }; #if defined(USE_LIBSPE2) && defined(__SPU__) ////////////////////MAIN///////////////////////////// #include "../SpuLibspe2Support.h" #include #include #include void * SamplelsMemoryFunc(); void SampleThreadFunc(void* userPtr,void* lsMemory); //#define DEBUG_LIBSPE2_MAINLOOP int main(unsigned long long speid, addr64 argp, addr64 envp) { printf("SPU is up \n"); ATTRIBUTE_ALIGNED128(btSpuStatus status); ATTRIBUTE_ALIGNED16( SpuSampleTaskDesc taskDesc ) ; unsigned int received_message = Spu_Mailbox_Event_Nothing; bool shutdown = false; cellDmaGet(&status, argp.ull, sizeof(btSpuStatus), DMA_TAG(3), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(3)); status.m_status = Spu_Status_Free; status.m_lsMemory.p = SamplelsMemoryFunc(); cellDmaLargePut(&status, argp.ull, sizeof(btSpuStatus), DMA_TAG(3), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(3)); while (!shutdown) { received_message = spu_read_in_mbox(); switch(received_message) { case Spu_Mailbox_Event_Shutdown: shutdown = true; break; case Spu_Mailbox_Event_Task: // refresh the status #ifdef DEBUG_LIBSPE2_MAINLOOP printf("SPU recieved Task \n"); #endif //DEBUG_LIBSPE2_MAINLOOP cellDmaGet(&status, argp.ull, sizeof(btSpuStatus), DMA_TAG(3), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(3)); btAssert(status.m_status==Spu_Status_Occupied); cellDmaGet(&taskDesc, status.m_taskDesc.p, sizeof(SpuSampleTaskDesc), DMA_TAG(3), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(3)); SampleThreadFunc((void*)&taskDesc, reinterpret_cast (taskDesc.m_mainMemoryPtr) ); break; case Spu_Mailbox_Event_Nothing: default: break; } // set to status free and wait for next task status.m_status = Spu_Status_Free; cellDmaLargePut(&status, argp.ull, sizeof(btSpuStatus), DMA_TAG(3), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(3)); } return 0; } ////////////////////////////////////////////////////// #endif #endif // MINICL_TASK_SCHEDULER_H critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuCollisionTaskProcess.h0000644000175000017500000001224711337073000027634 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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 SPU_COLLISION_TASK_PROCESS_H #define SPU_COLLISION_TASK_PROCESS_H #include #include #include "PlatformDefinitions.h" #include "LinearMath/btAlignedObjectArray.h" #include "SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h" // for definitions processCollisionTask and createCollisionLocalStoreMemory #include "btThreadSupportInterface.h" //#include "SPUAssert.h" #include #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionShapes/btCollisionShape.h" #include "BulletCollision/CollisionShapes/btConvexShape.h" #include #include #define DEBUG_SpuCollisionTaskProcess 1 #define CMD_GATHER_AND_PROCESS_PAIRLIST 1 class btCollisionObject; class btPersistentManifold; class btDispatcher; /////Task Description for SPU collision detection //struct SpuGatherAndProcessPairsTaskDesc //{ // uint64_t inPtr;//m_pairArrayPtr; // //mutex variable // uint32_t m_someMutexVariableInMainMemory; // // uint64_t m_dispatcher; // // uint32_t numOnLastPage; // // uint16_t numPages; // uint16_t taskId; // // struct CollisionTask_LocalStoreMemory* m_lsMemory; //} // //#if defined(__CELLOS_LV2__) || defined(USE_LIBSPE2) //__attribute__ ((aligned (16))) //#endif //; ///MidphaseWorkUnitInput stores individual primitive versus mesh collision detection input, to be processed by the SPU. ATTRIBUTE_ALIGNED16(struct) SpuGatherAndProcessWorkUnitInput { uint64_t m_pairArrayPtr; int m_startIndex; int m_endIndex; }; /// SpuCollisionTaskProcess handles SPU processing of collision pairs. /// Maintains a set of task buffers. /// When the task is full, the task is issued for SPUs to process. Contact output goes into btPersistentManifold /// associated with each task. /// When PPU issues a task, it will look for completed task buffers /// PPU will do postprocessing, dependent on workunit output (not likely) class SpuCollisionTaskProcess { unsigned char *m_workUnitTaskBuffers; // track task buffers that are being used, and total busy tasks btAlignedObjectArray m_taskBusy; btAlignedObjectArray m_spuGatherTaskDesc; class btThreadSupportInterface* m_threadInterface; unsigned int m_maxNumOutstandingTasks; unsigned int m_numBusyTasks; // the current task and the current entry to insert a new work unit unsigned int m_currentTask; unsigned int m_currentPage; unsigned int m_currentPageEntry; bool m_useEpa; #ifdef DEBUG_SpuCollisionTaskProcess bool m_initialized; #endif void issueTask2(); //void postProcess(unsigned int taskId, int outputSize); public: SpuCollisionTaskProcess(btThreadSupportInterface* threadInterface, unsigned int maxNumOutstandingTasks); ~SpuCollisionTaskProcess(); ///call initialize in the beginning of the frame, before addCollisionPairToTask void initialize2(bool useEpa = false); ///batch up additional work to a current task for SPU processing. When batch is full, it issues the task. void addWorkToTask(void* pairArrayPtr,int startIndex,int endIndex); ///call flush to submit potential outstanding work to SPUs and wait for all involved SPUs to be finished void flush2(); /// set the maximum number of SPU tasks allocated void setNumTasks(int maxNumTasks); int getNumTasks() const { return m_maxNumOutstandingTasks; } }; #define MIDPHASE_TASK_PTR(task) (&m_workUnitTaskBuffers[0] + MIDPHASE_WORKUNIT_TASK_SIZE*task) #define MIDPHASE_ENTRY_PTR(task,page,entry) (MIDPHASE_TASK_PTR(task) + MIDPHASE_WORKUNIT_PAGE_SIZE*page + sizeof(SpuGatherAndProcessWorkUnitInput)*entry) #define MIDPHASE_OUTPUT_PTR(task) (&m_contactOutputBuffers[0] + MIDPHASE_MAX_CONTACT_BUFFER_SIZE*task) #define MIDPHASE_TREENODES_PTR(task) (&m_complexShapeBuffers[0] + MIDPHASE_COMPLEX_SHAPE_BUFFER_SIZE*task) #define MIDPHASE_WORKUNIT_PAGE_SIZE (16) //#define MIDPHASE_WORKUNIT_PAGE_SIZE (128) #define MIDPHASE_NUM_WORKUNIT_PAGES 1 #define MIDPHASE_WORKUNIT_TASK_SIZE (MIDPHASE_WORKUNIT_PAGE_SIZE*MIDPHASE_NUM_WORKUNIT_PAGES) #define MIDPHASE_NUM_WORKUNITS_PER_PAGE (MIDPHASE_WORKUNIT_PAGE_SIZE / sizeof(SpuGatherAndProcessWorkUnitInput)) #define MIDPHASE_NUM_WORKUNITS_PER_TASK (MIDPHASE_NUM_WORKUNITS_PER_PAGE*MIDPHASE_NUM_WORKUNIT_PAGES) #endif // SPU_COLLISION_TASK_PROCESS_H critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/MiniCLTask/0000755000175000017500000000000011347266042024621 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/MiniCLTask/MiniCLTask.cpp0000644000175000017500000000662011337073000027254 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library, Copyright (c) 2007 Erwin Coumans 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 "MiniCLTask.h" #include "../PlatformDefinitions.h" #include "../SpuFakeDma.h" #include "LinearMath/btMinMax.h" #include "BulletMultiThreaded/MiniCLTask/MiniCLTask.h" #ifdef __SPU__ #include #else #include #define spu_printf printf #endif #define __kernel #define __global #define get_global_id(a) guid struct MiniCLTask_LocalStoreMemory { }; /////////////////////////////////////////////////// // OpenCL Kernel Function for element by element vector addition __kernel void VectorAdd(__global const float8* a, __global const float8* b, __global float8* c, int guid) { // get oct-float index into global data array int iGID = get_global_id(0); // read inputs into registers float8 f8InA = a[iGID]; float8 f8InB = b[iGID]; float8 f8Out = (float8)0.0f; // add the vector elements f8Out.s0 = f8InA.s0 + f8InB.s0; f8Out.s1 = f8InA.s1 + f8InB.s1; f8Out.s2 = f8InA.s2 + f8InB.s2; f8Out.s3 = f8InA.s3 + f8InB.s3; f8Out.s4 = f8InA.s4 + f8InB.s4; f8Out.s5 = f8InA.s5 + f8InB.s5; f8Out.s6 = f8InA.s6 + f8InB.s6; f8Out.s7 = f8InA.s7 + f8InB.s7; // write back out to GMEM c[get_global_id(0)] = f8Out; } /////////////////////////////////////////////////// //-- MAIN METHOD void processMiniCLTask(void* userPtr, void* lsMemory) { // BT_PROFILE("processSampleTask"); MiniCLTask_LocalStoreMemory* localMemory = (MiniCLTask_LocalStoreMemory*)lsMemory; MiniCLTaskDesc* taskDescPtr = (MiniCLTaskDesc*)userPtr; MiniCLTaskDesc& taskDesc = *taskDescPtr; printf("Compute Unit[%d] executed kernel %d work items [%d..%d)\n",taskDesc.m_taskId,taskDesc.m_kernelProgramId,taskDesc.m_firstWorkUnit,taskDesc.m_lastWorkUnit); switch (taskDesc.m_kernelProgramId) { case CMD_MINICL_ADDVECTOR: { for (unsigned int i=taskDesc.m_firstWorkUnit;i #define memalign(alignment, size) malloc(size); #include //memcpy #include #define spu_printf printf #else #include #include #include //for memcpy #if defined (__CELLOS_LV2__) // Playstation 3 Cell SDK #include #else // posix system #define USE_PTHREADS (1) #ifdef USE_LIBSPE2 #include #define spu_printf printf #define DWORD unsigned int typedef union { unsigned long long ull; unsigned int ui[2]; void *p; } addr64; #else #include #define spu_printf printf #endif // USE_LIBSPE2 #endif //__CELLOS_LV2__ #endif /* Included here because we need uint*_t typedefs */ #include "PpuAddressSpace.h" #endif //TYPE_DEFINITIONS_H critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/btGpu3DGridBroadphaseSharedTypes.h0000644000175000017500000000476711337073000031262 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org Copyright (C) 2006, 2009 Sony Computer Entertainment Inc. 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. */ //---------------------------------------------------------------------------------------- // Shared definitions for GPU-based 3D Grid collision detection broadphase //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // Keep this file free from Bullet headers // it is included into both CUDA and CPU code //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //---------------------------------------------------------------------------------------- #ifndef BTGPU3DGRIDBROADPHASESHAREDTYPES_H #define BTGPU3DGRIDBROADPHASESHAREDTYPES_H //---------------------------------------------------------------------------------------- #define BT_3DGRID_PAIR_FOUND_FLG (0x40000000) #define BT_3DGRID_PAIR_NEW_FLG (0x20000000) #define BT_3DGRID_PAIR_ANY_FLG (BT_3DGRID_PAIR_FOUND_FLG | BT_3DGRID_PAIR_NEW_FLG) //---------------------------------------------------------------------------------------- struct bt3DGridBroadphaseParams { unsigned int m_gridSizeX; unsigned int m_gridSizeY; unsigned int m_gridSizeZ; unsigned int m_numCells; float m_worldOriginX; float m_worldOriginY; float m_worldOriginZ; float m_cellSizeX; float m_cellSizeY; float m_cellSizeZ; unsigned int m_numBodies; unsigned int m_maxBodiesPerCell; }; //---------------------------------------------------------------------------------------- struct bt3DGrid3F1U { float fx; float fy; float fz; unsigned int uw; }; //---------------------------------------------------------------------------------------- #endif // BTGPU3DGRIDBROADPHASESHAREDTYPES_Hcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuContactManifoldCollisionAlgorithm.h0000644000175000017500000000725511337073000032312 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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 SPU_CONTACTMANIFOLD_COLLISION_ALGORITHM_H #define SPU_CONTACTMANIFOLD_COLLISION_ALGORITHM_H #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" #include "BulletCollision/BroadphaseCollision/btDispatcher.h" #include "LinearMath/btTransformUtil.h" class btPersistentManifold; //#define USE_SEPDISTANCE_UTIL 1 /// SpuContactManifoldCollisionAlgorithm provides contact manifold and should be processed on SPU. ATTRIBUTE_ALIGNED16(class) SpuContactManifoldCollisionAlgorithm : public btCollisionAlgorithm { btVector3 m_shapeDimensions0; btVector3 m_shapeDimensions1; btPersistentManifold* m_manifoldPtr; int m_shapeType0; int m_shapeType1; float m_collisionMargin0; float m_collisionMargin1; btCollisionObject* m_collisionObject0; btCollisionObject* m_collisionObject1; public: virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); SpuContactManifoldCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1); #ifdef USE_SEPDISTANCE_UTIL btConvexSeparatingDistanceUtil m_sepDistance; #endif //USE_SEPDISTANCE_UTIL virtual ~SpuContactManifoldCollisionAlgorithm(); virtual void getAllContactManifolds(btManifoldArray& manifoldArray) { if (m_manifoldPtr) manifoldArray.push_back(m_manifoldPtr); } btPersistentManifold* getContactManifoldPtr() { return m_manifoldPtr; } btCollisionObject* getCollisionObject0() { return m_collisionObject0; } btCollisionObject* getCollisionObject1() { return m_collisionObject1; } int getShapeType0() const { return m_shapeType0; } int getShapeType1() const { return m_shapeType1; } float getCollisionMargin0() const { return m_collisionMargin0; } float getCollisionMargin1() const { return m_collisionMargin1; } const btVector3& getShapeDimensions0() const { return m_shapeDimensions0; } const btVector3& getShapeDimensions1() const { return m_shapeDimensions1; } struct CreateFunc :public btCollisionAlgorithmCreateFunc { virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(SpuContactManifoldCollisionAlgorithm)); return new(mem) SpuContactManifoldCollisionAlgorithm(ci,body0,body1); } }; }; #endif //SPU_CONTACTMANIFOLD_COLLISION_ALGORITHM_H critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/PosixThreadSupport.cpp0000644000175000017500000001553511337073000027214 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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 #include "PosixThreadSupport.h" #ifdef USE_PTHREADS #include #include #include "SpuCollisionTaskProcess.h" #include "SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h" #define checkPThreadFunction(returnValue) \ if(0 != returnValue) { \ printf("PThread problem at line %i in file %s: %i %d\n", __LINE__, __FILE__, returnValue, errno); \ } // The number of threads should be equal to the number of available cores // Todo: each worker should be linked to a single core, using SetThreadIdealProcessor. // PosixThreadSupport helps to initialize/shutdown libspe2, start/stop SPU tasks and communication // Setup and initialize SPU/CELL/Libspe2 PosixThreadSupport::PosixThreadSupport(ThreadConstructionInfo& threadConstructionInfo) { startThreads(threadConstructionInfo); } // cleanup/shutdown Libspe2 PosixThreadSupport::~PosixThreadSupport() { stopSPU(); } #if (defined (__APPLE__)) #define NAMED_SEMAPHORES #endif // this semaphore will signal, if and how many threads are finished with their work static sem_t* mainSemaphore; static sem_t* createSem(const char* baseName) { static int semCount = 0; #ifdef NAMED_SEMAPHORES /// Named semaphore begin char name[32]; snprintf(name, 32, "/%s-%d-%4.4d", baseName, getpid(), semCount++); sem_t* tempSem = sem_open(name, O_CREAT, 0600, 0); if (tempSem != reinterpret_cast(SEM_FAILED)) { //printf("Created \"%s\" Semaphore %x\n", name, tempSem); } else { //printf("Error creating Semaphore %d\n", errno); exit(-1); } /// Named semaphore end #else sem_t* tempSem = new sem_t; checkPThreadFunction(sem_init(tempSem, 0, 0)); #endif return tempSem; } static void destroySem(sem_t* semaphore) { #ifdef NAMED_SEMAPHORES checkPThreadFunction(sem_close(semaphore)); #else checkPThreadFunction(sem_destroy(semaphore)); delete semaphore; #endif } static void *threadFunction(void *argument) { PosixThreadSupport::btSpuStatus* status = (PosixThreadSupport::btSpuStatus*)argument; while (1) { checkPThreadFunction(sem_wait(status->startSemaphore)); void* userPtr = status->m_userPtr; if (userPtr) { btAssert(status->m_status); status->m_userThreadFunc(userPtr,status->m_lsMemory); status->m_status = 2; checkPThreadFunction(sem_post(mainSemaphore)); status->threadUsed++; } else { //exit Thread status->m_status = 3; checkPThreadFunction(sem_post(mainSemaphore)); printf("Thread with taskId %i exiting\n",status->m_taskId); break; } } printf("Thread TERMINATED\n"); return 0; } ///send messages to SPUs void PosixThreadSupport::sendRequest(uint32_t uiCommand, ppu_address_t uiArgument0, uint32_t taskId) { /// gMidphaseSPU.sendRequest(CMD_GATHER_AND_PROCESS_PAIRLIST, (uint32_t) &taskDesc); ///we should spawn an SPU task here, and in 'waitForResponse' it should wait for response of the (one of) the first tasks that finished switch (uiCommand) { case CMD_GATHER_AND_PROCESS_PAIRLIST: { btSpuStatus& spuStatus = m_activeSpuStatus[taskId]; btAssert(taskId >= 0); btAssert(taskId < m_activeSpuStatus.size()); spuStatus.m_commandId = uiCommand; spuStatus.m_status = 1; spuStatus.m_userPtr = (void*)uiArgument0; // fire event to start new task checkPThreadFunction(sem_post(spuStatus.startSemaphore)); break; } default: { ///not implemented btAssert(0); } }; } ///check for messages from SPUs void PosixThreadSupport::waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1) { ///We should wait for (one of) the first tasks to finish (or other SPU messages), and report its response ///A possible response can be 'yes, SPU handled it', or 'no, please do a PPU fallback' btAssert(m_activeSpuStatus.size()); // wait for any of the threads to finish checkPThreadFunction(sem_wait(mainSemaphore)); // get at least one thread which has finished size_t last = -1; for(size_t t=0; t < m_activeSpuStatus.size(); ++t) { if(2 == m_activeSpuStatus[t].m_status) { last = t; break; } } btSpuStatus& spuStatus = m_activeSpuStatus[last]; btAssert(spuStatus.m_status > 1); spuStatus.m_status = 0; // need to find an active spu btAssert(last >= 0); *puiArgument0 = spuStatus.m_taskId; *puiArgument1 = spuStatus.m_status; } void PosixThreadSupport::startThreads(ThreadConstructionInfo& threadConstructionInfo) { printf("%s creating %i threads.\n", __FUNCTION__, threadConstructionInfo.m_numThreads); m_activeSpuStatus.resize(threadConstructionInfo.m_numThreads); mainSemaphore = createSem("main"); for (int i=0;i < threadConstructionInfo.m_numThreads;i++) { printf("starting thread %d\n",i); btSpuStatus& spuStatus = m_activeSpuStatus[i]; spuStatus.startSemaphore = createSem("threadLocal"); checkPThreadFunction(pthread_create(&spuStatus.thread, NULL, &threadFunction, (void*)&spuStatus)); spuStatus.m_userPtr=0; spuStatus.m_taskId = i; spuStatus.m_commandId = 0; spuStatus.m_status = 0; spuStatus.m_lsMemory = threadConstructionInfo.m_lsMemoryFunc(); spuStatus.m_userThreadFunc = threadConstructionInfo.m_userThreadFunc; spuStatus.threadUsed = 0; printf("started thread %d \n",i); } } void PosixThreadSupport::startSPU() { } ///tell the task scheduler we are done with the SPU tasks void PosixThreadSupport::stopSPU() { for(size_t t=0; t < m_activeSpuStatus.size(); ++t) { btSpuStatus& spuStatus = m_activeSpuStatus[t]; printf("%s: Thread %i used: %ld\n", __FUNCTION__, t, spuStatus.threadUsed); destroySem(spuStatus.startSemaphore); checkPThreadFunction(pthread_cancel(spuStatus.thread)); } destroySem(mainSemaphore); m_activeSpuStatus.clear(); } #endif // USE_PTHREADS critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/btThreadSupportInterface.h0000644000175000017500000000352411337073000030000 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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 THREAD_SUPPORT_INTERFACE_H #define THREAD_SUPPORT_INTERFACE_H //#include //for uint32_t etc. #include "PlatformDefinitions.h" #include "PpuAddressSpace.h" class btThreadSupportInterface { public: virtual ~btThreadSupportInterface(); ///send messages to SPUs virtual void sendRequest(uint32_t uiCommand, ppu_address_t uiArgument0, uint32_t uiArgument1) =0; ///check for messages from SPUs virtual void waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1) =0; ///start the spus (can be called at the beginning of each frame, to make sure that the right SPU program is loaded) virtual void startSPU() =0; ///tell the task scheduler we are done with the SPU tasks virtual void stopSPU()=0; ///tell the task scheduler to use no more than numTasks tasks virtual void setNumTasks(int numTasks)=0; virtual int getNumTasks() const = 0; }; #endif //THREAD_SUPPORT_INTERFACE_H critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuLibspe2Support.cpp0000644000175000017500000001411611337073000026744 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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. */ #ifdef USE_LIBSPE2 #include "SpuLibspe2Support.h" //SpuLibspe2Support helps to initialize/shutdown libspe2, start/stop SPU tasks and communication ///Setup and initialize SPU/CELL/Libspe2 SpuLibspe2Support::SpuLibspe2Support(spe_program_handle_t *speprog, int numThreads) { this->program = speprog; this->numThreads = ((numThreads <= spe_cpu_info_get(SPE_COUNT_PHYSICAL_SPES, -1)) ? numThreads : spe_cpu_info_get(SPE_COUNT_PHYSICAL_SPES, -1)); } ///cleanup/shutdown Libspe2 SpuLibspe2Support::~SpuLibspe2Support() { stopSPU(); } ///send messages to SPUs void SpuLibspe2Support::sendRequest(uint32_t uiCommand, uint32_t uiArgument0, uint32_t uiArgument1) { spe_context_ptr_t context; switch (uiCommand) { case CMD_SAMPLE_TASK_COMMAND: { //get taskdescription SpuSampleTaskDesc* taskDesc = (SpuSampleTaskDesc*) uiArgument0; btAssert(taskDesc->m_taskIdm_taskId]; //set data for spuStatus spuStatus.m_commandId = uiCommand; spuStatus.m_status = Spu_Status_Occupied; //set SPU as "occupied" spuStatus.m_taskDesc.p = taskDesc; //get context context = data[taskDesc->m_taskId].context; taskDesc->m_mainMemoryPtr = reinterpret_cast (spuStatus.m_lsMemory.p); break; } case CMD_GATHER_AND_PROCESS_PAIRLIST: { //get taskdescription SpuGatherAndProcessPairsTaskDesc* taskDesc = (SpuGatherAndProcessPairsTaskDesc*) uiArgument0; btAssert(taskDesc->taskIdtaskId]; //set data for spuStatus spuStatus.m_commandId = uiCommand; spuStatus.m_status = Spu_Status_Occupied; //set SPU as "occupied" spuStatus.m_taskDesc.p = taskDesc; //get context context = data[taskDesc->taskId].context; taskDesc->m_lsMemory = (CollisionTask_LocalStoreMemory*)spuStatus.m_lsMemory.p; break; } default: { ///not implemented btAssert(0); } }; //write taskdescription in mailbox unsigned int event = Spu_Mailbox_Event_Task; spe_in_mbox_write(context, &event, 1, SPE_MBOX_ANY_NONBLOCKING); } ///check for messages from SPUs void SpuLibspe2Support::waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1) { ///We should wait for (one of) the first tasks to finish (or other SPU messages), and report its response ///A possible response can be 'yes, SPU handled it', or 'no, please do a PPU fallback' btAssert(m_activeSpuStatus.size()); int last = -1; //find an active spu/thread while(last < 0) { for (int i=0;i=0); *puiArgument0 = spuStatus.m_taskId; *puiArgument1 = spuStatus.m_status; } void SpuLibspe2Support::startSPU() { this->internal_startSPU(); } ///start the spus group (can be called at the beginning of each frame, to make sure that the right SPU program is loaded) void SpuLibspe2Support::internal_startSPU() { m_activeSpuStatus.resize(numThreads); for (int i=0; i < numThreads; i++) { if(data[i].context == NULL) { /* Create context */ if ((data[i].context = spe_context_create(0, NULL)) == NULL) { perror ("Failed creating context"); exit(1); } /* Load program into context */ if(spe_program_load(data[i].context, this->program)) { perror ("Failed loading program"); exit(1); } m_activeSpuStatus[i].m_status = Spu_Status_Startup; m_activeSpuStatus[i].m_taskId = i; m_activeSpuStatus[i].m_commandId = 0; m_activeSpuStatus[i].m_lsMemory.p = NULL; data[i].entry = SPE_DEFAULT_ENTRY; data[i].flags = 0; data[i].argp.p = &m_activeSpuStatus[i]; data[i].envp.p = NULL; /* Create thread for each SPE context */ if (pthread_create(&data[i].pthread, NULL, &ppu_pthread_function, &(data[i]) )) { perror ("Failed creating thread"); exit(1); } /* else { printf("started thread %d\n",i); }*/ } } for (int i=0; i < numThreads; i++) { if(data[i].context != NULL) { while( m_activeSpuStatus[i].m_status == Spu_Status_Startup) { // wait for spu to set up sched_yield(); } printf("Spu %d is ready\n", i); } } } ///tell the task scheduler we are done with the SPU tasks void SpuLibspe2Support::stopSPU() { // wait for all threads to finish int i; for ( i = 0; i < this->numThreads; i++ ) { unsigned int event = Spu_Mailbox_Event_Shutdown; spe_context_ptr_t context = data[i].context; spe_in_mbox_write(context, &event, 1, SPE_MBOX_ALL_BLOCKING); pthread_join (data[i].pthread, NULL); } // close SPE program spe_image_close(program); // destroy SPE contexts for ( i = 0; i < this->numThreads; i++ ) { if(data[i].context != NULL) { spe_context_destroy (data[i].context); } } m_activeSpuStatus.clear(); } #endif //USE_LIBSPE2 critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/btGpu3DGridBroadphaseSharedCode.h0000644000175000017500000004371411337073000031023 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org Copyright (C) 2006, 2009 Sony Computer Entertainment Inc. 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. */ //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- // K E R N E L F U N C T I O N S //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- // calculate position in uniform grid BT_GPU___device__ int3 bt3DGrid_calcGridPos(float4 p) { int3 gridPos; gridPos.x = (int)floor((p.x - BT_GPU_params.m_worldOriginX) / BT_GPU_params.m_cellSizeX); gridPos.y = (int)floor((p.y - BT_GPU_params.m_worldOriginY) / BT_GPU_params.m_cellSizeY); gridPos.z = (int)floor((p.z - BT_GPU_params.m_worldOriginZ) / BT_GPU_params.m_cellSizeZ); return gridPos; } // bt3DGrid_calcGridPos() //---------------------------------------------------------------------------------------- // calculate address in grid from position (clamping to edges) BT_GPU___device__ uint bt3DGrid_calcGridHash(int3 gridPos) { gridPos.x = BT_GPU_max(0, BT_GPU_min(gridPos.x, (int)BT_GPU_params.m_gridSizeX - 1)); gridPos.y = BT_GPU_max(0, BT_GPU_min(gridPos.y, (int)BT_GPU_params.m_gridSizeY - 1)); gridPos.z = BT_GPU_max(0, BT_GPU_min(gridPos.z, (int)BT_GPU_params.m_gridSizeZ - 1)); return BT_GPU___mul24(BT_GPU___mul24(gridPos.z, BT_GPU_params.m_gridSizeY), BT_GPU_params.m_gridSizeX) + BT_GPU___mul24(gridPos.y, BT_GPU_params.m_gridSizeX) + gridPos.x; } // bt3DGrid_calcGridHash() //---------------------------------------------------------------------------------------- // calculate grid hash value for each body using its AABB BT_GPU___global__ void calcHashAABBD(bt3DGrid3F1U* pAABB, uint2* pHash, uint numBodies) { int index = BT_GPU___mul24(BT_GPU_blockIdx.x, BT_GPU_blockDim.x) + BT_GPU_threadIdx.x; if(index >= (int)numBodies) { return; } bt3DGrid3F1U bbMin = pAABB[index*2]; bt3DGrid3F1U bbMax = pAABB[index*2 + 1]; float4 pos; pos.x = (bbMin.fx + bbMax.fx) * 0.5f; pos.y = (bbMin.fy + bbMax.fy) * 0.5f; pos.z = (bbMin.fz + bbMax.fz) * 0.5f; // get address in grid int3 gridPos = bt3DGrid_calcGridPos(pos); uint gridHash = bt3DGrid_calcGridHash(gridPos); // store grid hash and body index pHash[index] = BT_GPU_make_uint2(gridHash, index); } // calcHashAABBD() //---------------------------------------------------------------------------------------- BT_GPU___global__ void findCellStartD(uint2* pHash, uint* cellStart, uint numBodies) { int index = BT_GPU___mul24(BT_GPU_blockIdx.x, BT_GPU_blockDim.x) + BT_GPU_threadIdx.x; if(index >= (int)numBodies) { return; } uint2 sortedData = pHash[index]; // Load hash data into shared memory so that we can look // at neighboring body's hash value without loading // two hash values per thread BT_GPU___shared__ uint sharedHash[257]; sharedHash[BT_GPU_threadIdx.x+1] = sortedData.x; if((index > 0) && (BT_GPU_threadIdx.x == 0)) { // first thread in block must load neighbor body hash volatile uint2 prevData = pHash[index-1]; sharedHash[0] = prevData.x; } BT_GPU___syncthreads(); if((index == 0) || (sortedData.x != sharedHash[BT_GPU_threadIdx.x])) { cellStart[sortedData.x] = index; } } // findCellStartD() //---------------------------------------------------------------------------------------- BT_GPU___device__ uint cudaTestAABBOverlap(bt3DGrid3F1U min0, bt3DGrid3F1U max0, bt3DGrid3F1U min1, bt3DGrid3F1U max1) { return (min0.fx <= max1.fx)&& (min1.fx <= max0.fx) && (min0.fy <= max1.fy)&& (min1.fy <= max0.fy) && (min0.fz <= max1.fz)&& (min1.fz <= max0.fz); } // cudaTestAABBOverlap() //---------------------------------------------------------------------------------------- BT_GPU___device__ void findPairsInCell( int3 gridPos, uint index, uint2* pHash, uint* pCellStart, bt3DGrid3F1U* pAABB, uint* pPairBuff, uint2* pPairBuffStartCurr, uint numBodies) { if ( (gridPos.x < 0) || (gridPos.x > (int)BT_GPU_params.m_gridSizeX - 1) || (gridPos.y < 0) || (gridPos.y > (int)BT_GPU_params.m_gridSizeY - 1) || (gridPos.z < 0) || (gridPos.z > (int)BT_GPU_params.m_gridSizeZ - 1)) { return; } uint gridHash = bt3DGrid_calcGridHash(gridPos); // get start of bucket for this cell uint bucketStart = pCellStart[gridHash]; if (bucketStart == 0xffffffff) { return; // cell empty } // iterate over bodies in this cell uint2 sortedData = pHash[index]; uint unsorted_indx = sortedData.y; bt3DGrid3F1U min0 = BT_GPU_FETCH(pAABB, unsorted_indx*2); bt3DGrid3F1U max0 = BT_GPU_FETCH(pAABB, unsorted_indx*2 + 1); uint handleIndex = min0.uw; uint2 start_curr = pPairBuffStartCurr[handleIndex]; uint start = start_curr.x; uint curr = start_curr.y; uint2 start_curr_next = pPairBuffStartCurr[handleIndex+1]; uint curr_max = start_curr_next.x - start - 1; uint bucketEnd = bucketStart + BT_GPU_params.m_maxBodiesPerCell; bucketEnd = (bucketEnd > numBodies) ? numBodies : bucketEnd; for(uint index2 = bucketStart; index2 < bucketEnd; index2++) { uint2 cellData = pHash[index2]; if (cellData.x != gridHash) { break; // no longer in same bucket } uint unsorted_indx2 = cellData.y; if (unsorted_indx2 < unsorted_indx) // check not colliding with self { bt3DGrid3F1U min1 = BT_GPU_FETCH(pAABB, unsorted_indx2*2); bt3DGrid3F1U max1 = BT_GPU_FETCH(pAABB, unsorted_indx2*2 + 1); if(cudaTestAABBOverlap(min0, max0, min1, max1)) { uint handleIndex2 = min1.uw; uint k; for(k = 0; k < curr; k++) { uint old_pair = pPairBuff[start+k] & (~BT_3DGRID_PAIR_ANY_FLG); if(old_pair == handleIndex2) { pPairBuff[start+k] |= BT_3DGRID_PAIR_FOUND_FLG; break; } } if(k == curr) { if(curr >= curr_max) { // not a good solution, but let's avoid crash break; } pPairBuff[start+curr] = handleIndex2 | BT_3DGRID_PAIR_NEW_FLG; curr++; } } } } pPairBuffStartCurr[handleIndex] = BT_GPU_make_uint2(start, curr); return; } // findPairsInCell() //---------------------------------------------------------------------------------------- BT_GPU___global__ void findOverlappingPairsD( bt3DGrid3F1U* pAABB, uint2* pHash, uint* pCellStart, uint* pPairBuff, uint2* pPairBuffStartCurr, uint numBodies) { int index = BT_GPU___mul24(BT_GPU_blockIdx.x, BT_GPU_blockDim.x) + BT_GPU_threadIdx.x; if(index >= (int)numBodies) { return; } uint2 sortedData = pHash[index]; uint unsorted_indx = sortedData.y; bt3DGrid3F1U bbMin = BT_GPU_FETCH(pAABB, unsorted_indx*2); bt3DGrid3F1U bbMax = BT_GPU_FETCH(pAABB, unsorted_indx*2 + 1); float4 pos; pos.x = (bbMin.fx + bbMax.fx) * 0.5f; pos.y = (bbMin.fy + bbMax.fy) * 0.5f; pos.z = (bbMin.fz + bbMax.fz) * 0.5f; // get address in grid int3 gridPos = bt3DGrid_calcGridPos(pos); // examine only neighbouring cells for(int z=-1; z<=1; z++) { for(int y=-1; y<=1; y++) { for(int x=-1; x<=1; x++) { findPairsInCell(gridPos + BT_GPU_make_int3(x, y, z), index, pHash, pCellStart, pAABB, pPairBuff, pPairBuffStartCurr, numBodies); } } } } // findOverlappingPairsD() //---------------------------------------------------------------------------------------- BT_GPU___global__ void findPairsLargeD( bt3DGrid3F1U* pAABB, uint2* pHash, uint* pCellStart, uint* pPairBuff, uint2* pPairBuffStartCurr, uint numBodies, uint numLarge) { int index = BT_GPU___mul24(BT_GPU_blockIdx.x, BT_GPU_blockDim.x) + BT_GPU_threadIdx.x; if(index >= (int)numBodies) { return; } uint2 sortedData = pHash[index]; uint unsorted_indx = sortedData.y; bt3DGrid3F1U min0 = BT_GPU_FETCH(pAABB, unsorted_indx*2); bt3DGrid3F1U max0 = BT_GPU_FETCH(pAABB, unsorted_indx*2 + 1); uint handleIndex = min0.uw; uint2 start_curr = pPairBuffStartCurr[handleIndex]; uint start = start_curr.x; uint curr = start_curr.y; uint2 start_curr_next = pPairBuffStartCurr[handleIndex+1]; uint curr_max = start_curr_next.x - start - 1; for(uint i = 0; i < numLarge; i++) { uint indx2 = numBodies + i; bt3DGrid3F1U min1 = BT_GPU_FETCH(pAABB, indx2*2); bt3DGrid3F1U max1 = BT_GPU_FETCH(pAABB, indx2*2 + 1); if(cudaTestAABBOverlap(min0, max0, min1, max1)) { uint k; uint handleIndex2 = min1.uw; for(k = 0; k < curr; k++) { uint old_pair = pPairBuff[start+k] & (~BT_3DGRID_PAIR_ANY_FLG); if(old_pair == handleIndex2) { pPairBuff[start+k] |= BT_3DGRID_PAIR_FOUND_FLG; break; } } if(k == curr) { pPairBuff[start+curr] = handleIndex2 | BT_3DGRID_PAIR_NEW_FLG; if(curr >= curr_max) { // not a good solution, but let's avoid crash break; } curr++; } } } pPairBuffStartCurr[handleIndex] = BT_GPU_make_uint2(start, curr); return; } // findPairsLargeD() //---------------------------------------------------------------------------------------- BT_GPU___global__ void computePairCacheChangesD(uint* pPairBuff, uint2* pPairBuffStartCurr, uint* pPairScan, bt3DGrid3F1U* pAABB, uint numBodies) { int index = BT_GPU___mul24(BT_GPU_blockIdx.x, BT_GPU_blockDim.x) + BT_GPU_threadIdx.x; if(index >= (int)numBodies) { return; } bt3DGrid3F1U bbMin = pAABB[index * 2]; uint handleIndex = bbMin.uw; uint2 start_curr = pPairBuffStartCurr[handleIndex]; uint start = start_curr.x; uint curr = start_curr.y; uint *pInp = pPairBuff + start; uint num_changes = 0; for(uint k = 0; k < curr; k++, pInp++) { if(!((*pInp) & BT_3DGRID_PAIR_FOUND_FLG)) { num_changes++; } } pPairScan[index+1] = num_changes; } // computePairCacheChangesD() //---------------------------------------------------------------------------------------- BT_GPU___global__ void squeezeOverlappingPairBuffD(uint* pPairBuff, uint2* pPairBuffStartCurr, uint* pPairScan, uint* pPairOut, bt3DGrid3F1U* pAABB, uint numBodies) { int index = BT_GPU___mul24(BT_GPU_blockIdx.x, BT_GPU_blockDim.x) + BT_GPU_threadIdx.x; if(index >= (int)numBodies) { return; } bt3DGrid3F1U bbMin = pAABB[index * 2]; uint handleIndex = bbMin.uw; uint2 start_curr = pPairBuffStartCurr[handleIndex]; uint start = start_curr.x; uint curr = start_curr.y; uint* pInp = pPairBuff + start; uint* pOut = pPairOut + pPairScan[index]; uint* pOut2 = pInp; uint num = 0; for(uint k = 0; k < curr; k++, pInp++) { if(!((*pInp) & BT_3DGRID_PAIR_FOUND_FLG)) { *pOut = *pInp; pOut++; } if((*pInp) & BT_3DGRID_PAIR_ANY_FLG) { *pOut2 = (*pInp) & (~BT_3DGRID_PAIR_ANY_FLG); pOut2++; num++; } } pPairBuffStartCurr[handleIndex] = BT_GPU_make_uint2(start, num); } // squeezeOverlappingPairBuffD() //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- // E N D O F K E R N E L F U N C T I O N S //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- //---------------------------------------------------------------------------------------- extern "C" { //---------------------------------------------------------------------------------------- void BT_GPU_PREF(calcHashAABB)(bt3DGrid3F1U* pAABB, unsigned int* hash, unsigned int numBodies) { int numThreads, numBlocks; BT_GPU_PREF(computeGridSize)(numBodies, 256, numBlocks, numThreads); // execute the kernel BT_GPU_EXECKERNEL(numBlocks, numThreads, calcHashAABBD, (pAABB, (uint2*)hash, numBodies)); // check if kernel invocation generated an error BT_GPU_CHECK_ERROR("calcHashAABBD kernel execution failed"); } // calcHashAABB() //---------------------------------------------------------------------------------------- void BT_GPU_PREF(findCellStart(unsigned int* hash, unsigned int* cellStart, unsigned int numBodies, unsigned int numCells)) { int numThreads, numBlocks; BT_GPU_PREF(computeGridSize)(numBodies, 256, numBlocks, numThreads); BT_GPU_SAFE_CALL(BT_GPU_Memset(cellStart, 0xffffffff, numCells*sizeof(uint))); BT_GPU_EXECKERNEL(numBlocks, numThreads, findCellStartD, ((uint2*)hash, (uint*)cellStart, numBodies)); BT_GPU_CHECK_ERROR("Kernel execution failed: findCellStartD"); } // findCellStart() //---------------------------------------------------------------------------------------- void BT_GPU_PREF(findOverlappingPairs(bt3DGrid3F1U* pAABB, unsigned int* pHash, unsigned int* pCellStart, unsigned int* pPairBuff, unsigned int* pPairBuffStartCurr, unsigned int numBodies)) { #if B_CUDA_USE_TEX BT_GPU_SAFE_CALL(cudaBindTexture(0, pAABBTex, pAABB, numBodies * 2 * sizeof(bt3DGrid3F1U))); #endif int numThreads, numBlocks; BT_GPU_PREF(computeGridSize)(numBodies, 64, numBlocks, numThreads); BT_GPU_EXECKERNEL(numBlocks, numThreads, findOverlappingPairsD, (pAABB,(uint2*)pHash,(uint*)pCellStart,(uint*)pPairBuff,(uint2*)pPairBuffStartCurr,numBodies)); BT_GPU_CHECK_ERROR("Kernel execution failed: bt_CudaFindOverlappingPairsD"); #if B_CUDA_USE_TEX BT_GPU_SAFE_CALL(cudaUnbindTexture(pAABBTex)); #endif } // findOverlappingPairs() //---------------------------------------------------------------------------------------- void BT_GPU_PREF(findPairsLarge(bt3DGrid3F1U* pAABB, unsigned int* pHash, unsigned int* pCellStart, unsigned int* pPairBuff, unsigned int* pPairBuffStartCurr, unsigned int numBodies, unsigned int numLarge)) { #if B_CUDA_USE_TEX BT_GPU_SAFE_CALL(cudaBindTexture(0, pAABBTex, pAABB, (numBodies+numLarge) * 2 * sizeof(bt3DGrid3F1U))); #endif int numThreads, numBlocks; BT_GPU_PREF(computeGridSize)(numBodies, 64, numBlocks, numThreads); BT_GPU_EXECKERNEL(numBlocks, numThreads, findPairsLargeD, (pAABB,(uint2*)pHash,(uint*)pCellStart,(uint*)pPairBuff,(uint2*)pPairBuffStartCurr,numBodies,numLarge)); BT_GPU_CHECK_ERROR("Kernel execution failed: btCuda_findPairsLargeD"); #if B_CUDA_USE_TEX BT_GPU_SAFE_CALL(cudaUnbindTexture(pAABBTex)); #endif } // findPairsLarge() //---------------------------------------------------------------------------------------- void BT_GPU_PREF(computePairCacheChanges(unsigned int* pPairBuff, unsigned int* pPairBuffStartCurr, unsigned int* pPairScan, bt3DGrid3F1U* pAABB, unsigned int numBodies)) { int numThreads, numBlocks; BT_GPU_PREF(computeGridSize)(numBodies, 256, numBlocks, numThreads); BT_GPU_EXECKERNEL(numBlocks, numThreads, computePairCacheChangesD, ((uint*)pPairBuff,(uint2*)pPairBuffStartCurr,(uint*)pPairScan,pAABB,numBodies)); BT_GPU_CHECK_ERROR("Kernel execution failed: btCudaComputePairCacheChangesD"); } // computePairCacheChanges() //---------------------------------------------------------------------------------------- void BT_GPU_PREF(squeezeOverlappingPairBuff(unsigned int* pPairBuff, unsigned int* pPairBuffStartCurr, unsigned int* pPairScan, unsigned int* pPairOut, bt3DGrid3F1U* pAABB, unsigned int numBodies)) { int numThreads, numBlocks; BT_GPU_PREF(computeGridSize)(numBodies, 256, numBlocks, numThreads); BT_GPU_EXECKERNEL(numBlocks, numThreads, squeezeOverlappingPairBuffD, ((uint*)pPairBuff,(uint2*)pPairBuffStartCurr,(uint*)pPairScan,(uint*)pPairOut,pAABB,numBodies)); BT_GPU_CHECK_ERROR("Kernel execution failed: btCudaSqueezeOverlappingPairBuffD"); } // btCuda_squeezeOverlappingPairBuff() //------------------------------------------------------------------------------------------------ } // extern "C" //------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------ //------------------------------------------------------------------------------------------------ critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/0000755000175000017500000000000011347266042030303 5ustar bobkebobke././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionShapes.hcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionSh0000644000175000017500000001366311337073000033142 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 __SPU_COLLISION_SHAPES_H #define __SPU_COLLISION_SHAPES_H #include "../SpuDoubleBuffer.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/CollisionShapes/btConvexInternalShape.h" #include "BulletCollision/CollisionShapes/btCylinderShape.h" #include "BulletCollision/CollisionShapes/btOptimizedBvh.h" #include "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" #include "BulletCollision/CollisionShapes/btCapsuleShape.h" #include "BulletCollision/CollisionShapes/btConvexShape.h" #include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" #include "BulletCollision/CollisionShapes/btConvexHullShape.h" #include "BulletCollision/CollisionShapes/btCompoundShape.h" #define MAX_NUM_SPU_CONVEX_POINTS 128 ATTRIBUTE_ALIGNED16(struct) SpuConvexPolyhedronVertexData { void* gSpuConvexShapePtr; btVector3* gConvexPoints; int gNumConvexPoints; int unused; ATTRIBUTE_ALIGNED16(btVector3 g_convexPointBuffer[MAX_NUM_SPU_CONVEX_POINTS]); }; #define MAX_SHAPE_SIZE 256 ATTRIBUTE_ALIGNED16(struct) CollisionShape_LocalStoreMemory { ATTRIBUTE_ALIGNED16(char collisionShape[MAX_SHAPE_SIZE]); }; ATTRIBUTE_ALIGNED16(struct) CompoundShape_LocalStoreMemory { // Compound data #define MAX_SPU_COMPOUND_SUBSHAPES 16 ATTRIBUTE_ALIGNED16(btCompoundShapeChild gSubshapes[MAX_SPU_COMPOUND_SUBSHAPES]); ATTRIBUTE_ALIGNED16(char gSubshapeShape[MAX_SPU_COMPOUND_SUBSHAPES][MAX_SHAPE_SIZE]); }; ATTRIBUTE_ALIGNED16(struct) bvhMeshShape_LocalStoreMemory { //ATTRIBUTE_ALIGNED16(btOptimizedBvh gOptimizedBvh); ATTRIBUTE_ALIGNED16(char gOptimizedBvh[sizeof(btOptimizedBvh)+16]); btOptimizedBvh* getOptimizedBvh() { return (btOptimizedBvh*) gOptimizedBvh; } ATTRIBUTE_ALIGNED16(btTriangleIndexVertexArray gTriangleMeshInterfaceStorage); btTriangleIndexVertexArray* gTriangleMeshInterfacePtr; ///only a single mesh part for now, we can add support for multiple parts, but quantized trees don't support this at the moment ATTRIBUTE_ALIGNED16(btIndexedMesh gIndexMesh); #define MAX_SPU_SUBTREE_HEADERS 32 //1024 ATTRIBUTE_ALIGNED16(btBvhSubtreeInfo gSubtreeHeaders[MAX_SPU_SUBTREE_HEADERS]); ATTRIBUTE_ALIGNED16(btQuantizedBvhNode gSubtreeNodes[MAX_SUBTREE_SIZE_IN_BYTES/sizeof(btQuantizedBvhNode)]); }; void computeAabb (btVector3& aabbMin, btVector3& aabbMax, btConvexInternalShape* convexShape, ppu_address_t convexShapePtr, int shapeType, const btTransform& xform); void dmaBvhShapeData (bvhMeshShape_LocalStoreMemory* bvhMeshShape, btBvhTriangleMeshShape* triMeshShape); void dmaBvhIndexedMesh (btIndexedMesh* IndexMesh, IndexedMeshArray& indexArray, int index, uint32_t dmaTag); void dmaBvhSubTreeHeaders (btBvhSubtreeInfo* subTreeHeaders, ppu_address_t subTreePtr, int batchSize, uint32_t dmaTag); void dmaBvhSubTreeNodes (btQuantizedBvhNode* nodes, const btBvhSubtreeInfo& subtree, QuantizedNodeArray& nodeArray, int dmaTag); int getShapeTypeSize(int shapeType); void dmaConvexVertexData (SpuConvexPolyhedronVertexData* convexVertexData, btConvexHullShape* convexShapeSPU); void dmaCollisionShape (void* collisionShapeLocation, ppu_address_t collisionShapePtr, uint32_t dmaTag, int shapeType); void dmaCompoundShapeInfo (CompoundShape_LocalStoreMemory* compoundShapeLocation, btCompoundShape* spuCompoundShape, uint32_t dmaTag); void dmaCompoundSubShapes (CompoundShape_LocalStoreMemory* compoundShapeLocation, btCompoundShape* spuCompoundShape, uint32_t dmaTag); #define USE_BRANCHFREE_TEST 1 #ifdef USE_BRANCHFREE_TEST SIMD_FORCE_INLINE unsigned int spuTestQuantizedAabbAgainstQuantizedAabb(unsigned short int* aabbMin1,unsigned short int* aabbMax1,const unsigned short int* aabbMin2,const unsigned short int* aabbMax2) { #if defined(__CELLOS_LV2__) && defined (__SPU__) vec_ushort8 vecMin = {aabbMin1[0],aabbMin2[0],aabbMin1[2],aabbMin2[2],aabbMin1[1],aabbMin2[1],0,0}; vec_ushort8 vecMax = {aabbMax2[0],aabbMax1[0],aabbMax2[2],aabbMax1[2],aabbMax2[1],aabbMax1[1],0,0}; vec_ushort8 isGt = spu_cmpgt(vecMin,vecMax); return spu_extract(spu_gather(isGt),0)==0; #else return btSelect((unsigned)((aabbMin1[0] <= aabbMax2[0]) & (aabbMax1[0] >= aabbMin2[0]) & (aabbMin1[2] <= aabbMax2[2]) & (aabbMax1[2] >= aabbMin2[2]) & (aabbMin1[1] <= aabbMax2[1]) & (aabbMax1[1] >= aabbMin2[1])), 1, 0); #endif } #else SIMD_FORCE_INLINE unsigned int spuTestQuantizedAabbAgainstQuantizedAabb(const unsigned short int* aabbMin1,const unsigned short int* aabbMax1,const unsigned short int* aabbMin2,const unsigned short int* aabbMax2) { unsigned int overlap = 1; overlap = (aabbMin1[0] > aabbMax2[0] || aabbMax1[0] < aabbMin2[0]) ? 0 : overlap; overlap = (aabbMin1[2] > aabbMax2[2] || aabbMax1[2] < aabbMin2[2]) ? 0 : overlap; overlap = (aabbMin1[1] > aabbMax2[1] || aabbMax1[1] < aabbMin2[1]) ? 0 : overlap; return overlap; } #endif void spuWalkStacklessQuantizedTree(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax,const btQuantizedBvhNode* rootNode,int startNodeIndex,int endNodeIndex); #endif ././@LongLink0000000000000000000000000000017300000000000011566 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuMinkowskiPenetrationDepthSolver.hcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuMinkowskiPe0000644000175000017500000000365211337073000033151 0ustar bobkebobke /* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 MINKOWSKI_PENETRATION_DEPTH_SOLVER_H #define MINKOWSKI_PENETRATION_DEPTH_SOLVER_H #include "BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h" class btStackAlloc; class btIDebugDraw; class btVoronoiSimplexSolver; class btConvexShape; ///MinkowskiPenetrationDepthSolver implements bruteforce penetration depth estimation. ///Implementation is based on sampling the depth using support mapping, and using GJK step to get the witness points. class SpuMinkowskiPenetrationDepthSolver : public btConvexPenetrationDepthSolver { public: SpuMinkowskiPenetrationDepthSolver() {} virtual ~SpuMinkowskiPenetrationDepthSolver() {}; virtual bool calcPenDepth( btSimplexSolverInterface& simplexSolver, const btConvexShape* convexA,const btConvexShape* convexB, const btTransform& transA,const btTransform& transB, btVector3& v, btVector3& pa, btVector3& pb, class btIDebugDraw* debugDraw,btStackAlloc* stackAlloc ); }; #endif //MINKOWSKI_PENETRATION_DEPTH_SOLVER_H ././@LongLink0000000000000000000000000000016400000000000011566 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.cppcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGatheringCo0000644000175000017500000013202411337073000033077 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "SpuGatheringCollisionTask.h" //#define DEBUG_SPU_COLLISION_DETECTION 1 #include "../SpuDoubleBuffer.h" #include "../SpuCollisionTaskProcess.h" #include "../SpuGatheringCollisionDispatcher.h" //for SPU_BATCHSIZE_BROADPHASE_PAIRS #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "../SpuContactManifoldCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "SpuContactResult.h" #include "BulletCollision/CollisionShapes/btOptimizedBvh.h" #include "BulletCollision/CollisionShapes/btTriangleIndexVertexArray.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" #include "BulletCollision/CollisionShapes/btConvexPointCloudShape.h" #include "BulletCollision/CollisionShapes/btCapsuleShape.h" #include "BulletCollision/CollisionShapes/btConvexShape.h" #include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" #include "BulletCollision/CollisionShapes/btConvexHullShape.h" #include "BulletCollision/CollisionShapes/btCompoundShape.h" #include "SpuMinkowskiPenetrationDepthSolver.h" //#include "SpuEpaPenetrationDepthSolver.h" #include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" #include "boxBoxDistance.h" #include "BulletMultiThreaded/vectormath2bullet.h" #include "SpuCollisionShapes.h" //definition of SpuConvexPolyhedronVertexData #include "BulletCollision/CollisionDispatch/btBoxBoxDetector.h" #include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h" #include "BulletCollision/CollisionShapes/btTriangleShape.h" #ifdef __SPU__ ///Software caching from the IBM Cell SDK, it reduces 25% SPU time for our test cases #ifndef USE_LIBSPE2 #define USE_SOFTWARE_CACHE 1 #endif #endif //__SPU__ int gSkippedCol = 0; int gProcessedCol = 0; //////////////////////////////////////////////// /// software caching #if USE_SOFTWARE_CACHE #include #include #include #include #define SPE_CACHE_NWAY 4 //#define SPE_CACHE_NSETS 32, 16 #define SPE_CACHE_NSETS 8 //#define SPE_CACHELINE_SIZE 512 #define SPE_CACHELINE_SIZE 128 #define SPE_CACHE_SET_TAGID(set) 15 ///make sure that spe_cache.h is below those defines! #include "../Extras/software_cache/cache/include/spe_cache.h" int g_CacheMisses=0; int g_CacheHits=0; #if 0 // Added to allow cache misses and hits to be tracked, change this to 1 to restore unmodified version #define spe_cache_read(ea) _spe_cache_lookup_xfer_wait_(ea, 0, 1) #else #define spe_cache_read(ea) \ ({ \ int set, idx, line, byte; \ _spe_cache_nway_lookup_(ea, set, idx); \ \ if (btUnlikely(idx < 0)) { \ ++g_CacheMisses; \ idx = _spe_cache_miss_(ea, set, -1); \ spu_writech(22, SPE_CACHE_SET_TAGMASK(set)); \ spu_mfcstat(MFC_TAG_UPDATE_ALL); \ } \ else \ { \ ++g_CacheHits; \ } \ line = _spe_cacheline_num_(set, idx); \ byte = _spe_cacheline_byte_offset_(ea); \ (void *) &spe_cache_mem[line + byte]; \ }) #endif #endif // USE_SOFTWARE_CACHE bool gUseEpa = false; #ifdef USE_SN_TUNER #include #endif //USE_SN_TUNER #if defined (__SPU__) && !defined (USE_LIBSPE2) #include #elif defined (USE_LIBSPE2) #define spu_printf(a) #else #define IGNORE_ALIGNMENT 1 #include #include #define spu_printf printf #endif //int gNumConvexPoints0=0; ///Make sure no destructors are called on this memory struct CollisionTask_LocalStoreMemory { ///This CollisionTask_LocalStoreMemory is mainly used for the SPU version, using explicit DMA ///Other platforms can use other memory programming models. ATTRIBUTE_ALIGNED16(btBroadphasePair gBroadphasePairsBuffer[SPU_BATCHSIZE_BROADPHASE_PAIRS]); DoubleBuffer g_workUnitTaskBuffers; ATTRIBUTE_ALIGNED16(char gSpuContactManifoldAlgoBuffer [sizeof(SpuContactManifoldCollisionAlgorithm)+16]); ATTRIBUTE_ALIGNED16(char gColObj0Buffer [sizeof(btCollisionObject)+16]); ATTRIBUTE_ALIGNED16(char gColObj1Buffer [sizeof(btCollisionObject)+16]); ///we reserve 32bit integer indices, even though they might be 16bit ATTRIBUTE_ALIGNED16(int spuIndices[16]); btPersistentManifold gPersistentManifoldBuffer; CollisionShape_LocalStoreMemory gCollisionShapes[2]; bvhMeshShape_LocalStoreMemory bvhShapeData; SpuConvexPolyhedronVertexData convexVertexData[2]; CompoundShape_LocalStoreMemory compoundShapeData[2]; ///The following pointers might either point into this local store memory, or to the original/other memory locations. ///See SpuFakeDma for implementation of cellDmaSmallGetReadOnly. btCollisionObject* m_lsColObj0Ptr; btCollisionObject* m_lsColObj1Ptr; btBroadphasePair* m_pairsPointer; btPersistentManifold* m_lsManifoldPtr; SpuContactManifoldCollisionAlgorithm* m_lsCollisionAlgorithmPtr; bool needsDmaPutContactManifoldAlgo; btCollisionObject* getColObj0() { return m_lsColObj0Ptr; } btCollisionObject* getColObj1() { return m_lsColObj1Ptr; } btBroadphasePair* getBroadphasePairPtr() { return m_pairsPointer; } SpuContactManifoldCollisionAlgorithm* getlocalCollisionAlgorithm() { return m_lsCollisionAlgorithmPtr; } btPersistentManifold* getContactManifoldPtr() { return m_lsManifoldPtr; } }; #if defined(__CELLOS_LV2__) || defined(USE_LIBSPE2) ATTRIBUTE_ALIGNED16(CollisionTask_LocalStoreMemory gLocalStoreMemory); void* createCollisionLocalStoreMemory() { return &gLocalStoreMemory; } #else void* createCollisionLocalStoreMemory() { return new CollisionTask_LocalStoreMemory; } #endif void ProcessSpuConvexConvexCollision(SpuCollisionPairInput* wuInput, CollisionTask_LocalStoreMemory* lsMemPtr, SpuContactResult& spuContacts); SIMD_FORCE_INLINE void small_cache_read(void* buffer, ppu_address_t ea, size_t size) { #if USE_SOFTWARE_CACHE // Check for alignment requirements. We need to make sure the entire request fits within one cache line, // so the first and last bytes should fall on the same cache line btAssert((ea & ~SPE_CACHELINE_MASK) == ((ea + size - 1) & ~SPE_CACHELINE_MASK)); void* ls = spe_cache_read(ea); memcpy(buffer, ls, size); #else stallingUnalignedDmaSmallGet(buffer,ea,size); #endif } SIMD_FORCE_INLINE void small_cache_read_triple( void* ls0, ppu_address_t ea0, void* ls1, ppu_address_t ea1, void* ls2, ppu_address_t ea2, size_t size) { btAssert(size<16); ATTRIBUTE_ALIGNED16(char tmpBuffer0[32]); ATTRIBUTE_ALIGNED16(char tmpBuffer1[32]); ATTRIBUTE_ALIGNED16(char tmpBuffer2[32]); uint32_t i; ///make sure last 4 bits are the same, for cellDmaSmallGet char* localStore0 = (char*)ls0; uint32_t last4BitsOffset = ea0 & 0x0f; char* tmpTarget0 = tmpBuffer0 + last4BitsOffset; #ifdef __SPU__ cellDmaSmallGet(tmpTarget0,ea0,size,DMA_TAG(1),0,0); #else tmpTarget0 = (char*)cellDmaSmallGetReadOnly(tmpTarget0,ea0,size,DMA_TAG(1),0,0); #endif char* localStore1 = (char*)ls1; last4BitsOffset = ea1 & 0x0f; char* tmpTarget1 = tmpBuffer1 + last4BitsOffset; #ifdef __SPU__ cellDmaSmallGet(tmpTarget1,ea1,size,DMA_TAG(1),0,0); #else tmpTarget1 = (char*)cellDmaSmallGetReadOnly(tmpTarget1,ea1,size,DMA_TAG(1),0,0); #endif char* localStore2 = (char*)ls2; last4BitsOffset = ea2 & 0x0f; char* tmpTarget2 = tmpBuffer2 + last4BitsOffset; #ifdef __SPU__ cellDmaSmallGet(tmpTarget2,ea2,size,DMA_TAG(1),0,0); #else tmpTarget2 = (char*)cellDmaSmallGetReadOnly(tmpTarget2,ea2,size,DMA_TAG(1),0,0); #endif cellDmaWaitTagStatusAll( DMA_MASK(1) ); //this is slowish, perhaps memcpy on SPU is smarter? for (i=0; btLikely( ibvhShapeData.gIndexMesh.m_indexType == PHY_SHORT) { unsigned short int* indexBasePtr = (unsigned short int*)(m_lsMemPtr->bvhShapeData.gIndexMesh.m_triangleIndexBase+triangleIndex*m_lsMemPtr->bvhShapeData.gIndexMesh.m_triangleIndexStride); ATTRIBUTE_ALIGNED16(unsigned short int tmpIndices[3]); small_cache_read_triple(&tmpIndices[0],(ppu_address_t)&indexBasePtr[0], &tmpIndices[1],(ppu_address_t)&indexBasePtr[1], &tmpIndices[2],(ppu_address_t)&indexBasePtr[2], sizeof(unsigned short int)); m_lsMemPtr->spuIndices[0] = int(tmpIndices[0]); m_lsMemPtr->spuIndices[1] = int(tmpIndices[1]); m_lsMemPtr->spuIndices[2] = int(tmpIndices[2]); } else { unsigned int* indexBasePtr = (unsigned int*)(m_lsMemPtr->bvhShapeData.gIndexMesh.m_triangleIndexBase+triangleIndex*m_lsMemPtr->bvhShapeData.gIndexMesh.m_triangleIndexStride); small_cache_read_triple(&m_lsMemPtr->spuIndices[0],(ppu_address_t)&indexBasePtr[0], &m_lsMemPtr->spuIndices[1],(ppu_address_t)&indexBasePtr[1], &m_lsMemPtr->spuIndices[2],(ppu_address_t)&indexBasePtr[2], sizeof(int)); } // spu_printf("SPU index0=%d ,",spuIndices[0]); // spu_printf("SPU index1=%d ,",spuIndices[1]); // spu_printf("SPU index2=%d ,",spuIndices[2]); // spu_printf("SPU: indexBasePtr=%llx\n",indexBasePtr); const btVector3& meshScaling = m_lsMemPtr->bvhShapeData.gTriangleMeshInterfacePtr->getScaling(); for (int j=2;btLikely( j>=0 );j--) { int graphicsindex = m_lsMemPtr->spuIndices[j]; // spu_printf("SPU index=%d ,",graphicsindex); btScalar* graphicsbasePtr = (btScalar*)(m_lsMemPtr->bvhShapeData.gIndexMesh.m_vertexBase+graphicsindex*m_lsMemPtr->bvhShapeData.gIndexMesh.m_vertexStride); // spu_printf("SPU graphicsbasePtr=%llx\n",graphicsbasePtr); ///handle un-aligned vertices... //another DMA for each vertex small_cache_read_triple(&spuUnscaledVertex[0],(ppu_address_t)&graphicsbasePtr[0], &spuUnscaledVertex[1],(ppu_address_t)&graphicsbasePtr[1], &spuUnscaledVertex[2],(ppu_address_t)&graphicsbasePtr[2], sizeof(btScalar)); m_tmpTriangleShape.getVertexPtr(j).setValue(spuUnscaledVertex[0]*meshScaling.getX(), spuUnscaledVertex[1]*meshScaling.getY(), spuUnscaledVertex[2]*meshScaling.getZ()); // spu_printf("SPU:triangle vertices:%f,%f,%f\n",spuTriangleVertices[j].x(),spuTriangleVertices[j].y(),spuTriangleVertices[j].z()); } SpuCollisionPairInput triangleConcaveInput(*m_wuInput); // triangleConcaveInput.m_spuCollisionShapes[1] = &spuTriangleVertices[0]; triangleConcaveInput.m_spuCollisionShapes[1] = &m_tmpTriangleShape; triangleConcaveInput.m_shapeType1 = TRIANGLE_SHAPE_PROXYTYPE; m_spuContacts.setShapeIdentifiersB(subPart,triangleIndex); // m_spuContacts.flush(); ProcessSpuConvexConvexCollision(&triangleConcaveInput, m_lsMemPtr,m_spuContacts); ///this flush should be automatic // m_spuContacts.flush(); } }; //////////////////////// /// Convex versus Concave triangle mesh collision detection (handles concave triangle mesh versus sphere, box, cylinder, triangle, cone, convex polyhedron etc) /////////////////// void ProcessConvexConcaveSpuCollision(SpuCollisionPairInput* wuInput, CollisionTask_LocalStoreMemory* lsMemPtr, SpuContactResult& spuContacts) { //order: first collision shape is convex, second concave. m_isSwapped is true, if the original order was opposite btBvhTriangleMeshShape* trimeshShape = (btBvhTriangleMeshShape*)wuInput->m_spuCollisionShapes[1]; //need the mesh interface, for access to triangle vertices dmaBvhShapeData (&lsMemPtr->bvhShapeData, trimeshShape); btVector3 aabbMin(-1,-400,-1); btVector3 aabbMax(1,400,1); //recalc aabbs btTransform convexInTriangleSpace; convexInTriangleSpace = wuInput->m_worldTransform1.inverse() * wuInput->m_worldTransform0; btConvexInternalShape* convexShape = (btConvexInternalShape*)wuInput->m_spuCollisionShapes[0]; computeAabb (aabbMin, aabbMax, convexShape, wuInput->m_collisionShapes[0], wuInput->m_shapeType0, convexInTriangleSpace); //CollisionShape* triangleShape = static_cast(triBody->m_collisionShape); //convexShape->getAabb(convexInTriangleSpace,m_aabbMin,m_aabbMax); // btScalar extraMargin = collisionMarginTriangle; // btVector3 extra(extraMargin,extraMargin,extraMargin); // aabbMax += extra; // aabbMin -= extra; ///quantize query AABB unsigned short int quantizedQueryAabbMin[3]; unsigned short int quantizedQueryAabbMax[3]; lsMemPtr->bvhShapeData.getOptimizedBvh()->quantizeWithClamp(quantizedQueryAabbMin,aabbMin,0); lsMemPtr->bvhShapeData.getOptimizedBvh()->quantizeWithClamp(quantizedQueryAabbMax,aabbMax,1); QuantizedNodeArray& nodeArray = lsMemPtr->bvhShapeData.getOptimizedBvh()->getQuantizedNodeArray(); //spu_printf("SPU: numNodes = %d\n",nodeArray.size()); BvhSubtreeInfoArray& subTrees = lsMemPtr->bvhShapeData.getOptimizedBvh()->getSubtreeInfoArray(); spuNodeCallback nodeCallback(wuInput,lsMemPtr,spuContacts); IndexedMeshArray& indexArray = lsMemPtr->bvhShapeData.gTriangleMeshInterfacePtr->getIndexedMeshArray(); //spu_printf("SPU:indexArray.size() = %d\n",indexArray.size()); // spu_printf("SPU: numSubTrees = %d\n",subTrees.size()); //not likely to happen if (subTrees.size() && indexArray.size() == 1) { ///DMA in the index info dmaBvhIndexedMesh (&lsMemPtr->bvhShapeData.gIndexMesh, indexArray, 0 /* index into indexArray */, 1 /* dmaTag */); cellDmaWaitTagStatusAll(DMA_MASK(1)); //display the headers int numBatch = subTrees.size(); for (int i=0;ibvhShapeData.gSubtreeHeaders[0], (ppu_address_t)(&subTrees[i]), nextBatch, 1); cellDmaWaitTagStatusAll(DMA_MASK(1)); // spu_printf("nextBatch = %d\n",nextBatch); for (int j=0;jbvhShapeData.gSubtreeHeaders[j]; unsigned int overlap = spuTestQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,subtree.m_quantizedAabbMin,subtree.m_quantizedAabbMax); if (overlap) { btAssert(subtree.m_subtreeSize); //dma the actual nodes of this subtree dmaBvhSubTreeNodes (&lsMemPtr->bvhShapeData.gSubtreeNodes[0], subtree, nodeArray, 2); cellDmaWaitTagStatusAll(DMA_MASK(2)); /* Walk this subtree */ spuWalkStacklessQuantizedTree(&nodeCallback,quantizedQueryAabbMin,quantizedQueryAabbMax, &lsMemPtr->bvhShapeData.gSubtreeNodes[0], 0, subtree.m_subtreeSize); } // spu_printf("subtreeSize = %d\n",gSubtreeHeaders[j].m_subtreeSize); } // unsigned short int m_quantizedAabbMin[3]; // unsigned short int m_quantizedAabbMax[3]; // int m_rootNodeIndex; // int m_subtreeSize; i+=nextBatch; } //pre-fetch first tree, then loop and double buffer } } int stats[11]={0,0,0,0,0,0,0,0,0,0,0}; int degenerateStats[11]={0,0,0,0,0,0,0,0,0,0,0}; //////////////////////// /// Convex versus Convex collision detection (handles collision between sphere, box, cylinder, triangle, cone, convex polyhedron etc) /////////////////// void ProcessSpuConvexConvexCollision(SpuCollisionPairInput* wuInput, CollisionTask_LocalStoreMemory* lsMemPtr, SpuContactResult& spuContacts) { register int dmaSize; register ppu_address_t dmaPpuAddress2; #ifdef DEBUG_SPU_COLLISION_DETECTION //spu_printf("SPU: ProcessSpuConvexConvexCollision\n"); #endif //DEBUG_SPU_COLLISION_DETECTION //CollisionShape* shape0 = (CollisionShape*)wuInput->m_collisionShapes[0]; //CollisionShape* shape1 = (CollisionShape*)wuInput->m_collisionShapes[1]; btPersistentManifold* manifold = (btPersistentManifold*)wuInput->m_persistentManifoldPtr; bool genericGjk = true; if (genericGjk) { //try generic GJK //SpuConvexPenetrationDepthSolver* penetrationSolver=0; btVoronoiSimplexSolver simplexSolver; btGjkEpaPenetrationDepthSolver epaPenetrationSolver2; btConvexPenetrationDepthSolver* penetrationSolver = &epaPenetrationSolver2; //SpuMinkowskiPenetrationDepthSolver minkowskiPenetrationSolver; #ifdef ENABLE_EPA if (gUseEpa) { penetrationSolver = &epaPenetrationSolver2; } else #endif { //penetrationSolver = &minkowskiPenetrationSolver; } ///DMA in the vertices for convex shapes ATTRIBUTE_ALIGNED16(char convexHullShape0[sizeof(btConvexHullShape)]); ATTRIBUTE_ALIGNED16(char convexHullShape1[sizeof(btConvexHullShape)]); if ( btLikely( wuInput->m_shapeType0== CONVEX_HULL_SHAPE_PROXYTYPE ) ) { // spu_printf("SPU: DMA btConvexHullShape\n"); dmaSize = sizeof(btConvexHullShape); dmaPpuAddress2 = wuInput->m_collisionShapes[0]; cellDmaGet(&convexHullShape0, dmaPpuAddress2 , dmaSize, DMA_TAG(1), 0, 0); //cellDmaWaitTagStatusAll(DMA_MASK(1)); } if ( btLikely( wuInput->m_shapeType1 == CONVEX_HULL_SHAPE_PROXYTYPE ) ) { // spu_printf("SPU: DMA btConvexHullShape\n"); dmaSize = sizeof(btConvexHullShape); dmaPpuAddress2 = wuInput->m_collisionShapes[1]; cellDmaGet(&convexHullShape1, dmaPpuAddress2 , dmaSize, DMA_TAG(1), 0, 0); //cellDmaWaitTagStatusAll(DMA_MASK(1)); } if ( btLikely( wuInput->m_shapeType0 == CONVEX_HULL_SHAPE_PROXYTYPE ) ) { cellDmaWaitTagStatusAll(DMA_MASK(1)); dmaConvexVertexData (&lsMemPtr->convexVertexData[0], (btConvexHullShape*)&convexHullShape0); lsMemPtr->convexVertexData[0].gSpuConvexShapePtr = wuInput->m_spuCollisionShapes[0]; } if ( btLikely( wuInput->m_shapeType1 == CONVEX_HULL_SHAPE_PROXYTYPE ) ) { cellDmaWaitTagStatusAll(DMA_MASK(1)); dmaConvexVertexData (&lsMemPtr->convexVertexData[1], (btConvexHullShape*)&convexHullShape1); lsMemPtr->convexVertexData[1].gSpuConvexShapePtr = wuInput->m_spuCollisionShapes[1]; } btConvexPointCloudShape cpc0,cpc1; if ( btLikely( wuInput->m_shapeType0 == CONVEX_HULL_SHAPE_PROXYTYPE ) ) { cellDmaWaitTagStatusAll(DMA_MASK(2)); lsMemPtr->convexVertexData[0].gConvexPoints = &lsMemPtr->convexVertexData[0].g_convexPointBuffer[0]; btConvexHullShape* ch = (btConvexHullShape*)wuInput->m_spuCollisionShapes[0]; const btVector3& localScaling = ch->getLocalScalingNV(); cpc0.setPoints(lsMemPtr->convexVertexData[0].gConvexPoints,lsMemPtr->convexVertexData[0].gNumConvexPoints,false,localScaling); wuInput->m_spuCollisionShapes[0] = &cpc0; } if ( btLikely( wuInput->m_shapeType1 == CONVEX_HULL_SHAPE_PROXYTYPE ) ) { cellDmaWaitTagStatusAll(DMA_MASK(2)); lsMemPtr->convexVertexData[1].gConvexPoints = &lsMemPtr->convexVertexData[1].g_convexPointBuffer[0]; btConvexHullShape* ch = (btConvexHullShape*)wuInput->m_spuCollisionShapes[1]; const btVector3& localScaling = ch->getLocalScalingNV(); cpc1.setPoints(lsMemPtr->convexVertexData[1].gConvexPoints,lsMemPtr->convexVertexData[1].gNumConvexPoints,false,localScaling); wuInput->m_spuCollisionShapes[1] = &cpc1; } const btConvexShape* shape0Ptr = (const btConvexShape*)wuInput->m_spuCollisionShapes[0]; const btConvexShape* shape1Ptr = (const btConvexShape*)wuInput->m_spuCollisionShapes[1]; int shapeType0 = wuInput->m_shapeType0; int shapeType1 = wuInput->m_shapeType1; float marginA = wuInput->m_collisionMargin0; float marginB = wuInput->m_collisionMargin1; SpuClosestPointInput cpInput; cpInput.m_convexVertexData[0] = &lsMemPtr->convexVertexData[0]; cpInput.m_convexVertexData[1] = &lsMemPtr->convexVertexData[1]; cpInput.m_transformA = wuInput->m_worldTransform0; cpInput.m_transformB = wuInput->m_worldTransform1; float sumMargin = (marginA+marginB+lsMemPtr->getContactManifoldPtr()->getContactBreakingThreshold()); cpInput.m_maximumDistanceSquared = sumMargin * sumMargin; ppu_address_t manifoldAddress = (ppu_address_t)manifold; btPersistentManifold* spuManifold=lsMemPtr->getContactManifoldPtr(); //spuContacts.setContactInfo(spuManifold,manifoldAddress,wuInput->m_worldTransform0,wuInput->m_worldTransform1,wuInput->m_isSwapped); spuContacts.setContactInfo(spuManifold,manifoldAddress,lsMemPtr->getColObj0()->getWorldTransform(), lsMemPtr->getColObj1()->getWorldTransform(), lsMemPtr->getColObj0()->getRestitution(),lsMemPtr->getColObj1()->getRestitution(), lsMemPtr->getColObj0()->getFriction(),lsMemPtr->getColObj1()->getFriction(), wuInput->m_isSwapped); { btGjkPairDetector gjk(shape0Ptr,shape1Ptr,shapeType0,shapeType1,marginA,marginB,&simplexSolver,penetrationSolver);//&vsSolver,penetrationSolver); gjk.getClosestPoints(cpInput,spuContacts,0);//,debugDraw); stats[gjk.m_lastUsedMethod]++; degenerateStats[gjk.m_degenerateSimplex]++; #ifdef USE_SEPDISTANCE_UTIL btScalar sepDist = gjk.getCachedSeparatingDistance()+spuManifold->getContactBreakingThreshold(); lsMemPtr->getlocalCollisionAlgorithm()->m_sepDistance.initSeparatingDistance(gjk.getCachedSeparatingAxis(),sepDist,wuInput->m_worldTransform0,wuInput->m_worldTransform1); lsMemPtr->needsDmaPutContactManifoldAlgo = true; #endif //USE_SEPDISTANCE_UTIL } } } template void DoSwap(T& a, T& b) { char tmp[sizeof(T)]; memcpy(tmp, &a, sizeof(T)); memcpy(&a, &b, sizeof(T)); memcpy(&b, tmp, sizeof(T)); } SIMD_FORCE_INLINE void dmaAndSetupCollisionObjects(SpuCollisionPairInput& collisionPairInput, CollisionTask_LocalStoreMemory& lsMem) { register int dmaSize; register ppu_address_t dmaPpuAddress2; dmaSize = sizeof(btCollisionObject);//btTransform); dmaPpuAddress2 = /*collisionPairInput.m_isSwapped ? (ppu_address_t)lsMem.gProxyPtr1->m_clientObject :*/ (ppu_address_t)lsMem.getlocalCollisionAlgorithm()->getCollisionObject0(); lsMem.m_lsColObj0Ptr = (btCollisionObject*)cellDmaGetReadOnly(&lsMem.gColObj0Buffer, dmaPpuAddress2 , dmaSize, DMA_TAG(1), 0, 0); dmaSize = sizeof(btCollisionObject);//btTransform); dmaPpuAddress2 = /*collisionPairInput.m_isSwapped ? (ppu_address_t)lsMem.gProxyPtr0->m_clientObject :*/ (ppu_address_t)lsMem.getlocalCollisionAlgorithm()->getCollisionObject1(); lsMem.m_lsColObj1Ptr = (btCollisionObject*)cellDmaGetReadOnly(&lsMem.gColObj1Buffer, dmaPpuAddress2 , dmaSize, DMA_TAG(2), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(1) | DMA_MASK(2)); btCollisionObject* ob0 = lsMem.getColObj0(); btCollisionObject* ob1 = lsMem.getColObj1(); collisionPairInput.m_worldTransform0 = ob0->getWorldTransform(); collisionPairInput.m_worldTransform1 = ob1->getWorldTransform(); } void handleCollisionPair(SpuCollisionPairInput& collisionPairInput, CollisionTask_LocalStoreMemory& lsMem, SpuContactResult &spuContacts, ppu_address_t collisionShape0Ptr, void* collisionShape0Loc, ppu_address_t collisionShape1Ptr, void* collisionShape1Loc, bool dmaShapes = true) { if (btBroadphaseProxy::isConvex(collisionPairInput.m_shapeType0) && btBroadphaseProxy::isConvex(collisionPairInput.m_shapeType1)) { if (dmaShapes) { dmaCollisionShape (collisionShape0Loc, collisionShape0Ptr, 1, collisionPairInput.m_shapeType0); dmaCollisionShape (collisionShape1Loc, collisionShape1Ptr, 2, collisionPairInput.m_shapeType1); cellDmaWaitTagStatusAll(DMA_MASK(1) | DMA_MASK(2)); } btConvexInternalShape* spuConvexShape0 = (btConvexInternalShape*)collisionShape0Loc; btConvexInternalShape* spuConvexShape1 = (btConvexInternalShape*)collisionShape1Loc; btVector3 dim0 = spuConvexShape0->getImplicitShapeDimensions(); btVector3 dim1 = spuConvexShape1->getImplicitShapeDimensions(); collisionPairInput.m_primitiveDimensions0 = dim0; collisionPairInput.m_primitiveDimensions1 = dim1; collisionPairInput.m_collisionShapes[0] = collisionShape0Ptr; collisionPairInput.m_collisionShapes[1] = collisionShape1Ptr; collisionPairInput.m_spuCollisionShapes[0] = spuConvexShape0; collisionPairInput.m_spuCollisionShapes[1] = spuConvexShape1; ProcessSpuConvexConvexCollision(&collisionPairInput,&lsMem,spuContacts); } else if (btBroadphaseProxy::isCompound(collisionPairInput.m_shapeType0) && btBroadphaseProxy::isCompound(collisionPairInput.m_shapeType1)) { //snPause(); dmaCollisionShape (collisionShape0Loc, collisionShape0Ptr, 1, collisionPairInput.m_shapeType0); dmaCollisionShape (collisionShape1Loc, collisionShape1Ptr, 2, collisionPairInput.m_shapeType1); cellDmaWaitTagStatusAll(DMA_MASK(1) | DMA_MASK(2)); // Both are compounds, do N^2 CD for now ///@todo: add some AABB-based pruning (probably not -> slower) btCompoundShape* spuCompoundShape0 = (btCompoundShape*)collisionShape0Loc; btCompoundShape* spuCompoundShape1 = (btCompoundShape*)collisionShape1Loc; dmaCompoundShapeInfo (&lsMem.compoundShapeData[0], spuCompoundShape0, 1); dmaCompoundShapeInfo (&lsMem.compoundShapeData[1], spuCompoundShape1, 2); cellDmaWaitTagStatusAll(DMA_MASK(1) | DMA_MASK(2)); dmaCompoundSubShapes (&lsMem.compoundShapeData[0], spuCompoundShape0, 1); cellDmaWaitTagStatusAll(DMA_MASK(1)); dmaCompoundSubShapes (&lsMem.compoundShapeData[1], spuCompoundShape1, 1); cellDmaWaitTagStatusAll(DMA_MASK(1)); int childShapeCount0 = spuCompoundShape0->getNumChildShapes(); int childShapeCount1 = spuCompoundShape1->getNumChildShapes(); // Start the N^2 for (int i = 0; i < childShapeCount0; ++i) { btCompoundShapeChild& childShape0 = lsMem.compoundShapeData[0].gSubshapes[i]; for (int j = 0; j < childShapeCount1; ++j) { btCompoundShapeChild& childShape1 = lsMem.compoundShapeData[1].gSubshapes[j]; /* Create a new collision pair input struct using the two child shapes */ SpuCollisionPairInput cinput (collisionPairInput); cinput.m_worldTransform0 = collisionPairInput.m_worldTransform0 * childShape0.m_transform; cinput.m_shapeType0 = childShape0.m_childShapeType; cinput.m_collisionMargin0 = childShape0.m_childMargin; cinput.m_worldTransform1 = collisionPairInput.m_worldTransform1 * childShape1.m_transform; cinput.m_shapeType1 = childShape1.m_childShapeType; cinput.m_collisionMargin1 = childShape1.m_childMargin; /* Recursively call handleCollisionPair () with new collision pair input */ handleCollisionPair(cinput, lsMem, spuContacts, (ppu_address_t)childShape0.m_childShape, lsMem.compoundShapeData[0].gSubshapeShape[i], (ppu_address_t)childShape1.m_childShape, lsMem.compoundShapeData[1].gSubshapeShape[j], false); // bug fix: changed index to j. } } } else if (btBroadphaseProxy::isCompound(collisionPairInput.m_shapeType0) ) { //snPause(); dmaCollisionShape (collisionShape0Loc, collisionShape0Ptr, 1, collisionPairInput.m_shapeType0); dmaCollisionShape (collisionShape1Loc, collisionShape1Ptr, 2, collisionPairInput.m_shapeType1); cellDmaWaitTagStatusAll(DMA_MASK(1) | DMA_MASK(2)); // object 0 compound, object 1 non-compound btCompoundShape* spuCompoundShape = (btCompoundShape*)collisionShape0Loc; dmaCompoundShapeInfo (&lsMem.compoundShapeData[0], spuCompoundShape, 1); cellDmaWaitTagStatusAll(DMA_MASK(1)); int childShapeCount = spuCompoundShape->getNumChildShapes(); for (int i = 0; i < childShapeCount; ++i) { btCompoundShapeChild& childShape = lsMem.compoundShapeData[0].gSubshapes[i]; // Dma the child shape dmaCollisionShape (&lsMem.compoundShapeData[0].gSubshapeShape[i], (ppu_address_t)childShape.m_childShape, 1, childShape.m_childShapeType); cellDmaWaitTagStatusAll(DMA_MASK(1)); SpuCollisionPairInput cinput (collisionPairInput); cinput.m_worldTransform0 = collisionPairInput.m_worldTransform0 * childShape.m_transform; cinput.m_shapeType0 = childShape.m_childShapeType; cinput.m_collisionMargin0 = childShape.m_childMargin; handleCollisionPair(cinput, lsMem, spuContacts, (ppu_address_t)childShape.m_childShape, lsMem.compoundShapeData[0].gSubshapeShape[i], collisionShape1Ptr, collisionShape1Loc, false); } } else if (btBroadphaseProxy::isCompound(collisionPairInput.m_shapeType1) ) { //snPause(); dmaCollisionShape (collisionShape0Loc, collisionShape0Ptr, 1, collisionPairInput.m_shapeType0); dmaCollisionShape (collisionShape1Loc, collisionShape1Ptr, 2, collisionPairInput.m_shapeType1); cellDmaWaitTagStatusAll(DMA_MASK(1) | DMA_MASK(2)); // object 0 non-compound, object 1 compound btCompoundShape* spuCompoundShape = (btCompoundShape*)collisionShape1Loc; dmaCompoundShapeInfo (&lsMem.compoundShapeData[0], spuCompoundShape, 1); cellDmaWaitTagStatusAll(DMA_MASK(1)); int childShapeCount = spuCompoundShape->getNumChildShapes(); for (int i = 0; i < childShapeCount; ++i) { btCompoundShapeChild& childShape = lsMem.compoundShapeData[0].gSubshapes[i]; // Dma the child shape dmaCollisionShape (&lsMem.compoundShapeData[0].gSubshapeShape[i], (ppu_address_t)childShape.m_childShape, 1, childShape.m_childShapeType); cellDmaWaitTagStatusAll(DMA_MASK(1)); SpuCollisionPairInput cinput (collisionPairInput); cinput.m_worldTransform1 = collisionPairInput.m_worldTransform1 * childShape.m_transform; cinput.m_shapeType1 = childShape.m_childShapeType; cinput.m_collisionMargin1 = childShape.m_childMargin; handleCollisionPair(cinput, lsMem, spuContacts, collisionShape0Ptr, collisionShape0Loc, (ppu_address_t)childShape.m_childShape, lsMem.compoundShapeData[0].gSubshapeShape[i], false); } } else { //a non-convex shape is involved bool handleConvexConcave = false; //snPause(); if (btBroadphaseProxy::isConcave(collisionPairInput.m_shapeType0) && btBroadphaseProxy::isConvex(collisionPairInput.m_shapeType1)) { // Swap stuff DoSwap(collisionShape0Ptr, collisionShape1Ptr); DoSwap(collisionShape0Loc, collisionShape1Loc); DoSwap(collisionPairInput.m_shapeType0, collisionPairInput.m_shapeType1); DoSwap(collisionPairInput.m_worldTransform0, collisionPairInput.m_worldTransform1); DoSwap(collisionPairInput.m_collisionMargin0, collisionPairInput.m_collisionMargin1); collisionPairInput.m_isSwapped = true; } if (btBroadphaseProxy::isConvex(collisionPairInput.m_shapeType0)&& btBroadphaseProxy::isConcave(collisionPairInput.m_shapeType1)) { handleConvexConcave = true; } if (handleConvexConcave) { if (dmaShapes) { dmaCollisionShape (collisionShape0Loc, collisionShape0Ptr, 1, collisionPairInput.m_shapeType0); dmaCollisionShape (collisionShape1Loc, collisionShape1Ptr, 2, collisionPairInput.m_shapeType1); cellDmaWaitTagStatusAll(DMA_MASK(1) | DMA_MASK(2)); } btConvexInternalShape* spuConvexShape0 = (btConvexInternalShape*)collisionShape0Loc; btBvhTriangleMeshShape* trimeshShape = (btBvhTriangleMeshShape*)collisionShape1Loc; btVector3 dim0 = spuConvexShape0->getImplicitShapeDimensions(); collisionPairInput.m_primitiveDimensions0 = dim0; collisionPairInput.m_collisionShapes[0] = collisionShape0Ptr; collisionPairInput.m_collisionShapes[1] = collisionShape1Ptr; collisionPairInput.m_spuCollisionShapes[0] = spuConvexShape0; collisionPairInput.m_spuCollisionShapes[1] = trimeshShape; ProcessConvexConcaveSpuCollision(&collisionPairInput,&lsMem,spuContacts); } } spuContacts.flush(); } void processCollisionTask(void* userPtr, void* lsMemPtr) { SpuGatherAndProcessPairsTaskDesc* taskDescPtr = (SpuGatherAndProcessPairsTaskDesc*)userPtr; SpuGatherAndProcessPairsTaskDesc& taskDesc = *taskDescPtr; CollisionTask_LocalStoreMemory* colMemPtr = (CollisionTask_LocalStoreMemory*)lsMemPtr; CollisionTask_LocalStoreMemory& lsMem = *(colMemPtr); gUseEpa = taskDesc.m_useEpa; // spu_printf("taskDescPtr=%llx\n",taskDescPtr); SpuContactResult spuContacts; //////////////////// ppu_address_t dmaInPtr = taskDesc.m_inPairPtr; unsigned int numPages = taskDesc.numPages; unsigned int numOnLastPage = taskDesc.numOnLastPage; // prefetch first set of inputs and wait lsMem.g_workUnitTaskBuffers.init(); unsigned int nextNumOnPage = (numPages > 1)? MIDPHASE_NUM_WORKUNITS_PER_PAGE : numOnLastPage; lsMem.g_workUnitTaskBuffers.backBufferDmaGet(dmaInPtr, nextNumOnPage*sizeof(SpuGatherAndProcessWorkUnitInput), DMA_TAG(3)); dmaInPtr += MIDPHASE_WORKUNIT_PAGE_SIZE; register unsigned char *inputPtr; register unsigned int numOnPage; register unsigned int j; SpuGatherAndProcessWorkUnitInput* wuInputs; register int dmaSize; register ppu_address_t dmaPpuAddress; register ppu_address_t dmaPpuAddress2; int numPairs; register int p; SpuCollisionPairInput collisionPairInput; for (unsigned int i = 0; btLikely(i < numPages); i++) { // wait for back buffer dma and swap buffers inputPtr = lsMem.g_workUnitTaskBuffers.swapBuffers(); // number on current page is number prefetched last iteration numOnPage = nextNumOnPage; // prefetch next set of inputs #if MIDPHASE_NUM_WORKUNIT_PAGES > 2 if ( btLikely( i < numPages-1 ) ) #else if ( btUnlikely( i < numPages-1 ) ) #endif { nextNumOnPage = (i == numPages-2)? numOnLastPage : MIDPHASE_NUM_WORKUNITS_PER_PAGE; lsMem.g_workUnitTaskBuffers.backBufferDmaGet(dmaInPtr, nextNumOnPage*sizeof(SpuGatherAndProcessWorkUnitInput), DMA_TAG(3)); dmaInPtr += MIDPHASE_WORKUNIT_PAGE_SIZE; } wuInputs = reinterpret_cast(inputPtr); for (j = 0; btLikely( j < numOnPage ); j++) { #ifdef DEBUG_SPU_COLLISION_DETECTION // printMidphaseInput(&wuInputs[j]); #endif //DEBUG_SPU_COLLISION_DETECTION numPairs = wuInputs[j].m_endIndex - wuInputs[j].m_startIndex; if ( btLikely( numPairs ) ) { dmaSize = numPairs*sizeof(btBroadphasePair); dmaPpuAddress = wuInputs[j].m_pairArrayPtr+wuInputs[j].m_startIndex * sizeof(btBroadphasePair); lsMem.m_pairsPointer = (btBroadphasePair*)cellDmaGetReadOnly(&lsMem.gBroadphasePairsBuffer, dmaPpuAddress , dmaSize, DMA_TAG(1), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(1)); for (p=0;pm_userInfo = %d\n",pair.m_userInfo); spu_printf("pair->m_algorithm = %d\n",pair.m_algorithm); spu_printf("pair->m_pProxy0 = %d\n",pair.m_pProxy0); spu_printf("pair->m_pProxy1 = %d\n",pair.m_pProxy1); #endif //DEBUG_SPU_COLLISION_DETECTION if (pair.m_internalTmpValue == 2 && pair.m_algorithm && pair.m_pProxy0 && pair.m_pProxy1) { dmaSize = sizeof(SpuContactManifoldCollisionAlgorithm); dmaPpuAddress2 = (ppu_address_t)pair.m_algorithm; lsMem.m_lsCollisionAlgorithmPtr = (SpuContactManifoldCollisionAlgorithm*)cellDmaGetReadOnly(&lsMem.gSpuContactManifoldAlgoBuffer, dmaPpuAddress2 , dmaSize, DMA_TAG(1), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(1)); lsMem.needsDmaPutContactManifoldAlgo = false; collisionPairInput.m_persistentManifoldPtr = (ppu_address_t) lsMem.getlocalCollisionAlgorithm()->getContactManifoldPtr(); collisionPairInput.m_isSwapped = false; if (1) { ///can wait on the combined DMA_MASK, or dma on the same tag #ifdef DEBUG_SPU_COLLISION_DETECTION // spu_printf("SPU collisionPairInput->m_shapeType0 = %d\n",collisionPairInput->m_shapeType0); // spu_printf("SPU collisionPairInput->m_shapeType1 = %d\n",collisionPairInput->m_shapeType1); #endif //DEBUG_SPU_COLLISION_DETECTION dmaSize = sizeof(btPersistentManifold); dmaPpuAddress2 = collisionPairInput.m_persistentManifoldPtr; lsMem.m_lsManifoldPtr = (btPersistentManifold*)cellDmaGetReadOnly(&lsMem.gPersistentManifoldBuffer, dmaPpuAddress2 , dmaSize, DMA_TAG(1), 0, 0); collisionPairInput.m_shapeType0 = lsMem.getlocalCollisionAlgorithm()->getShapeType0(); collisionPairInput.m_shapeType1 = lsMem.getlocalCollisionAlgorithm()->getShapeType1(); collisionPairInput.m_collisionMargin0 = lsMem.getlocalCollisionAlgorithm()->getCollisionMargin0(); collisionPairInput.m_collisionMargin1 = lsMem.getlocalCollisionAlgorithm()->getCollisionMargin1(); //??cellDmaWaitTagStatusAll(DMA_MASK(1)); if (1) { //snPause(); // Get the collision objects dmaAndSetupCollisionObjects(collisionPairInput, lsMem); if (lsMem.getColObj0()->isActive() || lsMem.getColObj1()->isActive()) { lsMem.needsDmaPutContactManifoldAlgo = true; #ifdef USE_SEPDISTANCE_UTIL lsMem.getlocalCollisionAlgorithm()->m_sepDistance.updateSeparatingDistance(collisionPairInput.m_worldTransform0,collisionPairInput.m_worldTransform1); #endif //USE_SEPDISTANCE_UTIL #define USE_DEDICATED_BOX_BOX 1 #ifdef USE_DEDICATED_BOX_BOX bool boxbox = ((lsMem.getlocalCollisionAlgorithm()->getShapeType0()==BOX_SHAPE_PROXYTYPE)&& (lsMem.getlocalCollisionAlgorithm()->getShapeType1()==BOX_SHAPE_PROXYTYPE)); if (boxbox) { //spu_printf("boxbox dist = %f\n",distance); btPersistentManifold* spuManifold=lsMem.getContactManifoldPtr(); btPersistentManifold* manifold = (btPersistentManifold*)collisionPairInput.m_persistentManifoldPtr; ppu_address_t manifoldAddress = (ppu_address_t)manifold; spuContacts.setContactInfo(spuManifold,manifoldAddress,lsMem.getColObj0()->getWorldTransform(), lsMem.getColObj1()->getWorldTransform(), lsMem.getColObj0()->getRestitution(),lsMem.getColObj1()->getRestitution(), lsMem.getColObj0()->getFriction(),lsMem.getColObj1()->getFriction(), collisionPairInput.m_isSwapped); float distance=0.f; btVector3 normalInB; if (//!gUseEpa && #ifdef USE_SEPDISTANCE_UTIL lsMem.getlocalCollisionAlgorithm()->m_sepDistance.getConservativeSeparatingDistance()<=0.f #else 1 #endif ) { //#define USE_PE_BOX_BOX 1 #ifdef USE_PE_BOX_BOX { //getCollisionMargin0 btScalar margin0 = lsMem.getlocalCollisionAlgorithm()->getCollisionMargin0(); btScalar margin1 = lsMem.getlocalCollisionAlgorithm()->getCollisionMargin1(); btVector3 shapeDim0 = lsMem.getlocalCollisionAlgorithm()->getShapeDimensions0()+btVector3(margin0,margin0,margin0); btVector3 shapeDim1 = lsMem.getlocalCollisionAlgorithm()->getShapeDimensions1()+btVector3(margin1,margin1,margin1); Box boxA(shapeDim0.getX(),shapeDim0.getY(),shapeDim0.getZ()); Vector3 vmPos0 = getVmVector3(collisionPairInput.m_worldTransform0.getOrigin()); Vector3 vmPos1 = getVmVector3(collisionPairInput.m_worldTransform1.getOrigin()); Matrix3 vmMatrix0 = getVmMatrix3(collisionPairInput.m_worldTransform0.getBasis()); Matrix3 vmMatrix1 = getVmMatrix3(collisionPairInput.m_worldTransform1.getBasis()); Transform3 transformA(vmMatrix0,vmPos0); Box boxB(shapeDim1.getX(),shapeDim1.getY(),shapeDim1.getZ()); Transform3 transformB(vmMatrix1,vmPos1); BoxPoint resultClosestBoxPointA; BoxPoint resultClosestBoxPointB; Vector3 resultNormal; #ifdef USE_SEPDISTANCE_UTIL float distanceThreshold = FLT_MAX #else float distanceThreshold = 0.f; #endif distance = boxBoxDistance(resultNormal,resultClosestBoxPointA,resultClosestBoxPointB, boxA, transformA, boxB,transformB,distanceThreshold); normalInB = -getBtVector3(resultNormal); if(distance < spuManifold->getContactBreakingThreshold()) { btVector3 pointOnB = collisionPairInput.m_worldTransform1(getBtVector3(resultClosestBoxPointB.localPoint)); spuContacts.addContactPoint( normalInB, pointOnB, distance); } } #else { btScalar margin0 = lsMem.getlocalCollisionAlgorithm()->getCollisionMargin0(); btScalar margin1 = lsMem.getlocalCollisionAlgorithm()->getCollisionMargin1(); btVector3 shapeDim0 = lsMem.getlocalCollisionAlgorithm()->getShapeDimensions0()+btVector3(margin0,margin0,margin0); btVector3 shapeDim1 = lsMem.getlocalCollisionAlgorithm()->getShapeDimensions1()+btVector3(margin1,margin1,margin1); btBoxShape box0(shapeDim0); btBoxShape box1(shapeDim1); struct SpuBridgeContactCollector : public btDiscreteCollisionDetectorInterface::Result { SpuContactResult& m_spuContacts; virtual void setShapeIdentifiersA(int partId0,int index0) { m_spuContacts.setShapeIdentifiersA(partId0,index0); } virtual void setShapeIdentifiersB(int partId1,int index1) { m_spuContacts.setShapeIdentifiersB(partId1,index1); } virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth) { m_spuContacts.addContactPoint(normalOnBInWorld,pointInWorld,depth); } SpuBridgeContactCollector(SpuContactResult& spuContacts) :m_spuContacts(spuContacts) { } }; SpuBridgeContactCollector bridgeOutput(spuContacts); btDiscreteCollisionDetectorInterface::ClosestPointInput input; input.m_maximumDistanceSquared = BT_LARGE_FLOAT; input.m_transformA = collisionPairInput.m_worldTransform0; input.m_transformB = collisionPairInput.m_worldTransform1; btBoxBoxDetector detector(&box0,&box1); detector.getClosestPoints(input,bridgeOutput,0); } #endif //USE_PE_BOX_BOX lsMem.needsDmaPutContactManifoldAlgo = true; #ifdef USE_SEPDISTANCE_UTIL btScalar sepDist2 = distance+spuManifold->getContactBreakingThreshold(); lsMem.getlocalCollisionAlgorithm()->m_sepDistance.initSeparatingDistance(normalInB,sepDist2,collisionPairInput.m_worldTransform0,collisionPairInput.m_worldTransform1); #endif //USE_SEPDISTANCE_UTIL gProcessedCol++; } else { gSkippedCol++; } spuContacts.flush(); } else #endif //USE_DEDICATED_BOX_BOX { if ( #ifdef USE_SEPDISTANCE_UTIL lsMem.getlocalCollisionAlgorithm()->m_sepDistance.getConservativeSeparatingDistance()<=0.f #else 1 #endif //USE_SEPDISTANCE_UTIL ) { handleCollisionPair(collisionPairInput, lsMem, spuContacts, (ppu_address_t)lsMem.getColObj0()->getCollisionShape(), &lsMem.gCollisionShapes[0].collisionShape, (ppu_address_t)lsMem.getColObj1()->getCollisionShape(), &lsMem.gCollisionShapes[1].collisionShape); } else { //spu_printf("boxbox dist = %f\n",distance); btPersistentManifold* spuManifold=lsMem.getContactManifoldPtr(); btPersistentManifold* manifold = (btPersistentManifold*)collisionPairInput.m_persistentManifoldPtr; ppu_address_t manifoldAddress = (ppu_address_t)manifold; spuContacts.setContactInfo(spuManifold,manifoldAddress,lsMem.getColObj0()->getWorldTransform(), lsMem.getColObj1()->getWorldTransform(), lsMem.getColObj0()->getRestitution(),lsMem.getColObj1()->getRestitution(), lsMem.getColObj0()->getFriction(),lsMem.getColObj1()->getFriction(), collisionPairInput.m_isSwapped); spuContacts.flush(); } } } } } #ifdef USE_SEPDISTANCE_UTIL #if defined (__SPU__) || defined (USE_LIBSPE2) if (lsMem.needsDmaPutContactManifoldAlgo) { dmaSize = sizeof(SpuContactManifoldCollisionAlgorithm); dmaPpuAddress2 = (ppu_address_t)pair.m_algorithm; cellDmaLargePut(&lsMem.gSpuContactManifoldAlgoBuffer, dmaPpuAddress2 , dmaSize, DMA_TAG(1), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(1)); } #endif #endif //#ifdef USE_SEPDISTANCE_UTIL } } } } //end for (j = 0; j < numOnPage; j++) }// for return; } ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuContactResult.hcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuContactResu0000644000175000017500000000634211337073000033142 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 SPU_CONTACT_RESULT2_H #define SPU_CONTACT_RESULT2_H #ifndef WIN32 #include #endif #include "../SpuDoubleBuffer.h" #include "LinearMath/btTransform.h" #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" #include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" class btCollisionShape; struct SpuCollisionPairInput { ppu_address_t m_collisionShapes[2]; btCollisionShape* m_spuCollisionShapes[2]; ppu_address_t m_persistentManifoldPtr; btVector3 m_primitiveDimensions0; btVector3 m_primitiveDimensions1; int m_shapeType0; int m_shapeType1; float m_collisionMargin0; float m_collisionMargin1; btTransform m_worldTransform0; btTransform m_worldTransform1; bool m_isSwapped; bool m_useEpa; }; struct SpuClosestPointInput : public btDiscreteCollisionDetectorInterface::ClosestPointInput { struct SpuConvexPolyhedronVertexData* m_convexVertexData[2]; }; ///SpuContactResult exports the contact points using double-buffered DMA transfers, only when needed ///So when an existing contact point is duplicated, no transfer/refresh is performed. class SpuContactResult : public btDiscreteCollisionDetectorInterface::Result { btTransform m_rootWorldTransform0; btTransform m_rootWorldTransform1; ppu_address_t m_manifoldAddress; btPersistentManifold* m_spuManifold; bool m_RequiresWriteBack; btScalar m_combinedFriction; btScalar m_combinedRestitution; bool m_isSwapped; DoubleBuffer g_manifoldDmaExport; public: SpuContactResult(); virtual ~SpuContactResult(); btPersistentManifold* GetSpuManifold() const { return m_spuManifold; } virtual void setShapeIdentifiersA(int partId0,int index0); virtual void setShapeIdentifiersB(int partId1,int index1); void setContactInfo(btPersistentManifold* spuManifold, ppu_address_t manifoldAddress,const btTransform& worldTrans0,const btTransform& worldTrans1, btScalar restitution0,btScalar restitution1, btScalar friction0,btScalar friction01, bool isSwapped); void writeDoubleBufferedManifold(btPersistentManifold* lsManifold, btPersistentManifold* mmManifold); virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth); void flush(); }; #endif //SPU_CONTACT_RESULT2_H ././@LongLink0000000000000000000000000000016200000000000011564 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.hcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuGatheringCo0000644000175000017500000000761011337073000033101 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 SPU_GATHERING_COLLISION_TASK_H #define SPU_GATHERING_COLLISION_TASK_H #include "../PlatformDefinitions.h" //#define DEBUG_SPU_COLLISION_DETECTION 1 ///Task Description for SPU collision detection struct SpuGatherAndProcessPairsTaskDesc { ppu_address_t m_inPairPtr;//m_pairArrayPtr; //mutex variable uint32_t m_someMutexVariableInMainMemory; ppu_address_t m_dispatcher; uint32_t numOnLastPage; uint16_t numPages; uint16_t taskId; bool m_useEpa; struct CollisionTask_LocalStoreMemory* m_lsMemory; } #if defined(__CELLOS_LV2__) || defined(USE_LIBSPE2) __attribute__ ((aligned (128))) #endif ; void processCollisionTask(void* userPtr, void* lsMemory); void* createCollisionLocalStoreMemory(); #if defined(USE_LIBSPE2) && defined(__SPU__) #include "../SpuLibspe2Support.h" #include #include #include //#define DEBUG_LIBSPE2_SPU_TASK int main(unsigned long long speid, addr64 argp, addr64 envp) { printf("SPU: hello \n"); ATTRIBUTE_ALIGNED128(btSpuStatus status); ATTRIBUTE_ALIGNED16( SpuGatherAndProcessPairsTaskDesc taskDesc ) ; unsigned int received_message = Spu_Mailbox_Event_Nothing; bool shutdown = false; cellDmaGet(&status, argp.ull, sizeof(btSpuStatus), DMA_TAG(3), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(3)); status.m_status = Spu_Status_Free; status.m_lsMemory.p = createCollisionLocalStoreMemory(); cellDmaLargePut(&status, argp.ull, sizeof(btSpuStatus), DMA_TAG(3), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(3)); while ( btLikely( !shutdown ) ) { received_message = spu_read_in_mbox(); if( btLikely( received_message == Spu_Mailbox_Event_Task )) { #ifdef DEBUG_LIBSPE2_SPU_TASK printf("SPU: received Spu_Mailbox_Event_Task\n"); #endif //DEBUG_LIBSPE2_SPU_TASK // refresh the status cellDmaGet(&status, argp.ull, sizeof(btSpuStatus), DMA_TAG(3), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(3)); btAssert(status.m_status==Spu_Status_Occupied); cellDmaGet(&taskDesc, status.m_taskDesc.p, sizeof(SpuGatherAndProcessPairsTaskDesc), DMA_TAG(3), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(3)); #ifdef DEBUG_LIBSPE2_SPU_TASK printf("SPU:processCollisionTask\n"); #endif //DEBUG_LIBSPE2_SPU_TASK processCollisionTask((void*)&taskDesc, taskDesc.m_lsMemory); #ifdef DEBUG_LIBSPE2_SPU_TASK printf("SPU:finished processCollisionTask\n"); #endif //DEBUG_LIBSPE2_SPU_TASK } else { #ifdef DEBUG_LIBSPE2_SPU_TASK printf("SPU: received ShutDown\n"); #endif //DEBUG_LIBSPE2_SPU_TASK if( btLikely( received_message == Spu_Mailbox_Event_Shutdown ) ) { shutdown = true; } else { //printf("SPU - Sth. recieved\n"); } } // set to status free and wait for next task status.m_status = Spu_Status_Free; cellDmaLargePut(&status, argp.ull, sizeof(btSpuStatus), DMA_TAG(3), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(3)); } printf("SPU: shutdown\n"); return 0; } #endif // USE_LIBSPE2 #endif //SPU_GATHERING_COLLISION_TASK_H ././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionShapes.cppcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuCollisionSh0000644000175000017500000002457411337073000033145 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "SpuCollisionShapes.h" ///not supported on IBM SDK, until we fix the alignment of btVector3 #if defined (__CELLOS_LV2__) && defined (__SPU__) #include static inline vec_float4 vec_dot3( vec_float4 vec0, vec_float4 vec1 ) { vec_float4 result; result = spu_mul( vec0, vec1 ); result = spu_madd( spu_rlqwbyte( vec0, 4 ), spu_rlqwbyte( vec1, 4 ), result ); return spu_madd( spu_rlqwbyte( vec0, 8 ), spu_rlqwbyte( vec1, 8 ), result ); } #endif //__SPU__ void computeAabb (btVector3& aabbMin, btVector3& aabbMax, btConvexInternalShape* convexShape, ppu_address_t convexShapePtr, int shapeType, const btTransform& xform) { //calculate the aabb, given the types... switch (shapeType) { case CYLINDER_SHAPE_PROXYTYPE: /* fall through */ case BOX_SHAPE_PROXYTYPE: { btScalar margin=convexShape->getMarginNV(); btVector3 halfExtents = convexShape->getImplicitShapeDimensions(); halfExtents += btVector3(margin,margin,margin); const btTransform& t = xform; btMatrix3x3 abs_b = t.getBasis().absolute(); btVector3 center = t.getOrigin(); btVector3 extent = btVector3(abs_b[0].dot(halfExtents),abs_b[1].dot(halfExtents),abs_b[2].dot(halfExtents)); aabbMin = center - extent; aabbMax = center + extent; break; } case CAPSULE_SHAPE_PROXYTYPE: { btScalar margin=convexShape->getMarginNV(); btVector3 halfExtents = convexShape->getImplicitShapeDimensions(); //add the radius to y-axis to get full height btScalar radius = halfExtents[0]; halfExtents[1] += radius; halfExtents += btVector3(margin,margin,margin); #if 0 int capsuleUpAxis = convexShape->getUpAxis(); btScalar halfHeight = convexShape->getHalfHeight(); btScalar radius = convexShape->getRadius(); halfExtents[capsuleUpAxis] = radius + halfHeight; #endif const btTransform& t = xform; btMatrix3x3 abs_b = t.getBasis().absolute(); btVector3 center = t.getOrigin(); btVector3 extent = btVector3(abs_b[0].dot(halfExtents),abs_b[1].dot(halfExtents),abs_b[2].dot(halfExtents)); aabbMin = center - extent; aabbMax = center + extent; break; } case SPHERE_SHAPE_PROXYTYPE: { btScalar radius = convexShape->getImplicitShapeDimensions().getX();// * convexShape->getLocalScaling().getX(); btScalar margin = radius + convexShape->getMarginNV(); const btTransform& t = xform; const btVector3& center = t.getOrigin(); btVector3 extent(margin,margin,margin); aabbMin = center - extent; aabbMax = center + extent; break; } case CONVEX_HULL_SHAPE_PROXYTYPE: { ATTRIBUTE_ALIGNED16(char convexHullShape0[sizeof(btConvexHullShape)]); cellDmaGet(&convexHullShape0, convexShapePtr , sizeof(btConvexHullShape), DMA_TAG(1), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(1)); btConvexHullShape* localPtr = (btConvexHullShape*)&convexHullShape0; const btTransform& t = xform; btScalar margin = convexShape->getMarginNV(); localPtr->getNonvirtualAabb(t,aabbMin,aabbMax,margin); //spu_printf("SPU convex aabbMin=%f,%f,%f=\n",aabbMin.getX(),aabbMin.getY(),aabbMin.getZ()); //spu_printf("SPU convex aabbMax=%f,%f,%f=\n",aabbMax.getX(),aabbMax.getY(),aabbMax.getZ()); break; } default: { // spu_printf("SPU: unsupported shapetype %d in AABB calculation\n"); } }; } void dmaBvhShapeData (bvhMeshShape_LocalStoreMemory* bvhMeshShape, btBvhTriangleMeshShape* triMeshShape) { register int dmaSize; register ppu_address_t dmaPpuAddress2; dmaSize = sizeof(btTriangleIndexVertexArray); dmaPpuAddress2 = reinterpret_cast(triMeshShape->getMeshInterface()); // spu_printf("trimeshShape->getMeshInterface() == %llx\n",dmaPpuAddress2); #ifdef __SPU__ cellDmaGet(&bvhMeshShape->gTriangleMeshInterfaceStorage, dmaPpuAddress2 , dmaSize, DMA_TAG(1), 0, 0); bvhMeshShape->gTriangleMeshInterfacePtr = &bvhMeshShape->gTriangleMeshInterfaceStorage; #else bvhMeshShape->gTriangleMeshInterfacePtr = (btTriangleIndexVertexArray*)cellDmaGetReadOnly(&bvhMeshShape->gTriangleMeshInterfaceStorage, dmaPpuAddress2 , dmaSize, DMA_TAG(1), 0, 0); #endif //cellDmaWaitTagStatusAll(DMA_MASK(1)); ///now DMA over the BVH dmaSize = sizeof(btOptimizedBvh); dmaPpuAddress2 = reinterpret_cast(triMeshShape->getOptimizedBvh()); //spu_printf("trimeshShape->getOptimizedBvh() == %llx\n",dmaPpuAddress2); cellDmaGet(&bvhMeshShape->gOptimizedBvh, dmaPpuAddress2 , dmaSize, DMA_TAG(2), 0, 0); //cellDmaWaitTagStatusAll(DMA_MASK(2)); cellDmaWaitTagStatusAll(DMA_MASK(1) | DMA_MASK(2)); } void dmaBvhIndexedMesh (btIndexedMesh* IndexMesh, IndexedMeshArray& indexArray, int index, uint32_t dmaTag) { cellDmaGet(IndexMesh, (ppu_address_t)&indexArray[index] , sizeof(btIndexedMesh), DMA_TAG(dmaTag), 0, 0); } void dmaBvhSubTreeHeaders (btBvhSubtreeInfo* subTreeHeaders, ppu_address_t subTreePtr, int batchSize, uint32_t dmaTag) { cellDmaGet(subTreeHeaders, subTreePtr, batchSize * sizeof(btBvhSubtreeInfo), DMA_TAG(dmaTag), 0, 0); } void dmaBvhSubTreeNodes (btQuantizedBvhNode* nodes, const btBvhSubtreeInfo& subtree, QuantizedNodeArray& nodeArray, int dmaTag) { cellDmaGet(nodes, reinterpret_cast(&nodeArray[subtree.m_rootNodeIndex]) , subtree.m_subtreeSize* sizeof(btQuantizedBvhNode), DMA_TAG(2), 0, 0); } ///getShapeTypeSize could easily be optimized, but it is not likely a bottleneck int getShapeTypeSize(int shapeType) { switch (shapeType) { case CYLINDER_SHAPE_PROXYTYPE: { int shapeSize = sizeof(btCylinderShape); btAssert(shapeSize < MAX_SHAPE_SIZE); return shapeSize; } case BOX_SHAPE_PROXYTYPE: { int shapeSize = sizeof(btBoxShape); btAssert(shapeSize < MAX_SHAPE_SIZE); return shapeSize; } case SPHERE_SHAPE_PROXYTYPE: { int shapeSize = sizeof(btSphereShape); btAssert(shapeSize < MAX_SHAPE_SIZE); return shapeSize; } case TRIANGLE_MESH_SHAPE_PROXYTYPE: { int shapeSize = sizeof(btBvhTriangleMeshShape); btAssert(shapeSize < MAX_SHAPE_SIZE); return shapeSize; } case CAPSULE_SHAPE_PROXYTYPE: { int shapeSize = sizeof(btCapsuleShape); btAssert(shapeSize < MAX_SHAPE_SIZE); return shapeSize; } case CONVEX_HULL_SHAPE_PROXYTYPE: { int shapeSize = sizeof(btConvexHullShape); btAssert(shapeSize < MAX_SHAPE_SIZE); return shapeSize; } case COMPOUND_SHAPE_PROXYTYPE: { int shapeSize = sizeof(btCompoundShape); btAssert(shapeSize < MAX_SHAPE_SIZE); return shapeSize; } default: btAssert(0); //unsupported shapetype, please add here return 0; } } void dmaConvexVertexData (SpuConvexPolyhedronVertexData* convexVertexData, btConvexHullShape* convexShapeSPU) { convexVertexData->gNumConvexPoints = convexShapeSPU->getNumPoints(); if (convexVertexData->gNumConvexPoints>MAX_NUM_SPU_CONVEX_POINTS) { btAssert(0); // spu_printf("SPU: Error: MAX_NUM_SPU_CONVEX_POINTS(%d) exceeded: %d\n",MAX_NUM_SPU_CONVEX_POINTS,convexVertexData->gNumConvexPoints); return; } register int dmaSize = convexVertexData->gNumConvexPoints*sizeof(btVector3); ppu_address_t pointsPPU = (ppu_address_t) convexShapeSPU->getUnscaledPoints(); cellDmaGet(&convexVertexData->g_convexPointBuffer[0], pointsPPU , dmaSize, DMA_TAG(2), 0, 0); } void dmaCollisionShape (void* collisionShapeLocation, ppu_address_t collisionShapePtr, uint32_t dmaTag, int shapeType) { register int dmaSize = getShapeTypeSize(shapeType); cellDmaGet(collisionShapeLocation, collisionShapePtr , dmaSize, DMA_TAG(dmaTag), 0, 0); //cellDmaWaitTagStatusAll(DMA_MASK(dmaTag)); } void dmaCompoundShapeInfo (CompoundShape_LocalStoreMemory* compoundShapeLocation, btCompoundShape* spuCompoundShape, uint32_t dmaTag) { register int dmaSize; register ppu_address_t dmaPpuAddress2; int childShapeCount = spuCompoundShape->getNumChildShapes(); dmaSize = childShapeCount * sizeof(btCompoundShapeChild); dmaPpuAddress2 = (ppu_address_t)spuCompoundShape->getChildList(); cellDmaGet(&compoundShapeLocation->gSubshapes[0], dmaPpuAddress2, dmaSize, DMA_TAG(dmaTag), 0, 0); } void dmaCompoundSubShapes (CompoundShape_LocalStoreMemory* compoundShapeLocation, btCompoundShape* spuCompoundShape, uint32_t dmaTag) { int childShapeCount = spuCompoundShape->getNumChildShapes(); int i; // DMA all the subshapes for ( i = 0; i < childShapeCount; ++i) { btCompoundShapeChild& childShape = compoundShapeLocation->gSubshapes[i]; dmaCollisionShape (&compoundShapeLocation->gSubshapeShape[i],(ppu_address_t)childShape.m_childShape, dmaTag, childShape.m_childShapeType); } } void spuWalkStacklessQuantizedTree(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax,const btQuantizedBvhNode* rootNode,int startNodeIndex,int endNodeIndex) { int curIndex = startNodeIndex; int walkIterations = 0; #ifdef BT_DEBUG int subTreeSize = endNodeIndex - startNodeIndex; #endif int escapeIndex; unsigned int aabbOverlap, isLeafNode; while (curIndex < endNodeIndex) { //catch bugs in tree data btAssert (walkIterations < subTreeSize); walkIterations++; aabbOverlap = spuTestQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,rootNode->m_quantizedAabbMin,rootNode->m_quantizedAabbMax); isLeafNode = rootNode->isLeafNode(); if (isLeafNode && aabbOverlap) { //printf("overlap with node %d\n",rootNode->getTriangleIndex()); nodeCallback->processNode(0,rootNode->getTriangleIndex()); // spu_printf("SPU: overlap detected with triangleIndex:%d\n",rootNode->getTriangleIndex()); } if (aabbOverlap || isLeafNode) { rootNode++; curIndex++; } else { escapeIndex = rootNode->getEscapeIndex(); rootNode += escapeIndex; curIndex += escapeIndex; } } } ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuLocalSupport.hcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuLocalSuppor0000644000175000017500000000167111337073000033153 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/readme.txt0000644000175000017500000000005611337073000032267 0ustar bobkebobkeEmpty placeholder for future Libspe2 SPU task ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/boxBoxDistance.cppcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/boxBoxDistance0000644000175000017500000011770411337073000033141 0ustar bobkebobke/* Copyright (C) 2006, 2008 Sony Computer Entertainment Inc. All rights reserved. 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 "Box.h" static inline float sqr( float a ) { return (a * a); } enum BoxSepAxisType { A_AXIS, B_AXIS, CROSS_AXIS }; //------------------------------------------------------------------------------------------------- // voronoiTol: bevels Voronoi planes slightly which helps when features are parallel. //------------------------------------------------------------------------------------------------- static const float voronoiTol = -1.0e-5f; //------------------------------------------------------------------------------------------------- // separating axis tests: gaps along each axis are computed, and the axis with the maximum // gap is stored. cross product axes are normalized. //------------------------------------------------------------------------------------------------- #define AaxisTest( dim, letter, first ) \ { \ if ( first ) \ { \ maxGap = gap = gapsA.get##letter(); \ if ( gap > distanceThreshold ) return gap; \ axisType = A_AXIS; \ faceDimA = dim; \ axisA = identity.getCol##dim(); \ } \ else \ { \ gap = gapsA.get##letter(); \ if ( gap > distanceThreshold ) return gap; \ else if ( gap > maxGap ) \ { \ maxGap = gap; \ axisType = A_AXIS; \ faceDimA = dim; \ axisA = identity.getCol##dim(); \ } \ } \ } #define BaxisTest( dim, letter ) \ { \ gap = gapsB.get##letter(); \ if ( gap > distanceThreshold ) return gap; \ else if ( gap > maxGap ) \ { \ maxGap = gap; \ axisType = B_AXIS; \ faceDimB = dim; \ axisB = identity.getCol##dim(); \ } \ } #define CrossAxisTest( dima, dimb, letterb ) \ { \ const float lsqr_tolerance = 1.0e-30f; \ float lsqr; \ \ lsqr = lsqrs.getCol##dima().get##letterb(); \ \ if ( lsqr > lsqr_tolerance ) \ { \ float l_recip = 1.0f / sqrtf( lsqr ); \ gap = float(gapsAxB.getCol##dima().get##letterb()) * l_recip; \ \ if ( gap > distanceThreshold ) \ { \ return gap; \ } \ \ if ( gap > maxGap ) \ { \ maxGap = gap; \ axisType = CROSS_AXIS; \ edgeDimA = dima; \ edgeDimB = dimb; \ axisA = cross(identity.getCol##dima(),matrixAB.getCol##dimb()) * l_recip; \ } \ } \ } //------------------------------------------------------------------------------------------------- // tests whether a vertex of box B and a face of box A are the closest features //------------------------------------------------------------------------------------------------- inline float VertexBFaceATest( bool & inVoronoi, float & t0, float & t1, const Vector3 & hA, PE_REF(Vector3) faceOffsetAB, PE_REF(Vector3) faceOffsetBA, const Matrix3 & matrixAB, const Matrix3 & matrixBA, PE_REF(Vector3) signsB, PE_REF(Vector3) scalesB ) { // compute a corner of box B in A's coordinate system Vector3 corner = Vector3( faceOffsetAB + matrixAB.getCol0() * scalesB.getX() + matrixAB.getCol1() * scalesB.getY() ); // compute the parameters of the point on A, closest to this corner t0 = corner[0]; t1 = corner[1]; if ( t0 > hA[0] ) t0 = hA[0]; else if ( t0 < -hA[0] ) t0 = -hA[0]; if ( t1 > hA[1] ) t1 = hA[1]; else if ( t1 < -hA[1] ) t1 = -hA[1]; // do the Voronoi test: already know the point on B is in the Voronoi region of the // point on A, check the reverse. Vector3 facePointB = Vector3( mulPerElem( faceOffsetBA + matrixBA.getCol0() * t0 + matrixBA.getCol1() * t1 - scalesB, signsB ) ); inVoronoi = ( ( facePointB[0] >= voronoiTol * facePointB[2] ) && ( facePointB[1] >= voronoiTol * facePointB[0] ) && ( facePointB[2] >= voronoiTol * facePointB[1] ) ); return (sqr( corner[0] - t0 ) + sqr( corner[1] - t1 ) + sqr( corner[2] )); } #define VertexBFaceA_SetNewMin() \ { \ minDistSqr = distSqr; \ localPointA.setX(t0); \ localPointA.setY(t1); \ localPointB.setX( scalesB.getX() ); \ localPointB.setY( scalesB.getY() ); \ featureA = F; \ featureB = V; \ } void VertexBFaceATests( bool & done, float & minDistSqr, Point3 & localPointA, Point3 & localPointB, FeatureType & featureA, FeatureType & featureB, const Vector3 & hA, PE_REF(Vector3) faceOffsetAB, PE_REF(Vector3) faceOffsetBA, const Matrix3 & matrixAB, const Matrix3 & matrixBA, PE_REF(Vector3) signsB, PE_REF(Vector3) scalesB, bool first ) { float t0, t1; float distSqr; distSqr = VertexBFaceATest( done, t0, t1, hA, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsB, scalesB ); if ( first ) { VertexBFaceA_SetNewMin(); } else { if ( distSqr < minDistSqr ) { VertexBFaceA_SetNewMin(); } } if ( done ) return; signsB.setX( -signsB.getX() ); scalesB.setX( -scalesB.getX() ); distSqr = VertexBFaceATest( done, t0, t1, hA, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsB, scalesB ); if ( distSqr < minDistSqr ) { VertexBFaceA_SetNewMin(); } if ( done ) return; signsB.setY( -signsB.getY() ); scalesB.setY( -scalesB.getY() ); distSqr = VertexBFaceATest( done, t0, t1, hA, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsB, scalesB ); if ( distSqr < minDistSqr ) { VertexBFaceA_SetNewMin(); } if ( done ) return; signsB.setX( -signsB.getX() ); scalesB.setX( -scalesB.getX() ); distSqr = VertexBFaceATest( done, t0, t1, hA, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsB, scalesB ); if ( distSqr < minDistSqr ) { VertexBFaceA_SetNewMin(); } } //------------------------------------------------------------------------------------------------- // VertexAFaceBTest: tests whether a vertex of box A and a face of box B are the closest features //------------------------------------------------------------------------------------------------- inline float VertexAFaceBTest( bool & inVoronoi, float & t0, float & t1, const Vector3 & hB, PE_REF(Vector3) faceOffsetAB, PE_REF(Vector3) faceOffsetBA, const Matrix3 & matrixAB, const Matrix3 & matrixBA, PE_REF(Vector3) signsA, PE_REF(Vector3) scalesA ) { Vector3 corner = Vector3( faceOffsetBA + matrixBA.getCol0() * scalesA.getX() + matrixBA.getCol1() * scalesA.getY() ); t0 = corner[0]; t1 = corner[1]; if ( t0 > hB[0] ) t0 = hB[0]; else if ( t0 < -hB[0] ) t0 = -hB[0]; if ( t1 > hB[1] ) t1 = hB[1]; else if ( t1 < -hB[1] ) t1 = -hB[1]; Vector3 facePointA = Vector3( mulPerElem( faceOffsetAB + matrixAB.getCol0() * t0 + matrixAB.getCol1() * t1 - scalesA, signsA ) ); inVoronoi = ( ( facePointA[0] >= voronoiTol * facePointA[2] ) && ( facePointA[1] >= voronoiTol * facePointA[0] ) && ( facePointA[2] >= voronoiTol * facePointA[1] ) ); return (sqr( corner[0] - t0 ) + sqr( corner[1] - t1 ) + sqr( corner[2] )); } #define VertexAFaceB_SetNewMin() \ { \ minDistSqr = distSqr; \ localPointB.setX(t0); \ localPointB.setY(t1); \ localPointA.setX( scalesA.getX() ); \ localPointA.setY( scalesA.getY() ); \ featureA = V; \ featureB = F; \ } void VertexAFaceBTests( bool & done, float & minDistSqr, Point3 & localPointA, Point3 & localPointB, FeatureType & featureA, FeatureType & featureB, const Vector3 & hB, PE_REF(Vector3) faceOffsetAB, PE_REF(Vector3) faceOffsetBA, const Matrix3 & matrixAB, const Matrix3 & matrixBA, PE_REF(Vector3) signsA, PE_REF(Vector3) scalesA, bool first ) { float t0, t1; float distSqr; distSqr = VertexAFaceBTest( done, t0, t1, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, scalesA ); if ( first ) { VertexAFaceB_SetNewMin(); } else { if ( distSqr < minDistSqr ) { VertexAFaceB_SetNewMin(); } } if ( done ) return; signsA.setX( -signsA.getX() ); scalesA.setX( -scalesA.getX() ); distSqr = VertexAFaceBTest( done, t0, t1, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, scalesA ); if ( distSqr < minDistSqr ) { VertexAFaceB_SetNewMin(); } if ( done ) return; signsA.setY( -signsA.getY() ); scalesA.setY( -scalesA.getY() ); distSqr = VertexAFaceBTest( done, t0, t1, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, scalesA ); if ( distSqr < minDistSqr ) { VertexAFaceB_SetNewMin(); } if ( done ) return; signsA.setX( -signsA.getX() ); scalesA.setX( -scalesA.getX() ); distSqr = VertexAFaceBTest( done, t0, t1, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, scalesA ); if ( distSqr < minDistSqr ) { VertexAFaceB_SetNewMin(); } } //------------------------------------------------------------------------------------------------- // EdgeEdgeTest: // // tests whether a pair of edges are the closest features // // note on the shorthand: // 'a' & 'b' refer to the edges. // 'c' is the dimension of the axis that points from the face center to the edge Center // 'd' is the dimension of the edge Direction // the dimension of the face normal is 2 //------------------------------------------------------------------------------------------------- #define EdgeEdgeTest( ac, ac_letter, ad, ad_letter, bc, bc_letter, bd, bd_letter ) \ { \ Vector3 edgeOffsetAB; \ Vector3 edgeOffsetBA; \ \ edgeOffsetAB = faceOffsetAB + matrixAB.getCol##bc() * scalesB.get##bc_letter(); \ edgeOffsetAB.set##ac_letter( edgeOffsetAB.get##ac_letter() - scalesA.get##ac_letter() ); \ \ edgeOffsetBA = faceOffsetBA + matrixBA.getCol##ac() * scalesA.get##ac_letter(); \ edgeOffsetBA.set##bc_letter( edgeOffsetBA.get##bc_letter() - scalesB.get##bc_letter() ); \ \ float dirDot = matrixAB.getCol##bd().get##ad_letter(); \ float denom = 1.0f - dirDot*dirDot; \ float edgeOffsetAB_ad = edgeOffsetAB.get##ad_letter(); \ float edgeOffsetBA_bd = edgeOffsetBA.get##bd_letter(); \ \ if ( denom == 0.0f ) \ { \ tA = 0.0f; \ } \ else \ { \ tA = ( edgeOffsetAB_ad + edgeOffsetBA_bd * dirDot ) / denom; \ } \ \ if ( tA < -hA[ad] ) tA = -hA[ad]; \ else if ( tA > hA[ad] ) tA = hA[ad]; \ \ tB = tA * dirDot + edgeOffsetBA_bd; \ \ if ( tB < -hB[bd] ) \ { \ tB = -hB[bd]; \ tA = tB * dirDot + edgeOffsetAB_ad; \ \ if ( tA < -hA[ad] ) tA = -hA[ad]; \ else if ( tA > hA[ad] ) tA = hA[ad]; \ } \ else if ( tB > hB[bd] ) \ { \ tB = hB[bd]; \ tA = tB * dirDot + edgeOffsetAB_ad; \ \ if ( tA < -hA[ad] ) tA = -hA[ad]; \ else if ( tA > hA[ad] ) tA = hA[ad]; \ } \ \ Vector3 edgeOffAB = Vector3( mulPerElem( edgeOffsetAB + matrixAB.getCol##bd() * tB, signsA ) );\ Vector3 edgeOffBA = Vector3( mulPerElem( edgeOffsetBA + matrixBA.getCol##ad() * tA, signsB ) );\ \ inVoronoi = ( edgeOffAB[ac] >= voronoiTol * edgeOffAB[2] ) && \ ( edgeOffAB[2] >= voronoiTol * edgeOffAB[ac] ) && \ ( edgeOffBA[bc] >= voronoiTol * edgeOffBA[2] ) && \ ( edgeOffBA[2] >= voronoiTol * edgeOffBA[bc] ); \ \ edgeOffAB[ad] -= tA; \ edgeOffBA[bd] -= tB; \ \ return dot(edgeOffAB,edgeOffAB); \ } float EdgeEdgeTest_0101( bool & inVoronoi, float & tA, float & tB, const Vector3 & hA, const Vector3 & hB, PE_REF(Vector3) faceOffsetAB, PE_REF(Vector3) faceOffsetBA, const Matrix3 & matrixAB, const Matrix3 & matrixBA, PE_REF(Vector3) signsA, PE_REF(Vector3) signsB, PE_REF(Vector3) scalesA, PE_REF(Vector3) scalesB ) { EdgeEdgeTest( 0, X, 1, Y, 0, X, 1, Y ); } float EdgeEdgeTest_0110( bool & inVoronoi, float & tA, float & tB, const Vector3 & hA, const Vector3 & hB, PE_REF(Vector3) faceOffsetAB, PE_REF(Vector3) faceOffsetBA, const Matrix3 & matrixAB, const Matrix3 & matrixBA, PE_REF(Vector3) signsA, PE_REF(Vector3) signsB, PE_REF(Vector3) scalesA, PE_REF(Vector3) scalesB ) { EdgeEdgeTest( 0, X, 1, Y, 1, Y, 0, X ); } float EdgeEdgeTest_1001( bool & inVoronoi, float & tA, float & tB, const Vector3 & hA, const Vector3 & hB, PE_REF(Vector3) faceOffsetAB, PE_REF(Vector3) faceOffsetBA, const Matrix3 & matrixAB, const Matrix3 & matrixBA, PE_REF(Vector3) signsA, PE_REF(Vector3) signsB, PE_REF(Vector3) scalesA, PE_REF(Vector3) scalesB ) { EdgeEdgeTest( 1, Y, 0, X, 0, X, 1, Y ); } float EdgeEdgeTest_1010( bool & inVoronoi, float & tA, float & tB, const Vector3 & hA, const Vector3 & hB, PE_REF(Vector3) faceOffsetAB, PE_REF(Vector3) faceOffsetBA, const Matrix3 & matrixAB, const Matrix3 & matrixBA, PE_REF(Vector3) signsA, PE_REF(Vector3) signsB, PE_REF(Vector3) scalesA, PE_REF(Vector3) scalesB ) { EdgeEdgeTest( 1, Y, 0, X, 1, Y, 0, X ); } #define EdgeEdge_SetNewMin( ac_letter, ad_letter, bc_letter, bd_letter ) \ { \ minDistSqr = distSqr; \ localPointA.set##ac_letter(scalesA.get##ac_letter()); \ localPointA.set##ad_letter(tA); \ localPointB.set##bc_letter(scalesB.get##bc_letter()); \ localPointB.set##bd_letter(tB); \ otherFaceDimA = testOtherFaceDimA; \ otherFaceDimB = testOtherFaceDimB; \ featureA = E; \ featureB = E; \ } void EdgeEdgeTests( bool & done, float & minDistSqr, Point3 & localPointA, Point3 & localPointB, int & otherFaceDimA, int & otherFaceDimB, FeatureType & featureA, FeatureType & featureB, const Vector3 & hA, const Vector3 & hB, PE_REF(Vector3) faceOffsetAB, PE_REF(Vector3) faceOffsetBA, const Matrix3 & matrixAB, const Matrix3 & matrixBA, PE_REF(Vector3) signsA, PE_REF(Vector3) signsB, PE_REF(Vector3) scalesA, PE_REF(Vector3) scalesB, bool first ) { float distSqr; float tA, tB; int testOtherFaceDimA, testOtherFaceDimB; testOtherFaceDimA = 0; testOtherFaceDimB = 0; distSqr = EdgeEdgeTest_0101( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, signsB, scalesA, scalesB ); if ( first ) { EdgeEdge_SetNewMin( X, Y, X, Y ); } else { if ( distSqr < minDistSqr ) { EdgeEdge_SetNewMin( X, Y, X, Y ); } } if ( done ) return; signsA.setX( -signsA.getX() ); scalesA.setX( -scalesA.getX() ); distSqr = EdgeEdgeTest_0101( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, signsB, scalesA, scalesB ); if ( distSqr < minDistSqr ) { EdgeEdge_SetNewMin( X, Y, X, Y ); } if ( done ) return; signsB.setX( -signsB.getX() ); scalesB.setX( -scalesB.getX() ); distSqr = EdgeEdgeTest_0101( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, signsB, scalesA, scalesB ); if ( distSqr < minDistSqr ) { EdgeEdge_SetNewMin( X, Y, X, Y ); } if ( done ) return; signsA.setX( -signsA.getX() ); scalesA.setX( -scalesA.getX() ); distSqr = EdgeEdgeTest_0101( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, signsB, scalesA, scalesB ); if ( distSqr < minDistSqr ) { EdgeEdge_SetNewMin( X, Y, X, Y ); } if ( done ) return; testOtherFaceDimA = 1; testOtherFaceDimB = 0; signsB.setX( -signsB.getX() ); scalesB.setX( -scalesB.getX() ); distSqr = EdgeEdgeTest_1001( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, signsB, scalesA, scalesB ); if ( distSqr < minDistSqr ) { EdgeEdge_SetNewMin( Y, X, X, Y ); } if ( done ) return; signsA.setY( -signsA.getY() ); scalesA.setY( -scalesA.getY() ); distSqr = EdgeEdgeTest_1001( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, signsB, scalesA, scalesB ); if ( distSqr < minDistSqr ) { EdgeEdge_SetNewMin( Y, X, X, Y ); } if ( done ) return; signsB.setX( -signsB.getX() ); scalesB.setX( -scalesB.getX() ); distSqr = EdgeEdgeTest_1001( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, signsB, scalesA, scalesB ); if ( distSqr < minDistSqr ) { EdgeEdge_SetNewMin( Y, X, X, Y ); } if ( done ) return; signsA.setY( -signsA.getY() ); scalesA.setY( -scalesA.getY() ); distSqr = EdgeEdgeTest_1001( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, signsB, scalesA, scalesB ); if ( distSqr < minDistSqr ) { EdgeEdge_SetNewMin( Y, X, X, Y ); } if ( done ) return; testOtherFaceDimA = 0; testOtherFaceDimB = 1; signsB.setX( -signsB.getX() ); scalesB.setX( -scalesB.getX() ); distSqr = EdgeEdgeTest_0110( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, signsB, scalesA, scalesB ); if ( distSqr < minDistSqr ) { EdgeEdge_SetNewMin( X, Y, Y, X ); } if ( done ) return; signsA.setX( -signsA.getX() ); scalesA.setX( -scalesA.getX() ); distSqr = EdgeEdgeTest_0110( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, signsB, scalesA, scalesB ); if ( distSqr < minDistSqr ) { EdgeEdge_SetNewMin( X, Y, Y, X ); } if ( done ) return; signsB.setY( -signsB.getY() ); scalesB.setY( -scalesB.getY() ); distSqr = EdgeEdgeTest_0110( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, signsB, scalesA, scalesB ); if ( distSqr < minDistSqr ) { EdgeEdge_SetNewMin( X, Y, Y, X ); } if ( done ) return; signsA.setX( -signsA.getX() ); scalesA.setX( -scalesA.getX() ); distSqr = EdgeEdgeTest_0110( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, signsB, scalesA, scalesB ); if ( distSqr < minDistSqr ) { EdgeEdge_SetNewMin( X, Y, Y, X ); } if ( done ) return; testOtherFaceDimA = 1; testOtherFaceDimB = 1; signsB.setY( -signsB.getY() ); scalesB.setY( -scalesB.getY() ); distSqr = EdgeEdgeTest_1010( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, signsB, scalesA, scalesB ); if ( distSqr < minDistSqr ) { EdgeEdge_SetNewMin( Y, X, Y, X ); } if ( done ) return; signsA.setY( -signsA.getY() ); scalesA.setY( -scalesA.getY() ); distSqr = EdgeEdgeTest_1010( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, signsB, scalesA, scalesB ); if ( distSqr < minDistSqr ) { EdgeEdge_SetNewMin( Y, X, Y, X ); } if ( done ) return; signsB.setY( -signsB.getY() ); scalesB.setY( -scalesB.getY() ); distSqr = EdgeEdgeTest_1010( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, signsB, scalesA, scalesB ); if ( distSqr < minDistSqr ) { EdgeEdge_SetNewMin( Y, X, Y, X ); } if ( done ) return; signsA.setY( -signsA.getY() ); scalesA.setY( -scalesA.getY() ); distSqr = EdgeEdgeTest_1010( done, tA, tB, hA, hB, faceOffsetAB, faceOffsetBA, matrixAB, matrixBA, signsA, signsB, scalesA, scalesB ); if ( distSqr < minDistSqr ) { EdgeEdge_SetNewMin( Y, X, Y, X ); } } float boxBoxDistance( Vector3& normal, BoxPoint& boxPointA, BoxPoint& boxPointB, PE_REF(Box) boxA, const Transform3& transformA, PE_REF(Box) boxB, const Transform3& transformB, float distanceThreshold ) { Matrix3 identity; identity = Matrix3::identity(); Vector3 ident[3]; ident[0] = identity.getCol0(); ident[1] = identity.getCol1(); ident[2] = identity.getCol2(); // get relative transformations Transform3 transformAB, transformBA; Matrix3 matrixAB, matrixBA; Vector3 offsetAB, offsetBA; transformAB = orthoInverse(transformA) * transformB; transformBA = orthoInverse(transformAB); matrixAB = transformAB.getUpper3x3(); offsetAB = transformAB.getTranslation(); matrixBA = transformBA.getUpper3x3(); offsetBA = transformBA.getTranslation(); Matrix3 absMatrixAB = absPerElem(matrixAB); Matrix3 absMatrixBA = absPerElem(matrixBA); // find separating axis with largest gap between projections BoxSepAxisType axisType; Vector3 axisA(0.0f), axisB(0.0f); float gap, maxGap; int faceDimA = 0, faceDimB = 0, edgeDimA = 0, edgeDimB = 0; // face axes Vector3 gapsA = absPerElem(offsetAB) - boxA.half - absMatrixAB * boxB.half; AaxisTest(0,X,true); AaxisTest(1,Y,false); AaxisTest(2,Z,false); Vector3 gapsB = absPerElem(offsetBA) - boxB.half - absMatrixBA * boxA.half; BaxisTest(0,X); BaxisTest(1,Y); BaxisTest(2,Z); // cross product axes // OςÔƂ̑΍ absMatrixAB += Matrix3(1.0e-5f); absMatrixBA += Matrix3(1.0e-5f); Matrix3 lsqrs, projOffset, projAhalf, projBhalf; lsqrs.setCol0( mulPerElem( matrixBA.getCol2(), matrixBA.getCol2() ) + mulPerElem( matrixBA.getCol1(), matrixBA.getCol1() ) ); lsqrs.setCol1( mulPerElem( matrixBA.getCol2(), matrixBA.getCol2() ) + mulPerElem( matrixBA.getCol0(), matrixBA.getCol0() ) ); lsqrs.setCol2( mulPerElem( matrixBA.getCol1(), matrixBA.getCol1() ) + mulPerElem( matrixBA.getCol0(), matrixBA.getCol0() ) ); projOffset.setCol0(matrixBA.getCol1() * offsetAB.getZ() - matrixBA.getCol2() * offsetAB.getY()); projOffset.setCol1(matrixBA.getCol2() * offsetAB.getX() - matrixBA.getCol0() * offsetAB.getZ()); projOffset.setCol2(matrixBA.getCol0() * offsetAB.getY() - matrixBA.getCol1() * offsetAB.getX()); projAhalf.setCol0(absMatrixBA.getCol1() * boxA.half.getZ() + absMatrixBA.getCol2() * boxA.half.getY()); projAhalf.setCol1(absMatrixBA.getCol2() * boxA.half.getX() + absMatrixBA.getCol0() * boxA.half.getZ()); projAhalf.setCol2(absMatrixBA.getCol0() * boxA.half.getY() + absMatrixBA.getCol1() * boxA.half.getX()); projBhalf.setCol0(absMatrixAB.getCol1() * boxB.half.getZ() + absMatrixAB.getCol2() * boxB.half.getY()); projBhalf.setCol1(absMatrixAB.getCol2() * boxB.half.getX() + absMatrixAB.getCol0() * boxB.half.getZ()); projBhalf.setCol2(absMatrixAB.getCol0() * boxB.half.getY() + absMatrixAB.getCol1() * boxB.half.getX()); Matrix3 gapsAxB = absPerElem(projOffset) - projAhalf - transpose(projBhalf); CrossAxisTest(0,0,X); CrossAxisTest(0,1,Y); CrossAxisTest(0,2,Z); CrossAxisTest(1,0,X); CrossAxisTest(1,1,Y); CrossAxisTest(1,2,Z); CrossAxisTest(2,0,X); CrossAxisTest(2,1,Y); CrossAxisTest(2,2,Z); // need to pick the face on each box whose normal best matches the separating axis. // will transform vectors to be in the coordinate system of this face to simplify things later. // for this, a permutation matrix can be used, which the next section computes. int dimA[3], dimB[3]; if ( axisType == A_AXIS ) { if ( dot(axisA,offsetAB) < 0.0f ) axisA = -axisA; axisB = matrixBA * -axisA; Vector3 absAxisB = Vector3(absPerElem(axisB)); if ( ( absAxisB[0] > absAxisB[1] ) && ( absAxisB[0] > absAxisB[2] ) ) faceDimB = 0; else if ( absAxisB[1] > absAxisB[2] ) faceDimB = 1; else faceDimB = 2; } else if ( axisType == B_AXIS ) { if ( dot(axisB,offsetBA) < 0.0f ) axisB = -axisB; axisA = matrixAB * -axisB; Vector3 absAxisA = Vector3(absPerElem(axisA)); if ( ( absAxisA[0] > absAxisA[1] ) && ( absAxisA[0] > absAxisA[2] ) ) faceDimA = 0; else if ( absAxisA[1] > absAxisA[2] ) faceDimA = 1; else faceDimA = 2; } if ( axisType == CROSS_AXIS ) { if ( dot(axisA,offsetAB) < 0.0f ) axisA = -axisA; axisB = matrixBA * -axisA; Vector3 absAxisA = Vector3(absPerElem(axisA)); Vector3 absAxisB = Vector3(absPerElem(axisB)); dimA[1] = edgeDimA; dimB[1] = edgeDimB; if ( edgeDimA == 0 ) { if ( absAxisA[1] > absAxisA[2] ) { dimA[0] = 2; dimA[2] = 1; } else { dimA[0] = 1; dimA[2] = 2; } } else if ( edgeDimA == 1 ) { if ( absAxisA[2] > absAxisA[0] ) { dimA[0] = 0; dimA[2] = 2; } else { dimA[0] = 2; dimA[2] = 0; } } else { if ( absAxisA[0] > absAxisA[1] ) { dimA[0] = 1; dimA[2] = 0; } else { dimA[0] = 0; dimA[2] = 1; } } if ( edgeDimB == 0 ) { if ( absAxisB[1] > absAxisB[2] ) { dimB[0] = 2; dimB[2] = 1; } else { dimB[0] = 1; dimB[2] = 2; } } else if ( edgeDimB == 1 ) { if ( absAxisB[2] > absAxisB[0] ) { dimB[0] = 0; dimB[2] = 2; } else { dimB[0] = 2; dimB[2] = 0; } } else { if ( absAxisB[0] > absAxisB[1] ) { dimB[0] = 1; dimB[2] = 0; } else { dimB[0] = 0; dimB[2] = 1; } } } else { dimA[2] = faceDimA; dimA[0] = (faceDimA+1)%3; dimA[1] = (faceDimA+2)%3; dimB[2] = faceDimB; dimB[0] = (faceDimB+1)%3; dimB[1] = (faceDimB+2)%3; } Matrix3 aperm_col, bperm_col; aperm_col.setCol0(ident[dimA[0]]); aperm_col.setCol1(ident[dimA[1]]); aperm_col.setCol2(ident[dimA[2]]); bperm_col.setCol0(ident[dimB[0]]); bperm_col.setCol1(ident[dimB[1]]); bperm_col.setCol2(ident[dimB[2]]); Matrix3 aperm_row, bperm_row; aperm_row = transpose(aperm_col); bperm_row = transpose(bperm_col); // permute all box parameters to be in the face coordinate systems Matrix3 matrixAB_perm = aperm_row * matrixAB * bperm_col; Matrix3 matrixBA_perm = transpose(matrixAB_perm); Vector3 offsetAB_perm, offsetBA_perm; offsetAB_perm = aperm_row * offsetAB; offsetBA_perm = bperm_row * offsetBA; Vector3 halfA_perm, halfB_perm; halfA_perm = aperm_row * boxA.half; halfB_perm = bperm_row * boxB.half; // compute the vector between the centers of each face, in each face's coordinate frame Vector3 signsA_perm, signsB_perm, scalesA_perm, scalesB_perm, faceOffsetAB_perm, faceOffsetBA_perm; signsA_perm = copySignPerElem(Vector3(1.0f),aperm_row * axisA); signsB_perm = copySignPerElem(Vector3(1.0f),bperm_row * axisB); scalesA_perm = mulPerElem( signsA_perm, halfA_perm ); scalesB_perm = mulPerElem( signsB_perm, halfB_perm ); faceOffsetAB_perm = offsetAB_perm + matrixAB_perm.getCol2() * scalesB_perm.getZ(); faceOffsetAB_perm.setZ( faceOffsetAB_perm.getZ() - scalesA_perm.getZ() ); faceOffsetBA_perm = offsetBA_perm + matrixBA_perm.getCol2() * scalesA_perm.getZ(); faceOffsetBA_perm.setZ( faceOffsetBA_perm.getZ() - scalesB_perm.getZ() ); if ( maxGap < 0.0f ) { // if boxes overlap, this will separate the faces for finding points of penetration. faceOffsetAB_perm -= aperm_row * axisA * maxGap * 1.01f; faceOffsetBA_perm -= bperm_row * axisB * maxGap * 1.01f; } // for each vertex/face or edge/edge pair of the two faces, find the closest points. // // these points each have an associated box feature (vertex, edge, or face). if each // point is in the external Voronoi region of the other's feature, they are the // closest points of the boxes, and the algorithm can exit. // // the feature pairs are arranged so that in the general case, the first test will // succeed. degenerate cases (parallel faces) may require up to all tests in the // worst case. // // if for some reason no case passes the Voronoi test, the features with the minimum // distance are returned. Point3 localPointA_perm, localPointB_perm; float minDistSqr; bool done; Vector3 hA_perm( halfA_perm ), hB_perm( halfB_perm ); localPointA_perm.setZ( scalesA_perm.getZ() ); localPointB_perm.setZ( scalesB_perm.getZ() ); scalesA_perm.setZ(0.0f); scalesB_perm.setZ(0.0f); int otherFaceDimA, otherFaceDimB; FeatureType featureA, featureB; if ( axisType == CROSS_AXIS ) { EdgeEdgeTests( done, minDistSqr, localPointA_perm, localPointB_perm, otherFaceDimA, otherFaceDimB, featureA, featureB, hA_perm, hB_perm, faceOffsetAB_perm, faceOffsetBA_perm, matrixAB_perm, matrixBA_perm, signsA_perm, signsB_perm, scalesA_perm, scalesB_perm, true ); if ( !done ) { VertexBFaceATests( done, minDistSqr, localPointA_perm, localPointB_perm, featureA, featureB, hA_perm, faceOffsetAB_perm, faceOffsetBA_perm, matrixAB_perm, matrixBA_perm, signsB_perm, scalesB_perm, false ); if ( !done ) { VertexAFaceBTests( done, minDistSqr, localPointA_perm, localPointB_perm, featureA, featureB, hB_perm, faceOffsetAB_perm, faceOffsetBA_perm, matrixAB_perm, matrixBA_perm, signsA_perm, scalesA_perm, false ); } } } else if ( axisType == B_AXIS ) { VertexAFaceBTests( done, minDistSqr, localPointA_perm, localPointB_perm, featureA, featureB, hB_perm, faceOffsetAB_perm, faceOffsetBA_perm, matrixAB_perm, matrixBA_perm, signsA_perm, scalesA_perm, true ); if ( !done ) { VertexBFaceATests( done, minDistSqr, localPointA_perm, localPointB_perm, featureA, featureB, hA_perm, faceOffsetAB_perm, faceOffsetBA_perm, matrixAB_perm, matrixBA_perm, signsB_perm, scalesB_perm, false ); if ( !done ) { EdgeEdgeTests( done, minDistSqr, localPointA_perm, localPointB_perm, otherFaceDimA, otherFaceDimB, featureA, featureB, hA_perm, hB_perm, faceOffsetAB_perm, faceOffsetBA_perm, matrixAB_perm, matrixBA_perm, signsA_perm, signsB_perm, scalesA_perm, scalesB_perm, false ); } } } else { VertexBFaceATests( done, minDistSqr, localPointA_perm, localPointB_perm, featureA, featureB, hA_perm, faceOffsetAB_perm, faceOffsetBA_perm, matrixAB_perm, matrixBA_perm, signsB_perm, scalesB_perm, true ); if ( !done ) { VertexAFaceBTests( done, minDistSqr, localPointA_perm, localPointB_perm, featureA, featureB, hB_perm, faceOffsetAB_perm, faceOffsetBA_perm, matrixAB_perm, matrixBA_perm, signsA_perm, scalesA_perm, false ); if ( !done ) { EdgeEdgeTests( done, minDistSqr, localPointA_perm, localPointB_perm, otherFaceDimA, otherFaceDimB, featureA, featureB, hA_perm, hB_perm, faceOffsetAB_perm, faceOffsetBA_perm, matrixAB_perm, matrixBA_perm, signsA_perm, signsB_perm, scalesA_perm, scalesB_perm, false ); } } } // convert local points from face-local to box-local coordinate system boxPointA.localPoint = Point3( aperm_col * Vector3( localPointA_perm ) ); boxPointB.localPoint = Point3( bperm_col * Vector3( localPointB_perm ) ); // find which features of the boxes are involved. // the only feature pairs which occur in this function are VF, FV, and EE, even though the // closest points might actually lie on sub-features, as in a VF contact might be used for // what's actually a VV contact. this means some feature pairs could possibly seem distinct // from others, although their contact positions are the same. don't know yet whether this // matters. int sA[3], sB[3]; sA[0] = boxPointA.localPoint.getX() > 0.0f; sA[1] = boxPointA.localPoint.getY() > 0.0f; sA[2] = boxPointA.localPoint.getZ() > 0.0f; sB[0] = boxPointB.localPoint.getX() > 0.0f; sB[1] = boxPointB.localPoint.getY() > 0.0f; sB[2] = boxPointB.localPoint.getZ() > 0.0f; if ( featureA == F ) { boxPointA.setFaceFeature( dimA[2], sA[dimA[2]] ); } else if ( featureA == E ) { boxPointA.setEdgeFeature( dimA[2], sA[dimA[2]], dimA[otherFaceDimA], sA[dimA[otherFaceDimA]] ); } else { boxPointA.setVertexFeature( sA[0], sA[1], sA[2] ); } if ( featureB == F ) { boxPointB.setFaceFeature( dimB[2], sB[dimB[2]] ); } else if ( featureB == E ) { boxPointB.setEdgeFeature( dimB[2], sB[dimB[2]], dimB[otherFaceDimB], sB[dimB[otherFaceDimB]] ); } else { boxPointB.setVertexFeature( sB[0], sB[1], sB[2] ); } normal = transformA * axisA; if ( maxGap < 0.0f ) { return (maxGap); } else { return (sqrtf( minDistSqr )); } } ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/boxBoxDistance.hcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/boxBoxDistance0000644000175000017500000000553711337073000033141 0ustar bobkebobke/* Copyright (C) 2006, 2008 Sony Computer Entertainment Inc. All rights reserved. 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 __BOXBOXDISTANCE_H__ #define __BOXBOXDISTANCE_H__ #include "Box.h" using namespace Vectormath::Aos; //--------------------------------------------------------------------------- // boxBoxDistance: // // description: // this computes info that can be used for the collision response of two boxes. when the boxes // do not overlap, the points are set to the closest points of the boxes, and a positive // distance between them is returned. if the boxes do overlap, a negative distance is returned // and the points are set to two points that would touch after the boxes are translated apart. // the contact normal gives the direction to repel or separate the boxes when they touch or // overlap (it's being approximated here as one of the 15 "separating axis" directions). // // returns: // positive or negative distance between two boxes. // // args: // Vector3& normal: set to a unit contact normal pointing from box A to box B. // // BoxPoint& boxPointA, BoxPoint& boxPointB: // set to a closest point or point of penetration on each box. // // Box boxA, Box boxB: // boxes, represented as 3 half-widths // // const Transform3& transformA, const Transform3& transformB: // box transformations, in world coordinates // // float distanceThreshold: // the algorithm will exit early if it finds that the boxes are more distant than this // threshold, and not compute a contact normal or points. if this distance returned // exceeds the threshold, all the other output data may not have been computed. by // default, this is set to MAX_FLOAT so it will have no effect. // //--------------------------------------------------------------------------- float boxBoxDistance(Vector3& normal, BoxPoint& boxPointA, BoxPoint& boxPointB, PE_REF(Box) boxA, const Transform3 & transformA, PE_REF(Box) boxB, const Transform3 & transformB, float distanceThreshold = FLT_MAX ); #endif /* __BOXBOXDISTANCE_H__ */ ././@LongLink0000000000000000000000000000017200000000000011565 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuPreferredPenetrationDirections.hcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuPreferredPe0000644000175000017500000000412311337073000033106 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://continuousphysics.com/Bullet/ 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 _SPU_PREFERRED_PENETRATION_DIRECTIONS_H #define _SPU_PREFERRED_PENETRATION_DIRECTIONS_H #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" int spuGetNumPreferredPenetrationDirections(int shapeType, void* shape) { switch (shapeType) { case TRIANGLE_SHAPE_PROXYTYPE: { return 2; //spu_printf("2\n"); break; } default: { #if __ASSERT spu_printf("spuGetNumPreferredPenetrationDirections() - Unsupported bound type: %d.\n", shapeType); #endif // __ASSERT } } return 0; } void spuGetPreferredPenetrationDirection(int shapeType, void* shape, int index, btVector3& penetrationVector) { switch (shapeType) { case TRIANGLE_SHAPE_PROXYTYPE: { btVector3* vertices = (btVector3*)shape; ///calcNormal penetrationVector = (vertices[1]-vertices[0]).cross(vertices[2]-vertices[0]); penetrationVector.normalize(); if (index) penetrationVector *= btScalar(-1.); break; } default: { #if __ASSERT spu_printf("spuGetNumPreferredPenetrationDirections() - Unsupported bound type: %d.\n", shapeType); #endif // __ASSERT } } } #endif //_SPU_PREFERRED_PENETRATION_DIRECTIONS_H ././@LongLink0000000000000000000000000000017500000000000011570 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuMinkowskiPenetrationDepthSolver.cppcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuMinkowskiPe0000644000175000017500000002657411337073000033161 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "SpuMinkowskiPenetrationDepthSolver.h" #include "SpuContactResult.h" #include "SpuPreferredPenetrationDirections.h" #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" #include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" #include "SpuCollisionShapes.h" #define NUM_UNITSPHERE_POINTS 42 static btVector3 sPenetrationDirections[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2] = { btVector3(btScalar(0.000000) , btScalar(-0.000000),btScalar(-1.000000)), btVector3(btScalar(0.723608) , btScalar(-0.525725),btScalar(-0.447219)), btVector3(btScalar(-0.276388) , btScalar(-0.850649),btScalar(-0.447219)), btVector3(btScalar(-0.894426) , btScalar(-0.000000),btScalar(-0.447216)), btVector3(btScalar(-0.276388) , btScalar(0.850649),btScalar(-0.447220)), btVector3(btScalar(0.723608) , btScalar(0.525725),btScalar(-0.447219)), btVector3(btScalar(0.276388) , btScalar(-0.850649),btScalar(0.447220)), btVector3(btScalar(-0.723608) , btScalar(-0.525725),btScalar(0.447219)), btVector3(btScalar(-0.723608) , btScalar(0.525725),btScalar(0.447219)), btVector3(btScalar(0.276388) , btScalar(0.850649),btScalar(0.447219)), btVector3(btScalar(0.894426) , btScalar(0.000000),btScalar(0.447216)), btVector3(btScalar(-0.000000) , btScalar(0.000000),btScalar(1.000000)), btVector3(btScalar(0.425323) , btScalar(-0.309011),btScalar(-0.850654)), btVector3(btScalar(-0.162456) , btScalar(-0.499995),btScalar(-0.850654)), btVector3(btScalar(0.262869) , btScalar(-0.809012),btScalar(-0.525738)), btVector3(btScalar(0.425323) , btScalar(0.309011),btScalar(-0.850654)), btVector3(btScalar(0.850648) , btScalar(-0.000000),btScalar(-0.525736)), btVector3(btScalar(-0.525730) , btScalar(-0.000000),btScalar(-0.850652)), btVector3(btScalar(-0.688190) , btScalar(-0.499997),btScalar(-0.525736)), btVector3(btScalar(-0.162456) , btScalar(0.499995),btScalar(-0.850654)), btVector3(btScalar(-0.688190) , btScalar(0.499997),btScalar(-0.525736)), btVector3(btScalar(0.262869) , btScalar(0.809012),btScalar(-0.525738)), btVector3(btScalar(0.951058) , btScalar(0.309013),btScalar(0.000000)), btVector3(btScalar(0.951058) , btScalar(-0.309013),btScalar(0.000000)), btVector3(btScalar(0.587786) , btScalar(-0.809017),btScalar(0.000000)), btVector3(btScalar(0.000000) , btScalar(-1.000000),btScalar(0.000000)), btVector3(btScalar(-0.587786) , btScalar(-0.809017),btScalar(0.000000)), btVector3(btScalar(-0.951058) , btScalar(-0.309013),btScalar(-0.000000)), btVector3(btScalar(-0.951058) , btScalar(0.309013),btScalar(-0.000000)), btVector3(btScalar(-0.587786) , btScalar(0.809017),btScalar(-0.000000)), btVector3(btScalar(-0.000000) , btScalar(1.000000),btScalar(-0.000000)), btVector3(btScalar(0.587786) , btScalar(0.809017),btScalar(-0.000000)), btVector3(btScalar(0.688190) , btScalar(-0.499997),btScalar(0.525736)), btVector3(btScalar(-0.262869) , btScalar(-0.809012),btScalar(0.525738)), btVector3(btScalar(-0.850648) , btScalar(0.000000),btScalar(0.525736)), btVector3(btScalar(-0.262869) , btScalar(0.809012),btScalar(0.525738)), btVector3(btScalar(0.688190) , btScalar(0.499997),btScalar(0.525736)), btVector3(btScalar(0.525730) , btScalar(0.000000),btScalar(0.850652)), btVector3(btScalar(0.162456) , btScalar(-0.499995),btScalar(0.850654)), btVector3(btScalar(-0.425323) , btScalar(-0.309011),btScalar(0.850654)), btVector3(btScalar(-0.425323) , btScalar(0.309011),btScalar(0.850654)), btVector3(btScalar(0.162456) , btScalar(0.499995),btScalar(0.850654)) }; bool SpuMinkowskiPenetrationDepthSolver::calcPenDepth( btSimplexSolverInterface& simplexSolver, const btConvexShape* convexA,const btConvexShape* convexB, const btTransform& transA,const btTransform& transB, btVector3& v, btVector3& pa, btVector3& pb, class btIDebugDraw* debugDraw,btStackAlloc* stackAlloc) { #if 0 (void)stackAlloc; (void)v; struct btIntermediateResult : public SpuContactResult { btIntermediateResult():m_hasResult(false) { } btVector3 m_normalOnBInWorld; btVector3 m_pointInWorld; btScalar m_depth; bool m_hasResult; virtual void setShapeIdentifiersA(int partId0,int index0) { (void)partId0; (void)index0; } virtual void setShapeIdentifiersB(int partId1,int index1) { (void)partId1; (void)index1; } void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth) { m_normalOnBInWorld = normalOnBInWorld; m_pointInWorld = pointInWorld; m_depth = depth; m_hasResult = true; } }; //just take fixed number of orientation, and sample the penetration depth in that direction btScalar minProj = btScalar(BT_LARGE_FLOAT); btVector3 minNorm(0.f,0.f,0.f); btVector3 minVertex; btVector3 minA,minB; btVector3 seperatingAxisInA,seperatingAxisInB; btVector3 pInA,qInB,pWorld,qWorld,w; //#define USE_BATCHED_SUPPORT 1 #ifdef USE_BATCHED_SUPPORT btVector3 supportVerticesABatch[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2]; btVector3 supportVerticesBBatch[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2]; btVector3 seperatingAxisInABatch[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2]; btVector3 seperatingAxisInBBatch[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2]; int i; int numSampleDirections = NUM_UNITSPHERE_POINTS; for (i=0;igetNumPreferredPenetrationDirections(); if (numPDA) { for (int i=0;igetPreferredPenetrationDirection(i,norm); norm = transA.getBasis() * norm; sPenetrationDirections[numSampleDirections] = norm; seperatingAxisInABatch[numSampleDirections] = (-norm) * transA.getBasis(); seperatingAxisInBBatch[numSampleDirections] = norm * transB.getBasis(); numSampleDirections++; } } } { int numPDB = convexB->getNumPreferredPenetrationDirections(); if (numPDB) { for (int i=0;igetPreferredPenetrationDirection(i,norm); norm = transB.getBasis() * norm; sPenetrationDirections[numSampleDirections] = norm; seperatingAxisInABatch[numSampleDirections] = (-norm) * transA.getBasis(); seperatingAxisInBBatch[numSampleDirections] = norm * transB.getBasis(); numSampleDirections++; } } } convexA->batchedUnitVectorGetSupportingVertexWithoutMargin(seperatingAxisInABatch,supportVerticesABatch,numSampleDirections); convexB->batchedUnitVectorGetSupportingVertexWithoutMargin(seperatingAxisInBBatch,supportVerticesBBatch,numSampleDirections); for (i=0;ilocalGetSupportVertexWithoutMarginNonVirtual( seperatingAxisInA);//, NULL); qInB = convexB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB);//, NULL); // pInA = convexA->localGetSupportingVertexWithoutMargin(seperatingAxisInA); // qInB = convexB->localGetSupportingVertexWithoutMargin(seperatingAxisInB); pWorld = transA(pInA); qWorld = transB(qInB); w = qWorld - pWorld; btScalar delta = norm.dot(w); //find smallest delta if (delta < minProj) { minProj = delta; minNorm = norm; minA = pWorld; minB = qWorld; } } #endif //USE_BATCHED_SUPPORT //add the margins minA += minNorm*marginA; minB -= minNorm*marginB; //no penetration if (minProj < btScalar(0.)) return false; minProj += (marginA + marginB) + btScalar(1.00); //#define DEBUG_DRAW 1 #ifdef DEBUG_DRAW if (debugDraw) { btVector3 color(0,1,0); debugDraw->drawLine(minA,minB,color); color = btVector3 (1,1,1); btVector3 vec = minB-minA; btScalar prj2 = minNorm.dot(vec); debugDraw->drawLine(minA,minA+(minNorm*minProj),color); } #endif //DEBUG_DRAW btGjkPairDetector gjkdet(convexA,convexB,&simplexSolver,0); btScalar offsetDist = minProj; btVector3 offset = minNorm * offsetDist; SpuClosestPointInput input; input.m_convexVertexData[0] = convexVertexDataA; input.m_convexVertexData[1] = convexVertexDataB; btVector3 newOrg = transA.getOrigin() + offset; btTransform displacedTrans = transA; displacedTrans.setOrigin(newOrg); input.m_transformA = displacedTrans; input.m_transformB = transB; input.m_maximumDistanceSquared = btScalar(BT_LARGE_FLOAT);//minProj; btIntermediateResult res; gjkdet.getClosestPoints(input,res,0); btScalar correctedMinNorm = minProj - res.m_depth; //the penetration depth is over-estimated, relax it btScalar penetration_relaxation= btScalar(1.); minNorm*=penetration_relaxation; if (res.m_hasResult) { pa = res.m_pointInWorld - minNorm * correctedMinNorm; pb = res.m_pointInWorld; #ifdef DEBUG_DRAW if (debugDraw) { btVector3 color(1,0,0); debugDraw->drawLine(pa,pb,color); } #endif//DEBUG_DRAW } else { // could not seperate shapes //btAssert (false); } return res.m_hasResult; #endif return false; } critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/Box.h0000644000175000017500000000757211337073000031204 0ustar bobkebobke/* Copyright (C) 2006, 2008 Sony Computer Entertainment Inc. All rights reserved. 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 __BOX_H__ #define __BOX_H__ #ifndef PE_REF #define PE_REF(a) a& #endif #include #include "BulletMultiThreaded/vectormath/scalar/cpp/vectormath_aos.h" // #include using namespace Vectormath::Aos; enum FeatureType { F, E, V }; //---------------------------------------------------------------------------- // Box //---------------------------------------------------------------------------- ///The Box is an internal class used by the boxBoxDistance calculation. class Box { public: Vector3 half; inline Box() {} inline Box(PE_REF(Vector3) half_); inline Box(float hx, float hy, float hz); inline void Set(PE_REF(Vector3) half_); inline void Set(float hx, float hy, float hz); inline Vector3 GetAABB(const Matrix3& rotation) const; }; inline Box::Box(PE_REF(Vector3) half_) { Set(half_); } inline Box::Box(float hx, float hy, float hz) { Set(hx, hy, hz); } inline void Box::Set(PE_REF(Vector3) half_) { half = half_; } inline void Box::Set(float hx, float hy, float hz) { half = Vector3(hx, hy, hz); } inline Vector3 Box::GetAABB(const Matrix3& rotation) const { return absPerElem(rotation) * half; } //------------------------------------------------------------------------------------------------- // BoxPoint //------------------------------------------------------------------------------------------------- ///The BoxPoint class is an internally used class to contain feature information for boxBoxDistance calculation. class BoxPoint { public: BoxPoint() : localPoint(0.0f) {} Point3 localPoint; FeatureType featureType; int featureIdx; inline void setVertexFeature(int plusX, int plusY, int plusZ); inline void setEdgeFeature(int dim0, int plus0, int dim1, int plus1); inline void setFaceFeature(int dim, int plus); inline void getVertexFeature(int & plusX, int & plusY, int & plusZ) const; inline void getEdgeFeature(int & dim0, int & plus0, int & dim1, int & plus1) const; inline void getFaceFeature(int & dim, int & plus) const; }; inline void BoxPoint::setVertexFeature(int plusX, int plusY, int plusZ) { featureType = V; featureIdx = plusX << 2 | plusY << 1 | plusZ; } inline void BoxPoint::setEdgeFeature(int dim0, int plus0, int dim1, int plus1) { featureType = E; if (dim0 > dim1) { featureIdx = plus1 << 5 | dim1 << 3 | plus0 << 2 | dim0; } else { featureIdx = plus0 << 5 | dim0 << 3 | plus1 << 2 | dim1; } } inline void BoxPoint::setFaceFeature(int dim, int plus) { featureType = F; featureIdx = plus << 2 | dim; } inline void BoxPoint::getVertexFeature(int & plusX, int & plusY, int & plusZ) const { plusX = featureIdx >> 2; plusY = featureIdx >> 1 & 1; plusZ = featureIdx & 1; } inline void BoxPoint::getEdgeFeature(int & dim0, int & plus0, int & dim1, int & plus1) const { plus0 = featureIdx >> 5; dim0 = featureIdx >> 3 & 3; plus1 = featureIdx >> 2 & 1; dim1 = featureIdx & 3; } inline void BoxPoint::getFaceFeature(int & dim, int & plus) const { plus = featureIdx >> 2; dim = featureIdx & 3; } #endif /* __BOX_H__ */ ././@LongLink0000000000000000000000000000017000000000000011563 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuConvexPenetrationDepthSolver.hcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuConvexPenet0000644000175000017500000000362011337073000033142 0ustar bobkebobke /* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 SPU_CONVEX_PENETRATION_DEPTH_H #define SPU_CONVEX_PENETRATION_DEPTH_H class btStackAlloc; class btIDebugDraw; #include "BulletCollision/NarrowphaseCollision/btConvexPenetrationDepthSolver.h" #include ///ConvexPenetrationDepthSolver provides an interface for penetration depth calculation. class SpuConvexPenetrationDepthSolver : public btConvexPenetrationDepthSolver { public: virtual ~SpuConvexPenetrationDepthSolver() {}; virtual bool calcPenDepth( SpuVoronoiSimplexSolver& simplexSolver, void* convexA,void* convexB,int shapeTypeA, int shapeTypeB, float marginA, float marginB, btTransform& transA,const btTransform& transB, btVector3& v, btVector3& pa, btVector3& pb, class btIDebugDraw* debugDraw,btStackAlloc* stackAlloc, struct SpuConvexPolyhedronVertexData* convexVertexDataA, struct SpuConvexPolyhedronVertexData* convexVertexDataB ) const = 0; }; #endif //SPU_CONVEX_PENETRATION_DEPTH_H ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuContactResult.cppcritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuNarrowPhaseCollisionTask/SpuContactResu0000644000175000017500000001722611337073000033145 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "SpuContactResult.h" //#define DEBUG_SPU_COLLISION_DETECTION 1 SpuContactResult::SpuContactResult() { m_manifoldAddress = 0; m_spuManifold = NULL; m_RequiresWriteBack = false; } SpuContactResult::~SpuContactResult() { g_manifoldDmaExport.swapBuffers(); } ///User can override this material combiner by implementing gContactAddedCallback and setting body0->m_collisionFlags |= btCollisionObject::customMaterialCallback; inline btScalar calculateCombinedFriction(btScalar friction0,btScalar friction1) { btScalar friction = friction0*friction1; const btScalar MAX_FRICTION = btScalar(10.); if (friction < -MAX_FRICTION) friction = -MAX_FRICTION; if (friction > MAX_FRICTION) friction = MAX_FRICTION; return friction; } inline btScalar calculateCombinedRestitution(btScalar restitution0,btScalar restitution1) { return restitution0*restitution1; } void SpuContactResult::setContactInfo(btPersistentManifold* spuManifold, ppu_address_t manifoldAddress,const btTransform& worldTrans0,const btTransform& worldTrans1, btScalar restitution0,btScalar restitution1, btScalar friction0,btScalar friction1, bool isSwapped) { //spu_printf("SpuContactResult::setContactInfo ManifoldAddress: %lu\n", manifoldAddress); m_rootWorldTransform0 = worldTrans0; m_rootWorldTransform1 = worldTrans1; m_manifoldAddress = manifoldAddress; m_spuManifold = spuManifold; m_combinedFriction = calculateCombinedFriction(friction0,friction1); m_combinedRestitution = calculateCombinedRestitution(restitution0,restitution1); m_isSwapped = isSwapped; } void SpuContactResult::setShapeIdentifiersA(int partId0,int index0) { } void SpuContactResult::setShapeIdentifiersB(int partId1,int index1) { } ///return true if it requires a dma transfer back bool ManifoldResultAddContactPoint(const btVector3& normalOnBInWorld, const btVector3& pointInWorld, float depth, btPersistentManifold* manifoldPtr, btTransform& transA, btTransform& transB, btScalar combinedFriction, btScalar combinedRestitution, bool isSwapped) { // float contactTreshold = manifoldPtr->getContactBreakingThreshold(); //spu_printf("SPU: add contactpoint, depth:%f, contactTreshold %f, manifoldPtr %llx\n",depth,contactTreshold,manifoldPtr); #ifdef DEBUG_SPU_COLLISION_DETECTION spu_printf("SPU: contactTreshold %f\n",contactTreshold); #endif //DEBUG_SPU_COLLISION_DETECTION if (depth > manifoldPtr->getContactBreakingThreshold()) return false; //provide inverses or just calculate? btTransform transAInv = transA.inverse();//m_body0->m_cachedInvertedWorldTransform; btTransform transBInv= transB.inverse();//m_body1->m_cachedInvertedWorldTransform; btVector3 pointA; btVector3 localA; btVector3 localB; btVector3 normal; if (isSwapped) { normal = normalOnBInWorld * -1; pointA = pointInWorld + normal * depth; localA = transAInv(pointA ); localB = transBInv(pointInWorld); /*localA = transBInv(pointA ); localB = transAInv(pointInWorld);*/ } else { normal = normalOnBInWorld; pointA = pointInWorld + normal * depth; localA = transAInv(pointA ); localB = transBInv(pointInWorld); } btManifoldPoint newPt(localA,localB,normal,depth); int insertIndex = manifoldPtr->getCacheEntry(newPt); if (insertIndex >= 0) { // manifoldPtr->replaceContactPoint(newPt,insertIndex); // return true; #ifdef DEBUG_SPU_COLLISION_DETECTION spu_printf("SPU: same contact detected, nothing done\n"); #endif //DEBUG_SPU_COLLISION_DETECTION // This is not needed, just use the old info! saves a DMA transfer as well } else { newPt.m_combinedFriction = combinedFriction; newPt.m_combinedRestitution = combinedRestitution; /* ///@todo: SPU callbacks, either immediate (local on the SPU), or deferred //User can override friction and/or restitution if (gContactAddedCallback && //and if either of the two bodies requires custom material ((m_body0->m_collisionFlags & btCollisionObject::customMaterialCallback) || (m_body1->m_collisionFlags & btCollisionObject::customMaterialCallback))) { //experimental feature info, for per-triangle material etc. (*gContactAddedCallback)(newPt,m_body0,m_partId0,m_index0,m_body1,m_partId1,m_index1); } */ manifoldPtr->addManifoldPoint(newPt); return true; } return false; } void SpuContactResult::writeDoubleBufferedManifold(btPersistentManifold* lsManifold, btPersistentManifold* mmManifold) { ///only write back the contact information on SPU. Other platforms avoid copying, and use the data in-place ///see SpuFakeDma.cpp 'cellDmaLargeGetReadOnly' #if defined (__SPU__) || defined (USE_LIBSPE2) memcpy(g_manifoldDmaExport.getFront(),lsManifold,sizeof(btPersistentManifold)); g_manifoldDmaExport.swapBuffers(); ppu_address_t mmAddr = (ppu_address_t)mmManifold; g_manifoldDmaExport.backBufferDmaPut(mmAddr, sizeof(btPersistentManifold), DMA_TAG(9)); // Should there be any kind of wait here? What if somebody tries to use this tag again? What if we call this function again really soon? //no, the swapBuffers does the wait #endif } void SpuContactResult::addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth) { //spu_printf("*** SpuContactResult::addContactPoint: depth = %f\n",depth); #ifdef DEBUG_SPU_COLLISION_DETECTION // int sman = sizeof(rage::phManifold); // spu_printf("sizeof_manifold = %i\n",sman); #endif //DEBUG_SPU_COLLISION_DETECTION btPersistentManifold* localManifold = m_spuManifold; btVector3 normalB(normalOnBInWorld.getX(),normalOnBInWorld.getY(),normalOnBInWorld.getZ()); btVector3 pointWrld(pointInWorld.getX(),pointInWorld.getY(),pointInWorld.getZ()); //process the contact point const bool retVal = ManifoldResultAddContactPoint(normalB, pointWrld, depth, localManifold, m_rootWorldTransform0, m_rootWorldTransform1, m_combinedFriction, m_combinedRestitution, m_isSwapped); m_RequiresWriteBack = m_RequiresWriteBack || retVal; } void SpuContactResult::flush() { if (m_spuManifold && m_spuManifold->getNumContacts()) { m_spuManifold->refreshContactPoints(m_rootWorldTransform0,m_rootWorldTransform1); m_RequiresWriteBack = true; } if (m_RequiresWriteBack) { #ifdef DEBUG_SPU_COLLISION_DETECTION spu_printf("SPU: Start SpuContactResult::flush (Put) DMA\n"); spu_printf("Num contacts:%d\n", m_spuManifold->getNumContacts()); spu_printf("Manifold address: %llu\n", m_manifoldAddress); #endif //DEBUG_SPU_COLLISION_DETECTION // spu_printf("writeDoubleBufferedManifold\n"); writeDoubleBufferedManifold(m_spuManifold, (btPersistentManifold*)m_manifoldAddress); #ifdef DEBUG_SPU_COLLISION_DETECTION spu_printf("SPU: Finished (Put) DMA\n"); #endif //DEBUG_SPU_COLLISION_DETECTION } m_spuManifold = NULL; m_RequiresWriteBack = false; } critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/vectormath2bullet.h0000644000175000017500000000561011337073000026471 0ustar bobkebobke/* Copyright (C) 2006, 2007 Sony Computer Entertainment Inc. All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the name of the Sony Computer Entertainment Inc nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #ifndef AOS_VECTORMATH_BULLET_CONVERT_H #define AOS_VECTORMATH_BULLET_CONVERT_H // #include #include "BulletMultiThreaded/vectormath/scalar/cpp/vectormath_aos.h" #include "LinearMath/btVector3.h" #include "LinearMath/btQuaternion.h" #include "LinearMath/btMatrix3x3.h" inline Vectormath::Aos::Vector3 getVmVector3(const btVector3& bulletVec) { return Vectormath::Aos::Vector3(bulletVec.getX(),bulletVec.getY(),bulletVec.getZ()); } inline btVector3 getBtVector3(const Vectormath::Aos::Vector3& vmVec) { return btVector3(vmVec.getX(),vmVec.getY(),vmVec.getZ()); } inline btVector3 getBtVector3(const Vectormath::Aos::Point3& vmVec) { return btVector3(vmVec.getX(),vmVec.getY(),vmVec.getZ()); } inline Vectormath::Aos::Quat getVmQuat(const btQuaternion& bulletQuat) { Vectormath::Aos::Quat vmQuat(bulletQuat.getX(),bulletQuat.getY(),bulletQuat.getZ(),bulletQuat.getW()); return vmQuat; } inline btQuaternion getBtQuat(const Vectormath::Aos::Quat& vmQuat) { return btQuaternion (vmQuat.getX(),vmQuat.getY(),vmQuat.getZ(),vmQuat.getW()); } inline Vectormath::Aos::Matrix3 getVmMatrix3(const btMatrix3x3& btMat) { Vectormath::Aos::Matrix3 mat( getVmVector3(btMat.getColumn(0)), getVmVector3(btMat.getColumn(1)), getVmVector3(btMat.getColumn(2))); return mat; } #endif //AOS_VECTORMATH_BULLET_CONVERT_H critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/out/0000755000175000017500000000000011347266042023472 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuDoubleBuffer.h0000644000175000017500000000412111337073000026053 0ustar bobkebobke#ifndef DOUBLE_BUFFER_H #define DOUBLE_BUFFER_H #include "SpuFakeDma.h" #include ///DoubleBuffer template class DoubleBuffer { #if defined(__SPU__) || defined(USE_LIBSPE2) ATTRIBUTE_ALIGNED128( T m_buffer0[size] ) ; ATTRIBUTE_ALIGNED128( T m_buffer1[size] ) ; #else T m_buffer0[size]; T m_buffer1[size]; #endif T *m_frontBuffer; T *m_backBuffer; unsigned int m_dmaTag; bool m_dmaPending; public: bool isPending() const { return m_dmaPending;} DoubleBuffer(); void init (); // dma get and put commands void backBufferDmaGet(uint64_t ea, unsigned int numBytes, unsigned int tag); void backBufferDmaPut(uint64_t ea, unsigned int numBytes, unsigned int tag); // gets pointer to a buffer T *getFront(); T *getBack(); // if back buffer dma was started, wait for it to complete // then move back to front and vice versa T *swapBuffers(); }; template DoubleBuffer::DoubleBuffer() { init (); } template void DoubleBuffer::init() { this->m_dmaPending = false; this->m_frontBuffer = &this->m_buffer0[0]; this->m_backBuffer = &this->m_buffer1[0]; } template void DoubleBuffer::backBufferDmaGet(uint64_t ea, unsigned int numBytes, unsigned int tag) { m_dmaPending = true; m_dmaTag = tag; if (numBytes) { m_backBuffer = (T*)cellDmaLargeGetReadOnly(m_backBuffer, ea, numBytes, tag, 0, 0); } } template void DoubleBuffer::backBufferDmaPut(uint64_t ea, unsigned int numBytes, unsigned int tag) { m_dmaPending = true; m_dmaTag = tag; cellDmaLargePut(m_backBuffer, ea, numBytes, tag, 0, 0); } template T * DoubleBuffer::getFront() { return m_frontBuffer; } template T * DoubleBuffer::getBack() { return m_backBuffer; } template T * DoubleBuffer::swapBuffers() { if (m_dmaPending) { cellDmaWaitTagStatusAll(1< #include "PlatformDefinitions.h" #include #include "LinearMath/btAlignedObjectArray.h" #include "SpuSampleTask/SpuSampleTask.h" //just add your commands here, try to keep them globally unique for debugging purposes #define CMD_SAMPLE_TASK_COMMAND 10 /// SpuSampleTaskProcess handles SPU processing of collision pairs. /// When PPU issues a task, it will look for completed task buffers /// PPU will do postprocessing, dependent on workunit output (not likely) class SpuSampleTaskProcess { // track task buffers that are being used, and total busy tasks btAlignedObjectArray m_taskBusy; btAlignedObjectArraym_spuSampleTaskDesc; int m_numBusyTasks; // the current task and the current entry to insert a new work unit int m_currentTask; bool m_initialized; void postProcess(int taskId, int outputSize); class btThreadSupportInterface* m_threadInterface; int m_maxNumOutstandingTasks; public: SpuSampleTaskProcess(btThreadSupportInterface* threadInterface, int maxNumOutstandingTasks); ~SpuSampleTaskProcess(); ///call initialize in the beginning of the frame, before addCollisionPairToTask void initialize(); void issueTask(void* sampleMainMemPtr,int sampleValue,int sampleCommand); ///call flush to submit potential outstanding work to SPUs and wait for all involved SPUs to be finished void flush(); }; #if defined(USE_LIBSPE2) && defined(__SPU__) ////////////////////MAIN///////////////////////////// #include "../SpuLibspe2Support.h" #include #include #include void * SamplelsMemoryFunc(); void SampleThreadFunc(void* userPtr,void* lsMemory); //#define DEBUG_LIBSPE2_MAINLOOP int main(unsigned long long speid, addr64 argp, addr64 envp) { printf("SPU is up \n"); ATTRIBUTE_ALIGNED128(btSpuStatus status); ATTRIBUTE_ALIGNED16( SpuSampleTaskDesc taskDesc ) ; unsigned int received_message = Spu_Mailbox_Event_Nothing; bool shutdown = false; cellDmaGet(&status, argp.ull, sizeof(btSpuStatus), DMA_TAG(3), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(3)); status.m_status = Spu_Status_Free; status.m_lsMemory.p = SamplelsMemoryFunc(); cellDmaLargePut(&status, argp.ull, sizeof(btSpuStatus), DMA_TAG(3), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(3)); while (!shutdown) { received_message = spu_read_in_mbox(); switch(received_message) { case Spu_Mailbox_Event_Shutdown: shutdown = true; break; case Spu_Mailbox_Event_Task: // refresh the status #ifdef DEBUG_LIBSPE2_MAINLOOP printf("SPU recieved Task \n"); #endif //DEBUG_LIBSPE2_MAINLOOP cellDmaGet(&status, argp.ull, sizeof(btSpuStatus), DMA_TAG(3), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(3)); btAssert(status.m_status==Spu_Status_Occupied); cellDmaGet(&taskDesc, status.m_taskDesc.p, sizeof(SpuSampleTaskDesc), DMA_TAG(3), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(3)); SampleThreadFunc((void*)&taskDesc, reinterpret_cast (taskDesc.m_mainMemoryPtr) ); break; case Spu_Mailbox_Event_Nothing: default: break; } // set to status free and wait for next task status.m_status = Spu_Status_Free; cellDmaLargePut(&status, argp.ull, sizeof(btSpuStatus), DMA_TAG(3), 0, 0); cellDmaWaitTagStatusAll(DMA_MASK(3)); } return 0; } ////////////////////////////////////////////////////// #endif #endif // SPU_SAMPLE_TASK_PROCESS_H critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuLibspe2Support.h0000644000175000017500000001026111337073000026406 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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 SPU_LIBSPE2_SUPPORT_H #define SPU_LIBSPE2_SUPPORT_H #include //for uint32_t etc. #ifdef USE_LIBSPE2 #include #include //#include "SpuNarrowPhaseCollisionTask/SpuGatheringCollisionTask.h" #include "PlatformDefinitions.h" //extern struct SpuGatherAndProcessPairsTaskDesc; enum { Spu_Mailbox_Event_Nothing = 0, Spu_Mailbox_Event_Task = 1, Spu_Mailbox_Event_Shutdown = 2, Spu_Mailbox_Event_ForceDword = 0xFFFFFFFF }; enum { Spu_Status_Free = 0, Spu_Status_Occupied = 1, Spu_Status_Startup = 2, Spu_Status_ForceDword = 0xFFFFFFFF }; struct btSpuStatus { uint32_t m_taskId; uint32_t m_commandId; uint32_t m_status; addr64 m_taskDesc; addr64 m_lsMemory; } __attribute__ ((aligned (128))) ; #ifndef __SPU__ #include "LinearMath/btAlignedObjectArray.h" #include "SpuCollisionTaskProcess.h" #include "SpuSampleTaskProcess.h" #include "btThreadSupportInterface.h" #include #include #include #define MAX_SPUS 4 typedef struct ppu_pthread_data { spe_context_ptr_t context; pthread_t pthread; unsigned int entry; unsigned int flags; addr64 argp; addr64 envp; spe_stop_info_t stopinfo; } ppu_pthread_data_t; static void *ppu_pthread_function(void *arg) { ppu_pthread_data_t * datap = (ppu_pthread_data_t *)arg; /* int rc; do {*/ spe_context_run(datap->context, &datap->entry, datap->flags, datap->argp.p, datap->envp.p, &datap->stopinfo); if (datap->stopinfo.stop_reason == SPE_EXIT) { if (datap->stopinfo.result.spe_exit_code != 0) { perror("FAILED: SPE returned a non-zero exit status: \n"); exit(1); } } else { perror("FAILED: SPE abnormally terminated\n"); exit(1); } //} while (rc > 0); // loop until exit or error, and while any stop & signal pthread_exit(NULL); } ///SpuLibspe2Support helps to initialize/shutdown libspe2, start/stop SPU tasks and communication class SpuLibspe2Support : public btThreadSupportInterface { btAlignedObjectArray m_activeSpuStatus; public: //Setup and initialize SPU/CELL/Libspe2 SpuLibspe2Support(spe_program_handle_t *speprog,int numThreads); // SPE program handle ptr. spe_program_handle_t *program; // SPE program data ppu_pthread_data_t data[MAX_SPUS]; //cleanup/shutdown Libspe2 ~SpuLibspe2Support(); ///send messages to SPUs void sendRequest(uint32_t uiCommand, uint32_t uiArgument0, uint32_t uiArgument1=0); //check for messages from SPUs void waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1); //start the spus (can be called at the beginning of each frame, to make sure that the right SPU program is loaded) virtual void startSPU(); //tell the task scheduler we are done with the SPU tasks virtual void stopSPU(); virtual void setNumTasks(int numTasks) { //changing the number of tasks after initialization is not implemented (yet) } private: ///start the spus (can be called at the beginning of each frame, to make sure that the right SPU program is loaded) void internal_startSPU(); int numThreads; }; #endif // NOT __SPU__ #endif //USE_LIBSPE2 #endif //SPU_LIBSPE2_SUPPORT_H critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuContactManifoldCollisionAlgorithm.cpp0000644000175000017500000000570711337073000032645 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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 "SpuContactManifoldCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionShapes/btCollisionShape.h" #include "BulletCollision/CollisionShapes/btPolyhedralConvexShape.h" void SpuContactManifoldCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { btAssert(0); } btScalar SpuContactManifoldCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { btAssert(0); return 1.f; } #ifndef __SPU__ SpuContactManifoldCollisionAlgorithm::SpuContactManifoldCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1) :btCollisionAlgorithm(ci) #ifdef USE_SEPDISTANCE_UTIL ,m_sepDistance(body0->getCollisionShape()->getAngularMotionDisc(),body1->getCollisionShape()->getAngularMotionDisc()) #endif //USE_SEPDISTANCE_UTIL { m_manifoldPtr = m_dispatcher->getNewManifold(body0,body1); m_shapeType0 = body0->getCollisionShape()->getShapeType(); m_shapeType1 = body1->getCollisionShape()->getShapeType(); m_collisionMargin0 = body0->getCollisionShape()->getMargin(); m_collisionMargin1 = body1->getCollisionShape()->getMargin(); m_collisionObject0 = body0; m_collisionObject1 = body1; if (body0->getCollisionShape()->isPolyhedral()) { btPolyhedralConvexShape* convex0 = (btPolyhedralConvexShape*)body0->getCollisionShape(); m_shapeDimensions0 = convex0->getImplicitShapeDimensions(); } if (body1->getCollisionShape()->isPolyhedral()) { btPolyhedralConvexShape* convex1 = (btPolyhedralConvexShape*)body1->getCollisionShape(); m_shapeDimensions1 = convex1->getImplicitShapeDimensions(); } } #endif //__SPU__ SpuContactManifoldCollisionAlgorithm::~SpuContactManifoldCollisionAlgorithm() { if (m_manifoldPtr) m_dispatcher->releaseManifold(m_manifoldPtr); } critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/MiniCLTaskScheduler.cpp0000644000175000017500000001166211337073000027157 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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. */ //#define __CELLOS_LV2__ 1 #define USE_SAMPLE_PROCESS 1 #ifdef USE_SAMPLE_PROCESS #include "MiniCLTaskScheduler.h" #include #ifdef __SPU__ void SampleThreadFunc(void* userPtr,void* lsMemory) { //do nothing printf("hello world\n"); } void* SamplelsMemoryFunc() { //don't create local store memory, just return 0 return 0; } #else #include "btThreadSupportInterface.h" //# include "SPUAssert.h" #include extern "C" { extern char SPU_SAMPLE_ELF_SYMBOL[]; } MiniCLTaskScheduler::MiniCLTaskScheduler(btThreadSupportInterface* threadInterface, int maxNumOutstandingTasks) :m_threadInterface(threadInterface), m_maxNumOutstandingTasks(maxNumOutstandingTasks) { m_taskBusy.resize(m_maxNumOutstandingTasks); m_spuSampleTaskDesc.resize(m_maxNumOutstandingTasks); for (int i = 0; i < m_maxNumOutstandingTasks; i++) { m_taskBusy[i] = false; } m_numBusyTasks = 0; m_currentTask = 0; m_initialized = false; m_threadInterface->startSPU(); } MiniCLTaskScheduler::~MiniCLTaskScheduler() { m_threadInterface->stopSPU(); } void MiniCLTaskScheduler::initialize() { #ifdef DEBUG_SPU_TASK_SCHEDULING printf("MiniCLTaskScheduler::initialize()\n"); #endif //DEBUG_SPU_TASK_SCHEDULING for (int i = 0; i < m_maxNumOutstandingTasks; i++) { m_taskBusy[i] = false; } m_numBusyTasks = 0; m_currentTask = 0; m_initialized = true; } void MiniCLTaskScheduler::issueTask(int firstWorkUnit, int lastWorkUnit,int kernelProgramId,char* argData,int* argSizes) { #ifdef DEBUG_SPU_TASK_SCHEDULING printf("MiniCLTaskScheduler::issueTask (m_currentTask= %d\)n", m_currentTask); #endif //DEBUG_SPU_TASK_SCHEDULING m_taskBusy[m_currentTask] = true; m_numBusyTasks++; MiniCLTaskDesc& taskDesc = m_spuSampleTaskDesc[m_currentTask]; { // send task description in event message taskDesc.m_firstWorkUnit = firstWorkUnit; taskDesc.m_lastWorkUnit = lastWorkUnit; taskDesc.m_kernelProgramId = kernelProgramId; //some bookkeeping to recognize finished tasks taskDesc.m_taskId = m_currentTask; for (int i=0;isendRequest(1, (ppu_address_t) &taskDesc, m_currentTask); // if all tasks busy, wait for spu event to clear the task. if (m_numBusyTasks >= m_maxNumOutstandingTasks) { unsigned int taskId; unsigned int outputSize; for (int i=0;iwaitForResponse(&taskId, &outputSize); //printf("PPU: after issue, received event: %u %d\n", taskId, outputSize); postProcess(taskId, outputSize); m_taskBusy[taskId] = false; m_numBusyTasks--; } // find new task buffer for (int i = 0; i < m_maxNumOutstandingTasks; i++) { if (!m_taskBusy[i]) { m_currentTask = i; break; } } } ///Optional PPU-size post processing for each task void MiniCLTaskScheduler::postProcess(int taskId, int outputSize) { } void MiniCLTaskScheduler::flush() { #ifdef DEBUG_SPU_TASK_SCHEDULING printf("\nSpuCollisionTaskProcess::flush()\n"); #endif //DEBUG_SPU_TASK_SCHEDULING // all tasks are issued, wait for all tasks to be complete while(m_numBusyTasks > 0) { // Consolidating SPU code unsigned int taskId; unsigned int outputSize; for (int i=0;iwaitForResponse(&taskId, &outputSize); } //printf("PPU: flushing, received event: %u %d\n", taskId, outputSize); postProcess(taskId, outputSize); m_taskBusy[taskId] = false; m_numBusyTasks--; } } #endif #endif //USE_SAMPLE_PROCESS critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuCollisionObjectWrapper.h0000644000175000017500000000300411337073000030131 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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 SPU_COLLISION_OBJECT_WRAPPER_H #define SPU_COLLISION_OBJECT_WRAPPER_H #include "PlatformDefinitions.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" ATTRIBUTE_ALIGNED16(class) SpuCollisionObjectWrapper { protected: int m_shapeType; float m_margin; ppu_address_t m_collisionObjectPtr; public: SpuCollisionObjectWrapper (); SpuCollisionObjectWrapper (const btCollisionObject* collisionObject); int getShapeType () const; float getCollisionMargin () const; ppu_address_t getCollisionObjectPtr () const; }; #endif //SPU_COLLISION_OBJECT_WRAPPER_H critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/btGpu3DGridBroadphase.cpp0000644000175000017500000004040711337073000027430 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org Copyright (C) 2006, 2009 Sony Computer Entertainment Inc. 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. */ ///The 3 following lines include the CPU implementation of the kernels, keep them in this order. #include "BulletMultiThreaded/btGpuDefines.h" #include "BulletMultiThreaded/btGpuUtilsSharedDefs.h" #include "BulletMultiThreaded/btGpuUtilsSharedCode.h" #include "LinearMath/btAlignedAllocator.h" #include "LinearMath/btQuickprof.h" #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" #include "btGpuDefines.h" #include "btGpuUtilsSharedDefs.h" #include "btGpu3DGridBroadphaseSharedDefs.h" #include "btGpu3DGridBroadphase.h" #include //for memset #include static bt3DGridBroadphaseParams s3DGridBroadphaseParams; btGpu3DGridBroadphase::btGpu3DGridBroadphase( const btVector3& worldAabbMin,const btVector3& worldAabbMax, int gridSizeX, int gridSizeY, int gridSizeZ, int maxSmallProxies, int maxLargeProxies, int maxPairsPerBody, int maxBodiesPerCell, btScalar cellFactorAABB) : btSimpleBroadphase(maxSmallProxies, // new (btAlignedAlloc(sizeof(btSortedOverlappingPairCache),16)) btSortedOverlappingPairCache), new (btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16)) btHashedOverlappingPairCache), m_bInitialized(false), m_numBodies(0) { _initialize(worldAabbMin, worldAabbMax, gridSizeX, gridSizeY, gridSizeZ, maxSmallProxies, maxLargeProxies, maxPairsPerBody, maxBodiesPerCell, cellFactorAABB); } btGpu3DGridBroadphase::btGpu3DGridBroadphase( btOverlappingPairCache* overlappingPairCache, const btVector3& worldAabbMin,const btVector3& worldAabbMax, int gridSizeX, int gridSizeY, int gridSizeZ, int maxSmallProxies, int maxLargeProxies, int maxPairsPerBody, int maxBodiesPerCell, btScalar cellFactorAABB) : btSimpleBroadphase(maxSmallProxies, overlappingPairCache), m_bInitialized(false), m_numBodies(0) { _initialize(worldAabbMin, worldAabbMax, gridSizeX, gridSizeY, gridSizeZ, maxSmallProxies, maxLargeProxies, maxPairsPerBody, maxBodiesPerCell, cellFactorAABB); } btGpu3DGridBroadphase::~btGpu3DGridBroadphase() { //btSimpleBroadphase will free memory of btSortedOverlappingPairCache, because m_ownsPairCache assert(m_bInitialized); _finalize(); } void btGpu3DGridBroadphase::_initialize( const btVector3& worldAabbMin,const btVector3& worldAabbMax, int gridSizeX, int gridSizeY, int gridSizeZ, int maxSmallProxies, int maxLargeProxies, int maxPairsPerBody, int maxBodiesPerCell, btScalar cellFactorAABB) { // set various paramerers m_ownsPairCache = true; m_params.m_gridSizeX = gridSizeX; m_params.m_gridSizeY = gridSizeY; m_params.m_gridSizeZ = gridSizeZ; m_params.m_numCells = m_params.m_gridSizeX * m_params.m_gridSizeY * m_params.m_gridSizeZ; btVector3 w_org = worldAabbMin; m_params.m_worldOriginX = w_org.getX(); m_params.m_worldOriginY = w_org.getY(); m_params.m_worldOriginZ = w_org.getZ(); btVector3 w_size = worldAabbMax - worldAabbMin; m_params.m_cellSizeX = w_size.getX() / m_params.m_gridSizeX; m_params.m_cellSizeY = w_size.getY() / m_params.m_gridSizeY; m_params.m_cellSizeZ = w_size.getZ() / m_params.m_gridSizeZ; m_maxRadius = btMin(btMin(m_params.m_cellSizeX, m_params.m_cellSizeY), m_params.m_cellSizeZ); m_maxRadius *= btScalar(0.5f); m_params.m_numBodies = m_numBodies; m_params.m_maxBodiesPerCell = maxBodiesPerCell; m_numLargeHandles = 0; m_maxLargeHandles = maxLargeProxies; m_maxPairsPerBody = maxPairsPerBody; m_cellFactorAABB = cellFactorAABB; m_LastLargeHandleIndex = -1; assert(!m_bInitialized); // allocate host storage m_hBodiesHash = new unsigned int[m_maxHandles * 2]; memset(m_hBodiesHash, 0x00, m_maxHandles*2*sizeof(unsigned int)); m_hCellStart = new unsigned int[m_params.m_numCells]; memset(m_hCellStart, 0x00, m_params.m_numCells * sizeof(unsigned int)); m_hPairBuffStartCurr = new unsigned int[m_maxHandles * 2 + 2]; // --------------- for now, init with m_maxPairsPerBody for each body m_hPairBuffStartCurr[0] = 0; m_hPairBuffStartCurr[1] = 0; for(int i = 1; i <= m_maxHandles; i++) { m_hPairBuffStartCurr[i * 2] = m_hPairBuffStartCurr[(i-1) * 2] + m_maxPairsPerBody; m_hPairBuffStartCurr[i * 2 + 1] = 0; } //---------------- unsigned int numAABB = m_maxHandles + m_maxLargeHandles; m_hAABB = new bt3DGrid3F1U[numAABB * 2]; // AABB Min & Max m_hPairBuff = new unsigned int[m_maxHandles * m_maxPairsPerBody]; memset(m_hPairBuff, 0x00, m_maxHandles * m_maxPairsPerBody * sizeof(unsigned int)); // needed? m_hPairScan = new unsigned int[m_maxHandles + 1]; m_hPairOut = new unsigned int[m_maxHandles * m_maxPairsPerBody]; // large proxies // allocate handles buffer and put all handles on free list m_pLargeHandlesRawPtr = btAlignedAlloc(sizeof(btSimpleBroadphaseProxy) * m_maxLargeHandles, 16); m_pLargeHandles = new(m_pLargeHandlesRawPtr) btSimpleBroadphaseProxy[m_maxLargeHandles]; m_firstFreeLargeHandle = 0; { for (int i = m_firstFreeLargeHandle; i < m_maxLargeHandles; i++) { m_pLargeHandles[i].SetNextFree(i + 1); m_pLargeHandles[i].m_uniqueId = m_maxHandles+2+i; } m_pLargeHandles[m_maxLargeHandles - 1].SetNextFree(0); } // debug data m_numPairsAdded = 0; m_numOverflows = 0; m_bInitialized = true; } void btGpu3DGridBroadphase::_finalize() { assert(m_bInitialized); delete [] m_hBodiesHash; delete [] m_hCellStart; delete [] m_hPairBuffStartCurr; delete [] m_hAABB; delete [] m_hPairBuff; delete [] m_hPairScan; delete [] m_hPairOut; btAlignedFree(m_pLargeHandlesRawPtr); m_bInitialized = false; } void btGpu3DGridBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher) { if(m_numHandles <= 0) { BT_PROFILE("addLarge2LargePairsToCache"); addLarge2LargePairsToCache(dispatcher); return; } // update constants setParameters(&m_params); // prepare AABB array prepareAABB(); // calculate hash calcHashAABB(); // sort bodies based on hash sortHash(); // find start of each cell findCellStart(); // findOverlappingPairs (small/small) findOverlappingPairs(); // findOverlappingPairs (small/large) findPairsLarge(); // add pairs to CPU cache computePairCacheChanges(); scanOverlappingPairBuff(); squeezeOverlappingPairBuff(); addPairsToCache(dispatcher); // find and add large/large pairs to CPU cache addLarge2LargePairsToCache(dispatcher); return; } void btGpu3DGridBroadphase::addPairsToCache(btDispatcher* dispatcher) { m_numPairsAdded = 0; m_numPairsRemoved = 0; for(int i = 0; i < m_numHandles; i++) { unsigned int num = m_hPairScan[i+1] - m_hPairScan[i]; if(!num) { continue; } unsigned int* pInp = m_hPairOut + m_hPairScan[i]; unsigned int index0 = m_hAABB[i * 2].uw; btSimpleBroadphaseProxy* proxy0 = &m_pHandles[index0]; for(unsigned int j = 0; j < num; j++) { unsigned int indx1_s = pInp[j]; unsigned int index1 = indx1_s & (~BT_3DGRID_PAIR_ANY_FLG); btSimpleBroadphaseProxy* proxy1; if(index1 < (unsigned int)m_maxHandles) { proxy1 = &m_pHandles[index1]; } else { index1 -= m_maxHandles; btAssert((index1 >= 0) && (index1 < (unsigned int)m_maxLargeHandles)); proxy1 = &m_pLargeHandles[index1]; } if(indx1_s & BT_3DGRID_PAIR_NEW_FLG) { m_pairCache->addOverlappingPair(proxy0,proxy1); m_numPairsAdded++; } else { m_pairCache->removeOverlappingPair(proxy0,proxy1,dispatcher); m_numPairsRemoved++; } } } } btBroadphaseProxy* btGpu3DGridBroadphase::createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy) { btBroadphaseProxy* proxy; bool bIsLarge = isLargeProxy(aabbMin, aabbMax); if(bIsLarge) { if (m_numLargeHandles >= m_maxLargeHandles) { ///you have to increase the cell size, so 'large' proxies become 'small' proxies (fitting a cell) btAssert(0); return 0; //should never happen, but don't let the game crash ;-) } btAssert((aabbMin[0]<= aabbMax[0]) && (aabbMin[1]<= aabbMax[1]) && (aabbMin[2]<= aabbMax[2])); int newHandleIndex = allocLargeHandle(); proxy = new (&m_pLargeHandles[newHandleIndex])btSimpleBroadphaseProxy(aabbMin,aabbMax,shapeType,userPtr,collisionFilterGroup,collisionFilterMask,multiSapProxy); } else { proxy = btSimpleBroadphase::createProxy(aabbMin, aabbMax, shapeType, userPtr, collisionFilterGroup, collisionFilterMask, dispatcher, multiSapProxy); } return proxy; } void btGpu3DGridBroadphase::destroyProxy(btBroadphaseProxy* proxy, btDispatcher* dispatcher) { bool bIsLarge = isLargeProxy(proxy); if(bIsLarge) { btSimpleBroadphaseProxy* proxy0 = static_cast(proxy); freeLargeHandle(proxy0); m_pairCache->removeOverlappingPairsContainingProxy(proxy,dispatcher); } else { btSimpleBroadphase::destroyProxy(proxy, dispatcher); } return; } void btGpu3DGridBroadphase::resetPool(btDispatcher* dispatcher) { m_hPairBuffStartCurr[0] = 0; m_hPairBuffStartCurr[1] = 0; for(int i = 1; i <= m_maxHandles; i++) { m_hPairBuffStartCurr[i * 2] = m_hPairBuffStartCurr[(i-1) * 2] + m_maxPairsPerBody; m_hPairBuffStartCurr[i * 2 + 1] = 0; } } bool btGpu3DGridBroadphase::isLargeProxy(const btVector3& aabbMin, const btVector3& aabbMax) { btVector3 diag = aabbMax - aabbMin; ///use the bounding sphere radius of this bounding box, to include rotation btScalar radius = diag.length() * btScalar(0.5f); radius *= m_cellFactorAABB; // user-defined factor return (radius > m_maxRadius); } bool btGpu3DGridBroadphase::isLargeProxy(btBroadphaseProxy* proxy) { return (proxy->getUid() >= (m_maxHandles+2)); } void btGpu3DGridBroadphase::addLarge2LargePairsToCache(btDispatcher* dispatcher) { int i,j; if (m_numLargeHandles <= 0) { return; } int new_largest_index = -1; for(i = 0; i <= m_LastLargeHandleIndex; i++) { btSimpleBroadphaseProxy* proxy0 = &m_pLargeHandles[i]; if(!proxy0->m_clientObject) { continue; } new_largest_index = i; for(j = i + 1; j <= m_LastLargeHandleIndex; j++) { btSimpleBroadphaseProxy* proxy1 = &m_pLargeHandles[j]; if(!proxy1->m_clientObject) { continue; } btAssert(proxy0 != proxy1); btSimpleBroadphaseProxy* p0 = getSimpleProxyFromProxy(proxy0); btSimpleBroadphaseProxy* p1 = getSimpleProxyFromProxy(proxy1); if(aabbOverlap(p0,p1)) { if (!m_pairCache->findPair(proxy0,proxy1)) { m_pairCache->addOverlappingPair(proxy0,proxy1); } } else { if(m_pairCache->findPair(proxy0,proxy1)) { m_pairCache->removeOverlappingPair(proxy0,proxy1,dispatcher); } } } } m_LastLargeHandleIndex = new_largest_index; return; } void btGpu3DGridBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback) { btSimpleBroadphase::rayTest(rayFrom, rayTo, rayCallback); for (int i=0; i <= m_LastLargeHandleIndex; i++) { btSimpleBroadphaseProxy* proxy = &m_pLargeHandles[i]; if(!proxy->m_clientObject) { continue; } rayCallback.process(proxy); } } // // overrides for CPU version // void btGpu3DGridBroadphase::prepareAABB() { BT_PROFILE("prepareAABB"); bt3DGrid3F1U* pBB = m_hAABB; int i; int new_largest_index = -1; unsigned int num_small = 0; for(i = 0; i <= m_LastHandleIndex; i++) { btSimpleBroadphaseProxy* proxy0 = &m_pHandles[i]; if(!proxy0->m_clientObject) { continue; } new_largest_index = i; pBB->fx = proxy0->m_aabbMin.getX(); pBB->fy = proxy0->m_aabbMin.getY(); pBB->fz = proxy0->m_aabbMin.getZ(); pBB->uw = i; pBB++; pBB->fx = proxy0->m_aabbMax.getX(); pBB->fy = proxy0->m_aabbMax.getY(); pBB->fz = proxy0->m_aabbMax.getZ(); pBB->uw = num_small; pBB++; num_small++; } m_LastHandleIndex = new_largest_index; new_largest_index = -1; unsigned int num_large = 0; for(i = 0; i <= m_LastLargeHandleIndex; i++) { btSimpleBroadphaseProxy* proxy0 = &m_pLargeHandles[i]; if(!proxy0->m_clientObject) { continue; } new_largest_index = i; pBB->fx = proxy0->m_aabbMin.getX(); pBB->fy = proxy0->m_aabbMin.getY(); pBB->fz = proxy0->m_aabbMin.getZ(); pBB->uw = i + m_maxHandles; pBB++; pBB->fx = proxy0->m_aabbMax.getX(); pBB->fy = proxy0->m_aabbMax.getY(); pBB->fz = proxy0->m_aabbMax.getZ(); pBB->uw = num_large + m_maxHandles; pBB++; num_large++; } m_LastLargeHandleIndex = new_largest_index; // paranoid checks btAssert(num_small == m_numHandles); btAssert(num_large == m_numLargeHandles); return; } void btGpu3DGridBroadphase::setParameters(bt3DGridBroadphaseParams* hostParams) { s3DGridBroadphaseParams = *hostParams; return; } void btGpu3DGridBroadphase::calcHashAABB() { BT_PROFILE("bt3DGrid_calcHashAABB"); btGpu_calcHashAABB(m_hAABB, m_hBodiesHash, m_numHandles); return; } void btGpu3DGridBroadphase::sortHash() { class bt3DGridHashKey { public: unsigned int hash; unsigned int index; void quickSort(bt3DGridHashKey* pData, int lo, int hi) { int i=lo, j=hi; bt3DGridHashKey x = pData[(lo+hi)/2]; do { while(pData[i].hash > x.hash) i++; while(x.hash > pData[j].hash) j--; if(i <= j) { bt3DGridHashKey t = pData[i]; pData[i] = pData[j]; pData[j] = t; i++; j--; } } while(i <= j); if(lo < j) pData->quickSort(pData, lo, j); if(i < hi) pData->quickSort(pData, i, hi); } }; BT_PROFILE("bt3DGrid_sortHash"); bt3DGridHashKey* pHash = (bt3DGridHashKey*)m_hBodiesHash; pHash->quickSort(pHash, 0, m_numHandles - 1); return; } void btGpu3DGridBroadphase::findCellStart() { BT_PROFILE("bt3DGrid_findCellStart"); btGpu_findCellStart(m_hBodiesHash, m_hCellStart, m_numHandles, m_params.m_numCells); return; } void btGpu3DGridBroadphase::findOverlappingPairs() { BT_PROFILE("bt3DGrid_findOverlappingPairs"); btGpu_findOverlappingPairs(m_hAABB, m_hBodiesHash, m_hCellStart, m_hPairBuff, m_hPairBuffStartCurr, m_numHandles); return; } void btGpu3DGridBroadphase::findPairsLarge() { BT_PROFILE("bt3DGrid_findPairsLarge"); btGpu_findPairsLarge(m_hAABB, m_hBodiesHash, m_hCellStart, m_hPairBuff, m_hPairBuffStartCurr, m_numHandles, m_numLargeHandles); return; } void btGpu3DGridBroadphase::computePairCacheChanges() { BT_PROFILE("bt3DGrid_computePairCacheChanges"); btGpu_computePairCacheChanges(m_hPairBuff, m_hPairBuffStartCurr, m_hPairScan, m_hAABB, m_numHandles); return; } void btGpu3DGridBroadphase::scanOverlappingPairBuff() { BT_PROFILE("bt3DGrid_scanOverlappingPairBuff"); m_hPairScan[0] = 0; for(int i = 1; i <= m_numHandles; i++) { unsigned int delta = m_hPairScan[i]; m_hPairScan[i] = m_hPairScan[i-1] + delta; } return; } void btGpu3DGridBroadphase::squeezeOverlappingPairBuff() { BT_PROFILE("bt3DGrid_squeezeOverlappingPairBuff"); btGpu_squeezeOverlappingPairBuff(m_hPairBuff, m_hPairBuffStartCurr, m_hPairScan, m_hPairOut, m_hAABB, m_numHandles); return; } #include "btGpu3DGridBroadphaseSharedCode.h" critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuSampleTaskProcess.cpp0000644000175000017500000001115111337073000027446 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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. */ //#define __CELLOS_LV2__ 1 #define USE_SAMPLE_PROCESS 1 #ifdef USE_SAMPLE_PROCESS #include "SpuSampleTaskProcess.h" #include #ifdef __SPU__ void SampleThreadFunc(void* userPtr,void* lsMemory) { //do nothing printf("hello world\n"); } void* SamplelsMemoryFunc() { //don't create local store memory, just return 0 return 0; } #else #include "btThreadSupportInterface.h" //# include "SPUAssert.h" #include extern "C" { extern char SPU_SAMPLE_ELF_SYMBOL[]; } SpuSampleTaskProcess::SpuSampleTaskProcess(btThreadSupportInterface* threadInterface, int maxNumOutstandingTasks) :m_threadInterface(threadInterface), m_maxNumOutstandingTasks(maxNumOutstandingTasks) { m_taskBusy.resize(m_maxNumOutstandingTasks); m_spuSampleTaskDesc.resize(m_maxNumOutstandingTasks); for (int i = 0; i < m_maxNumOutstandingTasks; i++) { m_taskBusy[i] = false; } m_numBusyTasks = 0; m_currentTask = 0; m_initialized = false; m_threadInterface->startSPU(); } SpuSampleTaskProcess::~SpuSampleTaskProcess() { m_threadInterface->stopSPU(); } void SpuSampleTaskProcess::initialize() { #ifdef DEBUG_SPU_TASK_SCHEDULING printf("SpuSampleTaskProcess::initialize()\n"); #endif //DEBUG_SPU_TASK_SCHEDULING for (int i = 0; i < m_maxNumOutstandingTasks; i++) { m_taskBusy[i] = false; } m_numBusyTasks = 0; m_currentTask = 0; m_initialized = true; } void SpuSampleTaskProcess::issueTask(void* sampleMainMemPtr,int sampleValue,int sampleCommand) { #ifdef DEBUG_SPU_TASK_SCHEDULING printf("SpuSampleTaskProcess::issueTask (m_currentTask= %d\)n", m_currentTask); #endif //DEBUG_SPU_TASK_SCHEDULING m_taskBusy[m_currentTask] = true; m_numBusyTasks++; SpuSampleTaskDesc& taskDesc = m_spuSampleTaskDesc[m_currentTask]; { // send task description in event message // no error checking here... // but, currently, event queue can be no larger than NUM_WORKUNIT_TASKS. taskDesc.m_mainMemoryPtr = reinterpret_cast(sampleMainMemPtr); taskDesc.m_sampleValue = sampleValue; taskDesc.m_sampleCommand = sampleCommand; //some bookkeeping to recognize finished tasks taskDesc.m_taskId = m_currentTask; } m_threadInterface->sendRequest(1, (ppu_address_t) &taskDesc, m_currentTask); // if all tasks busy, wait for spu event to clear the task. if (m_numBusyTasks >= m_maxNumOutstandingTasks) { unsigned int taskId; unsigned int outputSize; for (int i=0;iwaitForResponse(&taskId, &outputSize); //printf("PPU: after issue, received event: %u %d\n", taskId, outputSize); postProcess(taskId, outputSize); m_taskBusy[taskId] = false; m_numBusyTasks--; } // find new task buffer for (int i = 0; i < m_maxNumOutstandingTasks; i++) { if (!m_taskBusy[i]) { m_currentTask = i; break; } } } ///Optional PPU-size post processing for each task void SpuSampleTaskProcess::postProcess(int taskId, int outputSize) { } void SpuSampleTaskProcess::flush() { #ifdef DEBUG_SPU_TASK_SCHEDULING printf("\nSpuCollisionTaskProcess::flush()\n"); #endif //DEBUG_SPU_TASK_SCHEDULING // all tasks are issued, wait for all tasks to be complete while(m_numBusyTasks > 0) { // Consolidating SPU code unsigned int taskId; unsigned int outputSize; for (int i=0;iwaitForResponse(&taskId, &outputSize); } //printf("PPU: flushing, received event: %u %d\n", taskId, outputSize); postProcess(taskId, outputSize); m_taskBusy[taskId] = false; m_numBusyTasks--; } } #endif #endif //USE_SAMPLE_PROCESS critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuFakeDma.cpp0000644000175000017500000001143611337073000025341 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "SpuFakeDma.h" #include //for btAssert //Disabling memcpy sometimes helps debugging DMA #define USE_MEMCPY 1 #ifdef USE_MEMCPY #endif void* cellDmaLargeGetReadOnly(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) { #if defined (__SPU__) || defined (USE_LIBSPE2) cellDmaLargeGet(ls,ea,size,tag,tid,rid); return ls; #else return (void*)(uint32_t)ea; #endif } void* cellDmaSmallGetReadOnly(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) { #if defined (__SPU__) || defined (USE_LIBSPE2) mfc_get(ls,ea,size,tag,0,0); return ls; #else return (void*)(uint32_t)ea; #endif } void* cellDmaGetReadOnly(void *ls, uint64_t ea, uint32_t size, uint32_t tag, uint32_t tid, uint32_t rid) { #if defined (__SPU__) || defined (USE_LIBSPE2) cellDmaGet(ls,ea,size,tag,tid,rid); return ls; #else return (void*)(uint32_t)ea; #endif } ///this unalignedDma should not be frequently used, only for small data. It handles alignment and performs check on size (<16 bytes) int stallingUnalignedDmaSmallGet(void *ls, uint64_t ea, uint32_t size) { btAssert(size<32); ATTRIBUTE_ALIGNED16(char tmpBuffer[32]); char* localStore = (char*)ls; uint32_t i; ///make sure last 4 bits are the same, for cellDmaSmallGet uint32_t last4BitsOffset = ea & 0x0f; char* tmpTarget = tmpBuffer + last4BitsOffset; #if defined (__SPU__) || defined (USE_LIBSPE2) int remainingSize = size; //#define FORCE_cellDmaUnalignedGet 1 #ifdef FORCE_cellDmaUnalignedGet cellDmaUnalignedGet(tmpTarget,ea,size,DMA_TAG(1),0,0); #else char* remainingTmpTarget = tmpTarget; uint64_t remainingEa = ea; while (remainingSize) { switch (remainingSize) { case 1: case 2: case 4: case 8: case 16: { mfc_get(remainingTmpTarget,remainingEa,remainingSize,DMA_TAG(1),0,0); remainingSize=0; break; } default: { //spu_printf("unaligned DMA with non-natural size:%d\n",remainingSize); int actualSize = 0; if (remainingSize > 16) actualSize = 16; else if (remainingSize >8) actualSize=8; else if (remainingSize >4) actualSize=4; else if (remainingSize >2) actualSize=2; mfc_get(remainingTmpTarget,remainingEa,actualSize,DMA_TAG(1),0,0); remainingSize-=actualSize; remainingTmpTarget+=actualSize; remainingEa += actualSize; } } } #endif//FORCE_cellDmaUnalignedGet #else char* mainMem = (char*)ea; //copy into final destination #ifdef USE_MEMCPY memcpy(tmpTarget,mainMem,size); #else for ( i=0;i #else #include #endif ///The btSpinlock is a structure to allow multi-platform synchronization. This allows to port the SPU tasks to other platforms. class btSpinlock { public: //typedef volatile LONG SpinVariable; typedef CRITICAL_SECTION SpinVariable; btSpinlock (SpinVariable* var) : spinVariable (var) {} void Init () { //*spinVariable = 0; InitializeCriticalSection(spinVariable); } void Lock () { EnterCriticalSection(spinVariable); } void Unlock () { LeaveCriticalSection(spinVariable); } private: SpinVariable* spinVariable; }; #elif defined (__CELLOS_LV2__) //#include #include ///The btSpinlock is a structure to allow multi-platform synchronization. This allows to port the SPU tasks to other platforms. class btSpinlock { public: typedef CellSyncMutex SpinVariable; btSpinlock (SpinVariable* var) : spinVariable (var) {} void Init () { #ifndef __SPU__ //*spinVariable = 1; cellSyncMutexInitialize(spinVariable); #endif } void Lock () { #ifdef __SPU__ // lock semaphore /*while (cellAtomicTestAndDecr32(atomic_buf, (uint64_t)spinVariable) == 0) { };*/ cellSyncMutexLock((uint64_t)spinVariable); #endif } void Unlock () { #ifdef __SPU__ //cellAtomicIncr32(atomic_buf, (uint64_t)spinVariable); cellSyncMutexUnlock((uint64_t)spinVariable); #endif } private: SpinVariable* spinVariable; ATTRIBUTE_ALIGNED128(uint32_t atomic_buf[32]); }; #else //create a dummy implementation (without any locking) useful for serial processing class btSpinlock { public: typedef int SpinVariable; btSpinlock (SpinVariable* var) : spinVariable (var) {} void Init () { } void Lock () { } void Unlock () { } private: SpinVariable* spinVariable; }; #endif #endif critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/btGpuUtilsSharedCode.h0000644000175000017500000000442511337073000027052 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library, http://bulletphysics.org Copyright (C) 2006, 2009 Sony Computer Entertainment Inc. 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. */ //---------------------------------------------------------------------------------------- // Shared code for GPU-based utilities //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! // Keep this file free from Bullet headers // will be compiled by both CPU and CUDA compilers // file with definitions of BT_GPU_xxx should be included first //!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! //---------------------------------------------------------------------------------------- #include "btGpuUtilsSharedDefs.h" //---------------------------------------------------------------------------------------- extern "C" { //---------------------------------------------------------------------------------------- //Round a / b to nearest higher integer value int BT_GPU_PREF(iDivUp)(int a, int b) { return (a % b != 0) ? (a / b + 1) : (a / b); } // iDivUp() //---------------------------------------------------------------------------------------- // compute grid and thread block size for a given number of elements void BT_GPU_PREF(computeGridSize)(int n, int blockSize, int &numBlocks, int &numThreads) { numThreads = BT_GPU_min(blockSize, n); numBlocks = BT_GPU_PREF(iDivUp)(n, numThreads); } // computeGridSize() //---------------------------------------------------------------------------------------- } // extern "C"critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/SpuCollisionObjectWrapper.cpp0000644000175000017500000000322311337073000030467 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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 "SpuCollisionObjectWrapper.h" #include "BulletCollision/CollisionShapes/btCollisionShape.h" SpuCollisionObjectWrapper::SpuCollisionObjectWrapper () { } #ifndef __SPU__ SpuCollisionObjectWrapper::SpuCollisionObjectWrapper (const btCollisionObject* collisionObject) { m_shapeType = collisionObject->getCollisionShape()->getShapeType (); m_collisionObjectPtr = (ppu_address_t)collisionObject; m_margin = collisionObject->getCollisionShape()->getMargin (); } #endif int SpuCollisionObjectWrapper::getShapeType () const { return m_shapeType; } float SpuCollisionObjectWrapper::getCollisionMargin () const { return m_margin; } ppu_address_t SpuCollisionObjectWrapper::getCollisionObjectPtr () const { return m_collisionObjectPtr; } critterding-beta12.1/src/utils/bullet/BulletMultiThreaded/Win32ThreadSupport.h0000644000175000017500000000720211337073000026451 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://bulletphysics.com 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 "LinearMath/btScalar.h" #include "PlatformDefinitions.h" #ifdef USE_WIN32_THREADING //platform specific defines are defined in PlatformDefinitions.h #ifndef WIN32_THREAD_SUPPORT_H #define WIN32_THREAD_SUPPORT_H #include "LinearMath/btAlignedObjectArray.h" #include "btThreadSupportInterface.h" typedef void (*Win32ThreadFunc)(void* userPtr,void* lsMemory); typedef void* (*Win32lsMemorySetupFunc)(); ///Win32ThreadSupport helps to initialize/shutdown libspe2, start/stop SPU tasks and communication class Win32ThreadSupport : public btThreadSupportInterface { public: ///placeholder, until libspe2 support is there struct btSpuStatus { uint32_t m_taskId; uint32_t m_commandId; uint32_t m_status; Win32ThreadFunc m_userThreadFunc; void* m_userPtr; //for taskDesc etc void* m_lsMemory; //initialized using Win32LocalStoreMemorySetupFunc void* m_threadHandle; //this one is calling 'Win32ThreadFunc' void* m_eventStartHandle; char m_eventStartHandleName[32]; void* m_eventCompletetHandle; char m_eventCompletetHandleName[32]; }; private: btAlignedObjectArray m_activeSpuStatus; btAlignedObjectArray m_completeHandles; int m_maxNumTasks; public: ///Setup and initialize SPU/CELL/Libspe2 struct Win32ThreadConstructionInfo { Win32ThreadConstructionInfo(char* uniqueName, Win32ThreadFunc userThreadFunc, Win32lsMemorySetupFunc lsMemoryFunc, int numThreads=1, int threadStackSize=65535 ) :m_uniqueName(uniqueName), m_userThreadFunc(userThreadFunc), m_lsMemoryFunc(lsMemoryFunc), m_numThreads(numThreads), m_threadStackSize(threadStackSize) { } char* m_uniqueName; Win32ThreadFunc m_userThreadFunc; Win32lsMemorySetupFunc m_lsMemoryFunc; int m_numThreads; int m_threadStackSize; }; Win32ThreadSupport(const Win32ThreadConstructionInfo& threadConstructionInfo); ///cleanup/shutdown Libspe2 virtual ~Win32ThreadSupport(); void startThreads(const Win32ThreadConstructionInfo& threadInfo); ///send messages to SPUs virtual void sendRequest(uint32_t uiCommand, ppu_address_t uiArgument0, uint32_t uiArgument1); ///check for messages from SPUs virtual void waitForResponse(unsigned int *puiArgument0, unsigned int *puiArgument1); ///start the spus (can be called at the beginning of each frame, to make sure that the right SPU program is loaded) virtual void startSPU(); ///tell the task scheduler we are done with the SPU tasks virtual void stopSPU(); virtual void setNumTasks(int numTasks) { m_maxNumTasks = numTasks; } virtual int getNumTasks() const { return m_maxNumTasks; } }; #endif //WIN32_THREAD_SUPPORT_H #endif //USE_WIN32_THREADING critterding-beta12.1/src/utils/bullet/LICENSE0000644000175000017500000000247111337071441017765 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ All files in the Bullet/src folder are under this Zlib license. Optional Extras/GIMPACT and Extras/GIMPACTBullet is also under ZLib license. Other optional external libraries in Extras/Demos have own license,see respective files. This means Bullet can freely be used in any software, including commercial and console software. A Playstation 3 optimized version is available through Sony. critterding-beta12.1/src/utils/bullet/btBulletDynamicsCommon.h0000644000175000017500000000414511337071441023547 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BULLET_DYNAMICS_COMMON_H #define BULLET_DYNAMICS_COMMON_H ///Common headerfile includes for Bullet Dynamics, including Collision Detection #include "btBulletCollisionCommon.h" #include "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h" #include "BulletDynamics/Dynamics/btContinuousDynamicsWorld.h" #include "BulletDynamics/Dynamics/btSimpleDynamicsWorld.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "BulletDynamics/ConstraintSolver/btPoint2PointConstraint.h" #include "BulletDynamics/ConstraintSolver/btHingeConstraint.h" #include "BulletDynamics/ConstraintSolver/btConeTwistConstraint.h" #include "BulletDynamics/ConstraintSolver/btGeneric6DofConstraint.h" #include "BulletDynamics/ConstraintSolver/btSliderConstraint.h" #include "BulletDynamics/ConstraintSolver/btGeneric6DofSpringConstraint.h" #include "BulletDynamics/ConstraintSolver/btUniversalConstraint.h" #include "BulletDynamics/ConstraintSolver/btHinge2Constraint.h" #include "BulletDynamics/ConstraintSolver/btSequentialImpulseConstraintSolver.h" ///Vehicle simulation, with wheel contact simulated by raycasts #include "BulletDynamics/Vehicle/btRaycastVehicle.h" #endif //BULLET_DYNAMICS_COMMON_H critterding-beta12.1/src/utils/bullet/BulletSoftBody/0000755000175000017500000000000011347266042021661 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletSoftBody/btSoftSoftCollisionAlgorithm.h0000644000175000017500000000541011337071441027646 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 SOFT_SOFT_COLLISION_ALGORITHM_H #define SOFT_SOFT_COLLISION_ALGORITHM_H #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/BroadphaseCollision/btDispatcher.h" #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" class btPersistentManifold; class btSoftBody; ///collision detection between two btSoftBody shapes class btSoftSoftCollisionAlgorithm : public btCollisionAlgorithm { bool m_ownManifold; btPersistentManifold* m_manifoldPtr; btSoftBody* m_softBody0; btSoftBody* m_softBody1; public: btSoftSoftCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) : btCollisionAlgorithm(ci) {} virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual void getAllContactManifolds(btManifoldArray& manifoldArray) { if (m_manifoldPtr && m_ownManifold) manifoldArray.push_back(m_manifoldPtr); } btSoftSoftCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1); virtual ~btSoftSoftCollisionAlgorithm(); struct CreateFunc :public btCollisionAlgorithmCreateFunc { virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { int bbsize = sizeof(btSoftSoftCollisionAlgorithm); void* ptr = ci.m_dispatcher1->allocateCollisionAlgorithm(bbsize); return new(ptr) btSoftSoftCollisionAlgorithm(0,ci,body0,body1); } }; }; #endif //SOFT_SOFT_COLLISION_ALGORITHM_H critterding-beta12.1/src/utils/bullet/BulletSoftBody/btSoftBody.h0000644000175000017500000006615711337071441024124 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ ///btSoftBody implementation by Nathanael Presson #ifndef _BT_SOFT_BODY_H #define _BT_SOFT_BODY_H #include "LinearMath/btAlignedObjectArray.h" #include "LinearMath/btTransform.h" #include "LinearMath/btIDebugDraw.h" #include "BulletDynamics/Dynamics/btRigidBody.h" #include "BulletCollision/CollisionShapes/btConcaveShape.h" #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" #include "btSparseSDF.h" #include "BulletCollision/BroadphaseCollision/btDbvt.h" class btBroadphaseInterface; class btDispatcher; /* btSoftBodyWorldInfo */ struct btSoftBodyWorldInfo { btScalar air_density; btScalar water_density; btScalar water_offset; btVector3 water_normal; btBroadphaseInterface* m_broadphase; btDispatcher* m_dispatcher; btVector3 m_gravity; btSparseSdf<3> m_sparsesdf; }; ///The btSoftBody is an class to simulate cloth and volumetric soft bodies. ///There is two-way interaction between btSoftBody and btRigidBody/btCollisionObject. class btSoftBody : public btCollisionObject { public: btAlignedObjectArray m_collisionDisabledObjects; // // Enumerations // ///eAeroModel struct eAeroModel { enum _ { V_Point, ///Vertex normals are oriented toward velocity V_TwoSided, ///Vertex normals are fliped to match velocity V_OneSided, ///Vertex normals are taken as it is F_TwoSided, ///Face normals are fliped to match velocity F_OneSided, ///Face normals are taken as it is END };}; ///eVSolver : velocities solvers struct eVSolver { enum _ { Linear, ///Linear solver END };}; ///ePSolver : positions solvers struct ePSolver { enum _ { Linear, ///Linear solver Anchors, ///Anchor solver RContacts, ///Rigid contacts solver SContacts, ///Soft contacts solver END };}; ///eSolverPresets struct eSolverPresets { enum _ { Positions, Velocities, Default = Positions, END };}; ///eFeature struct eFeature { enum _ { None, Node, Link, Face, END };}; typedef btAlignedObjectArray tVSolverArray; typedef btAlignedObjectArray tPSolverArray; // // Flags // ///fCollision struct fCollision { enum _ { RVSmask = 0x000f, ///Rigid versus soft mask SDF_RS = 0x0001, ///SDF based rigid vs soft CL_RS = 0x0002, ///Cluster vs convex rigid vs soft SVSmask = 0x0030, ///Rigid versus soft mask VF_SS = 0x0010, ///Vertex vs face soft vs soft handling CL_SS = 0x0020, ///Cluster vs cluster soft vs soft handling CL_SELF = 0x0040, ///Cluster soft body self collision /* presets */ Default = SDF_RS, END };}; ///fMaterial struct fMaterial { enum _ { DebugDraw = 0x0001, /// Enable debug draw /* presets */ Default = DebugDraw, END };}; // // API Types // /* sRayCast */ struct sRayCast { btSoftBody* body; /// soft body eFeature::_ feature; /// feature type int index; /// feature index btScalar fraction; /// time of impact fraction (rayorg+(rayto-rayfrom)*fraction) }; /* ImplicitFn */ struct ImplicitFn { virtual btScalar Eval(const btVector3& x)=0; }; // // Internal types // typedef btAlignedObjectArray tScalarArray; typedef btAlignedObjectArray tVector3Array; /* sCti is Softbody contact info */ struct sCti { btCollisionObject* m_colObj; /* Rigid body */ btVector3 m_normal; /* Outward normal */ btScalar m_offset; /* Offset from origin */ }; /* sMedium */ struct sMedium { btVector3 m_velocity; /* Velocity */ btScalar m_pressure; /* Pressure */ btScalar m_density; /* Density */ }; /* Base type */ struct Element { void* m_tag; // User data Element() : m_tag(0) {} }; /* Material */ struct Material : Element { btScalar m_kLST; // Linear stiffness coefficient [0,1] btScalar m_kAST; // Area/Angular stiffness coefficient [0,1] btScalar m_kVST; // Volume stiffness coefficient [0,1] int m_flags; // Flags }; /* Feature */ struct Feature : Element { Material* m_material; // Material }; /* Node */ struct Node : Feature { btVector3 m_x; // Position btVector3 m_q; // Previous step position btVector3 m_v; // Velocity btVector3 m_f; // Force accumulator btVector3 m_n; // Normal btScalar m_im; // 1/mass btScalar m_area; // Area btDbvtNode* m_leaf; // Leaf data int m_battach:1; // Attached }; /* Link */ struct Link : Feature { Node* m_n[2]; // Node pointers btScalar m_rl; // Rest length int m_bbending:1; // Bending link btScalar m_c0; // (ima+imb)*kLST btScalar m_c1; // rl^2 btScalar m_c2; // |gradient|^2/c0 btVector3 m_c3; // gradient }; /* Face */ struct Face : Feature { Node* m_n[3]; // Node pointers btVector3 m_normal; // Normal btScalar m_ra; // Rest area btDbvtNode* m_leaf; // Leaf data }; /* Tetra */ struct Tetra : Feature { Node* m_n[4]; // Node pointers btScalar m_rv; // Rest volume btDbvtNode* m_leaf; // Leaf data btVector3 m_c0[4]; // gradients btScalar m_c1; // (4*kVST)/(im0+im1+im2+im3) btScalar m_c2; // m_c1/sum(|g0..3|^2) }; /* RContact */ struct RContact { sCti m_cti; // Contact infos Node* m_node; // Owner node btMatrix3x3 m_c0; // Impulse matrix btVector3 m_c1; // Relative anchor btScalar m_c2; // ima*dt btScalar m_c3; // Friction btScalar m_c4; // Hardness }; /* SContact */ struct SContact { Node* m_node; // Node Face* m_face; // Face btVector3 m_weights; // Weigths btVector3 m_normal; // Normal btScalar m_margin; // Margin btScalar m_friction; // Friction btScalar m_cfm[2]; // Constraint force mixing }; /* Anchor */ struct Anchor { Node* m_node; // Node pointer btVector3 m_local; // Anchor position in body space btRigidBody* m_body; // Body btMatrix3x3 m_c0; // Impulse matrix btVector3 m_c1; // Relative anchor btScalar m_c2; // ima*dt }; /* Note */ struct Note : Element { const char* m_text; // Text btVector3 m_offset; // Offset int m_rank; // Rank Node* m_nodes[4]; // Nodes btScalar m_coords[4]; // Coordinates }; /* Pose */ struct Pose { bool m_bvolume; // Is valid bool m_bframe; // Is frame btScalar m_volume; // Rest volume tVector3Array m_pos; // Reference positions tScalarArray m_wgh; // Weights btVector3 m_com; // COM btMatrix3x3 m_rot; // Rotation btMatrix3x3 m_scl; // Scale btMatrix3x3 m_aqq; // Base scaling }; /* Cluster */ struct Cluster { btAlignedObjectArray m_nodes; tScalarArray m_masses; tVector3Array m_framerefs; btTransform m_framexform; btScalar m_idmass; btScalar m_imass; btMatrix3x3 m_locii; btMatrix3x3 m_invwi; btVector3 m_com; btVector3 m_vimpulses[2]; btVector3 m_dimpulses[2]; int m_nvimpulses; int m_ndimpulses; btVector3 m_lv; btVector3 m_av; btDbvtNode* m_leaf; btScalar m_ndamping; /* Node damping */ btScalar m_ldamping; /* Linear damping */ btScalar m_adamping; /* Angular damping */ btScalar m_matching; btScalar m_maxSelfCollisionImpulse; btScalar m_selfCollisionImpulseFactor; bool m_containsAnchor; bool m_collide; int m_clusterIndex; Cluster() : m_leaf(0),m_ndamping(0),m_ldamping(0),m_adamping(0),m_matching(0) ,m_maxSelfCollisionImpulse(100.f), m_selfCollisionImpulseFactor(0.01f), m_containsAnchor(false) {} }; /* Impulse */ struct Impulse { btVector3 m_velocity; btVector3 m_drift; int m_asVelocity:1; int m_asDrift:1; Impulse() : m_velocity(0,0,0),m_drift(0,0,0),m_asVelocity(0),m_asDrift(0) {} Impulse operator -() const { Impulse i=*this; i.m_velocity=-i.m_velocity; i.m_drift=-i.m_drift; return(i); } Impulse operator*(btScalar x) const { Impulse i=*this; i.m_velocity*=x; i.m_drift*=x; return(i); } }; /* Body */ struct Body { Cluster* m_soft; btRigidBody* m_rigid; btCollisionObject* m_collisionObject; Body() : m_soft(0),m_rigid(0),m_collisionObject(0) {} Body(Cluster* p) : m_soft(p),m_rigid(0),m_collisionObject(0) {} Body(btCollisionObject* colObj) : m_soft(0),m_collisionObject(colObj) { m_rigid = btRigidBody::upcast(m_collisionObject); } void activate() const { if(m_rigid) m_rigid->activate(); } const btMatrix3x3& invWorldInertia() const { static const btMatrix3x3 iwi(0,0,0,0,0,0,0,0,0); if(m_rigid) return(m_rigid->getInvInertiaTensorWorld()); if(m_soft) return(m_soft->m_invwi); return(iwi); } btScalar invMass() const { if(m_rigid) return(m_rigid->getInvMass()); if(m_soft) return(m_soft->m_imass); return(0); } const btTransform& xform() const { static const btTransform identity=btTransform::getIdentity(); if(m_collisionObject) return(m_collisionObject->getInterpolationWorldTransform()); if(m_soft) return(m_soft->m_framexform); return(identity); } btVector3 linearVelocity() const { if(m_rigid) return(m_rigid->getLinearVelocity()); if(m_soft) return(m_soft->m_lv); return(btVector3(0,0,0)); } btVector3 angularVelocity(const btVector3& rpos) const { if(m_rigid) return(btCross(m_rigid->getAngularVelocity(),rpos)); if(m_soft) return(btCross(m_soft->m_av,rpos)); return(btVector3(0,0,0)); } btVector3 angularVelocity() const { if(m_rigid) return(m_rigid->getAngularVelocity()); if(m_soft) return(m_soft->m_av); return(btVector3(0,0,0)); } btVector3 velocity(const btVector3& rpos) const { return(linearVelocity()+angularVelocity(rpos)); } void applyVImpulse(const btVector3& impulse,const btVector3& rpos) const { if(m_rigid) m_rigid->applyImpulse(impulse,rpos); if(m_soft) btSoftBody::clusterVImpulse(m_soft,rpos,impulse); } void applyDImpulse(const btVector3& impulse,const btVector3& rpos) const { if(m_rigid) m_rigid->applyImpulse(impulse,rpos); if(m_soft) btSoftBody::clusterDImpulse(m_soft,rpos,impulse); } void applyImpulse(const Impulse& impulse,const btVector3& rpos) const { if(impulse.m_asVelocity) { // printf("impulse.m_velocity = %f,%f,%f\n",impulse.m_velocity.getX(),impulse.m_velocity.getY(),impulse.m_velocity.getZ()); applyVImpulse(impulse.m_velocity,rpos); } if(impulse.m_asDrift) { // printf("impulse.m_drift = %f,%f,%f\n",impulse.m_drift.getX(),impulse.m_drift.getY(),impulse.m_drift.getZ()); applyDImpulse(impulse.m_drift,rpos); } } void applyVAImpulse(const btVector3& impulse) const { if(m_rigid) m_rigid->applyTorqueImpulse(impulse); if(m_soft) btSoftBody::clusterVAImpulse(m_soft,impulse); } void applyDAImpulse(const btVector3& impulse) const { if(m_rigid) m_rigid->applyTorqueImpulse(impulse); if(m_soft) btSoftBody::clusterDAImpulse(m_soft,impulse); } void applyAImpulse(const Impulse& impulse) const { if(impulse.m_asVelocity) applyVAImpulse(impulse.m_velocity); if(impulse.m_asDrift) applyDAImpulse(impulse.m_drift); } void applyDCImpulse(const btVector3& impulse) const { if(m_rigid) m_rigid->applyCentralImpulse(impulse); if(m_soft) btSoftBody::clusterDCImpulse(m_soft,impulse); } }; /* Joint */ struct Joint { struct eType { enum _ { Linear, Angular, Contact };}; struct Specs { Specs() : erp(1),cfm(1),split(1) {} btScalar erp; btScalar cfm; btScalar split; }; Body m_bodies[2]; btVector3 m_refs[2]; btScalar m_cfm; btScalar m_erp; btScalar m_split; btVector3 m_drift; btVector3 m_sdrift; btMatrix3x3 m_massmatrix; bool m_delete; virtual ~Joint() {} Joint() : m_delete(false) {} virtual void Prepare(btScalar dt,int iterations); virtual void Solve(btScalar dt,btScalar sor)=0; virtual void Terminate(btScalar dt)=0; virtual eType::_ Type() const=0; }; /* LJoint */ struct LJoint : Joint { struct Specs : Joint::Specs { btVector3 position; }; btVector3 m_rpos[2]; void Prepare(btScalar dt,int iterations); void Solve(btScalar dt,btScalar sor); void Terminate(btScalar dt); eType::_ Type() const { return(eType::Linear); } }; /* AJoint */ struct AJoint : Joint { struct IControl { virtual void Prepare(AJoint*) {} virtual btScalar Speed(AJoint*,btScalar current) { return(current); } static IControl* Default() { static IControl def;return(&def); } }; struct Specs : Joint::Specs { Specs() : icontrol(IControl::Default()) {} btVector3 axis; IControl* icontrol; }; btVector3 m_axis[2]; IControl* m_icontrol; void Prepare(btScalar dt,int iterations); void Solve(btScalar dt,btScalar sor); void Terminate(btScalar dt); eType::_ Type() const { return(eType::Angular); } }; /* CJoint */ struct CJoint : Joint { int m_life; int m_maxlife; btVector3 m_rpos[2]; btVector3 m_normal; btScalar m_friction; void Prepare(btScalar dt,int iterations); void Solve(btScalar dt,btScalar sor); void Terminate(btScalar dt); eType::_ Type() const { return(eType::Contact); } }; /* Config */ struct Config { eAeroModel::_ aeromodel; // Aerodynamic model (default: V_Point) btScalar kVCF; // Velocities correction factor (Baumgarte) btScalar kDP; // Damping coefficient [0,1] btScalar kDG; // Drag coefficient [0,+inf] btScalar kLF; // Lift coefficient [0,+inf] btScalar kPR; // Pressure coefficient [-inf,+inf] btScalar kVC; // Volume conversation coefficient [0,+inf] btScalar kDF; // Dynamic friction coefficient [0,1] btScalar kMT; // Pose matching coefficient [0,1] btScalar kCHR; // Rigid contacts hardness [0,1] btScalar kKHR; // Kinetic contacts hardness [0,1] btScalar kSHR; // Soft contacts hardness [0,1] btScalar kAHR; // Anchors hardness [0,1] btScalar kSRHR_CL; // Soft vs rigid hardness [0,1] (cluster only) btScalar kSKHR_CL; // Soft vs kinetic hardness [0,1] (cluster only) btScalar kSSHR_CL; // Soft vs soft hardness [0,1] (cluster only) btScalar kSR_SPLT_CL; // Soft vs rigid impulse split [0,1] (cluster only) btScalar kSK_SPLT_CL; // Soft vs rigid impulse split [0,1] (cluster only) btScalar kSS_SPLT_CL; // Soft vs rigid impulse split [0,1] (cluster only) btScalar maxvolume; // Maximum volume ratio for pose btScalar timescale; // Time scale int viterations; // Velocities solver iterations int piterations; // Positions solver iterations int diterations; // Drift solver iterations int citerations; // Cluster solver iterations int collisions; // Collisions flags tVSolverArray m_vsequence; // Velocity solvers sequence tPSolverArray m_psequence; // Position solvers sequence tPSolverArray m_dsequence; // Drift solvers sequence }; /* SolverState */ struct SolverState { btScalar sdt; // dt*timescale btScalar isdt; // 1/sdt btScalar velmrg; // velocity margin btScalar radmrg; // radial margin btScalar updmrg; // Update margin }; /// RayFromToCaster takes a ray from, ray to (instead of direction!) struct RayFromToCaster : btDbvt::ICollide { btVector3 m_rayFrom; btVector3 m_rayTo; btVector3 m_rayNormalizedDirection; btScalar m_mint; Face* m_face; int m_tests; RayFromToCaster(const btVector3& rayFrom,const btVector3& rayTo,btScalar mxt); void Process(const btDbvtNode* leaf); static inline btScalar rayFromToTriangle(const btVector3& rayFrom, const btVector3& rayTo, const btVector3& rayNormalizedDirection, const btVector3& a, const btVector3& b, const btVector3& c, btScalar maxt=SIMD_INFINITY); }; // // Typedef's // typedef void (*psolver_t)(btSoftBody*,btScalar,btScalar); typedef void (*vsolver_t)(btSoftBody*,btScalar); typedef btAlignedObjectArray tClusterArray; typedef btAlignedObjectArray tNoteArray; typedef btAlignedObjectArray tNodeArray; typedef btAlignedObjectArray tLeafArray; typedef btAlignedObjectArray tLinkArray; typedef btAlignedObjectArray tFaceArray; typedef btAlignedObjectArray tTetraArray; typedef btAlignedObjectArray tAnchorArray; typedef btAlignedObjectArray tRContactArray; typedef btAlignedObjectArray tSContactArray; typedef btAlignedObjectArray tMaterialArray; typedef btAlignedObjectArray tJointArray; typedef btAlignedObjectArray tSoftBodyArray; // // Fields // Config m_cfg; // Configuration SolverState m_sst; // Solver state Pose m_pose; // Pose void* m_tag; // User data btSoftBodyWorldInfo* m_worldInfo; // World info tNoteArray m_notes; // Notes tNodeArray m_nodes; // Nodes tLinkArray m_links; // Links tFaceArray m_faces; // Faces tTetraArray m_tetras; // Tetras tAnchorArray m_anchors; // Anchors tRContactArray m_rcontacts; // Rigid contacts tSContactArray m_scontacts; // Soft contacts tJointArray m_joints; // Joints tMaterialArray m_materials; // Materials btScalar m_timeacc; // Time accumulator btVector3 m_bounds[2]; // Spatial bounds bool m_bUpdateRtCst; // Update runtime constants btDbvt m_ndbvt; // Nodes tree btDbvt m_fdbvt; // Faces tree btDbvt m_cdbvt; // Clusters tree tClusterArray m_clusters; // Clusters btAlignedObjectArraym_clusterConnectivity;//cluster connectivity, for self-collision btTransform m_initialWorldTransform; // // Api // /* ctor */ btSoftBody( btSoftBodyWorldInfo* worldInfo,int node_count, const btVector3* x, const btScalar* m); /* dtor */ virtual ~btSoftBody(); /* Check for existing link */ btAlignedObjectArray m_userIndexMapping; btSoftBodyWorldInfo* getWorldInfo() { return m_worldInfo; } ///@todo: avoid internal softbody shape hack and move collision code to collision library virtual void setCollisionShape(btCollisionShape* collisionShape) { } bool checkLink( int node0, int node1) const; bool checkLink( const Node* node0, const Node* node1) const; /* Check for existring face */ bool checkFace( int node0, int node1, int node2) const; /* Append material */ Material* appendMaterial(); /* Append note */ void appendNote( const char* text, const btVector3& o, const btVector4& c=btVector4(1,0,0,0), Node* n0=0, Node* n1=0, Node* n2=0, Node* n3=0); void appendNote( const char* text, const btVector3& o, Node* feature); void appendNote( const char* text, const btVector3& o, Link* feature); void appendNote( const char* text, const btVector3& o, Face* feature); /* Append node */ void appendNode( const btVector3& x,btScalar m); /* Append link */ void appendLink(int model=-1,Material* mat=0); void appendLink( int node0, int node1, Material* mat=0, bool bcheckexist=false); void appendLink( Node* node0, Node* node1, Material* mat=0, bool bcheckexist=false); /* Append face */ void appendFace(int model=-1,Material* mat=0); void appendFace( int node0, int node1, int node2, Material* mat=0); void appendTetra(int model,Material* mat); // void appendTetra(int node0, int node1, int node2, int node3, Material* mat=0); /* Append anchor */ void appendAnchor( int node, btRigidBody* body, bool disableCollisionBetweenLinkedBodies=false); /* Append linear joint */ void appendLinearJoint(const LJoint::Specs& specs,Cluster* body0,Body body1); void appendLinearJoint(const LJoint::Specs& specs,Body body=Body()); void appendLinearJoint(const LJoint::Specs& specs,btSoftBody* body); /* Append linear joint */ void appendAngularJoint(const AJoint::Specs& specs,Cluster* body0,Body body1); void appendAngularJoint(const AJoint::Specs& specs,Body body=Body()); void appendAngularJoint(const AJoint::Specs& specs,btSoftBody* body); /* Add force (or gravity) to the entire body */ void addForce( const btVector3& force); /* Add force (or gravity) to a node of the body */ void addForce( const btVector3& force, int node); /* Add velocity to the entire body */ void addVelocity( const btVector3& velocity); /* Set velocity for the entire body */ void setVelocity( const btVector3& velocity); /* Add velocity to a node of the body */ void addVelocity( const btVector3& velocity, int node); /* Set mass */ void setMass( int node, btScalar mass); /* Get mass */ btScalar getMass( int node) const; /* Get total mass */ btScalar getTotalMass() const; /* Set total mass (weighted by previous masses) */ void setTotalMass( btScalar mass, bool fromfaces=false); /* Set total density */ void setTotalDensity(btScalar density); /* Set volume mass (using tetrahedrons) */ void setVolumeMass( btScalar mass); /* Set volume density (using tetrahedrons) */ void setVolumeDensity( btScalar density); /* Transform */ void transform( const btTransform& trs); /* Translate */ void translate( const btVector3& trs); /* Rotate */ void rotate( const btQuaternion& rot); /* Scale */ void scale( const btVector3& scl); /* Set current state as pose */ void setPose( bool bvolume, bool bframe); /* Return the volume */ btScalar getVolume() const; /* Cluster count */ int clusterCount() const; /* Cluster center of mass */ static btVector3 clusterCom(const Cluster* cluster); btVector3 clusterCom(int cluster) const; /* Cluster velocity at rpos */ static btVector3 clusterVelocity(const Cluster* cluster,const btVector3& rpos); /* Cluster impulse */ static void clusterVImpulse(Cluster* cluster,const btVector3& rpos,const btVector3& impulse); static void clusterDImpulse(Cluster* cluster,const btVector3& rpos,const btVector3& impulse); static void clusterImpulse(Cluster* cluster,const btVector3& rpos,const Impulse& impulse); static void clusterVAImpulse(Cluster* cluster,const btVector3& impulse); static void clusterDAImpulse(Cluster* cluster,const btVector3& impulse); static void clusterAImpulse(Cluster* cluster,const Impulse& impulse); static void clusterDCImpulse(Cluster* cluster,const btVector3& impulse); /* Generate bending constraints based on distance in the adjency graph */ int generateBendingConstraints( int distance, Material* mat=0); /* Randomize constraints to reduce solver bias */ void randomizeConstraints(); /* Release clusters */ void releaseCluster(int index); void releaseClusters(); /* Generate clusters (K-mean) */ ///generateClusters with k=0 will create a convex cluster for each tetrahedron or triangle ///otherwise an approximation will be used (better performance) int generateClusters(int k,int maxiterations=8192); /* Refine */ void refine(ImplicitFn* ifn,btScalar accurary,bool cut); /* CutLink */ bool cutLink(int node0,int node1,btScalar position); bool cutLink(const Node* node0,const Node* node1,btScalar position); ///Ray casting using rayFrom and rayTo in worldspace, (not direction!) bool rayTest(const btVector3& rayFrom, const btVector3& rayTo, sRayCast& results); /* Solver presets */ void setSolver(eSolverPresets::_ preset); /* predictMotion */ void predictMotion(btScalar dt); /* solveConstraints */ void solveConstraints(); /* staticSolve */ void staticSolve(int iterations); /* solveCommonConstraints */ static void solveCommonConstraints(btSoftBody** bodies,int count,int iterations); /* solveClusters */ static void solveClusters(const btAlignedObjectArray& bodies); /* integrateMotion */ void integrateMotion(); /* defaultCollisionHandlers */ void defaultCollisionHandler(btCollisionObject* pco); void defaultCollisionHandler(btSoftBody* psb); // // Cast // static const btSoftBody* upcast(const btCollisionObject* colObj) { if (colObj->getInternalType()==CO_SOFT_BODY) return (const btSoftBody*)colObj; return 0; } static btSoftBody* upcast(btCollisionObject* colObj) { if (colObj->getInternalType()==CO_SOFT_BODY) return (btSoftBody*)colObj; return 0; } // // ::btCollisionObject // virtual void getAabb(btVector3& aabbMin,btVector3& aabbMax) const { aabbMin = m_bounds[0]; aabbMax = m_bounds[1]; } // // Private // void pointersToIndices(); void indicesToPointers(const int* map=0); int rayTest(const btVector3& rayFrom,const btVector3& rayTo, btScalar& mint,eFeature::_& feature,int& index,bool bcountonly) const; void initializeFaceTree(); btVector3 evaluateCom() const; bool checkContact(btCollisionObject* colObj,const btVector3& x,btScalar margin,btSoftBody::sCti& cti) const; void updateNormals(); void updateBounds(); void updatePose(); void updateConstants(); void initializeClusters(); void updateClusters(); void cleanupClusters(); void prepareClusters(int iterations); void solveClusters(btScalar sor); void applyClusters(bool drift); void dampClusters(); void applyForces(); static void PSolve_Anchors(btSoftBody* psb,btScalar kst,btScalar ti); static void PSolve_RContacts(btSoftBody* psb,btScalar kst,btScalar ti); static void PSolve_SContacts(btSoftBody* psb,btScalar,btScalar ti); static void PSolve_Links(btSoftBody* psb,btScalar kst,btScalar ti); static void VSolve_Links(btSoftBody* psb,btScalar kst); static psolver_t getSolver(ePSolver::_ solver); static vsolver_t getSolver(eVSolver::_ solver); }; #endif //_BT_SOFT_BODY_H critterding-beta12.1/src/utils/bullet/BulletSoftBody/btSoftRigidCollisionAlgorithm.h0000644000175000017500000000567711337071441030010 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 SOFT_RIGID_COLLISION_ALGORITHM_H #define SOFT_RIGID_COLLISION_ALGORITHM_H #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" class btPersistentManifold; #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "LinearMath/btVector3.h" class btSoftBody; /// btSoftRigidCollisionAlgorithm provides collision detection between btSoftBody and btRigidBody class btSoftRigidCollisionAlgorithm : public btCollisionAlgorithm { // bool m_ownManifold; // btPersistentManifold* m_manifoldPtr; btSoftBody* m_softBody; btCollisionObject* m_rigidCollisionObject; ///for rigid versus soft (instead of soft versus rigid), we use this swapped boolean bool m_isSwapped; public: btSoftRigidCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped); virtual ~btSoftRigidCollisionAlgorithm(); virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual void getAllContactManifolds(btManifoldArray& manifoldArray) { //we don't add any manifolds } struct CreateFunc :public btCollisionAlgorithmCreateFunc { virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btSoftRigidCollisionAlgorithm)); if (!m_swapped) { return new(mem) btSoftRigidCollisionAlgorithm(0,ci,body0,body1,false); } else { return new(mem) btSoftRigidCollisionAlgorithm(0,ci,body0,body1,true); } } }; }; #endif //SOFT_RIGID_COLLISION_ALGORITHM_H critterding-beta12.1/src/utils/bullet/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h0000644000175000017500000000433211337071441032310 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BT_SOFTBODY_RIGIDBODY_COLLISION_CONFIGURATION #define BT_SOFTBODY_RIGIDBODY_COLLISION_CONFIGURATION #include "BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.h" class btVoronoiSimplexSolver; class btGjkEpaPenetrationDepthSolver; ///btSoftBodyRigidBodyCollisionConfiguration add softbody interaction on top of btDefaultCollisionConfiguration class btSoftBodyRigidBodyCollisionConfiguration : public btDefaultCollisionConfiguration { //default CreationFunctions, filling the m_doubleDispatch table btCollisionAlgorithmCreateFunc* m_softSoftCreateFunc; btCollisionAlgorithmCreateFunc* m_softRigidConvexCreateFunc; btCollisionAlgorithmCreateFunc* m_swappedSoftRigidConvexCreateFunc; btCollisionAlgorithmCreateFunc* m_softRigidConcaveCreateFunc; btCollisionAlgorithmCreateFunc* m_swappedSoftRigidConcaveCreateFunc; public: btSoftBodyRigidBodyCollisionConfiguration(const btDefaultCollisionConstructionInfo& constructionInfo = btDefaultCollisionConstructionInfo()); virtual ~btSoftBodyRigidBodyCollisionConfiguration(); ///creation of soft-soft and soft-rigid, and otherwise fallback to base class implementation virtual btCollisionAlgorithmCreateFunc* getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1); }; #endif //BT_SOFTBODY_RIGIDBODY_COLLISION_CONFIGURATION critterding-beta12.1/src/utils/bullet/BulletSoftBody/btSoftRigidDynamicsWorld.cpp0000644000175000017500000002213111344267705027310 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btSoftRigidDynamicsWorld.h" #include "LinearMath/btQuickprof.h" //softbody & helpers #include "btSoftBody.h" #include "btSoftBodyHelpers.h" btSoftRigidDynamicsWorld::btSoftRigidDynamicsWorld(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolver* constraintSolver,btCollisionConfiguration* collisionConfiguration) :btDiscreteDynamicsWorld(dispatcher,pairCache,constraintSolver,collisionConfiguration) { m_drawFlags = fDrawFlags::Std; m_drawNodeTree = true; m_drawFaceTree = false; m_drawClusterTree = false; m_sbi.m_broadphase = pairCache; m_sbi.m_dispatcher = dispatcher; m_sbi.m_sparsesdf.Initialize(); m_sbi.m_sparsesdf.Reset(); } btSoftRigidDynamicsWorld::~btSoftRigidDynamicsWorld() { } void btSoftRigidDynamicsWorld::predictUnconstraintMotion(btScalar timeStep) { btDiscreteDynamicsWorld::predictUnconstraintMotion( timeStep); for ( int i=0;ipredictMotion(timeStep); } } void btSoftRigidDynamicsWorld::internalSingleStepSimulation( btScalar timeStep) { btDiscreteDynamicsWorld::internalSingleStepSimulation( timeStep ); ///solve soft bodies constraints solveSoftBodiesConstraints(); //self collisions for ( int i=0;idefaultCollisionHandler(psb); } ///update soft bodies updateSoftBodies(); } void btSoftRigidDynamicsWorld::updateSoftBodies() { BT_PROFILE("updateSoftBodies"); for ( int i=0;iintegrateMotion(); } } void btSoftRigidDynamicsWorld::solveSoftBodiesConstraints() { BT_PROFILE("solveSoftConstraints"); if(m_softBodies.size()) { btSoftBody::solveClusters(m_softBodies); } for(int i=0;isolveConstraints(); } } void btSoftRigidDynamicsWorld::addSoftBody(btSoftBody* body,short int collisionFilterGroup,short int collisionFilterMask) { m_softBodies.push_back(body); btCollisionWorld::addCollisionObject(body, collisionFilterGroup, collisionFilterMask); } void btSoftRigidDynamicsWorld::removeSoftBody(btSoftBody* body) { m_softBodies.remove(body); btCollisionWorld::removeCollisionObject(body); } void btSoftRigidDynamicsWorld::removeCollisionObject(btCollisionObject* collisionObject) { btSoftBody* body = btSoftBody::upcast(collisionObject); if (body) removeSoftBody(body); else btDiscreteDynamicsWorld::removeCollisionObject(collisionObject); } void btSoftRigidDynamicsWorld::debugDrawWorld() { btDiscreteDynamicsWorld::debugDrawWorld(); if (getDebugDrawer()) { int i; for ( i=0;im_softBodies.size();i++) { btSoftBody* psb=(btSoftBody*)this->m_softBodies[i]; btSoftBodyHelpers::DrawFrame(psb,m_debugDrawer); btSoftBodyHelpers::Draw(psb,m_debugDrawer,m_drawFlags); if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawAabb)) { if(m_drawNodeTree) btSoftBodyHelpers::DrawNodeTree(psb,m_debugDrawer); if(m_drawFaceTree) btSoftBodyHelpers::DrawFaceTree(psb,m_debugDrawer); if(m_drawClusterTree) btSoftBodyHelpers::DrawClusterTree(psb,m_debugDrawer); } } } } struct btSoftSingleRayCallback : public btBroadphaseRayCallback { btVector3 m_rayFromWorld; btVector3 m_rayToWorld; btTransform m_rayFromTrans; btTransform m_rayToTrans; btVector3 m_hitNormal; const btSoftRigidDynamicsWorld* m_world; btCollisionWorld::RayResultCallback& m_resultCallback; btSoftSingleRayCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld,const btSoftRigidDynamicsWorld* world,btCollisionWorld::RayResultCallback& resultCallback) :m_rayFromWorld(rayFromWorld), m_rayToWorld(rayToWorld), m_world(world), m_resultCallback(resultCallback) { m_rayFromTrans.setIdentity(); m_rayFromTrans.setOrigin(m_rayFromWorld); m_rayToTrans.setIdentity(); m_rayToTrans.setOrigin(m_rayToWorld); btVector3 rayDir = (rayToWorld-rayFromWorld); rayDir.normalize (); ///what about division by zero? --> just set rayDirection[i] to INF/1e30 m_rayDirectionInverse[0] = rayDir[0] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[0]; m_rayDirectionInverse[1] = rayDir[1] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[1]; m_rayDirectionInverse[2] = rayDir[2] == btScalar(0.0) ? btScalar(1e30) : btScalar(1.0) / rayDir[2]; m_signs[0] = m_rayDirectionInverse[0] < 0.0; m_signs[1] = m_rayDirectionInverse[1] < 0.0; m_signs[2] = m_rayDirectionInverse[2] < 0.0; m_lambda_max = rayDir.dot(m_rayToWorld-m_rayFromWorld); } virtual bool process(const btBroadphaseProxy* proxy) { ///terminate further ray tests, once the closestHitFraction reached zero if (m_resultCallback.m_closestHitFraction == btScalar(0.f)) return false; btCollisionObject* collisionObject = (btCollisionObject*)proxy->m_clientObject; //only perform raycast if filterMask matches if(m_resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) { //RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject(); //btVector3 collisionObjectAabbMin,collisionObjectAabbMax; #if 0 #ifdef RECALCULATE_AABB btVector3 collisionObjectAabbMin,collisionObjectAabbMax; collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax); #else //getBroadphase()->getAabb(collisionObject->getBroadphaseHandle(),collisionObjectAabbMin,collisionObjectAabbMax); const btVector3& collisionObjectAabbMin = collisionObject->getBroadphaseHandle()->m_aabbMin; const btVector3& collisionObjectAabbMax = collisionObject->getBroadphaseHandle()->m_aabbMax; #endif #endif //btScalar hitLambda = m_resultCallback.m_closestHitFraction; //culling already done by broadphase //if (btRayAabb(m_rayFromWorld,m_rayToWorld,collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,m_hitNormal)) { m_world->rayTestSingle(m_rayFromTrans,m_rayToTrans, collisionObject, collisionObject->getCollisionShape(), collisionObject->getWorldTransform(), m_resultCallback); } } return true; } }; void btSoftRigidDynamicsWorld::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const { BT_PROFILE("rayTest"); /// use the broadphase to accelerate the search for objects, based on their aabb /// and for each object with ray-aabb overlap, perform an exact ray test btSoftSingleRayCallback rayCB(rayFromWorld,rayToWorld,this,resultCallback); #ifndef USE_BRUTEFORCE_RAYBROADPHASE m_broadphasePairCache->rayTest(rayFromWorld,rayToWorld,rayCB); #else for (int i=0;igetNumCollisionObjects();i++) { rayCB.process(m_collisionObjects[i]->getBroadphaseHandle()); } #endif //USE_BRUTEFORCE_RAYBROADPHASE } void btSoftRigidDynamicsWorld::rayTestSingle(const btTransform& rayFromTrans,const btTransform& rayToTrans, btCollisionObject* collisionObject, const btCollisionShape* collisionShape, const btTransform& colObjWorldTransform, RayResultCallback& resultCallback) { if (collisionShape->isSoftBody()) { btSoftBody* softBody = btSoftBody::upcast(collisionObject); if (softBody) { btSoftBody::sRayCast softResult; if (softBody->rayTest(rayFromTrans.getOrigin(), rayToTrans.getOrigin(), softResult)) { if (softResult.fraction<= resultCallback.m_closestHitFraction) { btCollisionWorld::LocalShapeInfo shapeInfo; shapeInfo.m_shapePart = 0; shapeInfo.m_triangleIndex = softResult.index; // get the normal btVector3 normal = softBody->m_faces[softResult.index].m_normal; btVector3 rayDir = rayToTrans.getOrigin() - rayFromTrans.getOrigin(); if (normal.dot(rayDir) > 0) { // normal always point toward origin of the ray normal = -normal; } btCollisionWorld::LocalRayResult rayResult (collisionObject, &shapeInfo, normal, softResult.fraction); bool normalInWorldSpace = true; resultCallback.addSingleResult(rayResult,normalInWorldSpace); } } } } else { btCollisionWorld::rayTestSingle(rayFromTrans,rayToTrans,collisionObject,collisionShape,colObjWorldTransform,resultCallback); } } critterding-beta12.1/src/utils/bullet/BulletSoftBody/Jamfile0000644000175000017500000000032011337071441023142 0ustar bobkebobke SubDir TOP src BulletSoftBody ; Description bulletsoftbody : "Bullet Softbody Dynamics" ; Library bulletsoftbody : [ Wildcard *.h *.cpp ] ; LibDepends bulletsoftbody : bulletdynamics bulletcollision ; critterding-beta12.1/src/utils/bullet/BulletSoftBody/btSparseSDF.h0000644000175000017500000001543111337071441024152 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ ///btSparseSdf implementation by Nathanael Presson #ifndef _14F9D17F_EAE8_4aba_B41C_292DB2AA70F3_ #define _14F9D17F_EAE8_4aba_B41C_292DB2AA70F3_ #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h" // Modified Paul Hsieh hash template unsigned int HsiehHash(const void* pdata) { const unsigned short* data=(const unsigned short*)pdata; unsigned hash=DWORDLEN<<2,tmp; for(int i=0;i>11; } hash^=hash<<3;hash+=hash>>5; hash^=hash<<4;hash+=hash>>17; hash^=hash<<25;hash+=hash>>6; return(hash); } template struct btSparseSdf { // // Inner types // struct IntFrac { int b; int i; btScalar f; }; struct Cell { btScalar d[CELLSIZE+1][CELLSIZE+1][CELLSIZE+1]; int c[3]; int puid; unsigned hash; btCollisionShape* pclient; Cell* next; }; // // Fields // btAlignedObjectArray cells; btScalar voxelsz; int puid; int ncells; int nprobes; int nqueries; // // Methods // // void Initialize(int hashsize=2383) { cells.resize(hashsize,0); Reset(); } // void Reset() { for(int i=0,ni=cells.size();inext; delete pc; pc=pn; } } voxelsz =0.25; puid =0; ncells =0; nprobes =1; nqueries =1; } // void GarbageCollect(int lifetime=256) { const int life=puid-lifetime; for(int i=0;inext; if(pc->puidnext=pn; else root=pn; delete pc;pc=pp;--ncells; } pp=pc;pc=pn; } } //printf("GC[%d]: %d cells, PpQ: %f\r\n",puid,ncells,nprobes/(btScalar)nqueries); nqueries=1; nprobes=1; ++puid; ///@todo: Reset puid's when int range limit is reached */ /* else setup a priority list... */ } // int RemoveReferences(btCollisionShape* pcs) { int refcount=0; for(int i=0;inext; if(pc->pclient==pcs) { if(pp) pp->next=pn; else root=pn; delete pc;pc=pp;++refcount; } pp=pc;pc=pn; } } return(refcount); } // btScalar Evaluate( const btVector3& x, btCollisionShape* shape, btVector3& normal, btScalar margin) { /* Lookup cell */ const btVector3 scx=x/voxelsz; const IntFrac ix=Decompose(scx.x()); const IntFrac iy=Decompose(scx.y()); const IntFrac iz=Decompose(scx.z()); const unsigned h=Hash(ix.b,iy.b,iz.b,shape); Cell*& root=cells[static_cast(h%cells.size())]; Cell* c=root; ++nqueries; while(c) { ++nprobes; if( (c->hash==h) && (c->c[0]==ix.b) && (c->c[1]==iy.b) && (c->c[2]==iz.b) && (c->pclient==shape)) { break; } else { c=c->next; } } if(!c) { ++nprobes; ++ncells; c=new Cell(); c->next=root;root=c; c->pclient=shape; c->hash=h; c->c[0]=ix.b;c->c[1]=iy.b;c->c[2]=iz.b; BuildCell(*c); } c->puid=puid; /* Extract infos */ const int o[]={ ix.i,iy.i,iz.i}; const btScalar d[]={ c->d[o[0]+0][o[1]+0][o[2]+0], c->d[o[0]+1][o[1]+0][o[2]+0], c->d[o[0]+1][o[1]+1][o[2]+0], c->d[o[0]+0][o[1]+1][o[2]+0], c->d[o[0]+0][o[1]+0][o[2]+1], c->d[o[0]+1][o[1]+0][o[2]+1], c->d[o[0]+1][o[1]+1][o[2]+1], c->d[o[0]+0][o[1]+1][o[2]+1]}; /* Normal */ #if 1 const btScalar gx[]={ d[1]-d[0],d[2]-d[3], d[5]-d[4],d[6]-d[7]}; const btScalar gy[]={ d[3]-d[0],d[2]-d[1], d[7]-d[4],d[6]-d[5]}; const btScalar gz[]={ d[4]-d[0],d[5]-d[1], d[7]-d[3],d[6]-d[2]}; normal.setX(Lerp( Lerp(gx[0],gx[1],iy.f), Lerp(gx[2],gx[3],iy.f),iz.f)); normal.setY(Lerp( Lerp(gy[0],gy[1],ix.f), Lerp(gy[2],gy[3],ix.f),iz.f)); normal.setZ(Lerp( Lerp(gz[0],gz[1],ix.f), Lerp(gz[2],gz[3],ix.f),iy.f)); normal = normal.normalized(); #else normal = btVector3(d[1]-d[0],d[3]-d[0],d[4]-d[0]).normalized(); #endif /* Distance */ const btScalar d0=Lerp(Lerp(d[0],d[1],ix.f), Lerp(d[3],d[2],ix.f),iy.f); const btScalar d1=Lerp(Lerp(d[4],d[5],ix.f), Lerp(d[7],d[6],ix.f),iy.f); return(Lerp(d0,d1,iz.f)-margin); } // void BuildCell(Cell& c) { const btVector3 org=btVector3( (btScalar)c.c[0], (btScalar)c.c[1], (btScalar)c.c[2]) * CELLSIZE*voxelsz; for(int k=0;k<=CELLSIZE;++k) { const btScalar z=voxelsz*k+org.z(); for(int j=0;j<=CELLSIZE;++j) { const btScalar y=voxelsz*j+org.y(); for(int i=0;i<=CELLSIZE;++i) { const btScalar x=voxelsz*i+org.x(); c.d[i][j][k]=DistanceToShape( btVector3(x,y,z), c.pclient); } } } } // static inline btScalar DistanceToShape(const btVector3& x, btCollisionShape* shape) { btTransform unit; unit.setIdentity(); if(shape->isConvex()) { btGjkEpaSolver2::sResults res; btConvexShape* csh=static_cast(shape); return(btGjkEpaSolver2::SignedDistance(x,0,csh,unit,res)); } return(0); } // static inline IntFrac Decompose(btScalar x) { /* That one need a lot of improvements... */ /* Remove test, faster floor... */ IntFrac r; x/=CELLSIZE; const int o=x<0?(int)(-x+1):0; x+=o;r.b=(int)x; const btScalar k=(x-r.b)*CELLSIZE; r.i=(int)k;r.f=k-r.i;r.b-=o; return(r); } // static inline btScalar Lerp(btScalar a,btScalar b,btScalar t) { return(a+(b-a)*t); } // static inline unsigned int Hash(int x,int y,int z,btCollisionShape* shape) { struct btS { int x,y,z; void* p; }; btS myset; myset.x=x;myset.y=y;myset.z=z;myset.p=shape; const void* ptr = &myset; unsigned int result = HsiehHash (ptr); return result; } }; #endif critterding-beta12.1/src/utils/bullet/BulletSoftBody/btSoftRigidCollisionAlgorithm.cpp0000644000175000017500000000555111337071441030332 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btSoftRigidCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" #include "BulletCollision/CollisionShapes/btBoxShape.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "btSoftBody.h" ///TODO: include all the shapes that the softbody can collide with ///alternatively, implement special case collision algorithms (just like for rigid collision shapes) //#include btSoftRigidCollisionAlgorithm::btSoftRigidCollisionAlgorithm(btPersistentManifold* /*mf*/,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* /*col0*/,btCollisionObject* /*col1*/, bool isSwapped) : btCollisionAlgorithm(ci), //m_ownManifold(false), //m_manifoldPtr(mf), m_isSwapped(isSwapped) { } btSoftRigidCollisionAlgorithm::~btSoftRigidCollisionAlgorithm() { //m_softBody->m_overlappingRigidBodies.remove(m_rigidCollisionObject); /*if (m_ownManifold) { if (m_manifoldPtr) m_dispatcher->releaseManifold(m_manifoldPtr); } */ } #include void btSoftRigidCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { (void)dispatchInfo; (void)resultOut; //printf("btSoftRigidCollisionAlgorithm\n"); btSoftBody* softBody = m_isSwapped? (btSoftBody*)body1 : (btSoftBody*)body0; btCollisionObject* rigidCollisionObject = m_isSwapped? body0 : body1; if (softBody->m_collisionDisabledObjects.findLinearSearch(rigidCollisionObject)==softBody->m_collisionDisabledObjects.size()) { softBody->defaultCollisionHandler(rigidCollisionObject); } } btScalar btSoftRigidCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { (void)resultOut; (void)dispatchInfo; (void)col0; (void)col1; //not yet return btScalar(1.); } critterding-beta12.1/src/utils/bullet/BulletSoftBody/btSoftBodyHelpers.h0000644000175000017500000001071411344267705025443 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/ 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 SOFT_BODY_HELPERS_H #define SOFT_BODY_HELPERS_H #include "btSoftBody.h" // // Helpers // /* fDrawFlags */ struct fDrawFlags { enum _ { Nodes = 0x0001, Links = 0x0002, Faces = 0x0004, Tetras = 0x0008, Normals = 0x0010, Contacts = 0x0020, Anchors = 0x0040, Notes = 0x0080, Clusters = 0x0100, NodeTree = 0x0200, FaceTree = 0x0400, ClusterTree = 0x0800, Joints = 0x1000, /* presets */ Std = Links+Faces+Tetras+Anchors+Notes+Joints, StdTetra = Std-Faces+Tetras };}; struct btSoftBodyHelpers { /* Draw body */ static void Draw( btSoftBody* psb, btIDebugDraw* idraw, int drawflags=fDrawFlags::Std); /* Draw body infos */ static void DrawInfos( btSoftBody* psb, btIDebugDraw* idraw, bool masses, bool areas, bool stress); /* Draw node tree */ static void DrawNodeTree( btSoftBody* psb, btIDebugDraw* idraw, int mindepth=0, int maxdepth=-1); /* Draw face tree */ static void DrawFaceTree( btSoftBody* psb, btIDebugDraw* idraw, int mindepth=0, int maxdepth=-1); /* Draw cluster tree */ static void DrawClusterTree(btSoftBody* psb, btIDebugDraw* idraw, int mindepth=0, int maxdepth=-1); /* Draw rigid frame */ static void DrawFrame( btSoftBody* psb, btIDebugDraw* idraw); /* Create a rope */ static btSoftBody* CreateRope( btSoftBodyWorldInfo& worldInfo, const btVector3& from, const btVector3& to, int res, int fixeds); /* Create a patch */ static btSoftBody* CreatePatch(btSoftBodyWorldInfo& worldInfo, const btVector3& corner00, const btVector3& corner10, const btVector3& corner01, const btVector3& corner11, int resx, int resy, int fixeds, bool gendiags); /* Create a patch with UV Texture Coordinates */ static btSoftBody* CreatePatchUV(btSoftBodyWorldInfo& worldInfo, const btVector3& corner00, const btVector3& corner10, const btVector3& corner01, const btVector3& corner11, int resx, int resy, int fixeds, bool gendiags, float* tex_coords=0); static float CalculateUV(int resx,int resy,int ix,int iy,int id); /* Create an ellipsoid */ static btSoftBody* CreateEllipsoid(btSoftBodyWorldInfo& worldInfo, const btVector3& center, const btVector3& radius, int res); /* Create from trimesh */ static btSoftBody* CreateFromTriMesh( btSoftBodyWorldInfo& worldInfo, const btScalar* vertices, const int* triangles, int ntriangles, bool randomizeConstraints = true); /* Create from convex-hull */ static btSoftBody* CreateFromConvexHull( btSoftBodyWorldInfo& worldInfo, const btVector3* vertices, int nvertices, bool randomizeConstraints = true); /* Export TetGen compatible .smesh file */ static void ExportAsSMeshFile( btSoftBody* psb, const char* filename); /* Create from TetGen .ele, .face, .node files */ static btSoftBody* CreateFromTetGenFile( btSoftBodyWorldInfo& worldInfo, const char* ele, const char* face, const char* node, bool bfacelinks, bool btetralinks, bool bfacesfromtetras); /* Create from TetGen .ele, .face, .node data */ static btSoftBody* CreateFromTetGenData( btSoftBodyWorldInfo& worldInfo, const char* ele, const char* face, const char* node, bool bfacelinks, bool btetralinks, bool bfacesfromtetras); }; #endif //SOFT_BODY_HELPERS_H critterding-beta12.1/src/utils/bullet/BulletSoftBody/btSoftBodyHelpers.cpp0000644000175000017500000006500611344267705026002 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ ///btSoftBodyHelpers.cpp by Nathanael Presson #include "btSoftBodyInternals.h" #include #include #include "btSoftBodyHelpers.h" #include "LinearMath/btConvexHull.h" // static void drawVertex( btIDebugDraw* idraw, const btVector3& x,btScalar s,const btVector3& c) { idraw->drawLine(x-btVector3(s,0,0),x+btVector3(s,0,0),c); idraw->drawLine(x-btVector3(0,s,0),x+btVector3(0,s,0),c); idraw->drawLine(x-btVector3(0,0,s),x+btVector3(0,0,s),c); } // static void drawBox( btIDebugDraw* idraw, const btVector3& mins, const btVector3& maxs, const btVector3& color) { const btVector3 c[]={ btVector3(mins.x(),mins.y(),mins.z()), btVector3(maxs.x(),mins.y(),mins.z()), btVector3(maxs.x(),maxs.y(),mins.z()), btVector3(mins.x(),maxs.y(),mins.z()), btVector3(mins.x(),mins.y(),maxs.z()), btVector3(maxs.x(),mins.y(),maxs.z()), btVector3(maxs.x(),maxs.y(),maxs.z()), btVector3(mins.x(),maxs.y(),maxs.z())}; idraw->drawLine(c[0],c[1],color);idraw->drawLine(c[1],c[2],color); idraw->drawLine(c[2],c[3],color);idraw->drawLine(c[3],c[0],color); idraw->drawLine(c[4],c[5],color);idraw->drawLine(c[5],c[6],color); idraw->drawLine(c[6],c[7],color);idraw->drawLine(c[7],c[4],color); idraw->drawLine(c[0],c[4],color);idraw->drawLine(c[1],c[5],color); idraw->drawLine(c[2],c[6],color);idraw->drawLine(c[3],c[7],color); } // static void drawTree( btIDebugDraw* idraw, const btDbvtNode* node, int depth, const btVector3& ncolor, const btVector3& lcolor, int mindepth, int maxdepth) { if(node) { if(node->isinternal()&&((depthchilds[0],depth+1,ncolor,lcolor,mindepth,maxdepth); drawTree(idraw,node->childs[1],depth+1,ncolor,lcolor,mindepth,maxdepth); } if(depth>=mindepth) { const btScalar scl=(btScalar)(node->isinternal()?1:1); const btVector3 mi=node->volume.Center()-node->volume.Extents()*scl; const btVector3 mx=node->volume.Center()+node->volume.Extents()*scl; drawBox(idraw,mi,mx,node->isleaf()?lcolor:ncolor); } } } // template static inline T sum(const btAlignedObjectArray& items) { T v; if(items.size()) { v=items[0]; for(int i=1,ni=items.size();i static inline void add(btAlignedObjectArray& items,const Q& value) { for(int i=0,ni=items.size();i static inline void mul(btAlignedObjectArray& items,const Q& value) { for(int i=0,ni=items.size();i static inline T average(const btAlignedObjectArray& items) { const btScalar n=(btScalar)(items.size()>0?items.size():1); return(sum(items)/n); } // static inline btScalar tetravolume(const btVector3& x0, const btVector3& x1, const btVector3& x2, const btVector3& x3) { const btVector3 a=x1-x0; const btVector3 b=x2-x0; const btVector3 c=x3-x0; return(btDot(a,btCross(b,c))); } // #if 0 static btVector3 stresscolor(btScalar stress) { static const btVector3 spectrum[]= { btVector3(1,0,1), btVector3(0,0,1), btVector3(0,1,1), btVector3(0,1,0), btVector3(1,1,0), btVector3(1,0,0), btVector3(1,0,0)}; static const int ncolors=sizeof(spectrum)/sizeof(spectrum[0])-1; static const btScalar one=1; stress=btMax(0,btMin(1,stress))*ncolors; const int sel=(int)stress; const btScalar frc=stress-sel; return(spectrum[sel]+(spectrum[sel+1]-spectrum[sel])*frc); } #endif // void btSoftBodyHelpers::Draw( btSoftBody* psb, btIDebugDraw* idraw, int drawflags) { const btScalar scl=(btScalar)0.1; const btScalar nscl=scl*5; const btVector3 lcolor=btVector3(0,0,0); const btVector3 ncolor=btVector3(1,1,1); const btVector3 ccolor=btVector3(1,0,0); int i,j,nj; /* Nodes */ if(0!=(drawflags&fDrawFlags::Nodes)) { for(i=0;im_nodes.size();++i) { const btSoftBody::Node& n=psb->m_nodes[i]; if(0==(n.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue; idraw->drawLine(n.m_x-btVector3(scl,0,0),n.m_x+btVector3(scl,0,0),btVector3(1,0,0)); idraw->drawLine(n.m_x-btVector3(0,scl,0),n.m_x+btVector3(0,scl,0),btVector3(0,1,0)); idraw->drawLine(n.m_x-btVector3(0,0,scl),n.m_x+btVector3(0,0,scl),btVector3(0,0,1)); } } /* Links */ if(0!=(drawflags&fDrawFlags::Links)) { for(i=0;im_links.size();++i) { const btSoftBody::Link& l=psb->m_links[i]; if(0==(l.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue; idraw->drawLine(l.m_n[0]->m_x,l.m_n[1]->m_x,lcolor); } } /* Normals */ if(0!=(drawflags&fDrawFlags::Normals)) { for(i=0;im_nodes.size();++i) { const btSoftBody::Node& n=psb->m_nodes[i]; if(0==(n.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue; const btVector3 d=n.m_n*nscl; idraw->drawLine(n.m_x,n.m_x+d,ncolor); idraw->drawLine(n.m_x,n.m_x-d,ncolor*0.5); } } /* Contacts */ if(0!=(drawflags&fDrawFlags::Contacts)) { static const btVector3 axis[]={btVector3(1,0,0), btVector3(0,1,0), btVector3(0,0,1)}; for(i=0;im_rcontacts.size();++i) { const btSoftBody::RContact& c=psb->m_rcontacts[i]; const btVector3 o= c.m_node->m_x-c.m_cti.m_normal* (btDot(c.m_node->m_x,c.m_cti.m_normal)+c.m_cti.m_offset); const btVector3 x=btCross(c.m_cti.m_normal,axis[c.m_cti.m_normal.minAxis()]).normalized(); const btVector3 y=btCross(x,c.m_cti.m_normal).normalized(); idraw->drawLine(o-x*nscl,o+x*nscl,ccolor); idraw->drawLine(o-y*nscl,o+y*nscl,ccolor); idraw->drawLine(o,o+c.m_cti.m_normal*nscl*3,btVector3(1,1,0)); } } /* Anchors */ if(0!=(drawflags&fDrawFlags::Anchors)) { for(i=0;im_anchors.size();++i) { const btSoftBody::Anchor& a=psb->m_anchors[i]; const btVector3 q=a.m_body->getWorldTransform()*a.m_local; drawVertex(idraw,a.m_node->m_x,0.25,btVector3(1,0,0)); drawVertex(idraw,q,0.25,btVector3(0,1,0)); idraw->drawLine(a.m_node->m_x,q,btVector3(1,1,1)); } for(i=0;im_nodes.size();++i) { const btSoftBody::Node& n=psb->m_nodes[i]; if(0==(n.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue; if(n.m_im<=0) { drawVertex(idraw,n.m_x,0.25,btVector3(1,0,0)); } } } /* Faces */ if(0!=(drawflags&fDrawFlags::Faces)) { const btScalar scl=(btScalar)0.8; const btScalar alp=(btScalar)1; const btVector3 col(0,(btScalar)0.7,0); for(i=0;im_faces.size();++i) { const btSoftBody::Face& f=psb->m_faces[i]; if(0==(f.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue; const btVector3 x[]={f.m_n[0]->m_x,f.m_n[1]->m_x,f.m_n[2]->m_x}; const btVector3 c=(x[0]+x[1]+x[2])/3; idraw->drawTriangle((x[0]-c)*scl+c, (x[1]-c)*scl+c, (x[2]-c)*scl+c, col,alp); } } /* Clusters */ if(0!=(drawflags&fDrawFlags::Clusters)) { srand(1806); for(i=0;im_clusters.size();++i) { if(psb->m_clusters[i]->m_collide) { btVector3 color( rand()/(btScalar)RAND_MAX, rand()/(btScalar)RAND_MAX, rand()/(btScalar)RAND_MAX); color=color.normalized()*0.75; btAlignedObjectArray vertices; vertices.resize(psb->m_clusters[i]->m_nodes.size()); for(j=0,nj=vertices.size();jm_clusters[i]->m_nodes[j]->m_x; } HullDesc hdsc(QF_TRIANGLES,vertices.size(),&vertices[0]); HullResult hres; HullLibrary hlib; hdsc.mMaxVertices=vertices.size(); hlib.CreateConvexHull(hdsc,hres); const btVector3 center=average(hres.m_OutputVertices); add(hres.m_OutputVertices,-center); mul(hres.m_OutputVertices,(btScalar)1); add(hres.m_OutputVertices,center); for(j=0;j<(int)hres.mNumFaces;++j) { const int idx[]={hres.m_Indices[j*3+0],hres.m_Indices[j*3+1],hres.m_Indices[j*3+2]}; idraw->drawTriangle(hres.m_OutputVertices[idx[0]], hres.m_OutputVertices[idx[1]], hres.m_OutputVertices[idx[2]], color,1); } hlib.ReleaseResult(hres); } /* Velocities */ #if 0 for(int j=0;jm_clusters[i].m_nodes.size();++j) { const btSoftBody::Cluster& c=psb->m_clusters[i]; const btVector3 r=c.m_nodes[j]->m_x-c.m_com; const btVector3 v=c.m_lv+btCross(c.m_av,r); idraw->drawLine(c.m_nodes[j]->m_x,c.m_nodes[j]->m_x+v,btVector3(1,0,0)); } #endif /* Frame */ btSoftBody::Cluster& c=*psb->m_clusters[i]; idraw->drawLine(c.m_com,c.m_framexform*btVector3(10,0,0),btVector3(1,0,0)); idraw->drawLine(c.m_com,c.m_framexform*btVector3(0,10,0),btVector3(0,1,0)); idraw->drawLine(c.m_com,c.m_framexform*btVector3(0,0,10),btVector3(0,0,1)); } } /* Tetras */ if(0!=(drawflags&fDrawFlags::Tetras)) { const btScalar scl=(btScalar)0.8; const btScalar alp=(btScalar)1; const btVector3 col((btScalar)0.7,(btScalar)0.7,(btScalar)0.7); for(int i=0;im_tetras.size();++i) { const btSoftBody::Tetra& t=psb->m_tetras[i]; if(0==(t.m_material->m_flags&btSoftBody::fMaterial::DebugDraw)) continue; const btVector3 x[]={t.m_n[0]->m_x,t.m_n[1]->m_x,t.m_n[2]->m_x,t.m_n[3]->m_x}; const btVector3 c=(x[0]+x[1]+x[2]+x[3])/4; idraw->drawTriangle((x[0]-c)*scl+c,(x[1]-c)*scl+c,(x[2]-c)*scl+c,col,alp); idraw->drawTriangle((x[0]-c)*scl+c,(x[1]-c)*scl+c,(x[3]-c)*scl+c,col,alp); idraw->drawTriangle((x[1]-c)*scl+c,(x[2]-c)*scl+c,(x[3]-c)*scl+c,col,alp); idraw->drawTriangle((x[2]-c)*scl+c,(x[0]-c)*scl+c,(x[3]-c)*scl+c,col,alp); } } /* Notes */ if(0!=(drawflags&fDrawFlags::Notes)) { for(i=0;im_notes.size();++i) { const btSoftBody::Note& n=psb->m_notes[i]; btVector3 p=n.m_offset; for(int j=0;jm_x*n.m_coords[j]; } idraw->draw3dText(p,n.m_text); } } /* Node tree */ if(0!=(drawflags&fDrawFlags::NodeTree)) DrawNodeTree(psb,idraw); /* Face tree */ if(0!=(drawflags&fDrawFlags::FaceTree)) DrawFaceTree(psb,idraw); /* Cluster tree */ if(0!=(drawflags&fDrawFlags::ClusterTree)) DrawClusterTree(psb,idraw); /* Joints */ if(0!=(drawflags&fDrawFlags::Joints)) { for(i=0;im_joints.size();++i) { const btSoftBody::Joint* pj=psb->m_joints[i]; switch(pj->Type()) { case btSoftBody::Joint::eType::Linear: { const btSoftBody::LJoint* pjl=(const btSoftBody::LJoint*)pj; const btVector3 a0=pj->m_bodies[0].xform()*pjl->m_refs[0]; const btVector3 a1=pj->m_bodies[1].xform()*pjl->m_refs[1]; idraw->drawLine(pj->m_bodies[0].xform().getOrigin(),a0,btVector3(1,1,0)); idraw->drawLine(pj->m_bodies[1].xform().getOrigin(),a1,btVector3(0,1,1)); drawVertex(idraw,a0,0.25,btVector3(1,1,0)); drawVertex(idraw,a1,0.25,btVector3(0,1,1)); } break; case btSoftBody::Joint::eType::Angular: { //const btSoftBody::AJoint* pja=(const btSoftBody::AJoint*)pj; const btVector3 o0=pj->m_bodies[0].xform().getOrigin(); const btVector3 o1=pj->m_bodies[1].xform().getOrigin(); const btVector3 a0=pj->m_bodies[0].xform().getBasis()*pj->m_refs[0]; const btVector3 a1=pj->m_bodies[1].xform().getBasis()*pj->m_refs[1]; idraw->drawLine(o0,o0+a0*10,btVector3(1,1,0)); idraw->drawLine(o0,o0+a1*10,btVector3(1,1,0)); idraw->drawLine(o1,o1+a0*10,btVector3(0,1,1)); idraw->drawLine(o1,o1+a1*10,btVector3(0,1,1)); break; } default: { } } } } } // void btSoftBodyHelpers::DrawInfos( btSoftBody* psb, btIDebugDraw* idraw, bool masses, bool areas, bool /*stress*/) { for(int i=0;im_nodes.size();++i) { const btSoftBody::Node& n=psb->m_nodes[i]; char text[2048]={0}; char buff[1024]; if(masses) { sprintf(buff," M(%.2f)",1/n.m_im); strcat(text,buff); } if(areas) { sprintf(buff," A(%.2f)",n.m_area); strcat(text,buff); } if(text[0]) idraw->draw3dText(n.m_x,text); } } // void btSoftBodyHelpers::DrawNodeTree( btSoftBody* psb, btIDebugDraw* idraw, int mindepth, int maxdepth) { drawTree(idraw,psb->m_ndbvt.m_root,0,btVector3(1,0,1),btVector3(1,1,1),mindepth,maxdepth); } // void btSoftBodyHelpers::DrawFaceTree( btSoftBody* psb, btIDebugDraw* idraw, int mindepth, int maxdepth) { drawTree(idraw,psb->m_fdbvt.m_root,0,btVector3(0,1,0),btVector3(1,0,0),mindepth,maxdepth); } // void btSoftBodyHelpers::DrawClusterTree( btSoftBody* psb, btIDebugDraw* idraw, int mindepth, int maxdepth) { drawTree(idraw,psb->m_cdbvt.m_root,0,btVector3(0,1,1),btVector3(1,0,0),mindepth,maxdepth); } // void btSoftBodyHelpers::DrawFrame( btSoftBody* psb, btIDebugDraw* idraw) { if(psb->m_pose.m_bframe) { static const btScalar ascl=10; static const btScalar nscl=(btScalar)0.1; const btVector3 com=psb->m_pose.m_com; const btMatrix3x3 trs=psb->m_pose.m_rot*psb->m_pose.m_scl; const btVector3 Xaxis=(trs*btVector3(1,0,0)).normalized(); const btVector3 Yaxis=(trs*btVector3(0,1,0)).normalized(); const btVector3 Zaxis=(trs*btVector3(0,0,1)).normalized(); idraw->drawLine(com,com+Xaxis*ascl,btVector3(1,0,0)); idraw->drawLine(com,com+Yaxis*ascl,btVector3(0,1,0)); idraw->drawLine(com,com+Zaxis*ascl,btVector3(0,0,1)); for(int i=0;im_pose.m_pos.size();++i) { const btVector3 x=com+trs*psb->m_pose.m_pos[i]; drawVertex(idraw,x,nscl,btVector3(1,0,1)); } } } // btSoftBody* btSoftBodyHelpers::CreateRope( btSoftBodyWorldInfo& worldInfo, const btVector3& from, const btVector3& to, int res, int fixeds) { /* Create nodes */ const int r=res+2; btVector3* x=new btVector3[r]; btScalar* m=new btScalar[r]; int i; for(i=0;isetMass(0,0); if(fixeds&2) psb->setMass(r-1,0); delete[] x; delete[] m; /* Create links */ for(i=1;iappendLink(i-1,i); } /* Finished */ return(psb); } // btSoftBody* btSoftBodyHelpers::CreatePatch(btSoftBodyWorldInfo& worldInfo,const btVector3& corner00, const btVector3& corner10, const btVector3& corner01, const btVector3& corner11, int resx, int resy, int fixeds, bool gendiags) { #define IDX(_x_,_y_) ((_y_)*rx+(_x_)) /* Create nodes */ if((resx<2)||(resy<2)) return(0); const int rx=resx; const int ry=resy; const int tot=rx*ry; btVector3* x=new btVector3[tot]; btScalar* m=new btScalar[tot]; int iy; for(iy=0;iysetMass(IDX(0,0),0); if(fixeds&2) psb->setMass(IDX(rx-1,0),0); if(fixeds&4) psb->setMass(IDX(0,ry-1),0); if(fixeds&8) psb->setMass(IDX(rx-1,ry-1),0); delete[] x; delete[] m; /* Create links and faces */ for(iy=0;iyappendLink(idx,IDX(ix+1,iy)); if(mdy) psb->appendLink(idx,IDX(ix,iy+1)); if(mdx&&mdy) { if((ix+iy)&1) { psb->appendFace(IDX(ix,iy),IDX(ix+1,iy),IDX(ix+1,iy+1)); psb->appendFace(IDX(ix,iy),IDX(ix+1,iy+1),IDX(ix,iy+1)); if(gendiags) { psb->appendLink(IDX(ix,iy),IDX(ix+1,iy+1)); } } else { psb->appendFace(IDX(ix,iy+1),IDX(ix,iy),IDX(ix+1,iy)); psb->appendFace(IDX(ix,iy+1),IDX(ix+1,iy),IDX(ix+1,iy+1)); if(gendiags) { psb->appendLink(IDX(ix+1,iy),IDX(ix,iy+1)); } } } } } /* Finished */ #undef IDX return(psb); } // btSoftBody* btSoftBodyHelpers::CreatePatchUV(btSoftBodyWorldInfo& worldInfo, const btVector3& corner00, const btVector3& corner10, const btVector3& corner01, const btVector3& corner11, int resx, int resy, int fixeds, bool gendiags, float* tex_coords) { /* * * corners: * * [0][0] corner00 ------- corner01 [resx][0] * | | * | | * [0][resy] corner10 -------- corner11 [resx][resy] * * * * * * * "fixedgs" map: * * corner00 --> +1 * corner01 --> +2 * corner10 --> +4 * corner11 --> +8 * upper middle --> +16 * left middle --> +32 * right middle --> +64 * lower middle --> +128 * center --> +256 * * * tex_coords size (resx-1)*(resy-1)*12 * * * * SINGLE QUAD INTERNALS * * 1) btSoftBody's nodes and links, * diagonal link is optional ("gendiags") * * * node00 ------ node01 * | . * | . * | . * | . * | . * node10 node11 * * * * 2) Faces: * two triangles, * UV Coordinates (hier example for single quad) * * (0,1) (0,1) (1,1) * 1 |\ 3 \-----| 2 * | \ \ | * | \ \ | * | \ \ | * | \ \ | * 2 |-----\ 3 \| 1 * (0,0) (1,0) (1,0) * * * * * * */ #define IDX(_x_,_y_) ((_y_)*rx+(_x_)) /* Create nodes */ if((resx<2)||(resy<2)) return(0); const int rx=resx; const int ry=resy; const int tot=rx*ry; btVector3* x=new btVector3[tot]; btScalar* m=new btScalar[tot]; int iy; for(iy=0;iysetMass(IDX(0,0),0); if(fixeds&2) psb->setMass(IDX(rx-1,0),0); if(fixeds&4) psb->setMass(IDX(0,ry-1),0); if(fixeds&8) psb->setMass(IDX(rx-1,ry-1),0); if(fixeds&16) psb->setMass(IDX((rx-1)/2,0),0); if(fixeds&32) psb->setMass(IDX(0,(ry-1)/2),0); if(fixeds&64) psb->setMass(IDX(rx-1,(ry-1)/2),0); if(fixeds&128) psb->setMass(IDX((rx-1)/2,ry-1),0); if(fixeds&256) psb->setMass(IDX((rx-1)/2,(ry-1)/2),0); delete[] x; delete[] m; int z = 0; /* Create links and faces */ for(iy=0;iyappendLink(node00,node01); if(mdy) psb->appendLink(node00,node10); if(mdx&&mdy) { psb->appendFace(node00,node10,node11); if (tex_coords) { tex_coords[z+0]=CalculateUV(resx,resy,ix,iy,0); tex_coords[z+1]=CalculateUV(resx,resy,ix,iy,1); tex_coords[z+2]=CalculateUV(resx,resy,ix,iy,0); tex_coords[z+3]=CalculateUV(resx,resy,ix,iy,2); tex_coords[z+4]=CalculateUV(resx,resy,ix,iy,3); tex_coords[z+5]=CalculateUV(resx,resy,ix,iy,2); } psb->appendFace(node11,node01,node00); if (tex_coords) { tex_coords[z+6 ]=CalculateUV(resx,resy,ix,iy,3); tex_coords[z+7 ]=CalculateUV(resx,resy,ix,iy,2); tex_coords[z+8 ]=CalculateUV(resx,resy,ix,iy,3); tex_coords[z+9 ]=CalculateUV(resx,resy,ix,iy,1); tex_coords[z+10]=CalculateUV(resx,resy,ix,iy,0); tex_coords[z+11]=CalculateUV(resx,resy,ix,iy,1); } if (gendiags) psb->appendLink(node00,node11); z += 12; } } } /* Finished */ #undef IDX return(psb); } float btSoftBodyHelpers::CalculateUV(int resx,int resy,int ix,int iy,int id) { /* * * * node00 --- node01 * | | * node10 --- node11 * * * ID map: * * node00 s --> 0 * node00 t --> 1 * * node01 s --> 3 * node01 t --> 1 * * node10 s --> 0 * node10 t --> 2 * * node11 s --> 3 * node11 t --> 2 * * */ float tc=0.0f; if (id == 0) { tc = (1.0f/((resx-1))*ix); } else if (id==1) { tc = (1.0f/((resy-1))*(resy-1-iy)); } else if (id==2) { tc = (1.0f/((resy-1))*(resy-1-iy-1)); } else if (id==3) { tc = (1.0f/((resx-1))*(ix+1)); } return tc; } // btSoftBody* btSoftBodyHelpers::CreateEllipsoid(btSoftBodyWorldInfo& worldInfo,const btVector3& center, const btVector3& radius, int res) { struct Hammersley { static void Generate(btVector3* x,int n) { for(int i=0;i>=1) if(j&1) t+=p; btScalar w=2*t-1; btScalar a=(SIMD_PI+2*i*SIMD_PI)/n; btScalar s=btSqrt(1-w*w); *x++=btVector3(s*btCos(a),s*btSin(a),w); } } }; btAlignedObjectArray vtx; vtx.resize(3+res); Hammersley::Generate(&vtx[0],vtx.size()); for(int i=0;i chks; btAlignedObjectArray vtx; chks.resize(maxidx*maxidx,false); vtx.resize(maxidx); for(i=0,j=0,ni=maxidx*3;iappendLink(idx[j],idx[k]); } } #undef IDX psb->appendFace(idx[0],idx[1],idx[2]); } if (randomizeConstraints) { psb->randomizeConstraints(); } return(psb); } // btSoftBody* btSoftBodyHelpers::CreateFromConvexHull(btSoftBodyWorldInfo& worldInfo, const btVector3* vertices, int nvertices, bool randomizeConstraints) { HullDesc hdsc(QF_TRIANGLES,nvertices,vertices); HullResult hres; HullLibrary hlib;/*??*/ hdsc.mMaxVertices=nvertices; hlib.CreateConvexHull(hdsc,hres); btSoftBody* psb=new btSoftBody(&worldInfo,(int)hres.mNumOutputVertices, &hres.m_OutputVertices[0],0); for(int i=0;i<(int)hres.mNumFaces;++i) { const int idx[]={ hres.m_Indices[i*3+0], hres.m_Indices[i*3+1], hres.m_Indices[i*3+2]}; if(idx[0]appendLink( idx[0],idx[1]); if(idx[1]appendLink( idx[1],idx[2]); if(idx[2]appendLink( idx[2],idx[0]); psb->appendFace(idx[0],idx[1],idx[2]); } hlib.ReleaseResult(hres); if (randomizeConstraints) { psb->randomizeConstraints(); } return(psb); } static int nextLine(const char* buffer) { int numBytesRead=0; while (*buffer != '\n') { buffer++; numBytesRead++; } if (buffer[0]==0x0a) { buffer++; numBytesRead++; } return numBytesRead; } /* Create from TetGen .ele, .face, .node data */ btSoftBody* btSoftBodyHelpers::CreateFromTetGenData(btSoftBodyWorldInfo& worldInfo, const char* ele, const char* face, const char* node, bool bfacelinks, bool btetralinks, bool bfacesfromtetras) { btAlignedObjectArray pos; int nnode=0; int ndims=0; int nattrb=0; int hasbounds=0; int result = sscanf(node,"%d %d %d %d",&nnode,&ndims,&nattrb,&hasbounds); result = sscanf(node,"%d %d %d %d",&nnode,&ndims,&nattrb,&hasbounds); node += nextLine(node); pos.resize(nnode); for(int i=0;i>index; // sn>>x;sn>>y;sn>>z; node += nextLine(node); //for(int j=0;j>a; //if(hasbounds) // sn>>bound; pos[index].setX(btScalar(x)); pos[index].setY(btScalar(y)); pos[index].setZ(btScalar(z)); } btSoftBody* psb=new btSoftBody(&worldInfo,nnode,&pos[0],0); #if 0 if(face&&face[0]) { int nface=0; sf>>nface;sf>>hasbounds; for(int i=0;i>index; sf>>ni[0];sf>>ni[1];sf>>ni[2]; sf>>bound; psb->appendFace(ni[0],ni[1],ni[2]); if(btetralinks) { psb->appendLink(ni[0],ni[1],0,true); psb->appendLink(ni[1],ni[2],0,true); psb->appendLink(ni[2],ni[0],0,true); } } } #endif if(ele&&ele[0]) { int ntetra=0; int ncorner=0; int neattrb=0; sscanf(ele,"%d %d %d",&ntetra,&ncorner,&neattrb); ele += nextLine(ele); //se>>ntetra;se>>ncorner;se>>neattrb; for(int i=0;i>index; //se>>ni[0];se>>ni[1];se>>ni[2];se>>ni[3]; sscanf(ele,"%d %d %d %d %d",&index,&ni[0],&ni[1],&ni[2],&ni[3]); ele+=nextLine(ele); //for(int j=0;j>a; psb->appendTetra(ni[0],ni[1],ni[2],ni[3]); if(btetralinks) { psb->appendLink(ni[0],ni[1],0,true); psb->appendLink(ni[1],ni[2],0,true); psb->appendLink(ni[2],ni[0],0,true); psb->appendLink(ni[0],ni[3],0,true); psb->appendLink(ni[1],ni[3],0,true); psb->appendLink(ni[2],ni[3],0,true); } } } printf("Nodes: %u\r\n",psb->m_nodes.size()); printf("Links: %u\r\n",psb->m_links.size()); printf("Faces: %u\r\n",psb->m_faces.size()); printf("Tetras: %u\r\n",psb->m_tetras.size()); return(psb); } critterding-beta12.1/src/utils/bullet/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.cpp0000644000175000017500000003103311344267705031472 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btSoftBodyConcaveCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionShapes/btMultiSphereShape.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/CollisionShapes/btConcaveShape.h" #include "BulletCollision/CollisionDispatch/btManifoldResult.h" #include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h" #include "BulletCollision/CollisionShapes/btTriangleShape.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" #include "BulletCollision/CollisionShapes/btTetrahedronShape.h" #include "BulletCollision/CollisionShapes/btConvexHullShape.h" #include "LinearMath/btIDebugDraw.h" #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" #include "BulletSoftBody/btSoftBody.h" #define BT_SOFTBODY_TRIANGLE_EXTRUSION btScalar(0.06)//make this configurable btSoftBodyConcaveCollisionAlgorithm::btSoftBodyConcaveCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1,bool isSwapped) : btCollisionAlgorithm(ci), m_isSwapped(isSwapped), m_btSoftBodyTriangleCallback(ci.m_dispatcher1,body0,body1,isSwapped) { } btSoftBodyConcaveCollisionAlgorithm::~btSoftBodyConcaveCollisionAlgorithm() { } btSoftBodyTriangleCallback::btSoftBodyTriangleCallback(btDispatcher* dispatcher,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped): m_dispatcher(dispatcher), m_dispatchInfoPtr(0) { m_softBody = (btSoftBody*) (isSwapped? body1:body0); m_triBody = isSwapped? body0:body1; // // create the manifold from the dispatcher 'manifold pool' // // m_manifoldPtr = m_dispatcher->getNewManifold(m_convexBody,m_triBody); clearCache(); } btSoftBodyTriangleCallback::~btSoftBodyTriangleCallback() { clearCache(); // m_dispatcher->releaseManifold( m_manifoldPtr ); } void btSoftBodyTriangleCallback::clearCache() { for (int i=0;im_childShape); m_softBody->getWorldInfo()->m_sparsesdf.RemoveReferences(tmp->m_childShape);//necessary? delete tmp->m_childShape; } m_shapeCache.clear(); } void btSoftBodyTriangleCallback::processTriangle(btVector3* triangle,int partId, int triangleIndex) { //just for debugging purposes //printf("triangle %d",m_triangleCount++); btCollisionObject* ob = static_cast(m_triBody); btCollisionAlgorithmConstructionInfo ci; ci.m_dispatcher1 = m_dispatcher; ///debug drawing of the overlapping triangles if (m_dispatchInfoPtr && m_dispatchInfoPtr->m_debugDraw && m_dispatchInfoPtr->m_debugDraw->getDebugMode() &btIDebugDraw::DBG_DrawWireframe) { btVector3 color(1,1,0); btTransform& tr = ob->getWorldTransform(); m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[0]),tr(triangle[1]),color); m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[1]),tr(triangle[2]),color); m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[2]),tr(triangle[0]),color); } btTriIndex triIndex(partId,triangleIndex,0); btHashKey triKey(triIndex.getUid()); btTriIndex* shapeIndex = m_shapeCache[triKey]; if (shapeIndex) { btCollisionShape* tm = shapeIndex->m_childShape; btAssert(tm); //copy over user pointers to temporary shape tm->setUserPointer(ob->getRootCollisionShape()->getUserPointer()); btCollisionShape* tmpShape = ob->getCollisionShape(); ob->internalSetTemporaryCollisionShape( tm ); btCollisionAlgorithm* colAlgo = ci.m_dispatcher1->findAlgorithm(m_softBody,m_triBody,0);//m_manifoldPtr); colAlgo->processCollision(m_softBody,m_triBody,*m_dispatchInfoPtr,m_resultOut); colAlgo->~btCollisionAlgorithm(); ci.m_dispatcher1->freeCollisionAlgorithm(colAlgo); ob->internalSetTemporaryCollisionShape( tmpShape); return; } //aabb filter is already applied! //btCollisionObject* colObj = static_cast(m_convexProxy->m_clientObject); // if (m_softBody->getCollisionShape()->getShapeType()== { // btVector3 other; btVector3 normal = (triangle[1]-triangle[0]).cross(triangle[2]-triangle[0]); normal.normalize(); normal*= BT_SOFTBODY_TRIANGLE_EXTRUSION; // other=(triangle[0]+triangle[1]+triangle[2])*0.333333f; // other+=normal*22.f; btVector3 pts[6] = {triangle[0]+normal, triangle[1]+normal, triangle[2]+normal, triangle[0]-normal, triangle[1]-normal, triangle[2]-normal}; btConvexHullShape* tm = new btConvexHullShape(&pts[0].getX(),6); // btBU_Simplex1to4 tm(triangle[0],triangle[1],triangle[2],other); //btTriangleShape tm(triangle[0],triangle[1],triangle[2]); // tm.setMargin(m_collisionMarginTriangle); //copy over user pointers to temporary shape tm->setUserPointer(ob->getRootCollisionShape()->getUserPointer()); btCollisionShape* tmpShape = ob->getCollisionShape(); ob->internalSetTemporaryCollisionShape( tm ); btCollisionAlgorithm* colAlgo = ci.m_dispatcher1->findAlgorithm(m_softBody,m_triBody,0);//m_manifoldPtr); ///this should use the btDispatcher, so the actual registered algorithm is used // btConvexConvexAlgorithm cvxcvxalgo(m_manifoldPtr,ci,m_convexBody,m_triBody); //m_resultOut->setShapeIdentifiersB(partId,triangleIndex); // cvxcvxalgo.processCollision(m_convexBody,m_triBody,*m_dispatchInfoPtr,m_resultOut); colAlgo->processCollision(m_softBody,m_triBody,*m_dispatchInfoPtr,m_resultOut); colAlgo->~btCollisionAlgorithm(); ci.m_dispatcher1->freeCollisionAlgorithm(colAlgo); ob->internalSetTemporaryCollisionShape( tmpShape ); triIndex.m_childShape = tm; m_shapeCache.insert(triKey,triIndex); } } void btSoftBodyTriangleCallback::setTimeStepAndCounters(btScalar collisionMarginTriangle,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { m_dispatchInfoPtr = &dispatchInfo; m_collisionMarginTriangle = collisionMarginTriangle+btScalar(BT_SOFTBODY_TRIANGLE_EXTRUSION); m_resultOut = resultOut; btVector3 aabbWorldSpaceMin,aabbWorldSpaceMax; m_softBody->getAabb(aabbWorldSpaceMin,aabbWorldSpaceMax); btVector3 halfExtents = (aabbWorldSpaceMax-aabbWorldSpaceMin)*btScalar(0.5); btVector3 softBodyCenter = (aabbWorldSpaceMax+aabbWorldSpaceMin)*btScalar(0.5); btTransform softTransform; softTransform.setIdentity(); softTransform.setOrigin(softBodyCenter); btTransform convexInTriangleSpace; convexInTriangleSpace = m_triBody->getWorldTransform().inverse() * softTransform; btTransformAabb(halfExtents,m_collisionMarginTriangle,convexInTriangleSpace,m_aabbMin,m_aabbMax); } void btSoftBodyConcaveCollisionAlgorithm::clearCache() { m_btSoftBodyTriangleCallback.clearCache(); } void btSoftBodyConcaveCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { //btCollisionObject* convexBody = m_isSwapped ? body1 : body0; btCollisionObject* triBody = m_isSwapped ? body0 : body1; if (triBody->getCollisionShape()->isConcave()) { btCollisionObject* triOb = triBody; btConcaveShape* concaveShape = static_cast( triOb->getCollisionShape()); // if (convexBody->getCollisionShape()->isConvex()) { btScalar collisionMarginTriangle = concaveShape->getMargin(); // resultOut->setPersistentManifold(m_btSoftBodyTriangleCallback.m_manifoldPtr); m_btSoftBodyTriangleCallback.setTimeStepAndCounters(collisionMarginTriangle,dispatchInfo,resultOut); //Disable persistency. previously, some older algorithm calculated all contacts in one go, so you can clear it here. //m_dispatcher->clearManifold(m_btSoftBodyTriangleCallback.m_manifoldPtr); // m_btSoftBodyTriangleCallback.m_manifoldPtr->setBodies(convexBody,triBody); concaveShape->processAllTriangles( &m_btSoftBodyTriangleCallback,m_btSoftBodyTriangleCallback.getAabbMin(),m_btSoftBodyTriangleCallback.getAabbMax()); // resultOut->refreshContactPoints(); } } } btScalar btSoftBodyConcaveCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { (void)resultOut; (void)dispatchInfo; btCollisionObject* convexbody = m_isSwapped ? body1 : body0; btCollisionObject* triBody = m_isSwapped ? body0 : body1; //quick approximation using raycast, todo: hook up to the continuous collision detection (one of the btConvexCast) //only perform CCD above a certain threshold, this prevents blocking on the long run //because object in a blocked ccd state (hitfraction<1) get their linear velocity halved each frame... btScalar squareMot0 = (convexbody->getInterpolationWorldTransform().getOrigin() - convexbody->getWorldTransform().getOrigin()).length2(); if (squareMot0 < convexbody->getCcdSquareMotionThreshold()) { return btScalar(1.); } //const btVector3& from = convexbody->m_worldTransform.getOrigin(); //btVector3 to = convexbody->m_interpolationWorldTransform.getOrigin(); //todo: only do if the motion exceeds the 'radius' btTransform triInv = triBody->getWorldTransform().inverse(); btTransform convexFromLocal = triInv * convexbody->getWorldTransform(); btTransform convexToLocal = triInv * convexbody->getInterpolationWorldTransform(); struct LocalTriangleSphereCastCallback : public btTriangleCallback { btTransform m_ccdSphereFromTrans; btTransform m_ccdSphereToTrans; btTransform m_meshTransform; btScalar m_ccdSphereRadius; btScalar m_hitFraction; LocalTriangleSphereCastCallback(const btTransform& from,const btTransform& to,btScalar ccdSphereRadius,btScalar hitFraction) :m_ccdSphereFromTrans(from), m_ccdSphereToTrans(to), m_ccdSphereRadius(ccdSphereRadius), m_hitFraction(hitFraction) { } virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex) { (void)partId; (void)triangleIndex; //do a swept sphere for now btTransform ident; ident.setIdentity(); btConvexCast::CastResult castResult; castResult.m_fraction = m_hitFraction; btSphereShape pointShape(m_ccdSphereRadius); btTriangleShape triShape(triangle[0],triangle[1],triangle[2]); btVoronoiSimplexSolver simplexSolver; btSubsimplexConvexCast convexCaster(&pointShape,&triShape,&simplexSolver); //GjkConvexCast convexCaster(&pointShape,convexShape,&simplexSolver); //ContinuousConvexCollision convexCaster(&pointShape,convexShape,&simplexSolver,0); //local space? if (convexCaster.calcTimeOfImpact(m_ccdSphereFromTrans,m_ccdSphereToTrans, ident,ident,castResult)) { if (m_hitFraction > castResult.m_fraction) m_hitFraction = castResult.m_fraction; } } }; if (triBody->getCollisionShape()->isConcave()) { btVector3 rayAabbMin = convexFromLocal.getOrigin(); rayAabbMin.setMin(convexToLocal.getOrigin()); btVector3 rayAabbMax = convexFromLocal.getOrigin(); rayAabbMax.setMax(convexToLocal.getOrigin()); btScalar ccdRadius0 = convexbody->getCcdSweptSphereRadius(); rayAabbMin -= btVector3(ccdRadius0,ccdRadius0,ccdRadius0); rayAabbMax += btVector3(ccdRadius0,ccdRadius0,ccdRadius0); btScalar curHitFraction = btScalar(1.); //is this available? LocalTriangleSphereCastCallback raycastCallback(convexFromLocal,convexToLocal, convexbody->getCcdSweptSphereRadius(),curHitFraction); raycastCallback.m_hitFraction = convexbody->getHitFraction(); btCollisionObject* concavebody = triBody; btConcaveShape* triangleMesh = (btConcaveShape*) concavebody->getCollisionShape(); if (triangleMesh) { triangleMesh->processAllTriangles(&raycastCallback,rayAabbMin,rayAabbMax); } if (raycastCallback.m_hitFraction < convexbody->getHitFraction()) { convexbody->setHitFraction( raycastCallback.m_hitFraction); return raycastCallback.m_hitFraction; } } return btScalar(1.); } critterding-beta12.1/src/utils/bullet/BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.cpp0000644000175000017500000001245111337071441032644 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btSoftBodyRigidBodyCollisionConfiguration.h" #include "btSoftRigidCollisionAlgorithm.h" #include "btSoftBodyConcaveCollisionAlgorithm.h" #include "btSoftSoftCollisionAlgorithm.h" #include "LinearMath/btPoolAllocator.h" #define ENABLE_SOFTBODY_CONCAVE_COLLISIONS 1 btSoftBodyRigidBodyCollisionConfiguration::btSoftBodyRigidBodyCollisionConfiguration(const btDefaultCollisionConstructionInfo& constructionInfo) :btDefaultCollisionConfiguration(constructionInfo) { void* mem; mem = btAlignedAlloc(sizeof(btSoftSoftCollisionAlgorithm::CreateFunc),16); m_softSoftCreateFunc = new(mem) btSoftSoftCollisionAlgorithm::CreateFunc; mem = btAlignedAlloc(sizeof(btSoftRigidCollisionAlgorithm::CreateFunc),16); m_softRigidConvexCreateFunc = new(mem) btSoftRigidCollisionAlgorithm::CreateFunc; mem = btAlignedAlloc(sizeof(btSoftRigidCollisionAlgorithm::CreateFunc),16); m_swappedSoftRigidConvexCreateFunc = new(mem) btSoftRigidCollisionAlgorithm::CreateFunc; m_swappedSoftRigidConvexCreateFunc->m_swapped=true; #ifdef ENABLE_SOFTBODY_CONCAVE_COLLISIONS mem = btAlignedAlloc(sizeof(btSoftBodyConcaveCollisionAlgorithm::CreateFunc),16); m_softRigidConcaveCreateFunc = new(mem) btSoftBodyConcaveCollisionAlgorithm::CreateFunc; mem = btAlignedAlloc(sizeof(btSoftBodyConcaveCollisionAlgorithm::CreateFunc),16); m_swappedSoftRigidConcaveCreateFunc = new(mem) btSoftBodyConcaveCollisionAlgorithm::SwappedCreateFunc; m_swappedSoftRigidConcaveCreateFunc->m_swapped=true; #endif //replace pool by a new one, with potential larger size if (m_ownsCollisionAlgorithmPool && m_collisionAlgorithmPool) { int curElemSize = m_collisionAlgorithmPool->getElementSize(); ///calculate maximum element size, big enough to fit any collision algorithm in the memory pool int maxSize0 = sizeof(btSoftSoftCollisionAlgorithm); int maxSize1 = sizeof(btSoftRigidCollisionAlgorithm); int maxSize2 = sizeof(btSoftBodyConcaveCollisionAlgorithm); int collisionAlgorithmMaxElementSize = btMax(maxSize0,maxSize1); collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize2); if (collisionAlgorithmMaxElementSize > curElemSize) { m_collisionAlgorithmPool->~btPoolAllocator(); btAlignedFree(m_collisionAlgorithmPool); void* mem = btAlignedAlloc(sizeof(btPoolAllocator),16); m_collisionAlgorithmPool = new(mem) btPoolAllocator(collisionAlgorithmMaxElementSize,constructionInfo.m_defaultMaxCollisionAlgorithmPoolSize); } } } btSoftBodyRigidBodyCollisionConfiguration::~btSoftBodyRigidBodyCollisionConfiguration() { m_softSoftCreateFunc->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_softSoftCreateFunc); m_softRigidConvexCreateFunc->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_softRigidConvexCreateFunc); m_swappedSoftRigidConvexCreateFunc->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_swappedSoftRigidConvexCreateFunc); #ifdef ENABLE_SOFTBODY_CONCAVE_COLLISIONS m_softRigidConcaveCreateFunc->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_softRigidConcaveCreateFunc); m_swappedSoftRigidConcaveCreateFunc->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_swappedSoftRigidConcaveCreateFunc); #endif } ///creation of soft-soft and soft-rigid, and otherwise fallback to base class implementation btCollisionAlgorithmCreateFunc* btSoftBodyRigidBodyCollisionConfiguration::getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1) { ///try to handle the softbody interactions first if ((proxyType0 == SOFTBODY_SHAPE_PROXYTYPE ) && (proxyType1==SOFTBODY_SHAPE_PROXYTYPE)) { return m_softSoftCreateFunc; } ///softbody versus convex if (proxyType0 == SOFTBODY_SHAPE_PROXYTYPE && btBroadphaseProxy::isConvex(proxyType1)) { return m_softRigidConvexCreateFunc; } ///convex versus soft body if (btBroadphaseProxy::isConvex(proxyType0) && proxyType1 == SOFTBODY_SHAPE_PROXYTYPE ) { return m_swappedSoftRigidConvexCreateFunc; } #ifdef ENABLE_SOFTBODY_CONCAVE_COLLISIONS ///softbody versus convex if (proxyType0 == SOFTBODY_SHAPE_PROXYTYPE && btBroadphaseProxy::isConcave(proxyType1)) { return m_softRigidConcaveCreateFunc; } ///convex versus soft body if (btBroadphaseProxy::isConcave(proxyType0) && proxyType1 == SOFTBODY_SHAPE_PROXYTYPE ) { return m_swappedSoftRigidConcaveCreateFunc; } #endif ///fallback to the regular rigid collision shape return btDefaultCollisionConfiguration::getCollisionAlgorithmCreateFunc(proxyType0,proxyType1); } critterding-beta12.1/src/utils/bullet/BulletSoftBody/btSoftSoftCollisionAlgorithm.cpp0000644000175000017500000000406511337071441030206 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btSoftSoftCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/CollisionShapes/btBoxShape.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "btSoftBody.h" #define USE_PERSISTENT_CONTACTS 1 btSoftSoftCollisionAlgorithm::btSoftSoftCollisionAlgorithm(btPersistentManifold* /*mf*/,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* /*obj0*/,btCollisionObject* /*obj1*/) : btCollisionAlgorithm(ci) //m_ownManifold(false), //m_manifoldPtr(mf) { } btSoftSoftCollisionAlgorithm::~btSoftSoftCollisionAlgorithm() { } void btSoftSoftCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& /*dispatchInfo*/,btManifoldResult* /*resultOut*/) { btSoftBody* soft0 = (btSoftBody*)body0; btSoftBody* soft1 = (btSoftBody*)body1; soft0->defaultCollisionHandler(soft1); } btScalar btSoftSoftCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* /*body0*/,btCollisionObject* /*body1*/,const btDispatcherInfo& /*dispatchInfo*/,btManifoldResult* /*resultOut*/) { //not yet return 1.f; } critterding-beta12.1/src/utils/bullet/BulletSoftBody/btSoftRigidDynamicsWorld.h0000644000175000017500000000643211344267705026763 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BT_SOFT_RIGID_DYNAMICS_WORLD_H #define BT_SOFT_RIGID_DYNAMICS_WORLD_H #include "BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h" #include "btSoftBody.h" typedef btAlignedObjectArray btSoftBodyArray; class btSoftRigidDynamicsWorld : public btDiscreteDynamicsWorld { btSoftBodyArray m_softBodies; int m_drawFlags; bool m_drawNodeTree; bool m_drawFaceTree; bool m_drawClusterTree; btSoftBodyWorldInfo m_sbi; protected: virtual void predictUnconstraintMotion(btScalar timeStep); virtual void internalSingleStepSimulation( btScalar timeStep); void updateSoftBodies(); void solveSoftBodiesConstraints(); public: btSoftRigidDynamicsWorld(btDispatcher* dispatcher,btBroadphaseInterface* pairCache,btConstraintSolver* constraintSolver,btCollisionConfiguration* collisionConfiguration); virtual ~btSoftRigidDynamicsWorld(); virtual void debugDrawWorld(); void addSoftBody(btSoftBody* body,short int collisionFilterGroup=btBroadphaseProxy::DefaultFilter,short int collisionFilterMask=btBroadphaseProxy::AllFilter); void removeSoftBody(btSoftBody* body); ///removeCollisionObject will first check if it is a rigid body, if so call removeRigidBody otherwise call btDiscreteDynamicsWorld::removeCollisionObject virtual void removeCollisionObject(btCollisionObject* collisionObject); int getDrawFlags() const { return(m_drawFlags); } void setDrawFlags(int f) { m_drawFlags=f; } btSoftBodyWorldInfo& getWorldInfo() { return m_sbi; } const btSoftBodyWorldInfo& getWorldInfo() const { return m_sbi; } btSoftBodyArray& getSoftBodyArray() { return m_softBodies; } const btSoftBodyArray& getSoftBodyArray() const { return m_softBodies; } virtual void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const; /// rayTestSingle performs a raycast call and calls the resultCallback. It is used internally by rayTest. /// In a future implementation, we consider moving the ray test as a virtual method in btCollisionShape. /// This allows more customization. static void rayTestSingle(const btTransform& rayFromTrans,const btTransform& rayToTrans, btCollisionObject* collisionObject, const btCollisionShape* collisionShape, const btTransform& colObjWorldTransform, RayResultCallback& resultCallback); }; #endif //BT_SOFT_RIGID_DYNAMICS_WORLD_H critterding-beta12.1/src/utils/bullet/BulletSoftBody/btSoftBodyInternals.h0000644000175000017500000006023611337071441025774 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ ///btSoftBody implementation by Nathanael Presson #ifndef _BT_SOFT_BODY_INTERNALS_H #define _BT_SOFT_BODY_INTERNALS_H #include "btSoftBody.h" #include "LinearMath/btQuickprof.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/CollisionShapes/btConvexInternalShape.h" #include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h" // // btSymMatrix // template struct btSymMatrix { btSymMatrix() : dim(0) {} btSymMatrix(int n,const T& init=T()) { resize(n,init); } void resize(int n,const T& init=T()) { dim=n;store.resize((n*(n+1))/2,init); } int index(int c,int r) const { if(c>r) btSwap(c,r);btAssert(r store; int dim; }; // // btSoftBodyCollisionShape // class btSoftBodyCollisionShape : public btConcaveShape { public: btSoftBody* m_body; btSoftBodyCollisionShape(btSoftBody* backptr) { m_shapeType = SOFTBODY_SHAPE_PROXYTYPE; m_body=backptr; } virtual ~btSoftBodyCollisionShape() { } void processAllTriangles(btTriangleCallback* /*callback*/,const btVector3& /*aabbMin*/,const btVector3& /*aabbMax*/) const { //not yet btAssert(0); } ///getAabb returns the axis aligned bounding box in the coordinate frame of the given transform t. virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const { /* t should be identity, but better be safe than...fast? */ const btVector3 mins=m_body->m_bounds[0]; const btVector3 maxs=m_body->m_bounds[1]; const btVector3 crns[]={t*btVector3(mins.x(),mins.y(),mins.z()), t*btVector3(maxs.x(),mins.y(),mins.z()), t*btVector3(maxs.x(),maxs.y(),mins.z()), t*btVector3(mins.x(),maxs.y(),mins.z()), t*btVector3(mins.x(),mins.y(),maxs.z()), t*btVector3(maxs.x(),mins.y(),maxs.z()), t*btVector3(maxs.x(),maxs.y(),maxs.z()), t*btVector3(mins.x(),maxs.y(),maxs.z())}; aabbMin=aabbMax=crns[0]; for(int i=1;i<8;++i) { aabbMin.setMin(crns[i]); aabbMax.setMax(crns[i]); } } virtual void setLocalScaling(const btVector3& /*scaling*/) { ///na } virtual const btVector3& getLocalScaling() const { static const btVector3 dummy(1,1,1); return dummy; } virtual void calculateLocalInertia(btScalar /*mass*/,btVector3& /*inertia*/) const { ///not yet btAssert(0); } virtual const char* getName()const { return "SoftBody"; } }; // // btSoftClusterCollisionShape // class btSoftClusterCollisionShape : public btConvexInternalShape { public: const btSoftBody::Cluster* m_cluster; btSoftClusterCollisionShape (const btSoftBody::Cluster* cluster) : m_cluster(cluster) { setMargin(0); } virtual btVector3 localGetSupportingVertex(const btVector3& vec) const { btSoftBody::Node* const * n=&m_cluster->m_nodes[0]; btScalar d=btDot(vec,n[0]->m_x); int j=0; for(int i=1,ni=m_cluster->m_nodes.size();im_x); if(k>d) { d=k;j=i; } } return(n[j]->m_x); } virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const { return(localGetSupportingVertex(vec)); } //notice that the vectors should be unit length virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const {} virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const {} virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const {} virtual int getShapeType() const { return SOFTBODY_SHAPE_PROXYTYPE; } //debugging virtual const char* getName()const {return "SOFTCLUSTER";} virtual void setMargin(btScalar margin) { btConvexInternalShape::setMargin(margin); } virtual btScalar getMargin() const { return getMargin(); } }; // // Inline's // // template static inline void ZeroInitialize(T& value) { static const T zerodummy; value=zerodummy; } // template static inline bool CompLess(const T& a,const T& b) { return(a static inline bool CompGreater(const T& a,const T& b) { return(a>b); } // template static inline T Lerp(const T& a,const T& b,btScalar t) { return(a+(b-a)*t); } // template static inline T InvLerp(const T& a,const T& b,btScalar t) { return((b+a*t-b*t)/(a*b)); } // static inline btMatrix3x3 Lerp( const btMatrix3x3& a, const btMatrix3x3& b, btScalar t) { btMatrix3x3 r; r[0]=Lerp(a[0],b[0],t); r[1]=Lerp(a[1],b[1],t); r[2]=Lerp(a[2],b[2],t); return(r); } // static inline btVector3 Clamp(const btVector3& v,btScalar maxlength) { const btScalar sql=v.length2(); if(sql>(maxlength*maxlength)) return((v*maxlength)/btSqrt(sql)); else return(v); } // template static inline T Clamp(const T& x,const T& l,const T& h) { return(xh?h:x); } // template static inline T Sq(const T& x) { return(x*x); } // template static inline T Cube(const T& x) { return(x*x*x); } // template static inline T Sign(const T& x) { return((T)(x<0?-1:+1)); } // template static inline bool SameSign(const T& x,const T& y) { return((x*y)>0); } // static inline btScalar ClusterMetric(const btVector3& x,const btVector3& y) { const btVector3 d=x-y; return(btFabs(d[0])+btFabs(d[1])+btFabs(d[2])); } // static inline btMatrix3x3 ScaleAlongAxis(const btVector3& a,btScalar s) { const btScalar xx=a.x()*a.x(); const btScalar yy=a.y()*a.y(); const btScalar zz=a.z()*a.z(); const btScalar xy=a.x()*a.y(); const btScalar yz=a.y()*a.z(); const btScalar zx=a.z()*a.x(); btMatrix3x3 m; m[0]=btVector3(1-xx+xx*s,xy*s-xy,zx*s-zx); m[1]=btVector3(xy*s-xy,1-yy+yy*s,yz*s-yz); m[2]=btVector3(zx*s-zx,yz*s-yz,1-zz+zz*s); return(m); } // static inline btMatrix3x3 Cross(const btVector3& v) { btMatrix3x3 m; m[0]=btVector3(0,-v.z(),+v.y()); m[1]=btVector3(+v.z(),0,-v.x()); m[2]=btVector3(-v.y(),+v.x(),0); return(m); } // static inline btMatrix3x3 Diagonal(btScalar x) { btMatrix3x3 m; m[0]=btVector3(x,0,0); m[1]=btVector3(0,x,0); m[2]=btVector3(0,0,x); return(m); } // static inline btMatrix3x3 Add(const btMatrix3x3& a, const btMatrix3x3& b) { btMatrix3x3 r; for(int i=0;i<3;++i) r[i]=a[i]+b[i]; return(r); } // static inline btMatrix3x3 Sub(const btMatrix3x3& a, const btMatrix3x3& b) { btMatrix3x3 r; for(int i=0;i<3;++i) r[i]=a[i]-b[i]; return(r); } // static inline btMatrix3x3 Mul(const btMatrix3x3& a, btScalar b) { btMatrix3x3 r; for(int i=0;i<3;++i) r[i]=a[i]*b; return(r); } // static inline void Orthogonalize(btMatrix3x3& m) { m[2]=btCross(m[0],m[1]).normalized(); m[1]=btCross(m[2],m[0]).normalized(); m[0]=btCross(m[1],m[2]).normalized(); } // static inline btMatrix3x3 MassMatrix(btScalar im,const btMatrix3x3& iwi,const btVector3& r) { const btMatrix3x3 cr=Cross(r); return(Sub(Diagonal(im),cr*iwi*cr)); } // static inline btMatrix3x3 ImpulseMatrix( btScalar dt, btScalar ima, btScalar imb, const btMatrix3x3& iwi, const btVector3& r) { return(Diagonal(1/dt)*Add(Diagonal(ima),MassMatrix(imb,iwi,r)).inverse()); } // static inline btMatrix3x3 ImpulseMatrix( btScalar ima,const btMatrix3x3& iia,const btVector3& ra, btScalar imb,const btMatrix3x3& iib,const btVector3& rb) { return(Add(MassMatrix(ima,iia,ra),MassMatrix(imb,iib,rb)).inverse()); } // static inline btMatrix3x3 AngularImpulseMatrix( const btMatrix3x3& iia, const btMatrix3x3& iib) { return(Add(iia,iib).inverse()); } // static inline btVector3 ProjectOnAxis( const btVector3& v, const btVector3& a) { return(a*btDot(v,a)); } // static inline btVector3 ProjectOnPlane( const btVector3& v, const btVector3& a) { return(v-ProjectOnAxis(v,a)); } // static inline void ProjectOrigin( const btVector3& a, const btVector3& b, btVector3& prj, btScalar& sqd) { const btVector3 d=b-a; const btScalar m2=d.length2(); if(m2>SIMD_EPSILON) { const btScalar t=Clamp(-btDot(a,d)/m2,0,1); const btVector3 p=a+d*t; const btScalar l2=p.length2(); if(l2SIMD_EPSILON) { const btVector3 n=q/btSqrt(m2); const btScalar k=btDot(a,n); const btScalar k2=k*k; if(k20)&& (btDot(btCross(b-p,c-p),q)>0)&& (btDot(btCross(c-p,a-p),q)>0)) { prj=p; sqd=k2; } else { ProjectOrigin(a,b,prj,sqd); ProjectOrigin(b,c,prj,sqd); ProjectOrigin(c,a,prj,sqd); } } } } // template static inline T BaryEval( const T& a, const T& b, const T& c, const btVector3& coord) { return(a*coord.x()+b*coord.y()+c*coord.z()); } // static inline btVector3 BaryCoord( const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& p) { const btScalar w[]={ btCross(a-p,b-p).length(), btCross(b-p,c-p).length(), btCross(c-p,a-p).length()}; const btScalar isum=1/(w[0]+w[1]+w[2]); return(btVector3(w[1]*isum,w[2]*isum,w[0]*isum)); } // static btScalar ImplicitSolve( btSoftBody::ImplicitFn* fn, const btVector3& a, const btVector3& b, const btScalar accuracy, const int maxiterations=256) { btScalar span[2]={0,1}; btScalar values[2]={fn->Eval(a),fn->Eval(b)}; if(values[0]>values[1]) { btSwap(span[0],span[1]); btSwap(values[0],values[1]); } if(values[0]>-accuracy) return(-1); if(values[1]<+accuracy) return(-1); for(int i=0;iEval(Lerp(a,b,t)); if((t<=0)||(t>=1)) break; if(btFabs(v)SIMD_EPSILON) return(v/l); else return(btVector3(0,0,0)); } // static inline btDbvtVolume VolumeOf( const btSoftBody::Face& f, btScalar margin) { const btVector3* pts[]={ &f.m_n[0]->m_x, &f.m_n[1]->m_x, &f.m_n[2]->m_x}; btDbvtVolume vol=btDbvtVolume::FromPoints(pts,3); vol.Expand(btVector3(margin,margin,margin)); return(vol); } // static inline btVector3 CenterOf( const btSoftBody::Face& f) { return((f.m_n[0]->m_x+f.m_n[1]->m_x+f.m_n[2]->m_x)/3); } // static inline btScalar AreaOf( const btVector3& x0, const btVector3& x1, const btVector3& x2) { const btVector3 a=x1-x0; const btVector3 b=x2-x0; const btVector3 cr=btCross(a,b); const btScalar area=cr.length(); return(area); } // static inline btScalar VolumeOf( const btVector3& x0, const btVector3& x1, const btVector3& x2, const btVector3& x3) { const btVector3 a=x1-x0; const btVector3 b=x2-x0; const btVector3 c=x3-x0; return(btDot(a,btCross(b,c))); } // static void EvaluateMedium( const btSoftBodyWorldInfo* wfi, const btVector3& x, btSoftBody::sMedium& medium) { medium.m_velocity = btVector3(0,0,0); medium.m_pressure = 0; medium.m_density = wfi->air_density; if(wfi->water_density>0) { const btScalar depth=-(btDot(x,wfi->water_normal)+wfi->water_offset); if(depth>0) { medium.m_density = wfi->water_density; medium.m_pressure = depth*wfi->water_density*wfi->m_gravity.length(); } } } // static inline void ApplyClampedForce( btSoftBody::Node& n, const btVector3& f, btScalar dt) { const btScalar dtim=dt*n.m_im; if((f*dtim).length2()>n.m_v.length2()) {/* Clamp */ n.m_f-=ProjectOnAxis(n.m_v,f.normalized())/dtim; } else {/* Apply */ n.m_f+=f; } } // static inline int MatchEdge( const btSoftBody::Node* a, const btSoftBody::Node* b, const btSoftBody::Node* ma, const btSoftBody::Node* mb) { if((a==ma)&&(b==mb)) return(0); if((a==mb)&&(b==ma)) return(1); return(-1); } // // btEigen : Extract eigen system, // straitforward implementation of http://math.fullerton.edu/mathews/n2003/JacobiMethodMod.html // outputs are NOT sorted. // struct btEigen { static int system(btMatrix3x3& a,btMatrix3x3* vectors,btVector3* values=0) { static const int maxiterations=16; static const btScalar accuracy=(btScalar)0.0001; btMatrix3x3& v=*vectors; int iterations=0; vectors->setIdentity(); do { int p=0,q=1; if(btFabs(a[p][q])accuracy) { const btScalar w=(a[q][q]-a[p][p])/(2*a[p][q]); const btScalar z=btFabs(w); const btScalar t=w/(z*(btSqrt(1+w*w)+z)); if(t==t)/* [WARNING] let hope that one does not get thrown aways by some compilers... */ { const btScalar c=1/btSqrt(t*t+1); const btScalar s=c*t; mulPQ(a,c,s,p,q); mulTPQ(a,c,s,p,q); mulPQ(v,c,s,p,q); } else break; } else break; } while((++iterations)accuracy) det=ndet; else break; } /* Final orthogonalization */ Orthogonalize(q); /* Compute 'S' */ s=q.transpose()*m; } else { q.setIdentity(); s.setIdentity(); } return(i); } // // btSoftColliders // struct btSoftColliders { // // ClusterBase // struct ClusterBase : btDbvt::ICollide { btScalar erp; btScalar idt; btScalar m_margin; btScalar friction; btScalar threshold; ClusterBase() { erp =(btScalar)1; idt =0; m_margin =0; friction =0; threshold =(btScalar)0; } bool SolveContact( const btGjkEpaSolver2::sResults& res, btSoftBody::Body ba,btSoftBody::Body bb, btSoftBody::CJoint& joint) { if(res.distancedata; btSoftClusterCollisionShape cshape(cluster); const btConvexShape* rshape=(const btConvexShape*)m_colObj->getCollisionShape(); ///don't collide an anchored cluster with a static/kinematic object if(m_colObj->isStaticOrKinematicObject() && cluster->m_containsAnchor) return; btGjkEpaSolver2::sResults res; if(btGjkEpaSolver2::SignedDistance( &cshape,btTransform::getIdentity(), rshape,m_colObj->getInterpolationWorldTransform(), btVector3(1,0,0),res)) { btSoftBody::CJoint joint; if(SolveContact(res,cluster,m_colObj,joint))//prb,joint)) { btSoftBody::CJoint* pj=new(btAlignedAlloc(sizeof(btSoftBody::CJoint),16)) btSoftBody::CJoint(); *pj=joint;psb->m_joints.push_back(pj); if(m_colObj->isStaticOrKinematicObject()) { pj->m_erp *= psb->m_cfg.kSKHR_CL; pj->m_split *= psb->m_cfg.kSK_SPLT_CL; } else { pj->m_erp *= psb->m_cfg.kSRHR_CL; pj->m_split *= psb->m_cfg.kSR_SPLT_CL; } } } } void Process(btSoftBody* ps,btCollisionObject* colOb) { psb = ps; m_colObj = colOb; idt = ps->m_sst.isdt; m_margin = m_colObj->getCollisionShape()->getMargin()+psb->getCollisionShape()->getMargin(); ///Bullet rigid body uses multiply instead of minimum to determine combined friction. Some customization would be useful. friction = btMin(psb->m_cfg.kDF,m_colObj->getFriction()); btVector3 mins; btVector3 maxs; ATTRIBUTE_ALIGNED16(btDbvtVolume) volume; colOb->getCollisionShape()->getAabb(colOb->getInterpolationWorldTransform(),mins,maxs); volume=btDbvtVolume::FromMM(mins,maxs); volume.Expand(btVector3(1,1,1)*m_margin); ps->m_cdbvt.collideTV(ps->m_cdbvt.m_root,volume,*this); } }; // // CollideCL_SS // struct CollideCL_SS : ClusterBase { btSoftBody* bodies[2]; void Process(const btDbvtNode* la,const btDbvtNode* lb) { btSoftBody::Cluster* cla=(btSoftBody::Cluster*)la->data; btSoftBody::Cluster* clb=(btSoftBody::Cluster*)lb->data; bool connected=false; if ((bodies[0]==bodies[1])&&(bodies[0]->m_clusterConnectivity.size())) { connected = bodies[0]->m_clusterConnectivity[cla->m_clusterIndex+bodies[0]->m_clusters.size()*clb->m_clusterIndex]; } if (!connected) { btSoftClusterCollisionShape csa(cla); btSoftClusterCollisionShape csb(clb); btGjkEpaSolver2::sResults res; if(btGjkEpaSolver2::SignedDistance( &csa,btTransform::getIdentity(), &csb,btTransform::getIdentity(), cla->m_com-clb->m_com,res)) { btSoftBody::CJoint joint; if(SolveContact(res,cla,clb,joint)) { btSoftBody::CJoint* pj=new(btAlignedAlloc(sizeof(btSoftBody::CJoint),16)) btSoftBody::CJoint(); *pj=joint;bodies[0]->m_joints.push_back(pj); pj->m_erp *= btMax(bodies[0]->m_cfg.kSSHR_CL,bodies[1]->m_cfg.kSSHR_CL); pj->m_split *= (bodies[0]->m_cfg.kSS_SPLT_CL+bodies[1]->m_cfg.kSS_SPLT_CL)/2; } } } else { static int count=0; count++; //printf("count=%d\n",count); } } void Process(btSoftBody* psa,btSoftBody* psb) { idt = psa->m_sst.isdt; //m_margin = (psa->getCollisionShape()->getMargin()+psb->getCollisionShape()->getMargin())/2; m_margin = (psa->getCollisionShape()->getMargin()+psb->getCollisionShape()->getMargin()); friction = btMin(psa->m_cfg.kDF,psb->m_cfg.kDF); bodies[0] = psa; bodies[1] = psb; psa->m_cdbvt.collideTT(psa->m_cdbvt.m_root,psb->m_cdbvt.m_root,*this); } }; // // CollideSDF_RS // struct CollideSDF_RS : btDbvt::ICollide { void Process(const btDbvtNode* leaf) { btSoftBody::Node* node=(btSoftBody::Node*)leaf->data; DoNode(*node); } void DoNode(btSoftBody::Node& n) const { const btScalar m=n.m_im>0?dynmargin:stamargin; btSoftBody::RContact c; if( (!n.m_battach)&& psb->checkContact(m_colObj1,n.m_x,m,c.m_cti)) { const btScalar ima=n.m_im; const btScalar imb= m_rigidBody? m_rigidBody->getInvMass() : 0.f; const btScalar ms=ima+imb; if(ms>0) { const btTransform& wtr=m_rigidBody?m_rigidBody->getInterpolationWorldTransform() : m_colObj1->getWorldTransform(); static const btMatrix3x3 iwiStatic(0,0,0,0,0,0,0,0,0); const btMatrix3x3& iwi=m_rigidBody?m_rigidBody->getInvInertiaTensorWorld() : iwiStatic; const btVector3 ra=n.m_x-wtr.getOrigin(); const btVector3 va=m_rigidBody ? m_rigidBody->getVelocityInLocalPoint(ra)*psb->m_sst.sdt : btVector3(0,0,0); const btVector3 vb=n.m_x-n.m_q; const btVector3 vr=vb-va; const btScalar dn=btDot(vr,c.m_cti.m_normal); const btVector3 fv=vr-c.m_cti.m_normal*dn; const btScalar fc=psb->m_cfg.kDF*m_colObj1->getFriction(); c.m_node = &n; c.m_c0 = ImpulseMatrix(psb->m_sst.sdt,ima,imb,iwi,ra); c.m_c1 = ra; c.m_c2 = ima*psb->m_sst.sdt; c.m_c3 = fv.length2()<(btFabs(dn)*fc)?0:1-fc; c.m_c4 = m_colObj1->isStaticOrKinematicObject()?psb->m_cfg.kKHR:psb->m_cfg.kCHR; psb->m_rcontacts.push_back(c); if (m_rigidBody) m_rigidBody->activate(); } } } btSoftBody* psb; btCollisionObject* m_colObj1; btRigidBody* m_rigidBody; btScalar dynmargin; btScalar stamargin; }; // // CollideVF_SS // struct CollideVF_SS : btDbvt::ICollide { void Process(const btDbvtNode* lnode, const btDbvtNode* lface) { btSoftBody::Node* node=(btSoftBody::Node*)lnode->data; btSoftBody::Face* face=(btSoftBody::Face*)lface->data; btVector3 o=node->m_x; btVector3 p; btScalar d=SIMD_INFINITY; ProjectOrigin( face->m_n[0]->m_x-o, face->m_n[1]->m_x-o, face->m_n[2]->m_x-o, p,d); const btScalar m=mrg+(o-node->m_q).length()*2; if(d<(m*m)) { const btSoftBody::Node* n[]={face->m_n[0],face->m_n[1],face->m_n[2]}; const btVector3 w=BaryCoord(n[0]->m_x,n[1]->m_x,n[2]->m_x,p+o); const btScalar ma=node->m_im; btScalar mb=BaryEval(n[0]->m_im,n[1]->m_im,n[2]->m_im,w); if( (n[0]->m_im<=0)|| (n[1]->m_im<=0)|| (n[2]->m_im<=0)) { mb=0; } const btScalar ms=ma+mb; if(ms>0) { btSoftBody::SContact c; c.m_normal = p/-btSqrt(d); c.m_margin = m; c.m_node = node; c.m_face = face; c.m_weights = w; c.m_friction = btMax(psb[0]->m_cfg.kDF,psb[1]->m_cfg.kDF); c.m_cfm[0] = ma/ms*psb[0]->m_cfg.kSHR; c.m_cfm[1] = mb/ms*psb[1]->m_cfg.kSHR; psb[0]->m_scontacts.push_back(c); } } } btSoftBody* psb[2]; btScalar mrg; }; }; #endif //_BT_SOFT_BODY_INTERNALS_H critterding-beta12.1/src/utils/bullet/BulletSoftBody/btSoftBody.cpp0000644000175000017500000020302611344267705024453 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ ///btSoftBody implementation by Nathanael Presson #include "btSoftBodyInternals.h" // btSoftBody::btSoftBody(btSoftBodyWorldInfo* worldInfo,int node_count, const btVector3* x, const btScalar* m) :m_worldInfo(worldInfo) { /* Init */ m_internalType = CO_SOFT_BODY; m_cfg.aeromodel = eAeroModel::V_Point; m_cfg.kVCF = 1; m_cfg.kDG = 0; m_cfg.kLF = 0; m_cfg.kDP = 0; m_cfg.kPR = 0; m_cfg.kVC = 0; m_cfg.kDF = (btScalar)0.2; m_cfg.kMT = 0; m_cfg.kCHR = (btScalar)1.0; m_cfg.kKHR = (btScalar)0.1; m_cfg.kSHR = (btScalar)1.0; m_cfg.kAHR = (btScalar)0.7; m_cfg.kSRHR_CL = (btScalar)0.1; m_cfg.kSKHR_CL = (btScalar)1; m_cfg.kSSHR_CL = (btScalar)0.5; m_cfg.kSR_SPLT_CL = (btScalar)0.5; m_cfg.kSK_SPLT_CL = (btScalar)0.5; m_cfg.kSS_SPLT_CL = (btScalar)0.5; m_cfg.maxvolume = (btScalar)1; m_cfg.timescale = 1; m_cfg.viterations = 0; m_cfg.piterations = 1; m_cfg.diterations = 0; m_cfg.citerations = 4; m_cfg.collisions = fCollision::Default; m_pose.m_bvolume = false; m_pose.m_bframe = false; m_pose.m_volume = 0; m_pose.m_com = btVector3(0,0,0); m_pose.m_rot.setIdentity(); m_pose.m_scl.setIdentity(); m_tag = 0; m_timeacc = 0; m_bUpdateRtCst = true; m_bounds[0] = btVector3(0,0,0); m_bounds[1] = btVector3(0,0,0); m_worldTransform.setIdentity(); setSolver(eSolverPresets::Positions); /* Default material */ Material* pm=appendMaterial(); pm->m_kLST = 1; pm->m_kAST = 1; pm->m_kVST = 1; pm->m_flags = fMaterial::Default; /* Collision shape */ ///for now, create a collision shape internally m_collisionShape = new btSoftBodyCollisionShape(this); m_collisionShape->setMargin(0.25); /* Nodes */ const btScalar margin=getCollisionShape()->getMargin(); m_nodes.resize(node_count); for(int i=0,ni=node_count;i0?1/n.m_im:0; n.m_leaf = m_ndbvt.insert(btDbvtVolume::FromCR(n.m_x,margin),&n); n.m_material= pm; } updateBounds(); m_initialWorldTransform.setIdentity(); } // btSoftBody::~btSoftBody() { //for now, delete the internal shape delete m_collisionShape; int i; releaseClusters(); for(i=0;i0) *pm=*m_materials[0]; else ZeroInitialize(*pm); m_materials.push_back(pm); return(pm); } // void btSoftBody::appendNote( const char* text, const btVector3& o, const btVector4& c, Node* n0, Node* n1, Node* n2, Node* n3) { Note n; ZeroInitialize(n); n.m_rank = 0; n.m_text = text; n.m_offset = o; n.m_coords[0] = c.x(); n.m_coords[1] = c.y(); n.m_coords[2] = c.z(); n.m_coords[3] = c.w(); n.m_nodes[0] = n0;n.m_rank+=n0?1:0; n.m_nodes[1] = n1;n.m_rank+=n1?1:0; n.m_nodes[2] = n2;n.m_rank+=n2?1:0; n.m_nodes[3] = n3;n.m_rank+=n3?1:0; m_notes.push_back(n); } // void btSoftBody::appendNote( const char* text, const btVector3& o, Node* feature) { appendNote(text,o,btVector4(1,0,0,0),feature); } // void btSoftBody::appendNote( const char* text, const btVector3& o, Link* feature) { static const btScalar w=1/(btScalar)2; appendNote(text,o,btVector4(w,w,0,0), feature->m_n[0], feature->m_n[1]); } // void btSoftBody::appendNote( const char* text, const btVector3& o, Face* feature) { static const btScalar w=1/(btScalar)3; appendNote(text,o,btVector4(w,w,w,0), feature->m_n[0], feature->m_n[1], feature->m_n[2]); } // void btSoftBody::appendNode( const btVector3& x,btScalar m) { if(m_nodes.capacity()==m_nodes.size()) { pointersToIndices(); m_nodes.reserve(m_nodes.size()*2+1); indicesToPointers(); } const btScalar margin=getCollisionShape()->getMargin(); m_nodes.push_back(Node()); Node& n=m_nodes[m_nodes.size()-1]; ZeroInitialize(n); n.m_x = x; n.m_q = n.m_x; n.m_im = m>0?1/m:0; n.m_material = m_materials[0]; n.m_leaf = m_ndbvt.insert(btDbvtVolume::FromCR(n.m_x,margin),&n); } // void btSoftBody::appendLink(int model,Material* mat) { Link l; if(model>=0) l=m_links[model]; else { ZeroInitialize(l);l.m_material=mat?mat:m_materials[0]; } m_links.push_back(l); } // void btSoftBody::appendLink( int node0, int node1, Material* mat, bool bcheckexist) { appendLink(&m_nodes[node0],&m_nodes[node1],mat,bcheckexist); } // void btSoftBody::appendLink( Node* node0, Node* node1, Material* mat, bool bcheckexist) { if((!bcheckexist)||(!checkLink(node0,node1))) { appendLink(-1,mat); Link& l=m_links[m_links.size()-1]; l.m_n[0] = node0; l.m_n[1] = node1; l.m_rl = (l.m_n[0]->m_x-l.m_n[1]->m_x).length(); m_bUpdateRtCst=true; } } // void btSoftBody::appendFace(int model,Material* mat) { Face f; if(model>=0) { f=m_faces[model]; } else { ZeroInitialize(f);f.m_material=mat?mat:m_materials[0]; } m_faces.push_back(f); } // void btSoftBody::appendFace(int node0,int node1,int node2,Material* mat) { if (node0==node1) return; if (node1==node2) return; if (node2==node0) return; appendFace(-1,mat); Face& f=m_faces[m_faces.size()-1]; btAssert(node0!=node1); btAssert(node1!=node2); btAssert(node2!=node0); f.m_n[0] = &m_nodes[node0]; f.m_n[1] = &m_nodes[node1]; f.m_n[2] = &m_nodes[node2]; f.m_ra = AreaOf( f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x); m_bUpdateRtCst=true; } // void btSoftBody::appendTetra(int model,Material* mat) { Tetra t; if(model>=0) t=m_tetras[model]; else { ZeroInitialize(t);t.m_material=mat?mat:m_materials[0]; } m_tetras.push_back(t); } // void btSoftBody::appendTetra(int node0, int node1, int node2, int node3, Material* mat) { appendTetra(-1,mat); Tetra& t=m_tetras[m_tetras.size()-1]; t.m_n[0] = &m_nodes[node0]; t.m_n[1] = &m_nodes[node1]; t.m_n[2] = &m_nodes[node2]; t.m_n[3] = &m_nodes[node3]; t.m_rv = VolumeOf(t.m_n[0]->m_x,t.m_n[1]->m_x,t.m_n[2]->m_x,t.m_n[3]->m_x); m_bUpdateRtCst=true; } // void btSoftBody::appendAnchor(int node,btRigidBody* body, bool disableCollisionBetweenLinkedBodies) { if (disableCollisionBetweenLinkedBodies) { if (m_collisionDisabledObjects.findLinearSearch(body)==m_collisionDisabledObjects.size()) { m_collisionDisabledObjects.push_back(body); } } Anchor a; a.m_node = &m_nodes[node]; a.m_body = body; a.m_local = body->getInterpolationWorldTransform().inverse()*a.m_node->m_x; a.m_node->m_battach = 1; m_anchors.push_back(a); } // void btSoftBody::appendLinearJoint(const LJoint::Specs& specs,Cluster* body0,Body body1) { LJoint* pj = new(btAlignedAlloc(sizeof(LJoint),16)) LJoint(); pj->m_bodies[0] = body0; pj->m_bodies[1] = body1; pj->m_refs[0] = pj->m_bodies[0].xform().inverse()*specs.position; pj->m_refs[1] = pj->m_bodies[1].xform().inverse()*specs.position; pj->m_cfm = specs.cfm; pj->m_erp = specs.erp; pj->m_split = specs.split; m_joints.push_back(pj); } // void btSoftBody::appendLinearJoint(const LJoint::Specs& specs,Body body) { appendLinearJoint(specs,m_clusters[0],body); } // void btSoftBody::appendLinearJoint(const LJoint::Specs& specs,btSoftBody* body) { appendLinearJoint(specs,m_clusters[0],body->m_clusters[0]); } // void btSoftBody::appendAngularJoint(const AJoint::Specs& specs,Cluster* body0,Body body1) { AJoint* pj = new(btAlignedAlloc(sizeof(AJoint),16)) AJoint(); pj->m_bodies[0] = body0; pj->m_bodies[1] = body1; pj->m_refs[0] = pj->m_bodies[0].xform().inverse().getBasis()*specs.axis; pj->m_refs[1] = pj->m_bodies[1].xform().inverse().getBasis()*specs.axis; pj->m_cfm = specs.cfm; pj->m_erp = specs.erp; pj->m_split = specs.split; pj->m_icontrol = specs.icontrol; m_joints.push_back(pj); } // void btSoftBody::appendAngularJoint(const AJoint::Specs& specs,Body body) { appendAngularJoint(specs,m_clusters[0],body); } // void btSoftBody::appendAngularJoint(const AJoint::Specs& specs,btSoftBody* body) { appendAngularJoint(specs,m_clusters[0],body->m_clusters[0]); } // void btSoftBody::addForce(const btVector3& force) { for(int i=0,ni=m_nodes.size();i0) { n.m_f += force; } } // void btSoftBody::addVelocity(const btVector3& velocity) { for(int i=0,ni=m_nodes.size();i0) { n.m_v = velocity; } } } // void btSoftBody::addVelocity(const btVector3& velocity,int node) { Node& n=m_nodes[node]; if(n.m_im>0) { n.m_v += velocity; } } // void btSoftBody::setMass(int node,btScalar mass) { m_nodes[node].m_im=mass>0?1/mass:0; m_bUpdateRtCst=true; } // btScalar btSoftBody::getMass(int node) const { return(m_nodes[node].m_im>0?1/m_nodes[node].m_im:0); } // btScalar btSoftBody::getTotalMass() const { btScalar mass=0; for(int i=0;im_x, f.m_n[1]->m_x, f.m_n[2]->m_x); for(int j=0;j<3;++j) { f.m_n[j]->m_im+=twicearea; } } for( i=0;i ranks; ranks.resize(m_nodes.size(),0); int i; for(i=0;im_im+=btFabs(t.m_rv); ranks[int(t.m_n[j]-&m_nodes[0])]+=1; } } for( i=0;i0) { m_nodes[i].m_im=ranks[i]/m_nodes[i].m_im; } } setTotalMass(mass,false); } // void btSoftBody::setVolumeDensity(btScalar density) { btScalar volume=0; for(int i=0;igetMargin(); ATTRIBUTE_ALIGNED16(btDbvtVolume) vol; for(int i=0,ni=m_nodes.size();igetMargin(); ATTRIBUTE_ALIGNED16(btDbvtVolume) vol; for(int i=0,ni=m_nodes.size();i0 ? 1/(m_nodes[i].m_im*tmass) : kmass/tmass; } /* Pos */ const btVector3 com=evaluateCom(); m_pose.m_pos.resize(m_nodes.size()); for( i=0,ni=m_nodes.size();i0) { int i,ni; const btVector3 org=m_nodes[0].m_x; for(i=0,ni=m_faces.size();im_x-org,btCross(f.m_n[1]->m_x-org,f.m_n[2]->m_x-org)); } vol/=(btScalar)6; } return(vol); } // int btSoftBody::clusterCount() const { return(m_clusters.size()); } // btVector3 btSoftBody::clusterCom(const Cluster* cluster) { btVector3 com(0,0,0); for(int i=0,ni=cluster->m_nodes.size();im_nodes[i]->m_x*cluster->m_masses[i]; } return(com*cluster->m_imass); } // btVector3 btSoftBody::clusterCom(int cluster) const { return(clusterCom(m_clusters[cluster])); } // btVector3 btSoftBody::clusterVelocity(const Cluster* cluster,const btVector3& rpos) { return(cluster->m_lv+btCross(cluster->m_av,rpos)); } // void btSoftBody::clusterVImpulse(Cluster* cluster,const btVector3& rpos,const btVector3& impulse) { const btVector3 li=cluster->m_imass*impulse; const btVector3 ai=cluster->m_invwi*btCross(rpos,impulse); cluster->m_vimpulses[0]+=li;cluster->m_lv+=li; cluster->m_vimpulses[1]+=ai;cluster->m_av+=ai; cluster->m_nvimpulses++; } // void btSoftBody::clusterDImpulse(Cluster* cluster,const btVector3& rpos,const btVector3& impulse) { const btVector3 li=cluster->m_imass*impulse; const btVector3 ai=cluster->m_invwi*btCross(rpos,impulse); cluster->m_dimpulses[0]+=li; cluster->m_dimpulses[1]+=ai; cluster->m_ndimpulses++; } // void btSoftBody::clusterImpulse(Cluster* cluster,const btVector3& rpos,const Impulse& impulse) { if(impulse.m_asVelocity) clusterVImpulse(cluster,rpos,impulse.m_velocity); if(impulse.m_asDrift) clusterDImpulse(cluster,rpos,impulse.m_drift); } // void btSoftBody::clusterVAImpulse(Cluster* cluster,const btVector3& impulse) { const btVector3 ai=cluster->m_invwi*impulse; cluster->m_vimpulses[1]+=ai;cluster->m_av+=ai; cluster->m_nvimpulses++; } // void btSoftBody::clusterDAImpulse(Cluster* cluster,const btVector3& impulse) { const btVector3 ai=cluster->m_invwi*impulse; cluster->m_dimpulses[1]+=ai; cluster->m_ndimpulses++; } // void btSoftBody::clusterAImpulse(Cluster* cluster,const Impulse& impulse) { if(impulse.m_asVelocity) clusterVAImpulse(cluster,impulse.m_velocity); if(impulse.m_asDrift) clusterDAImpulse(cluster,impulse.m_drift); } // void btSoftBody::clusterDCImpulse(Cluster* cluster,const btVector3& impulse) { cluster->m_dimpulses[0]+=impulse*cluster->m_imass; cluster->m_ndimpulses++; } struct NodeLinks { btAlignedObjectArray m_links; }; // int btSoftBody::generateBendingConstraints(int distance,Material* mat) { int i,j; if(distance>1) { /* Build graph */ const int n=m_nodes.size(); const unsigned inf=(~(unsigned)0)>>1; unsigned* adj=new unsigned[n*n]; #define IDX(_x_,_y_) ((_y_)*n+(_x_)) for(j=0;j nodeLinks; /* Build node links */ nodeLinks.resize(m_nodes.size()); for( i=0;isum) { adj[IDX(i,j)]=adj[IDX(j,i)]=sum; } } } } } } else { ///generic Floyd's algorithm for(int k=0;ksum) { adj[IDX(i,j)]=adj[IDX(j,i)]=sum; } } } } } /* Build links */ int nlinks=0; for(j=0;jm_leaf) m_cdbvt.remove(c->m_leaf); c->~Cluster(); btAlignedFree(c); m_clusters.remove(c); } // void btSoftBody::releaseClusters() { while(m_clusters.size()>0) releaseCluster(0); } // int btSoftBody::generateClusters(int k,int maxiterations) { int i; releaseClusters(); m_clusters.resize(btMin(k,m_nodes.size())); for(i=0;im_collide= true; } k=m_clusters.size(); if(k>0) { /* Initialize */ btAlignedObjectArray centers; btVector3 cog(0,0,0); int i; for(i=0;im_nodes.push_back(&m_nodes[i]); } cog/=(btScalar)m_nodes.size(); centers.resize(k,cog); /* Iterate */ const btScalar slope=16; bool changed; int iterations=0; do { const btScalar w=2-btMin(1,iterations/slope); changed=false; iterations++; int i; for(i=0;im_nodes.size();++j) { c+=m_clusters[i]->m_nodes[j]->m_x; } if(m_clusters[i]->m_nodes.size()) { c /= (btScalar)m_clusters[i]->m_nodes.size(); c = centers[i]+(c-centers[i])*w; changed |= ((c-centers[i]).length2()>SIMD_EPSILON); centers[i] = c; m_clusters[i]->m_nodes.resize(0); } } for(i=0;im_nodes.push_back(&m_nodes[i]); } } while(changed&&(iterations cids; cids.resize(m_nodes.size(),-1); for(i=0;im_nodes.size();++j) { cids[int(m_clusters[i]->m_nodes[j]-&m_nodes[0])]=i; } } for(i=0;im_nodes.findLinearSearch(&m_nodes[kid])==m_clusters[cid]->m_nodes.size()) { m_clusters[cid]->m_nodes.push_back(&m_nodes[kid]); } } } } } /* Master */ if(m_clusters.size()>1) { Cluster* pmaster=new(btAlignedAlloc(sizeof(Cluster),16)) Cluster(); pmaster->m_collide = false; pmaster->m_nodes.reserve(m_nodes.size()); for(int i=0;im_nodes.push_back(&m_nodes[i]); m_clusters.push_back(pmaster); btSwap(m_clusters[0],m_clusters[m_clusters.size()-1]); } /* Terminate */ for(i=0;im_nodes.size()==0) { releaseCluster(i--); } } } else { //create a cluster for each tetrahedron (if tetrahedra exist) or each face if (m_tetras.size()) { m_clusters.resize(m_tetras.size()); for(i=0;im_collide= true; } for (i=0;im_nodes.push_back(m_tetras[i].m_n[j]); } } } else { m_clusters.resize(m_faces.size()); for(i=0;im_collide= true; } for(i=0;im_nodes.push_back(m_faces[i].m_n[j]); } } } } if (m_clusters.size()) { initializeClusters(); updateClusters(); //for self-collision m_clusterConnectivity.resize(m_clusters.size()*m_clusters.size()); { for (int c0=0;c0m_clusterIndex=c0; for (int c1=0;c1m_nodes.size();i++) { for (int j=0;jm_nodes.size();j++) { if (cla->m_nodes[i] == clb->m_nodes[j]) { connected=true; break; } } } m_clusterConnectivity[c0+c1*m_clusters.size()]=connected; } } } } return(m_clusters.size()); } // void btSoftBody::refine(ImplicitFn* ifn,btScalar accurary,bool cut) { const Node* nbase = &m_nodes[0]; int ncount = m_nodes.size(); btSymMatrix edges(ncount,-2); int newnodes=0; int i,j,k,ni; /* Filter out */ for(i=0;iEval(l.m_n[0]->m_x),ifn->Eval(l.m_n[1]->m_x))) { btSwap(m_links[i],m_links[m_links.size()-1]); m_links.pop_back();--i; } } } /* Fill edges */ for(i=0;i0) { const btVector3 x=Lerp(a.m_x,b.m_x,t); const btVector3 v=Lerp(a.m_v,b.m_v,t); btScalar m=0; if(a.m_im>0) { if(b.m_im>0) { const btScalar ma=1/a.m_im; const btScalar mb=1/b.m_im; const btScalar mc=Lerp(ma,mb,t); const btScalar f=(ma+mb)/(ma+mb+mc); a.m_im=1/(ma*f); b.m_im=1/(mb*f); m=mc*f; } else { a.m_im/=0.5;m=1/a.m_im; } } else { if(b.m_im>0) { b.m_im/=0.5;m=1/b.m_im; } else m=0; } appendNode(x,m); edges(i,j)=m_nodes.size()-1; m_nodes[edges(i,j)].m_v=v; ++newnodes; } } } } nbase=&m_nodes[0]; /* Refine links */ for(i=0,ni=m_links.size();i0) { appendLink(i); Link* pft[]={ &m_links[i], &m_links[m_links.size()-1]}; pft[0]->m_n[0]=&m_nodes[idx[0]]; pft[0]->m_n[1]=&m_nodes[ni]; pft[1]->m_n[0]=&m_nodes[ni]; pft[1]->m_n[1]=&m_nodes[idx[1]]; } } } /* Refine faces */ for(i=0;i0) { appendFace(i); const int l=(k+1)%3; Face* pft[]={ &m_faces[i], &m_faces[m_faces.size()-1]}; pft[0]->m_n[0]=&m_nodes[idx[l]]; pft[0]->m_n[1]=&m_nodes[idx[j]]; pft[0]->m_n[2]=&m_nodes[ni]; pft[1]->m_n[0]=&m_nodes[ni]; pft[1]->m_n[1]=&m_nodes[idx[k]]; pft[1]->m_n[2]=&m_nodes[idx[l]]; appendLink(ni,idx[l],pft[0]->m_material); --i;break; } } } } /* Cut */ if(cut) { btAlignedObjectArray cnodes; const int pcount=ncount; int i; ncount=m_nodes.size(); cnodes.resize(ncount,0); /* Nodes */ for(i=0;i=pcount)||(btFabs(ifn->Eval(x))0) { m*=0.5;m_nodes[i].m_im/=0.5; } appendNode(x,m); cnodes[i]=m_nodes.size()-1; m_nodes[cnodes[i]].m_v=v; } } nbase=&m_nodes[0]; /* Links */ for(i=0,ni=m_links.size();iEval(m_nodes[id[0]].m_x)Eval(m_nodes[id[1]].m_x)Eval(n[0]->m_x)Eval(n[1]->m_x)Eval(n[2]->m_x) ranks; btAlignedObjectArray todelete; ranks.resize(nnodes,0); for(i=0,ni=m_links.size();i=0;--i) { if(!ranks[i]) todelete.push_back(i); } if(todelete.size()) { btAlignedObjectArray& map=ranks; for(int i=0;im_v=v; pn[1]->m_v=v; for(i=0,ni=m_links.size();im_n[1]=pn[mtch]; pft[1]->m_n[0]=pn[1-mtch]; done=true; } } for(i=0,ni=m_faces.size();im_n[l]=pn[mtch]; pft[1]->m_n[k]=pn[1-mtch]; appendLink(pn[0],pft[0]->m_n[(l+1)%3],pft[0]->m_material,true); appendLink(pn[1],pft[0]->m_n[(l+1)%3],pft[0]->m_material,true); } } } if(!done) { m_ndbvt.remove(pn[0]->m_leaf); m_ndbvt.remove(pn[1]->m_leaf); m_nodes.pop_back(); m_nodes.pop_back(); } return(done); } // bool btSoftBody::rayTest(const btVector3& rayFrom, const btVector3& rayTo, sRayCast& results) { if(m_faces.size()&&m_fdbvt.empty()) initializeFaceTree(); results.body = this; results.fraction = 1.f; results.feature = eFeature::None; results.index = -1; return(rayTest(rayFrom,rayTo,results.fraction,results.feature,results.index,false)!=0); } // void btSoftBody::setSolver(eSolverPresets::_ preset) { m_cfg.m_vsequence.clear(); m_cfg.m_psequence.clear(); m_cfg.m_dsequence.clear(); switch(preset) { case eSolverPresets::Positions: m_cfg.m_psequence.push_back(ePSolver::Anchors); m_cfg.m_psequence.push_back(ePSolver::RContacts); m_cfg.m_psequence.push_back(ePSolver::SContacts); m_cfg.m_psequence.push_back(ePSolver::Linear); break; case eSolverPresets::Velocities: m_cfg.m_vsequence.push_back(eVSolver::Linear); m_cfg.m_psequence.push_back(ePSolver::Anchors); m_cfg.m_psequence.push_back(ePSolver::RContacts); m_cfg.m_psequence.push_back(ePSolver::SContacts); m_cfg.m_dsequence.push_back(ePSolver::Linear); break; } } // void btSoftBody::predictMotion(btScalar dt) { int i,ni; /* Update */ if(m_bUpdateRtCst) { m_bUpdateRtCst=false; updateConstants(); m_fdbvt.clear(); if(m_cfg.collisions&fCollision::VF_SS) { initializeFaceTree(); } } /* Prepare */ m_sst.sdt = dt*m_cfg.timescale; m_sst.isdt = 1/m_sst.sdt; m_sst.velmrg = m_sst.sdt*3; m_sst.radmrg = getCollisionShape()->getMargin(); m_sst.updmrg = m_sst.radmrg*(btScalar)0.25; /* Forces */ addVelocity(m_worldInfo->m_gravity*m_sst.sdt); applyForces(); /* Integrate */ for(i=0,ni=m_nodes.size();im_v+ f.m_n[1]->m_v+ f.m_n[2]->m_v)/3; vol = VolumeOf(f,m_sst.radmrg); m_fdbvt.update( f.m_leaf, vol, v*m_sst.velmrg, m_sst.updmrg); } } /* Pose */ updatePose(); /* Match */ if(m_pose.m_bframe&&(m_cfg.kMT>0)) { const btMatrix3x3 posetrs=m_pose.m_rot; for(int i=0,ni=m_nodes.size();i0) { const btVector3 x=posetrs*m_pose.m_pos[i]+m_pose.m_com; n.m_x=Lerp(n.m_x,x,m_cfg.kMT); } } } /* Clear contacts */ m_rcontacts.resize(0); m_scontacts.resize(0); /* Optimize dbvt's */ m_ndbvt.optimizeIncremental(1); m_fdbvt.optimizeIncremental(1); m_cdbvt.optimizeIncremental(1); } // void btSoftBody::solveConstraints() { /* Apply clusters */ applyClusters(false); /* Prepare links */ int i,ni; for(i=0,ni=m_links.size();im_q-l.m_n[0]->m_q; l.m_c2 = 1/(l.m_c3.length2()*l.m_c0); } /* Prepare anchors */ for(i=0,ni=m_anchors.size();igetWorldTransform().getBasis()*a.m_local; a.m_c0 = ImpulseMatrix( m_sst.sdt, a.m_node->m_im, a.m_body->getInvMass(), a.m_body->getInvInertiaTensorWorld(), ra); a.m_c1 = ra; a.m_c2 = m_sst.sdt*a.m_node->m_im; a.m_body->activate(); } /* Solve velocities */ if(m_cfg.viterations>0) { /* Solve */ for(int isolve=0;isolve0) { for(int isolve=0;isolve0) { const btScalar vcf=m_cfg.kVCF*m_sst.isdt; for(i=0,ni=m_nodes.size();i& bodies) { const int nb=bodies.size(); int iterations=0; int i; for(i=0;im_cfg.citerations); } for(i=0;iprepareClusters(iterations); } for(i=0;isolveClusters(sor); } } for(i=0;icleanupClusters(); } } // void btSoftBody::integrateMotion() { /* Update */ updateNormals(); } // btSoftBody::RayFromToCaster::RayFromToCaster(const btVector3& rayFrom,const btVector3& rayTo,btScalar mxt) { m_rayFrom = rayFrom; m_rayNormalizedDirection = (rayTo-rayFrom); m_rayTo = rayTo; m_mint = mxt; m_face = 0; m_tests = 0; } // void btSoftBody::RayFromToCaster::Process(const btDbvtNode* leaf) { btSoftBody::Face& f=*(btSoftBody::Face*)leaf->data; const btScalar t=rayFromToTriangle( m_rayFrom,m_rayTo,m_rayNormalizedDirection, f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, m_mint); if((t>0)&&(tteps)&&(tceps) && (btDot(n,btCross(b-hit,c-hit))>ceps) && (btDot(n,btCross(c-hit,a-hit))>ceps)) { return(t); } } } return(-1); } // void btSoftBody::pointersToIndices() { #define PTR2IDX(_p_,_b_) reinterpret_cast((_p_)-(_b_)) btSoftBody::Node* base=&m_nodes[0]; int i,ni; for(i=0,ni=m_nodes.size();idata=*(void**)&i; } } for(i=0,ni=m_links.size();idata=*(void**)&i; } } for(i=0,ni=m_anchors.size();idata=&m_nodes[i]; } } for(i=0,ni=m_links.size();idata=&m_faces[i]; } } for(i=0,ni=m_anchors.size();im_x, f.m_n[1]->m_x, f.m_n[2]->m_x, mint); if(t>0) { ++cnt; if(!bcountonly) { feature=btSoftBody::eFeature::Face; index=i; mint=t; } } } } else {/* Use dbvt */ RayFromToCaster collider(rayFrom,rayTo,mint); btDbvt::rayTest(m_fdbvt.m_root,rayFrom,rayTo,collider); if(collider.m_face) { mint=collider.m_mint; feature=btSoftBody::eFeature::Face; index=(int)(collider.m_face-&m_faces[0]); cnt=1; } } return(cnt); } // void btSoftBody::initializeFaceTree() { m_fdbvt.clear(); for(int i=0;igetCollisionShape(); btRigidBody* tmpRigid = btRigidBody::upcast(colObj); const btTransform& wtr=tmpRigid? tmpRigid->getInterpolationWorldTransform() : colObj->getWorldTransform(); btScalar dst=m_worldInfo->m_sparsesdf.Evaluate( wtr.invXform(x), shp, nrm, margin); if(dst<0) { cti.m_colObj = colObj; cti.m_normal = wtr.getBasis()*nrm; cti.m_offset = -btDot( cti.m_normal, x-cti.m_normal*dst); return(true); } return(false); } // void btSoftBody::updateNormals() { const btVector3 zv(0,0,0); int i,ni; for(i=0,ni=m_nodes.size();im_x-f.m_n[0]->m_x, f.m_n[2]->m_x-f.m_n[0]->m_x); f.m_normal=n.normalized(); f.m_n[0]->m_n+=n; f.m_n[1]->m_n+=n; f.m_n[2]->m_n+=n; } for(i=0,ni=m_nodes.size();iSIMD_EPSILON) m_nodes[i].m_n /= len; } } // void btSoftBody::updateBounds() { if(m_ndbvt.m_root) { const btVector3& mins=m_ndbvt.m_root->volume.Mins(); const btVector3& maxs=m_ndbvt.m_root->volume.Maxs(); const btScalar csm=getCollisionShape()->getMargin(); const btVector3 mrg=btVector3( csm, csm, csm)*1; // ??? to investigate... m_bounds[0]=mins-mrg; m_bounds[1]=maxs+mrg; if(0!=getBroadphaseHandle()) { m_worldInfo->m_broadphase->setAabb( getBroadphaseHandle(), m_bounds[0], m_bounds[1], m_worldInfo->m_dispatcher); } } else { m_bounds[0]= m_bounds[1]=btVector3(0,0,0); } } // void btSoftBody::updatePose() { if(m_pose.m_bframe) { btSoftBody::Pose& pose=m_pose; const btVector3 com=evaluateCom(); /* Com */ pose.m_com = com; /* Rotation */ btMatrix3x3 Apq; const btScalar eps=SIMD_EPSILON; Apq[0]=Apq[1]=Apq[2]=btVector3(0,0,0); Apq[0].setX(eps);Apq[1].setY(eps*2);Apq[2].setZ(eps*3); for(int i=0,ni=m_nodes.size();i1) { const btScalar idet=Clamp( 1/pose.m_scl.determinant(), 1,m_cfg.maxvolume); pose.m_scl=Mul(pose.m_scl,idet); } } } // void btSoftBody::updateConstants() { int i,ni; /* Links */ for(i=0,ni=m_links.size();im_x-l.m_n[1]->m_x).length(); l.m_c0 = (l.m_n[0]->m_im+l.m_n[1]->m_im)/m.m_kLST; l.m_c1 = l.m_rl*l.m_rl; } /* Faces */ for(i=0,ni=m_faces.size();im_x,f.m_n[1]->m_x,f.m_n[2]->m_x); } /* Area's */ btAlignedObjectArray counts; counts.resize(m_nodes.size(),0); for(i=0,ni=m_nodes.size();im_area+=btFabs(f.m_ra); } } for(i=0,ni=m_nodes.size();i0) m_nodes[i].m_area/=(btScalar)counts[i]; else m_nodes[i].m_area=0; } } // void btSoftBody::initializeClusters() { int i; for( i=0;im_im==0) { c.m_containsAnchor = true; c.m_masses[j] = BT_LARGE_FLOAT; } else { c.m_masses[j] = btScalar(1.)/c.m_nodes[j]->m_im; } c.m_imass += c.m_masses[j]; } c.m_imass = btScalar(1.)/c.m_imass; c.m_com = btSoftBody::clusterCom(&c); c.m_lv = btVector3(0,0,0); c.m_av = btVector3(0,0,0); c.m_leaf = 0; /* Inertia */ btMatrix3x3& ii=c.m_locii; ii[0]=ii[1]=ii[2]=btVector3(0,0,0); { int i,ni; for(i=0,ni=c.m_nodes.size();im_x-c.m_com; const btVector3 q=k*k; const btScalar m=c.m_masses[i]; ii[0][0] += m*(q[1]+q[2]); ii[1][1] += m*(q[0]+q[2]); ii[2][2] += m*(q[0]+q[1]); ii[0][1] -= m*k[0]*k[1]; ii[0][2] -= m*k[0]*k[2]; ii[1][2] -= m*k[1]*k[2]; } } ii[1][0]=ii[0][1]; ii[2][0]=ii[0][2]; ii[2][1]=ii[1][2]; ii = ii.inverse(); /* Frame */ c.m_framexform.setIdentity(); c.m_framexform.setOrigin(c.m_com); c.m_framerefs.resize(c.m_nodes.size()); { int i; for(i=0;im_x-c.m_com; } } } } // void btSoftBody::updateClusters() { BT_PROFILE("UpdateClusters"); int i; for(i=0;im_x-c.m_com; const btVector3& b=c.m_framerefs[i]; m[0]+=a[0]*b;m[1]+=a[1]*b;m[2]+=a[2]*b; } PolarDecompose(m,r,s); c.m_framexform.setOrigin(c.m_com); c.m_framexform.setBasis(r); /* Inertia */ #if 1/* Constant */ c.m_invwi=c.m_framexform.getBasis()*c.m_locii*c.m_framexform.getBasis().transpose(); #else #if 0/* Sphere */ const btScalar rk=(2*c.m_extents.length2())/(5*c.m_imass); const btVector3 inertia(rk,rk,rk); const btVector3 iin(btFabs(inertia[0])>SIMD_EPSILON?1/inertia[0]:0, btFabs(inertia[1])>SIMD_EPSILON?1/inertia[1]:0, btFabs(inertia[2])>SIMD_EPSILON?1/inertia[2]:0); c.m_invwi=c.m_xform.getBasis().scaled(iin)*c.m_xform.getBasis().transpose(); #else/* Actual */ c.m_invwi[0]=c.m_invwi[1]=c.m_invwi[2]=btVector3(0,0,0); for(int i=0;im_x-c.m_com; const btVector3 q=k*k; const btScalar m=1/c.m_nodes[i]->m_im; c.m_invwi[0][0] += m*(q[1]+q[2]); c.m_invwi[1][1] += m*(q[0]+q[2]); c.m_invwi[2][2] += m*(q[0]+q[1]); c.m_invwi[0][1] -= m*k[0]*k[1]; c.m_invwi[0][2] -= m*k[0]*k[2]; c.m_invwi[1][2] -= m*k[1]*k[2]; } c.m_invwi[1][0]=c.m_invwi[0][1]; c.m_invwi[2][0]=c.m_invwi[0][2]; c.m_invwi[2][1]=c.m_invwi[1][2]; c.m_invwi=c.m_invwi.inverse(); #endif #endif /* Velocities */ c.m_lv=btVector3(0,0,0); c.m_av=btVector3(0,0,0); { int i; for(i=0;im_v*c.m_masses[i]; c.m_lv += v; c.m_av += btCross(c.m_nodes[i]->m_x-c.m_com,v); } } c.m_lv=c.m_imass*c.m_lv*(1-c.m_ldamping); c.m_av=c.m_invwi*c.m_av*(1-c.m_adamping); c.m_vimpulses[0] = c.m_vimpulses[1] = btVector3(0,0,0); c.m_dimpulses[0] = c.m_dimpulses[1] = btVector3(0,0,0); c.m_nvimpulses = 0; c.m_ndimpulses = 0; /* Matching */ if(c.m_matching>0) { for(int j=0;jm_x; btVector3 mx=mi; for(int j=1;jm_x); mx.setMax(c.m_nodes[j]->m_x); } ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds=btDbvtVolume::FromMM(mi,mx); if(c.m_leaf) m_cdbvt.update(c.m_leaf,bounds,c.m_lv*m_sst.sdt*3,m_sst.radmrg); else c.m_leaf=m_cdbvt.insert(bounds,&c); } } } } // void btSoftBody::cleanupClusters() { for(int i=0;iTerminate(m_sst.sdt); if(m_joints[i]->m_delete) { btAlignedFree(m_joints[i]); m_joints.remove(m_joints[i--]); } } } // void btSoftBody::prepareClusters(int iterations) { for(int i=0;iPrepare(m_sst.sdt,iterations); } } // void btSoftBody::solveClusters(btScalar sor) { for(int i=0,ni=m_joints.size();iSolve(m_sst.sdt,sor); } } // void btSoftBody::applyClusters(bool drift) { BT_PROFILE("ApplyClusters"); // const btScalar f0=m_sst.sdt; //const btScalar f1=f0/2; btAlignedObjectArray deltas; btAlignedObjectArray weights; deltas.resize(m_nodes.size(),btVector3(0,0,0)); weights.resize(m_nodes.size(),0); int i; if(drift) { for(i=0;im_x; const btScalar q=c.m_masses[j]; deltas[idx] += (v+btCross(w,x-c.m_com))*q; weights[idx] += q; } } } for(i=0;i0) m_nodes[i].m_x+=deltas[i]/weights[i]; } } // void btSoftBody::dampClusters() { int i; for(i=0;i0) { for(int j=0;j0) { const btVector3 vx=c.m_lv+btCross(c.m_av,c.m_nodes[j]->m_q-c.m_com); if(vx.length2()<=n.m_v.length2()) { n.m_v += c.m_ndamping*(vx-n.m_v); } } } } } } // void btSoftBody::Joint::Prepare(btScalar dt,int) { m_bodies[0].activate(); m_bodies[1].activate(); } // void btSoftBody::LJoint::Prepare(btScalar dt,int iterations) { static const btScalar maxdrift=4; Joint::Prepare(dt,iterations); m_rpos[0] = m_bodies[0].xform()*m_refs[0]; m_rpos[1] = m_bodies[1].xform()*m_refs[1]; m_drift = Clamp(m_rpos[0]-m_rpos[1],maxdrift)*m_erp/dt; m_rpos[0] -= m_bodies[0].xform().getOrigin(); m_rpos[1] -= m_bodies[1].xform().getOrigin(); m_massmatrix = ImpulseMatrix( m_bodies[0].invMass(),m_bodies[0].invWorldInertia(),m_rpos[0], m_bodies[1].invMass(),m_bodies[1].invWorldInertia(),m_rpos[1]); if(m_split>0) { m_sdrift = m_massmatrix*(m_drift*m_split); m_drift *= 1-m_split; } m_drift /=(btScalar)iterations; } // void btSoftBody::LJoint::Solve(btScalar dt,btScalar sor) { const btVector3 va=m_bodies[0].velocity(m_rpos[0]); const btVector3 vb=m_bodies[1].velocity(m_rpos[1]); const btVector3 vr=va-vb; btSoftBody::Impulse impulse; impulse.m_asVelocity = 1; impulse.m_velocity = m_massmatrix*(m_drift+vr*m_cfm)*sor; m_bodies[0].applyImpulse(-impulse,m_rpos[0]); m_bodies[1].applyImpulse( impulse,m_rpos[1]); } // void btSoftBody::LJoint::Terminate(btScalar dt) { if(m_split>0) { m_bodies[0].applyDImpulse(-m_sdrift,m_rpos[0]); m_bodies[1].applyDImpulse( m_sdrift,m_rpos[1]); } } // void btSoftBody::AJoint::Prepare(btScalar dt,int iterations) { static const btScalar maxdrift=SIMD_PI/16; m_icontrol->Prepare(this); Joint::Prepare(dt,iterations); m_axis[0] = m_bodies[0].xform().getBasis()*m_refs[0]; m_axis[1] = m_bodies[1].xform().getBasis()*m_refs[1]; m_drift = NormalizeAny(btCross(m_axis[1],m_axis[0])); m_drift *= btMin(maxdrift,btAcos(Clamp(btDot(m_axis[0],m_axis[1]),-1,+1))); m_drift *= m_erp/dt; m_massmatrix= AngularImpulseMatrix(m_bodies[0].invWorldInertia(),m_bodies[1].invWorldInertia()); if(m_split>0) { m_sdrift = m_massmatrix*(m_drift*m_split); m_drift *= 1-m_split; } m_drift /=(btScalar)iterations; } // void btSoftBody::AJoint::Solve(btScalar dt,btScalar sor) { const btVector3 va=m_bodies[0].angularVelocity(); const btVector3 vb=m_bodies[1].angularVelocity(); const btVector3 vr=va-vb; const btScalar sp=btDot(vr,m_axis[0]); const btVector3 vc=vr-m_axis[0]*m_icontrol->Speed(this,sp); btSoftBody::Impulse impulse; impulse.m_asVelocity = 1; impulse.m_velocity = m_massmatrix*(m_drift+vc*m_cfm)*sor; m_bodies[0].applyAImpulse(-impulse); m_bodies[1].applyAImpulse( impulse); } // void btSoftBody::AJoint::Terminate(btScalar dt) { if(m_split>0) { m_bodies[0].applyDAImpulse(-m_sdrift); m_bodies[1].applyDAImpulse( m_sdrift); } } // void btSoftBody::CJoint::Prepare(btScalar dt,int iterations) { Joint::Prepare(dt,iterations); const bool dodrift=(m_life==0); m_delete=(++m_life)>m_maxlife; if(dodrift) { m_drift=m_drift*m_erp/dt; if(m_split>0) { m_sdrift = m_massmatrix*(m_drift*m_split); m_drift *= 1-m_split; } m_drift/=(btScalar)iterations; } else { m_drift=m_sdrift=btVector3(0,0,0); } } // void btSoftBody::CJoint::Solve(btScalar dt,btScalar sor) { const btVector3 va=m_bodies[0].velocity(m_rpos[0]); const btVector3 vb=m_bodies[1].velocity(m_rpos[1]); const btVector3 vrel=va-vb; const btScalar rvac=btDot(vrel,m_normal); btSoftBody::Impulse impulse; impulse.m_asVelocity = 1; impulse.m_velocity = m_drift; if(rvac<0) { const btVector3 iv=m_normal*rvac; const btVector3 fv=vrel-iv; impulse.m_velocity += iv+fv*m_friction; } impulse.m_velocity=m_massmatrix*impulse.m_velocity*sor; if (m_bodies[0].m_soft==m_bodies[1].m_soft) { if ((impulse.m_velocity.getX() ==impulse.m_velocity.getX())&&(impulse.m_velocity.getY() ==impulse.m_velocity.getY())&& (impulse.m_velocity.getZ() ==impulse.m_velocity.getZ())) { if (impulse.m_asVelocity) { if (impulse.m_velocity.length() m_maxSelfCollisionImpulse) { } else { m_bodies[0].applyImpulse(-impulse*m_bodies[0].m_soft->m_selfCollisionImpulseFactor,m_rpos[0]); m_bodies[1].applyImpulse( impulse*m_bodies[0].m_soft->m_selfCollisionImpulseFactor,m_rpos[1]); } } } } else { m_bodies[0].applyImpulse(-impulse,m_rpos[0]); m_bodies[1].applyImpulse( impulse,m_rpos[1]); } } // void btSoftBody::CJoint::Terminate(btScalar dt) { if(m_split>0) { m_bodies[0].applyDImpulse(-m_sdrift,m_rpos[0]); m_bodies[1].applyDImpulse( m_sdrift,m_rpos[1]); } } // void btSoftBody::applyForces() { BT_PROFILE("SoftBody applyForces"); const btScalar dt=m_sst.sdt; const btScalar kLF=m_cfg.kLF; const btScalar kDG=m_cfg.kDG; const btScalar kPR=m_cfg.kPR; const btScalar kVC=m_cfg.kVC; const bool as_lift=kLF>0; const bool as_drag=kDG>0; const bool as_pressure=kPR!=0; const bool as_volume=kVC>0; const bool as_aero= as_lift || as_drag ; const bool as_vaero= as_aero && (m_cfg.aeromodel=btSoftBody::eAeroModel::F_TwoSided); const bool use_medium= as_aero; const bool use_volume= as_pressure || as_volume ; btScalar volume=0; btScalar ivolumetp=0; btScalar dvolumetv=0; btSoftBody::sMedium medium; if(use_volume) { volume = getVolume(); ivolumetp = 1/btFabs(volume)*kPR; dvolumetv = (m_pose.m_volume-volume)*kVC; } /* Per vertex forces */ int i,ni; for(i=0,ni=m_nodes.size();i0) { if(use_medium) { EvaluateMedium(m_worldInfo,n.m_x,medium); /* Aerodynamics */ if(as_vaero) { const btVector3 rel_v=n.m_v-medium.m_velocity; const btScalar rel_v2=rel_v.length2(); if(rel_v2>SIMD_EPSILON) { btVector3 nrm=n.m_n; /* Setup normal */ switch(m_cfg.aeromodel) { case btSoftBody::eAeroModel::V_Point: nrm=NormalizeAny(rel_v);break; case btSoftBody::eAeroModel::V_TwoSided: nrm*=(btScalar)(btDot(nrm,rel_v)<0?-1:+1);break; default: { } } const btScalar dvn=btDot(rel_v,nrm); /* Compute forces */ if(dvn>0) { btVector3 force(0,0,0); const btScalar c0 = n.m_area*dvn*rel_v2/2; const btScalar c1 = c0*medium.m_density; force += nrm*(-c1*kLF); force += rel_v.normalized()*(-c1*kDG); ApplyClampedForce(n,force,dt); } } } } /* Pressure */ if(as_pressure) { n.m_f += n.m_n*(n.m_area*ivolumetp); } /* Volume */ if(as_volume) { n.m_f += n.m_n*(n.m_area*dvolumetv); } } } /* Per face forces */ for(i=0,ni=m_faces.size();im_v+f.m_n[1]->m_v+f.m_n[2]->m_v)/3; const btVector3 x=(f.m_n[0]->m_x+f.m_n[1]->m_x+f.m_n[2]->m_x)/3; EvaluateMedium(m_worldInfo,x,medium); const btVector3 rel_v=v-medium.m_velocity; const btScalar rel_v2=rel_v.length2(); if(rel_v2>SIMD_EPSILON) { btVector3 nrm=f.m_normal; /* Setup normal */ switch(m_cfg.aeromodel) { case btSoftBody::eAeroModel::F_TwoSided: nrm*=(btScalar)(btDot(nrm,rel_v)<0?-1:+1);break; default: { } } const btScalar dvn=btDot(rel_v,nrm); /* Compute forces */ if(dvn>0) { btVector3 force(0,0,0); const btScalar c0 = f.m_ra*dvn*rel_v2; const btScalar c1 = c0*medium.m_density; force += nrm*(-c1*kLF); force += rel_v.normalized()*(-c1*kDG); force /= 3; for(int j=0;j<3;++j) ApplyClampedForce(*f.m_n[j],force,dt); } } } } } // void btSoftBody::PSolve_Anchors(btSoftBody* psb,btScalar kst,btScalar ti) { const btScalar kAHR=psb->m_cfg.kAHR*kst; const btScalar dt=psb->m_sst.sdt; for(int i=0,ni=psb->m_anchors.size();im_anchors[i]; const btTransform& t=a.m_body->getInterpolationWorldTransform(); Node& n=*a.m_node; const btVector3 wa=t*a.m_local; const btVector3 va=a.m_body->getVelocityInLocalPoint(a.m_c1)*dt; const btVector3 vb=n.m_x-n.m_q; const btVector3 vr=(va-vb)+(wa-n.m_x)*kAHR; const btVector3 impulse=a.m_c0*vr; n.m_x+=impulse*a.m_c2; a.m_body->applyImpulse(-impulse,a.m_c1); } } // void btSoftBody::PSolve_RContacts(btSoftBody* psb,btScalar kst,btScalar ti) { const btScalar dt=psb->m_sst.sdt; const btScalar mrg=psb->getCollisionShape()->getMargin(); for(int i=0,ni=psb->m_rcontacts.size();im_rcontacts[i]; const sCti& cti=c.m_cti; btRigidBody* tmpRigid = btRigidBody::upcast(cti.m_colObj); const btVector3 va=tmpRigid ? tmpRigid->getVelocityInLocalPoint(c.m_c1)*dt : btVector3(0,0,0); const btVector3 vb=c.m_node->m_x-c.m_node->m_q; const btVector3 vr=vb-va; const btScalar dn=btDot(vr,cti.m_normal); if(dn<=SIMD_EPSILON) { const btScalar dp=btMin(btDot(c.m_node->m_x,cti.m_normal)+cti.m_offset,mrg); const btVector3 fv=vr-cti.m_normal*dn; const btVector3 impulse=c.m_c0*((vr-fv*c.m_c3+cti.m_normal*(dp*c.m_c4))*kst); c.m_node->m_x-=impulse*c.m_c2; if (tmpRigid) tmpRigid->applyImpulse(impulse,c.m_c1); } } } // void btSoftBody::PSolve_SContacts(btSoftBody* psb,btScalar,btScalar ti) { for(int i=0,ni=psb->m_scontacts.size();im_scontacts[i]; const btVector3& nr=c.m_normal; Node& n=*c.m_node; Face& f=*c.m_face; const btVector3 p=BaryEval( f.m_n[0]->m_x, f.m_n[1]->m_x, f.m_n[2]->m_x, c.m_weights); const btVector3 q=BaryEval( f.m_n[0]->m_q, f.m_n[1]->m_q, f.m_n[2]->m_q, c.m_weights); const btVector3 vr=(n.m_x-n.m_q)-(p-q); btVector3 corr(0,0,0); btScalar dot = btDot(vr,nr); if(dot<0) { const btScalar j=c.m_margin-(btDot(nr,n.m_x)-btDot(nr,p)); corr+=c.m_normal*j; } corr -= ProjectOnPlane(vr,nr)*c.m_friction; n.m_x += corr*c.m_cfm[0]; f.m_n[0]->m_x -= corr*(c.m_cfm[1]*c.m_weights.x()); f.m_n[1]->m_x -= corr*(c.m_cfm[1]*c.m_weights.y()); f.m_n[2]->m_x -= corr*(c.m_cfm[1]*c.m_weights.z()); } } // void btSoftBody::PSolve_Links(btSoftBody* psb,btScalar kst,btScalar ti) { for(int i=0,ni=psb->m_links.size();im_links[i]; if(l.m_c0>0) { Node& a=*l.m_n[0]; Node& b=*l.m_n[1]; const btVector3 del=b.m_x-a.m_x; const btScalar len=del.length2(); const btScalar k=((l.m_c1-len)/(l.m_c0*(l.m_c1+len)))*kst; //const btScalar t=k*a.m_im; a.m_x-=del*(k*a.m_im); b.m_x+=del*(k*b.m_im); } } } // void btSoftBody::VSolve_Links(btSoftBody* psb,btScalar kst) { for(int i=0,ni=psb->m_links.size();im_links[i]; Node** n=l.m_n; const btScalar j=-btDot(l.m_c3,n[0]->m_v-n[1]->m_v)*l.m_c2*kst; n[0]->m_v+= l.m_c3*(j*n[0]->m_im); n[1]->m_v-= l.m_c3*(j*n[1]->m_im); } } // btSoftBody::psolver_t btSoftBody::getSolver(ePSolver::_ solver) { switch(solver) { case ePSolver::Anchors: return(&btSoftBody::PSolve_Anchors); case ePSolver::Linear: return(&btSoftBody::PSolve_Links); case ePSolver::RContacts: return(&btSoftBody::PSolve_RContacts); case ePSolver::SContacts: return(&btSoftBody::PSolve_SContacts); default: { } } return(0); } // btSoftBody::vsolver_t btSoftBody::getSolver(eVSolver::_ solver) { switch(solver) { case eVSolver::Linear: return(&btSoftBody::VSolve_Links); default: { } } return(0); } // void btSoftBody::defaultCollisionHandler(btCollisionObject* pco) { switch(m_cfg.collisions&fCollision::RVSmask) { case fCollision::SDF_RS: { btSoftColliders::CollideSDF_RS docollide; btRigidBody* prb1=btRigidBody::upcast(pco); btTransform wtr=prb1 ? prb1->getInterpolationWorldTransform() : pco->getWorldTransform(); const btTransform ctr=pco->getWorldTransform(); const btScalar timemargin=(wtr.getOrigin()-ctr.getOrigin()).length(); const btScalar basemargin=getCollisionShape()->getMargin(); btVector3 mins; btVector3 maxs; ATTRIBUTE_ALIGNED16(btDbvtVolume) volume; pco->getCollisionShape()->getAabb( pco->getInterpolationWorldTransform(), mins, maxs); volume=btDbvtVolume::FromMM(mins,maxs); volume.Expand(btVector3(basemargin,basemargin,basemargin)); docollide.psb = this; docollide.m_colObj1 = pco; docollide.m_rigidBody = prb1; docollide.dynmargin = basemargin+timemargin; docollide.stamargin = basemargin; m_ndbvt.collideTV(m_ndbvt.m_root,volume,docollide); } break; case fCollision::CL_RS: { btSoftColliders::CollideCL_RS collider; collider.Process(this,pco); } break; } } // void btSoftBody::defaultCollisionHandler(btSoftBody* psb) { const int cf=m_cfg.collisions&psb->m_cfg.collisions; switch(cf&fCollision::SVSmask) { case fCollision::CL_SS: { //support self-collision if CL_SELF flag set if (this!=psb || psb->m_cfg.collisions&fCollision::CL_SELF) { btSoftColliders::CollideCL_SS docollide; docollide.Process(this,psb); } } break; case fCollision::VF_SS: { //only self-collision for Cluster, not Vertex-Face yet if (this!=psb) { btSoftColliders::CollideVF_SS docollide; /* common */ docollide.mrg= getCollisionShape()->getMargin()+ psb->getCollisionShape()->getMargin(); /* psb0 nodes vs psb1 faces */ docollide.psb[0]=this; docollide.psb[1]=psb; docollide.psb[0]->m_ndbvt.collideTT( docollide.psb[0]->m_ndbvt.m_root, docollide.psb[1]->m_fdbvt.m_root, docollide); /* psb1 nodes vs psb0 faces */ docollide.psb[0]=psb; docollide.psb[1]=this; docollide.psb[0]->m_ndbvt.collideTT( docollide.psb[0]->m_ndbvt.m_root, docollide.psb[1]->m_fdbvt.m_root, docollide); } } break; default: { } } } critterding-beta12.1/src/utils/bullet/BulletSoftBody/btSoftBodyConcaveCollisionAlgorithm.h0000644000175000017500000001226311337071441031133 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 SOFT_BODY_CONCAVE_COLLISION_ALGORITHM_H #define SOFT_BODY_CONCAVE_COLLISION_ALGORITHM_H #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btDispatcher.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" #include "BulletCollision/CollisionShapes/btTriangleCallback.h" #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" class btDispatcher; #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" class btSoftBody; class btCollisionShape; #include "LinearMath/btHashMap.h" #include "BulletCollision/BroadphaseCollision/btQuantizedBvh.h" //for definition of MAX_NUM_PARTS_IN_BITS struct btTriIndex { int m_PartIdTriangleIndex; class btCollisionShape* m_childShape; btTriIndex(int partId,int triangleIndex,btCollisionShape* shape) { m_PartIdTriangleIndex = (partId<<(31-MAX_NUM_PARTS_IN_BITS)) | triangleIndex; m_childShape = shape; } int getTriangleIndex() const { // Get only the lower bits where the triangle index is stored return (m_PartIdTriangleIndex&~((~0)<<(31-MAX_NUM_PARTS_IN_BITS))); } int getPartId() const { // Get only the highest bits where the part index is stored return (m_PartIdTriangleIndex>>(31-MAX_NUM_PARTS_IN_BITS)); } int getUid() const { return m_PartIdTriangleIndex; } }; ///For each triangle in the concave mesh that overlaps with the AABB of a soft body (m_softBody), processTriangle is called. class btSoftBodyTriangleCallback : public btTriangleCallback { btSoftBody* m_softBody; btCollisionObject* m_triBody; btVector3 m_aabbMin; btVector3 m_aabbMax ; btManifoldResult* m_resultOut; btDispatcher* m_dispatcher; const btDispatcherInfo* m_dispatchInfoPtr; btScalar m_collisionMarginTriangle; btHashMap,btTriIndex> m_shapeCache; public: int m_triangleCount; // btPersistentManifold* m_manifoldPtr; btSoftBodyTriangleCallback(btDispatcher* dispatcher,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped); void setTimeStepAndCounters(btScalar collisionMarginTriangle,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual ~btSoftBodyTriangleCallback(); virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex); void clearCache(); SIMD_FORCE_INLINE const btVector3& getAabbMin() const { return m_aabbMin; } SIMD_FORCE_INLINE const btVector3& getAabbMax() const { return m_aabbMax; } }; /// btSoftBodyConcaveCollisionAlgorithm supports collision between soft body shapes and (concave) trianges meshes. class btSoftBodyConcaveCollisionAlgorithm : public btCollisionAlgorithm { bool m_isSwapped; btSoftBodyTriangleCallback m_btSoftBodyTriangleCallback; public: btSoftBodyConcaveCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped); virtual ~btSoftBodyConcaveCollisionAlgorithm(); virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual void getAllContactManifolds(btManifoldArray& manifoldArray) { //we don't add any manifolds } void clearCache(); struct CreateFunc :public btCollisionAlgorithmCreateFunc { virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btSoftBodyConcaveCollisionAlgorithm)); return new(mem) btSoftBodyConcaveCollisionAlgorithm(ci,body0,body1,false); } }; struct SwappedCreateFunc :public btCollisionAlgorithmCreateFunc { virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btSoftBodyConcaveCollisionAlgorithm)); return new(mem) btSoftBodyConcaveCollisionAlgorithm(ci,body0,body1,true); } }; }; #endif //SOFT_BODY_CONCAVE_COLLISION_ALGORITHM_H critterding-beta12.1/src/utils/bullet/BulletSoftBody/CMakeLists.txt0000644000175000017500000000342711344267705024433 0ustar bobkebobke INCLUDE_DIRECTORIES( ${BULLET_PHYSICS_SOURCE_DIR}/src ) SET(BulletSoftBody_SRCS btSoftBody.cpp btSoftBodyConcaveCollisionAlgorithm.cpp btSoftBodyHelpers.cpp btSoftBodyRigidBodyCollisionConfiguration.cpp btSoftRigidCollisionAlgorithm.cpp btSoftRigidDynamicsWorld.cpp btSoftSoftCollisionAlgorithm.cpp ) SET(BulletSoftBody_HDRS btSoftBody.h btSoftBodyConcaveCollisionAlgorithm.h btSoftBodyHelpers.h btSoftBodyRigidBodyCollisionConfiguration.h btSoftRigidCollisionAlgorithm.h btSoftRigidDynamicsWorld.h btSoftSoftCollisionAlgorithm.h btSparseSDF.h ) ADD_LIBRARY(BulletSoftBody ${BulletSoftBody_SRCS} ${BulletSoftBody_HDRS}) SET_TARGET_PROPERTIES(BulletSoftBody PROPERTIES VERSION ${BULLET_VERSION}) SET_TARGET_PROPERTIES(BulletSoftBody PROPERTIES SOVERSION ${BULLET_VERSION}) IF (BUILD_SHARED_LIBS) TARGET_LINK_LIBRARIES(BulletSoftBody BulletDynamics) ENDIF (BUILD_SHARED_LIBS) IF (INSTALL_LIBS) IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) INSTALL(TARGETS BulletSoftBody DESTINATION .) ELSE (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) INSTALL(TARGETS BulletSoftBody DESTINATION lib${LIB_SUFFIX}) INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DESTINATION include FILES_MATCHING PATTERN "*.h") ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) SET_TARGET_PROPERTIES(BulletSoftBody PROPERTIES FRAMEWORK true) SET_TARGET_PROPERTIES(BulletSoftBody PROPERTIES PUBLIC_HEADER ${BulletSoftBody_HDRS}) ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) ENDIF (INSTALL_LIBS)critterding-beta12.1/src/utils/bullet/BulletCollision/0000755000175000017500000000000011347266042022063 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/0000755000175000017500000000000011347266042026170 5ustar bobkebobke././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.hcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollisi0000644000175000017500000000421111337071441033303 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 CONTINUOUS_COLLISION_CONVEX_CAST_H #define CONTINUOUS_COLLISION_CONVEX_CAST_H #include "btConvexCast.h" #include "btSimplexSolverInterface.h" class btConvexPenetrationDepthSolver; class btConvexShape; /// btContinuousConvexCollision implements angular and linear time of impact for convex objects. /// Based on Brian Mirtich's Conservative Advancement idea (PhD thesis). /// Algorithm operates in worldspace, in order to keep inbetween motion globally consistent. /// It uses GJK at the moment. Future improvement would use minkowski sum / supporting vertex, merging innerloops class btContinuousConvexCollision : public btConvexCast { btSimplexSolverInterface* m_simplexSolver; btConvexPenetrationDepthSolver* m_penetrationDepthSolver; const btConvexShape* m_convexA; const btConvexShape* m_convexB; public: btContinuousConvexCollision (const btConvexShape* shapeA,const btConvexShape* shapeB ,btSimplexSolverInterface* simplexSolver,btConvexPenetrationDepthSolver* penetrationDepthSolver); virtual bool calcTimeOfImpact( const btTransform& fromA, const btTransform& toA, const btTransform& fromB, const btTransform& toB, CastResult& result); }; #endif //CONTINUOUS_COLLISION_CONVEX_CAST_H critterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btConvexCast.cpp0000644000175000017500000000176211337071441031301 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btConvexCast.h" btConvexCast::~btConvexCast() { } ././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.hcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthS0000644000175000017500000000337611337071441033130 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ EPA Copyright (c) Ricardo Padrela 2006 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 BT_GJP_EPA_PENETRATION_DEPTH_H #define BT_GJP_EPA_PENETRATION_DEPTH_H #include "btConvexPenetrationDepthSolver.h" ///EpaPenetrationDepthSolver uses the Expanding Polytope Algorithm to ///calculate the penetration depth between two convex shapes. class btGjkEpaPenetrationDepthSolver : public btConvexPenetrationDepthSolver { public : btGjkEpaPenetrationDepthSolver() { } bool calcPenDepth( btSimplexSolverInterface& simplexSolver, const btConvexShape* pConvexA, const btConvexShape* pConvexB, const btTransform& transformA, const btTransform& transformB, btVector3& v, btVector3& wWitnessOnA, btVector3& wWitnessOnB, class btIDebugDraw* debugDraw,btStackAlloc* stackAlloc ); private : }; #endif // BT_GJP_EPA_PENETRATION_DEPTH_H ././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.hcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthS0000644000175000017500000000321311337071441033217 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 __CONVEX_PENETRATION_DEPTH_H #define __CONVEX_PENETRATION_DEPTH_H class btStackAlloc; class btVector3; #include "btSimplexSolverInterface.h" class btConvexShape; class btTransform; ///ConvexPenetrationDepthSolver provides an interface for penetration depth calculation. class btConvexPenetrationDepthSolver { public: virtual ~btConvexPenetrationDepthSolver() {}; virtual bool calcPenDepth( btSimplexSolverInterface& simplexSolver, const btConvexShape* convexA,const btConvexShape* convexB, const btTransform& transA,const btTransform& transB, btVector3& v, btVector3& pa, btVector3& pb, class btIDebugDraw* debugDraw,btStackAlloc* stackAlloc ) = 0; }; #endif //CONVEX_PENETRATION_DEPTH_H critterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btGjkEpa2.cpp0000644000175000017500000006075311337071441030454 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ /* GJK-EPA collision solver by Nathanael Presson, 2008 */ #include "BulletCollision/CollisionShapes/btConvexInternalShape.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" #include "btGjkEpa2.h" #if defined(DEBUG) || defined (_DEBUG) #include //for debug printf #ifdef __SPU__ #include #define printf spu_printf #endif //__SPU__ #endif namespace gjkepa2_impl { // Config /* GJK */ #define GJK_MAX_ITERATIONS 128 #define GJK_ACCURARY ((btScalar)0.0001) #define GJK_MIN_DISTANCE ((btScalar)0.0001) #define GJK_DUPLICATED_EPS ((btScalar)0.0001) #define GJK_SIMPLEX2_EPS ((btScalar)0.0) #define GJK_SIMPLEX3_EPS ((btScalar)0.0) #define GJK_SIMPLEX4_EPS ((btScalar)0.0) /* EPA */ #define EPA_MAX_VERTICES 64 #define EPA_MAX_FACES (EPA_MAX_VERTICES*2) #define EPA_MAX_ITERATIONS 255 #define EPA_ACCURACY ((btScalar)0.0001) #define EPA_FALLBACK (10*EPA_ACCURACY) #define EPA_PLANE_EPS ((btScalar)0.00001) #define EPA_INSIDE_EPS ((btScalar)0.01) // Shorthands typedef unsigned int U; typedef unsigned char U1; // MinkowskiDiff struct MinkowskiDiff { const btConvexShape* m_shapes[2]; btMatrix3x3 m_toshape1; btTransform m_toshape0; #ifdef __SPU__ bool m_enableMargin; #else btVector3 (btConvexShape::*Ls)(const btVector3&) const; #endif//__SPU__ MinkowskiDiff() { } #ifdef __SPU__ void EnableMargin(bool enable) { m_enableMargin = enable; } inline btVector3 Support0(const btVector3& d) const { if (m_enableMargin) { return m_shapes[0]->localGetSupportVertexNonVirtual(d); } else { return m_shapes[0]->localGetSupportVertexWithoutMarginNonVirtual(d); } } inline btVector3 Support1(const btVector3& d) const { if (m_enableMargin) { return m_toshape0*(m_shapes[1]->localGetSupportVertexNonVirtual(m_toshape1*d)); } else { return m_toshape0*(m_shapes[1]->localGetSupportVertexWithoutMarginNonVirtual(m_toshape1*d)); } } #else void EnableMargin(bool enable) { if(enable) Ls=&btConvexShape::localGetSupportVertexNonVirtual; else Ls=&btConvexShape::localGetSupportVertexWithoutMarginNonVirtual; } inline btVector3 Support0(const btVector3& d) const { return(((m_shapes[0])->*(Ls))(d)); } inline btVector3 Support1(const btVector3& d) const { return(m_toshape0*((m_shapes[1])->*(Ls))(m_toshape1*d)); } #endif //__SPU__ inline btVector3 Support(const btVector3& d) const { return(Support0(d)-Support1(-d)); } btVector3 Support(const btVector3& d,U index) const { if(index) return(Support1(d)); else return(Support0(d)); } }; typedef MinkowskiDiff tShape; // GJK struct GJK { /* Types */ struct sSV { btVector3 d,w; }; struct sSimplex { sSV* c[4]; btScalar p[4]; U rank; }; struct eStatus { enum _ { Valid, Inside, Failed };}; /* Fields */ tShape m_shape; btVector3 m_ray; btScalar m_distance; sSimplex m_simplices[2]; sSV m_store[4]; sSV* m_free[4]; U m_nfree; U m_current; sSimplex* m_simplex; eStatus::_ m_status; /* Methods */ GJK() { Initialize(); } void Initialize() { m_ray = btVector3(0,0,0); m_nfree = 0; m_status = eStatus::Failed; m_current = 0; m_distance = 0; } eStatus::_ Evaluate(const tShape& shapearg,const btVector3& guess) { U iterations=0; btScalar sqdist=0; btScalar alpha=0; btVector3 lastw[4]; U clastw=0; /* Initialize solver */ m_free[0] = &m_store[0]; m_free[1] = &m_store[1]; m_free[2] = &m_store[2]; m_free[3] = &m_store[3]; m_nfree = 4; m_current = 0; m_status = eStatus::Valid; m_shape = shapearg; m_distance = 0; /* Initialize simplex */ m_simplices[0].rank = 0; m_ray = guess; const btScalar sqrl= m_ray.length2(); appendvertice(m_simplices[0],sqrl>0?-m_ray:btVector3(1,0,0)); m_simplices[0].p[0] = 1; m_ray = m_simplices[0].c[0]->w; sqdist = sqrl; lastw[0] = lastw[1] = lastw[2] = lastw[3] = m_ray; /* Loop */ do { const U next=1-m_current; sSimplex& cs=m_simplices[m_current]; sSimplex& ns=m_simplices[next]; /* Check zero */ const btScalar rl=m_ray.length(); if(rlw; bool found=false; for(U i=0;i<4;++i) { if((w-lastw[i]).length2()w, cs.c[1]->w, weights,mask);break; case 3: sqdist=projectorigin( cs.c[0]->w, cs.c[1]->w, cs.c[2]->w, weights,mask);break; case 4: sqdist=projectorigin( cs.c[0]->w, cs.c[1]->w, cs.c[2]->w, cs.c[3]->w, weights,mask);break; } if(sqdist>=0) {/* Valid */ ns.rank = 0; m_ray = btVector3(0,0,0); m_current = next; for(U i=0,ni=cs.rank;iw*weights[i]; } else { m_free[m_nfree++] = cs.c[i]; } } if(mask==15) m_status=eStatus::Inside; } else {/* Return old simplex */ removevertice(m_simplices[m_current]); break; } m_status=((++iterations)rank) { case 1: { for(U i=0;i<3;++i) { btVector3 axis=btVector3(0,0,0); axis[i]=1; appendvertice(*m_simplex, axis); if(EncloseOrigin()) return(true); removevertice(*m_simplex); appendvertice(*m_simplex,-axis); if(EncloseOrigin()) return(true); removevertice(*m_simplex); } } break; case 2: { const btVector3 d=m_simplex->c[1]->w-m_simplex->c[0]->w; for(U i=0;i<3;++i) { btVector3 axis=btVector3(0,0,0); axis[i]=1; const btVector3 p=btCross(d,axis); if(p.length2()>0) { appendvertice(*m_simplex, p); if(EncloseOrigin()) return(true); removevertice(*m_simplex); appendvertice(*m_simplex,-p); if(EncloseOrigin()) return(true); removevertice(*m_simplex); } } } break; case 3: { const btVector3 n=btCross(m_simplex->c[1]->w-m_simplex->c[0]->w, m_simplex->c[2]->w-m_simplex->c[0]->w); if(n.length2()>0) { appendvertice(*m_simplex,n); if(EncloseOrigin()) return(true); removevertice(*m_simplex); appendvertice(*m_simplex,-n); if(EncloseOrigin()) return(true); removevertice(*m_simplex); } } break; case 4: { if(btFabs(det( m_simplex->c[0]->w-m_simplex->c[3]->w, m_simplex->c[1]->w-m_simplex->c[3]->w, m_simplex->c[2]->w-m_simplex->c[3]->w))>0) return(true); } break; } return(false); } /* Internals */ void getsupport(const btVector3& d,sSV& sv) const { sv.d = d/d.length(); sv.w = m_shape.Support(sv.d); } void removevertice(sSimplex& simplex) { m_free[m_nfree++]=simplex.c[--simplex.rank]; } void appendvertice(sSimplex& simplex,const btVector3& v) { simplex.p[simplex.rank]=0; simplex.c[simplex.rank]=m_free[--m_nfree]; getsupport(v,*simplex.c[simplex.rank++]); } static btScalar det(const btVector3& a,const btVector3& b,const btVector3& c) { return( a.y()*b.z()*c.x()+a.z()*b.x()*c.y()- a.x()*b.z()*c.y()-a.y()*b.x()*c.z()+ a.x()*b.y()*c.z()-a.z()*b.y()*c.x()); } static btScalar projectorigin( const btVector3& a, const btVector3& b, btScalar* w,U& m) { const btVector3 d=b-a; const btScalar l=d.length2(); if(l>GJK_SIMPLEX2_EPS) { const btScalar t(l>0?-btDot(a,d)/l:0); if(t>=1) { w[0]=0;w[1]=1;m=2;return(b.length2()); } else if(t<=0) { w[0]=1;w[1]=0;m=1;return(a.length2()); } else { w[0]=1-(w[1]=t);m=3;return((a+d*t).length2()); } } return(-1); } static btScalar projectorigin( const btVector3& a, const btVector3& b, const btVector3& c, btScalar* w,U& m) { static const U imd3[]={1,2,0}; const btVector3* vt[]={&a,&b,&c}; const btVector3 dl[]={a-b,b-c,c-a}; const btVector3 n=btCross(dl[0],dl[1]); const btScalar l=n.length2(); if(l>GJK_SIMPLEX3_EPS) { btScalar mindist=-1; btScalar subw[2]={0.f,0.f}; U subm(0); for(U i=0;i<3;++i) { if(btDot(*vt[i],btCross(dl[i],n))>0) { const U j=imd3[i]; const btScalar subd(projectorigin(*vt[i],*vt[j],subw,subm)); if((mindist<0)||(subd(((subm&1)?1<GJK_SIMPLEX4_EPS)) { btScalar mindist=-1; btScalar subw[3]={0.f,0.f,0.f}; U subm(0); for(U i=0;i<3;++i) { const U j=imd3[i]; const btScalar s=vl*btDot(d,btCross(dl[i],dl[j])); if(s>0) { const btScalar subd=projectorigin(*vt[i],*vt[j],d,subw,subm); if((mindist<0)||(subd((subm&1?1<e[ea]=(U1)eb;fa->f[ea]=fb; fb->e[eb]=(U1)ea;fb->f[eb]=fa; } static inline void append(sList& list,sFace* face) { face->l[0] = 0; face->l[1] = list.root; if(list.root) list.root->l[0]=face; list.root = face; ++list.count; } static inline void remove(sList& list,sFace* face) { if(face->l[1]) face->l[1]->l[0]=face->l[0]; if(face->l[0]) face->l[0]->l[1]=face->l[1]; if(face==list.root) list.root=face->l[1]; --list.count; } void Initialize() { m_status = eStatus::Failed; m_normal = btVector3(0,0,0); m_depth = 0; m_nextsv = 0; for(U i=0;i1)&&gjk.EncloseOrigin()) { /* Clean up */ while(m_hull.root) { sFace* f = m_hull.root; remove(m_hull,f); append(m_stock,f); } m_status = eStatus::Valid; m_nextsv = 0; /* Orient simplex */ if(gjk.det( simplex.c[0]->w-simplex.c[3]->w, simplex.c[1]->w-simplex.c[3]->w, simplex.c[2]->w-simplex.c[3]->w)<0) { btSwap(simplex.c[0],simplex.c[1]); btSwap(simplex.p[0],simplex.p[1]); } /* Build initial hull */ sFace* tetra[]={newface(simplex.c[0],simplex.c[1],simplex.c[2],true), newface(simplex.c[1],simplex.c[0],simplex.c[3],true), newface(simplex.c[2],simplex.c[1],simplex.c[3],true), newface(simplex.c[0],simplex.c[2],simplex.c[3],true)}; if(m_hull.count==4) { sFace* best=findbest(); sFace outer=*best; U pass=0; U iterations=0; bind(tetra[0],0,tetra[1],0); bind(tetra[0],1,tetra[2],0); bind(tetra[0],2,tetra[3],0); bind(tetra[1],1,tetra[3],2); bind(tetra[1],2,tetra[2],1); bind(tetra[2],2,tetra[3],1); m_status=eStatus::Valid; for(;iterationspass = (U1)(++pass); gjk.getsupport(best->n,*w); const btScalar wdist=btDot(best->n,w->w)-best->d; if(wdist>EPA_ACCURACY) { for(U j=0;(j<3)&&valid;++j) { valid&=expand( pass,w, best->f[j],best->e[j], horizon); } if(valid&&(horizon.nf>=3)) { bind(horizon.cf,1,horizon.ff,2); remove(m_hull,best); append(m_stock,best); best=findbest(); if(best->p>=outer.p) outer=*best; } else { m_status=eStatus::InvalidHull;break; } } else { m_status=eStatus::AccuraryReached;break; } } else { m_status=eStatus::OutOfVertices;break; } } const btVector3 projection=outer.n*outer.d; m_normal = outer.n; m_depth = outer.d; m_result.rank = 3; m_result.c[0] = outer.c[0]; m_result.c[1] = outer.c[1]; m_result.c[2] = outer.c[2]; m_result.p[0] = btCross( outer.c[1]->w-projection, outer.c[2]->w-projection).length(); m_result.p[1] = btCross( outer.c[2]->w-projection, outer.c[0]->w-projection).length(); m_result.p[2] = btCross( outer.c[0]->w-projection, outer.c[1]->w-projection).length(); const btScalar sum=m_result.p[0]+m_result.p[1]+m_result.p[2]; m_result.p[0] /= sum; m_result.p[1] /= sum; m_result.p[2] /= sum; return(m_status); } } /* Fallback */ m_status = eStatus::FallBack; m_normal = -guess; const btScalar nl=m_normal.length(); if(nl>0) m_normal = m_normal/nl; else m_normal = btVector3(1,0,0); m_depth = 0; m_result.rank=1; m_result.c[0]=simplex.c[0]; m_result.p[0]=1; return(m_status); } sFace* newface(sSV* a,sSV* b,sSV* c,bool forced) { if(m_stock.root) { sFace* face=m_stock.root; remove(m_stock,face); append(m_hull,face); face->pass = 0; face->c[0] = a; face->c[1] = b; face->c[2] = c; face->n = btCross(b->w-a->w,c->w-a->w); const btScalar l=face->n.length(); const bool v=l>EPA_ACCURACY; face->p = btMin(btMin( btDot(a->w,btCross(face->n,a->w-b->w)), btDot(b->w,btCross(face->n,b->w-c->w))), btDot(c->w,btCross(face->n,c->w-a->w))) / (v?l:1); face->p = face->p>=-EPA_INSIDE_EPS?0:face->p; if(v) { face->d = btDot(a->w,face->n)/l; face->n /= l; if(forced||(face->d>=-EPA_PLANE_EPS)) { return(face); } else m_status=eStatus::NonConvex; } else m_status=eStatus::Degenerated; remove(m_hull,face); append(m_stock,face); return(0); } m_status=m_stock.root?eStatus::OutOfVertices:eStatus::OutOfFaces; return(0); } sFace* findbest() { sFace* minf=m_hull.root; btScalar mind=minf->d*minf->d; btScalar maxp=minf->p; for(sFace* f=minf->l[1];f;f=f->l[1]) { const btScalar sqd=f->d*f->d; if((f->p>=maxp)&&(sqdp; } } return(minf); } bool expand(U pass,sSV* w,sFace* f,U e,sHorizon& horizon) { static const U i1m3[]={1,2,0}; static const U i2m3[]={2,0,1}; if(f->pass!=pass) { const U e1=i1m3[e]; if((btDot(f->n,w->w)-f->d)<-EPA_PLANE_EPS) { sFace* nf=newface(f->c[e1],f->c[e],w,false); if(nf) { bind(nf,0,f,e); if(horizon.cf) bind(horizon.cf,1,nf,2); else horizon.ff=nf; horizon.cf=nf; ++horizon.nf; return(true); } } else { const U e2=i2m3[e]; f->pass = (U1)pass; if( expand(pass,w,f->f[e1],f->e[e1],horizon)&& expand(pass,w,f->f[e2],f->e[e2],horizon)) { remove(m_hull,f); append(m_stock,f); return(true); } } } return(false); } }; // static void Initialize( const btConvexShape* shape0,const btTransform& wtrs0, const btConvexShape* shape1,const btTransform& wtrs1, btGjkEpaSolver2::sResults& results, tShape& shape, bool withmargins) { /* Results */ results.witnesses[0] = results.witnesses[1] = btVector3(0,0,0); results.status = btGjkEpaSolver2::sResults::Separated; /* Shape */ shape.m_shapes[0] = shape0; shape.m_shapes[1] = shape1; shape.m_toshape1 = wtrs1.getBasis().transposeTimes(wtrs0.getBasis()); shape.m_toshape0 = wtrs0.inverseTimes(wtrs1); shape.EnableMargin(withmargins); } } // // Api // using namespace gjkepa2_impl; // int btGjkEpaSolver2::StackSizeRequirement() { return(sizeof(GJK)+sizeof(EPA)); } // bool btGjkEpaSolver2::Distance( const btConvexShape* shape0, const btTransform& wtrs0, const btConvexShape* shape1, const btTransform& wtrs1, const btVector3& guess, sResults& results) { tShape shape; Initialize(shape0,wtrs0,shape1,wtrs1,results,shape,false); GJK gjk; GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,guess); if(gjk_status==GJK::eStatus::Valid) { btVector3 w0=btVector3(0,0,0); btVector3 w1=btVector3(0,0,0); for(U i=0;irank;++i) { const btScalar p=gjk.m_simplex->p[i]; w0+=shape.Support( gjk.m_simplex->c[i]->d,0)*p; w1+=shape.Support(-gjk.m_simplex->c[i]->d,1)*p; } results.witnesses[0] = wtrs0*w0; results.witnesses[1] = wtrs0*w1; results.normal = w0-w1; results.distance = results.normal.length(); results.normal /= results.distance>GJK_MIN_DISTANCE?results.distance:1; return(true); } else { results.status = gjk_status==GJK::eStatus::Inside? sResults::Penetrating : sResults::GJK_Failed ; return(false); } } // bool btGjkEpaSolver2::Penetration( const btConvexShape* shape0, const btTransform& wtrs0, const btConvexShape* shape1, const btTransform& wtrs1, const btVector3& guess, sResults& results, bool usemargins) { tShape shape; Initialize(shape0,wtrs0,shape1,wtrs1,results,shape,usemargins); GJK gjk; GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,-guess); switch(gjk_status) { case GJK::eStatus::Inside: { EPA epa; EPA::eStatus::_ epa_status=epa.Evaluate(gjk,-guess); if(epa_status!=EPA::eStatus::Failed) { btVector3 w0=btVector3(0,0,0); for(U i=0;id,0)*epa.m_result.p[i]; } results.status = sResults::Penetrating; results.witnesses[0] = wtrs0*w0; results.witnesses[1] = wtrs0*(w0-epa.m_normal*epa.m_depth); results.normal = -epa.m_normal; results.distance = -epa.m_depth; return(true); } else results.status=sResults::EPA_Failed; } break; case GJK::eStatus::Failed: results.status=sResults::GJK_Failed; break; default: { } } return(false); } #ifndef __SPU__ // btScalar btGjkEpaSolver2::SignedDistance(const btVector3& position, btScalar margin, const btConvexShape* shape0, const btTransform& wtrs0, sResults& results) { tShape shape; btSphereShape shape1(margin); btTransform wtrs1(btQuaternion(0,0,0,1),position); Initialize(shape0,wtrs0,&shape1,wtrs1,results,shape,false); GJK gjk; GJK::eStatus::_ gjk_status=gjk.Evaluate(shape,btVector3(1,1,1)); if(gjk_status==GJK::eStatus::Valid) { btVector3 w0=btVector3(0,0,0); btVector3 w1=btVector3(0,0,0); for(U i=0;irank;++i) { const btScalar p=gjk.m_simplex->p[i]; w0+=shape.Support( gjk.m_simplex->c[i]->d,0)*p; w1+=shape.Support(-gjk.m_simplex->c[i]->d,1)*p; } results.witnesses[0] = wtrs0*w0; results.witnesses[1] = wtrs0*w1; const btVector3 delta= results.witnesses[1]- results.witnesses[0]; const btScalar margin= shape0->getMarginNonVirtual()+ shape1.getMarginNonVirtual(); const btScalar length= delta.length(); results.normal = delta/length; results.witnesses[0] += results.normal*margin; return(length-margin); } else { if(gjk_status==GJK::eStatus::Inside) { if(Penetration(shape0,wtrs0,&shape1,wtrs1,gjk.m_ray,results)) { const btVector3 delta= results.witnesses[0]- results.witnesses[1]; const btScalar length= delta.length(); if (length >= SIMD_EPSILON) results.normal = delta/length; return(-length); } } } return(SIMD_INFINITY); } // bool btGjkEpaSolver2::SignedDistance(const btConvexShape* shape0, const btTransform& wtrs0, const btConvexShape* shape1, const btTransform& wtrs1, const btVector3& guess, sResults& results) { if(!Distance(shape0,wtrs0,shape1,wtrs1,guess,results)) return(Penetration(shape0,wtrs0,shape1,wtrs1,guess,results,false)); else return(true); } #endif //__SPU__ /* Symbols cleanup */ #undef GJK_MAX_ITERATIONS #undef GJK_ACCURARY #undef GJK_MIN_DISTANCE #undef GJK_DUPLICATED_EPS #undef GJK_SIMPLEX2_EPS #undef GJK_SIMPLEX3_EPS #undef GJK_SIMPLEX4_EPS #undef EPA_MAX_VERTICES #undef EPA_MAX_FACES #undef EPA_MAX_ITERATIONS #undef EPA_ACCURACY #undef EPA_FALLBACK #undef EPA_PLANE_EPS #undef EPA_INSIDE_EPS ././@LongLink0000000000000000000000000000016100000000000011563 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDep0000644000175000017500000002703711344267705033273 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btMinkowskiPenetrationDepthSolver.h" #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" #include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" #include "BulletCollision/CollisionShapes/btConvexShape.h" #define NUM_UNITSPHERE_POINTS 42 bool btMinkowskiPenetrationDepthSolver::calcPenDepth(btSimplexSolverInterface& simplexSolver, const btConvexShape* convexA,const btConvexShape* convexB, const btTransform& transA,const btTransform& transB, btVector3& v, btVector3& pa, btVector3& pb, class btIDebugDraw* debugDraw,btStackAlloc* stackAlloc ) { (void)stackAlloc; (void)v; bool check2d= convexA->isConvex2d() && convexB->isConvex2d(); struct btIntermediateResult : public btDiscreteCollisionDetectorInterface::Result { btIntermediateResult():m_hasResult(false) { } btVector3 m_normalOnBInWorld; btVector3 m_pointInWorld; btScalar m_depth; bool m_hasResult; virtual void setShapeIdentifiersA(int partId0,int index0) { (void)partId0; (void)index0; } virtual void setShapeIdentifiersB(int partId1,int index1) { (void)partId1; (void)index1; } void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth) { m_normalOnBInWorld = normalOnBInWorld; m_pointInWorld = pointInWorld; m_depth = depth; m_hasResult = true; } }; //just take fixed number of orientation, and sample the penetration depth in that direction btScalar minProj = btScalar(BT_LARGE_FLOAT); btVector3 minNorm(btScalar(0.), btScalar(0.), btScalar(0.)); btVector3 minA,minB; btVector3 seperatingAxisInA,seperatingAxisInB; btVector3 pInA,qInB,pWorld,qWorld,w; #ifndef __SPU__ #define USE_BATCHED_SUPPORT 1 #endif #ifdef USE_BATCHED_SUPPORT btVector3 supportVerticesABatch[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2]; btVector3 supportVerticesBBatch[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2]; btVector3 seperatingAxisInABatch[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2]; btVector3 seperatingAxisInBBatch[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2]; int i; int numSampleDirections = NUM_UNITSPHERE_POINTS; for (i=0;igetNumPreferredPenetrationDirections(); if (numPDA) { for (int i=0;igetPreferredPenetrationDirection(i,norm); norm = transA.getBasis() * norm; getPenetrationDirections()[numSampleDirections] = norm; seperatingAxisInABatch[numSampleDirections] = (-norm) * transA.getBasis(); seperatingAxisInBBatch[numSampleDirections] = norm * transB.getBasis(); numSampleDirections++; } } } { int numPDB = convexB->getNumPreferredPenetrationDirections(); if (numPDB) { for (int i=0;igetPreferredPenetrationDirection(i,norm); norm = transB.getBasis() * norm; getPenetrationDirections()[numSampleDirections] = norm; seperatingAxisInABatch[numSampleDirections] = (-norm) * transA.getBasis(); seperatingAxisInBBatch[numSampleDirections] = norm * transB.getBasis(); numSampleDirections++; } } } convexA->batchedUnitVectorGetSupportingVertexWithoutMargin(seperatingAxisInABatch,supportVerticesABatch,numSampleDirections); convexB->batchedUnitVectorGetSupportingVertexWithoutMargin(seperatingAxisInBBatch,supportVerticesBBatch,numSampleDirections); for (i=0;i0.01) { seperatingAxisInA = seperatingAxisInABatch[i]; seperatingAxisInB = seperatingAxisInBBatch[i]; pInA = supportVerticesABatch[i]; qInB = supportVerticesBBatch[i]; pWorld = transA(pInA); qWorld = transB(qInB); if (check2d) { pWorld[2] = 0.f; qWorld[2] = 0.f; } w = qWorld - pWorld; btScalar delta = norm.dot(w); //find smallest delta if (delta < minProj) { minProj = delta; minNorm = norm; minA = pWorld; minB = qWorld; } } } #else int numSampleDirections = NUM_UNITSPHERE_POINTS; #ifndef __SPU__ { int numPDA = convexA->getNumPreferredPenetrationDirections(); if (numPDA) { for (int i=0;igetPreferredPenetrationDirection(i,norm); norm = transA.getBasis() * norm; getPenetrationDirections()[numSampleDirections] = norm; numSampleDirections++; } } } { int numPDB = convexB->getNumPreferredPenetrationDirections(); if (numPDB) { for (int i=0;igetPreferredPenetrationDirection(i,norm); norm = transB.getBasis() * norm; getPenetrationDirections()[numSampleDirections] = norm; numSampleDirections++; } } } #endif // __SPU__ for (int i=0;ilocalGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA); qInB = convexB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB); pWorld = transA(pInA); qWorld = transB(qInB); w = qWorld - pWorld; btScalar delta = norm.dot(w); //find smallest delta if (delta < minProj) { minProj = delta; minNorm = norm; minA = pWorld; minB = qWorld; } } #endif //USE_BATCHED_SUPPORT //add the margins minA += minNorm*convexA->getMarginNonVirtual(); minB -= minNorm*convexB->getMarginNonVirtual(); //no penetration if (minProj < btScalar(0.)) return false; btScalar extraSeparation = 0.5f;///scale dependent minProj += extraSeparation+(convexA->getMarginNonVirtual() + convexB->getMarginNonVirtual()); //#define DEBUG_DRAW 1 #ifdef DEBUG_DRAW if (debugDraw) { btVector3 color(0,1,0); debugDraw->drawLine(minA,minB,color); color = btVector3 (1,1,1); btVector3 vec = minB-minA; btScalar prj2 = minNorm.dot(vec); debugDraw->drawLine(minA,minA+(minNorm*minProj),color); } #endif //DEBUG_DRAW btGjkPairDetector gjkdet(convexA,convexB,&simplexSolver,0); btScalar offsetDist = minProj; btVector3 offset = minNorm * offsetDist; btGjkPairDetector::ClosestPointInput input; btVector3 newOrg = transA.getOrigin() + offset; btTransform displacedTrans = transA; displacedTrans.setOrigin(newOrg); input.m_transformA = displacedTrans; input.m_transformB = transB; input.m_maximumDistanceSquared = btScalar(BT_LARGE_FLOAT);//minProj; btIntermediateResult res; gjkdet.setCachedSeperatingAxis(-minNorm); gjkdet.getClosestPoints(input,res,debugDraw); btScalar correctedMinNorm = minProj - res.m_depth; //the penetration depth is over-estimated, relax it btScalar penetration_relaxation= btScalar(1.); minNorm*=penetration_relaxation; if (res.m_hasResult) { pa = res.m_pointInWorld - minNorm * correctedMinNorm; pb = res.m_pointInWorld; v = minNorm; #ifdef DEBUG_DRAW if (debugDraw) { btVector3 color(1,0,0); debugDraw->drawLine(pa,pb,color); } #endif//DEBUG_DRAW } return res.m_hasResult; } btVector3* btMinkowskiPenetrationDepthSolver::getPenetrationDirections() { static btVector3 sPenetrationDirections[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2] = { btVector3(btScalar(0.000000) , btScalar(-0.000000),btScalar(-1.000000)), btVector3(btScalar(0.723608) , btScalar(-0.525725),btScalar(-0.447219)), btVector3(btScalar(-0.276388) , btScalar(-0.850649),btScalar(-0.447219)), btVector3(btScalar(-0.894426) , btScalar(-0.000000),btScalar(-0.447216)), btVector3(btScalar(-0.276388) , btScalar(0.850649),btScalar(-0.447220)), btVector3(btScalar(0.723608) , btScalar(0.525725),btScalar(-0.447219)), btVector3(btScalar(0.276388) , btScalar(-0.850649),btScalar(0.447220)), btVector3(btScalar(-0.723608) , btScalar(-0.525725),btScalar(0.447219)), btVector3(btScalar(-0.723608) , btScalar(0.525725),btScalar(0.447219)), btVector3(btScalar(0.276388) , btScalar(0.850649),btScalar(0.447219)), btVector3(btScalar(0.894426) , btScalar(0.000000),btScalar(0.447216)), btVector3(btScalar(-0.000000) , btScalar(0.000000),btScalar(1.000000)), btVector3(btScalar(0.425323) , btScalar(-0.309011),btScalar(-0.850654)), btVector3(btScalar(-0.162456) , btScalar(-0.499995),btScalar(-0.850654)), btVector3(btScalar(0.262869) , btScalar(-0.809012),btScalar(-0.525738)), btVector3(btScalar(0.425323) , btScalar(0.309011),btScalar(-0.850654)), btVector3(btScalar(0.850648) , btScalar(-0.000000),btScalar(-0.525736)), btVector3(btScalar(-0.525730) , btScalar(-0.000000),btScalar(-0.850652)), btVector3(btScalar(-0.688190) , btScalar(-0.499997),btScalar(-0.525736)), btVector3(btScalar(-0.162456) , btScalar(0.499995),btScalar(-0.850654)), btVector3(btScalar(-0.688190) , btScalar(0.499997),btScalar(-0.525736)), btVector3(btScalar(0.262869) , btScalar(0.809012),btScalar(-0.525738)), btVector3(btScalar(0.951058) , btScalar(0.309013),btScalar(0.000000)), btVector3(btScalar(0.951058) , btScalar(-0.309013),btScalar(0.000000)), btVector3(btScalar(0.587786) , btScalar(-0.809017),btScalar(0.000000)), btVector3(btScalar(0.000000) , btScalar(-1.000000),btScalar(0.000000)), btVector3(btScalar(-0.587786) , btScalar(-0.809017),btScalar(0.000000)), btVector3(btScalar(-0.951058) , btScalar(-0.309013),btScalar(-0.000000)), btVector3(btScalar(-0.951058) , btScalar(0.309013),btScalar(-0.000000)), btVector3(btScalar(-0.587786) , btScalar(0.809017),btScalar(-0.000000)), btVector3(btScalar(-0.000000) , btScalar(1.000000),btScalar(-0.000000)), btVector3(btScalar(0.587786) , btScalar(0.809017),btScalar(-0.000000)), btVector3(btScalar(0.688190) , btScalar(-0.499997),btScalar(0.525736)), btVector3(btScalar(-0.262869) , btScalar(-0.809012),btScalar(0.525738)), btVector3(btScalar(-0.850648) , btScalar(0.000000),btScalar(0.525736)), btVector3(btScalar(-0.262869) , btScalar(0.809012),btScalar(0.525738)), btVector3(btScalar(0.688190) , btScalar(0.499997),btScalar(0.525736)), btVector3(btScalar(0.525730) , btScalar(0.000000),btScalar(0.850652)), btVector3(btScalar(0.162456) , btScalar(-0.499995),btScalar(0.850654)), btVector3(btScalar(-0.425323) , btScalar(-0.309011),btScalar(0.850654)), btVector3(btScalar(-0.425323) , btScalar(0.309011),btScalar(0.850654)), btVector3(btScalar(0.162456) , btScalar(0.499995),btScalar(0.850654)) }; return sPenetrationDirections; } critterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.cpp0000644000175000017500000001072011337071441031727 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btGjkConvexCast.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" #include "btGjkPairDetector.h" #include "btPointCollector.h" #include "LinearMath/btTransformUtil.h" #ifdef BT_USE_DOUBLE_PRECISION #define MAX_ITERATIONS 64 #else #define MAX_ITERATIONS 32 #endif btGjkConvexCast::btGjkConvexCast(const btConvexShape* convexA,const btConvexShape* convexB,btSimplexSolverInterface* simplexSolver) :m_simplexSolver(simplexSolver), m_convexA(convexA), m_convexB(convexB) { } bool btGjkConvexCast::calcTimeOfImpact( const btTransform& fromA, const btTransform& toA, const btTransform& fromB, const btTransform& toB, CastResult& result) { m_simplexSolver->reset(); /// compute linear velocity for this interval, to interpolate //assume no rotation/angular velocity, assert here? btVector3 linVelA,linVelB; linVelA = toA.getOrigin()-fromA.getOrigin(); linVelB = toB.getOrigin()-fromB.getOrigin(); btScalar radius = btScalar(0.001); btScalar lambda = btScalar(0.); btVector3 v(1,0,0); int maxIter = MAX_ITERATIONS; btVector3 n; n.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); bool hasResult = false; btVector3 c; btVector3 r = (linVelA-linVelB); btScalar lastLambda = lambda; //btScalar epsilon = btScalar(0.001); int numIter = 0; //first solution, using GJK btTransform identityTrans; identityTrans.setIdentity(); // result.drawCoordSystem(sphereTr); btPointCollector pointCollector; btGjkPairDetector gjk(m_convexA,m_convexB,m_simplexSolver,0);//m_penetrationDepthSolver); btGjkPairDetector::ClosestPointInput input; //we don't use margins during CCD // gjk.setIgnoreMargin(true); input.m_transformA = fromA; input.m_transformB = fromB; gjk.getClosestPoints(input,pointCollector,0); hasResult = pointCollector.m_hasResult; c = pointCollector.m_pointInWorld; if (hasResult) { btScalar dist; dist = pointCollector.m_distance; n = pointCollector.m_normalOnBInWorld; //not close enough while (dist > radius) { numIter++; if (numIter > maxIter) { return false; //todo: report a failure } btScalar dLambda = btScalar(0.); btScalar projectedLinearVelocity = r.dot(n); dLambda = dist / (projectedLinearVelocity); lambda = lambda - dLambda; if (lambda > btScalar(1.)) return false; if (lambda < btScalar(0.)) return false; //todo: next check with relative epsilon if (lambda <= lastLambda) { return false; //n.setValue(0,0,0); break; } lastLambda = lambda; //interpolate to next lambda result.DebugDraw( lambda ); input.m_transformA.getOrigin().setInterpolate3(fromA.getOrigin(),toA.getOrigin(),lambda); input.m_transformB.getOrigin().setInterpolate3(fromB.getOrigin(),toB.getOrigin(),lambda); gjk.getClosestPoints(input,pointCollector,0); if (pointCollector.m_hasResult) { if (pointCollector.m_distance < btScalar(0.)) { result.m_fraction = lastLambda; n = pointCollector.m_normalOnBInWorld; result.m_normal=n; result.m_hitPoint = pointCollector.m_pointInWorld; return true; } c = pointCollector.m_pointInWorld; n = pointCollector.m_normalOnBInWorld; dist = pointCollector.m_distance; } else { //?? return false; } } //is n normalized? //don't report time of impact for motion away from the contact normal (or causes minor penetration) if (n.dot(r)>=-result.m_allowedPenetration) return false; result.m_fraction = lambda; result.m_normal = n; result.m_hitPoint = c; return true; } return false; } critterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.h0000644000175000017500000001531611344267705032513 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 PERSISTENT_MANIFOLD_H #define PERSISTENT_MANIFOLD_H #include "LinearMath/btVector3.h" #include "LinearMath/btTransform.h" #include "btManifoldPoint.h" #include "LinearMath/btAlignedAllocator.h" struct btCollisionResult; ///maximum contact breaking and merging threshold extern btScalar gContactBreakingThreshold; typedef bool (*ContactDestroyedCallback)(void* userPersistentData); typedef bool (*ContactProcessedCallback)(btManifoldPoint& cp,void* body0,void* body1); extern ContactDestroyedCallback gContactDestroyedCallback; extern ContactProcessedCallback gContactProcessedCallback; enum btContactManifoldTypes { BT_PERSISTENT_MANIFOLD_TYPE = 1, MAX_CONTACT_MANIFOLD_TYPE }; #define MANIFOLD_CACHE_SIZE 4 ///btPersistentManifold is a contact point cache, it stays persistent as long as objects are overlapping in the broadphase. ///Those contact points are created by the collision narrow phase. ///The cache can be empty, or hold 1,2,3 or 4 points. Some collision algorithms (GJK) might only add one point at a time. ///updates/refreshes old contact points, and throw them away if necessary (distance becomes too large) ///reduces the cache to 4 points, when more then 4 points are added, using following rules: ///the contact point with deepest penetration is always kept, and it tries to maximuze the area covered by the points ///note that some pairs of objects might have more then one contact manifold. ATTRIBUTE_ALIGNED16( class) btPersistentManifold : public btTypedObject { btManifoldPoint m_pointCache[MANIFOLD_CACHE_SIZE]; /// this two body pointers can point to the physics rigidbody class. /// void* will allow any rigidbody class void* m_body0; void* m_body1; int m_cachedPoints; btScalar m_contactBreakingThreshold; btScalar m_contactProcessingThreshold; /// sort cached points so most isolated points come first int sortCachedPoints(const btManifoldPoint& pt); int findContactPoint(const btManifoldPoint* unUsed, int numUnused,const btManifoldPoint& pt); public: BT_DECLARE_ALIGNED_ALLOCATOR(); int m_index1a; btPersistentManifold(); btPersistentManifold(void* body0,void* body1,int , btScalar contactBreakingThreshold,btScalar contactProcessingThreshold) : btTypedObject(BT_PERSISTENT_MANIFOLD_TYPE), m_body0(body0),m_body1(body1),m_cachedPoints(0), m_contactBreakingThreshold(contactBreakingThreshold), m_contactProcessingThreshold(contactProcessingThreshold) { } SIMD_FORCE_INLINE void* getBody0() { return m_body0;} SIMD_FORCE_INLINE void* getBody1() { return m_body1;} SIMD_FORCE_INLINE const void* getBody0() const { return m_body0;} SIMD_FORCE_INLINE const void* getBody1() const { return m_body1;} void setBodies(void* body0,void* body1) { m_body0 = body0; m_body1 = body1; } void clearUserCache(btManifoldPoint& pt); #ifdef DEBUG_PERSISTENCY void DebugPersistency(); #endif // SIMD_FORCE_INLINE int getNumContacts() const { return m_cachedPoints;} SIMD_FORCE_INLINE const btManifoldPoint& getContactPoint(int index) const { btAssert(index < m_cachedPoints); return m_pointCache[index]; } SIMD_FORCE_INLINE btManifoldPoint& getContactPoint(int index) { btAssert(index < m_cachedPoints); return m_pointCache[index]; } ///@todo: get this margin from the current physics / collision environment btScalar getContactBreakingThreshold() const; btScalar getContactProcessingThreshold() const { return m_contactProcessingThreshold; } int getCacheEntry(const btManifoldPoint& newPoint) const; int addManifoldPoint( const btManifoldPoint& newPoint); void removeContactPoint (int index) { clearUserCache(m_pointCache[index]); int lastUsedIndex = getNumContacts() - 1; // m_pointCache[index] = m_pointCache[lastUsedIndex]; if(index != lastUsedIndex) { m_pointCache[index] = m_pointCache[lastUsedIndex]; //get rid of duplicated userPersistentData pointer m_pointCache[lastUsedIndex].m_userPersistentData = 0; m_pointCache[lastUsedIndex].m_appliedImpulse = 0.f; m_pointCache[lastUsedIndex].m_lateralFrictionInitialized = false; m_pointCache[lastUsedIndex].m_appliedImpulseLateral1 = 0.f; m_pointCache[lastUsedIndex].m_appliedImpulseLateral2 = 0.f; m_pointCache[lastUsedIndex].m_lifeTime = 0; } btAssert(m_pointCache[lastUsedIndex].m_userPersistentData==0); m_cachedPoints--; } void replaceContactPoint(const btManifoldPoint& newPoint,int insertIndex) { btAssert(validContactDistance(newPoint)); #define MAINTAIN_PERSISTENCY 1 #ifdef MAINTAIN_PERSISTENCY int lifeTime = m_pointCache[insertIndex].getLifeTime(); btScalar appliedImpulse = m_pointCache[insertIndex].m_appliedImpulse; btScalar appliedLateralImpulse1 = m_pointCache[insertIndex].m_appliedImpulseLateral1; btScalar appliedLateralImpulse2 = m_pointCache[insertIndex].m_appliedImpulseLateral2; btAssert(lifeTime>=0); void* cache = m_pointCache[insertIndex].m_userPersistentData; m_pointCache[insertIndex] = newPoint; m_pointCache[insertIndex].m_userPersistentData = cache; m_pointCache[insertIndex].m_appliedImpulse = appliedImpulse; m_pointCache[insertIndex].m_appliedImpulseLateral1 = appliedLateralImpulse1; m_pointCache[insertIndex].m_appliedImpulseLateral2 = appliedLateralImpulse2; m_pointCache[insertIndex].m_lifeTime = lifeTime; #else clearUserCache(m_pointCache[insertIndex]); m_pointCache[insertIndex] = newPoint; #endif } bool validContactDistance(const btManifoldPoint& pt) const { return pt.m_distance1 <= getContactBreakingThreshold(); } /// calculated new worldspace coordinates and depth, and reject points that exceed the collision margin void refreshContactPoints( const btTransform& trA,const btTransform& trB); SIMD_FORCE_INLINE void clearManifold() { int i; for (i=0;igetSimplexSolver()->setEqualVertexThreshold(0.f) to disable/configure #define BT_USE_EQUAL_VERTEX_THRESHOLD #define VORONOI_DEFAULT_EQUAL_VERTEX_THRESHOLD 0.0001f struct btUsageBitfield{ btUsageBitfield() { reset(); } void reset() { usedVertexA = false; usedVertexB = false; usedVertexC = false; usedVertexD = false; } unsigned short usedVertexA : 1; unsigned short usedVertexB : 1; unsigned short usedVertexC : 1; unsigned short usedVertexD : 1; unsigned short unused1 : 1; unsigned short unused2 : 1; unsigned short unused3 : 1; unsigned short unused4 : 1; }; struct btSubSimplexClosestResult { btVector3 m_closestPointOnSimplex; //MASK for m_usedVertices //stores the simplex vertex-usage, using the MASK, // if m_usedVertices & MASK then the related vertex is used btUsageBitfield m_usedVertices; btScalar m_barycentricCoords[4]; bool m_degenerate; void reset() { m_degenerate = false; setBarycentricCoordinates(); m_usedVertices.reset(); } bool isValid() { bool valid = (m_barycentricCoords[0] >= btScalar(0.)) && (m_barycentricCoords[1] >= btScalar(0.)) && (m_barycentricCoords[2] >= btScalar(0.)) && (m_barycentricCoords[3] >= btScalar(0.)); return valid; } void setBarycentricCoordinates(btScalar a=btScalar(0.),btScalar b=btScalar(0.),btScalar c=btScalar(0.),btScalar d=btScalar(0.)) { m_barycentricCoords[0] = a; m_barycentricCoords[1] = b; m_barycentricCoords[2] = c; m_barycentricCoords[3] = d; } }; /// btVoronoiSimplexSolver is an implementation of the closest point distance algorithm from a 1-4 points simplex to the origin. /// Can be used with GJK, as an alternative to Johnson distance algorithm. #ifdef NO_VIRTUAL_INTERFACE class btVoronoiSimplexSolver #else class btVoronoiSimplexSolver : public btSimplexSolverInterface #endif { public: int m_numVertices; btVector3 m_simplexVectorW[VORONOI_SIMPLEX_MAX_VERTS]; btVector3 m_simplexPointsP[VORONOI_SIMPLEX_MAX_VERTS]; btVector3 m_simplexPointsQ[VORONOI_SIMPLEX_MAX_VERTS]; btVector3 m_cachedP1; btVector3 m_cachedP2; btVector3 m_cachedV; btVector3 m_lastW; btScalar m_equalVertexThreshold; bool m_cachedValidClosest; btSubSimplexClosestResult m_cachedBC; bool m_needsUpdate; void removeVertex(int index); void reduceVertices (const btUsageBitfield& usedVerts); bool updateClosestVectorAndPoints(); bool closestPtPointTetrahedron(const btVector3& p, const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d, btSubSimplexClosestResult& finalResult); int pointOutsideOfPlane(const btVector3& p, const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d); bool closestPtPointTriangle(const btVector3& p, const btVector3& a, const btVector3& b, const btVector3& c,btSubSimplexClosestResult& result); public: btVoronoiSimplexSolver() : m_equalVertexThreshold(VORONOI_DEFAULT_EQUAL_VERTEX_THRESHOLD) { } void reset(); void addVertex(const btVector3& w, const btVector3& p, const btVector3& q); void setEqualVertexThreshold(btScalar threshold) { m_equalVertexThreshold = threshold; } btScalar getEqualVertexThreshold() const { return m_equalVertexThreshold; } bool closest(btVector3& v); btScalar maxVertex(); bool fullSimplex() const { return (m_numVertices == 4); } int getSimplex(btVector3 *pBuf, btVector3 *qBuf, btVector3 *yBuf) const; bool inSimplex(const btVector3& w); void backup_closest(btVector3& v) ; bool emptySimplex() const ; void compute_points(btVector3& p1, btVector3& p2) ; int numVertices() const { return m_numVertices; } }; #endif //VoronoiSimplexSolver ././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.hcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDep0000644000175000017500000000337511344267705033272 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 MINKOWSKI_PENETRATION_DEPTH_SOLVER_H #define MINKOWSKI_PENETRATION_DEPTH_SOLVER_H #include "btConvexPenetrationDepthSolver.h" ///MinkowskiPenetrationDepthSolver implements bruteforce penetration depth estimation. ///Implementation is based on sampling the depth using support mapping, and using GJK step to get the witness points. class btMinkowskiPenetrationDepthSolver : public btConvexPenetrationDepthSolver { protected: static btVector3* getPenetrationDirections(); public: virtual bool calcPenDepth( btSimplexSolverInterface& simplexSolver, const btConvexShape* convexA,const btConvexShape* convexB, const btTransform& transA,const btTransform& transB, btVector3& v, btVector3& pa, btVector3& pb, class btIDebugDraw* debugDraw,btStackAlloc* stackAlloc ); }; #endif //MINKOWSKI_PENETRATION_DEPTH_SOLVER_H ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.hcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.0000644000175000017500000000420311337071441033147 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 SIMPLEX_SOLVER_INTERFACE_H #define SIMPLEX_SOLVER_INTERFACE_H #include "LinearMath/btVector3.h" #define NO_VIRTUAL_INTERFACE 1 #ifdef NO_VIRTUAL_INTERFACE #include "btVoronoiSimplexSolver.h" #define btSimplexSolverInterface btVoronoiSimplexSolver #else /// btSimplexSolverInterface can incrementally calculate distance between origin and up to 4 vertices /// Used by GJK or Linear Casting. Can be implemented by the Johnson-algorithm or alternative approaches based on /// voronoi regions or barycentric coordinates class btSimplexSolverInterface { public: virtual ~btSimplexSolverInterface() {}; virtual void reset() = 0; virtual void addVertex(const btVector3& w, const btVector3& p, const btVector3& q) = 0; virtual bool closest(btVector3& v) = 0; virtual btScalar maxVertex() = 0; virtual bool fullSimplex() const = 0; virtual int getSimplex(btVector3 *pBuf, btVector3 *qBuf, btVector3 *yBuf) const = 0; virtual bool inSimplex(const btVector3& w) = 0; virtual void backup_closest(btVector3& v) = 0; virtual bool emptySimplex() const = 0; virtual void compute_points(btVector3& p1, btVector3& p2) = 0; virtual int numVertices() const =0; }; #endif #endif //SIMPLEX_SOLVER_INTERFACE_H critterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btGjkEpa2.h0000644000175000017500000000477111337071441030117 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2008 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ /* GJK-EPA collision solver by Nathanael Presson, 2008 */ #ifndef _68DA1F85_90B7_4bb0_A705_83B4040A75C6_ #define _68DA1F85_90B7_4bb0_A705_83B4040A75C6_ #include "BulletCollision/CollisionShapes/btConvexShape.h" ///btGjkEpaSolver contributed under zlib by Nathanael Presson struct btGjkEpaSolver2 { struct sResults { enum eStatus { Separated, /* Shapes doesnt penetrate */ Penetrating, /* Shapes are penetrating */ GJK_Failed, /* GJK phase fail, no big issue, shapes are probably just 'touching' */ EPA_Failed /* EPA phase fail, bigger problem, need to save parameters, and debug */ } status; btVector3 witnesses[2]; btVector3 normal; btScalar distance; }; static int StackSizeRequirement(); static bool Distance( const btConvexShape* shape0,const btTransform& wtrs0, const btConvexShape* shape1,const btTransform& wtrs1, const btVector3& guess, sResults& results); static bool Penetration(const btConvexShape* shape0,const btTransform& wtrs0, const btConvexShape* shape1,const btTransform& wtrs1, const btVector3& guess, sResults& results, bool usemargins=true); #ifndef __SPU__ static btScalar SignedDistance( const btVector3& position, btScalar margin, const btConvexShape* shape, const btTransform& wtrs, sResults& results); static bool SignedDistance( const btConvexShape* shape0,const btTransform& wtrs0, const btConvexShape* shape1,const btTransform& wtrs1, const btVector3& guess, sResults& results); #endif //__SPU__ }; #endif critterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btRaycastCallback.h0000644000175000017500000000524511337071441031714 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 RAYCAST_TRI_CALLBACK_H #define RAYCAST_TRI_CALLBACK_H #include "BulletCollision/CollisionShapes/btTriangleCallback.h" #include "LinearMath/btTransform.h" struct btBroadphaseProxy; class btConvexShape; class btTriangleRaycastCallback: public btTriangleCallback { public: //input btVector3 m_from; btVector3 m_to; //@BP Mod - allow backface filtering and unflipped normals enum EFlags { kF_None = 0, kF_FilterBackfaces = 1 << 0, kF_KeepUnflippedNormal = 1 << 1, // Prevents returned face normal getting flipped when a ray hits a back-facing triangle kF_Terminator = 0xFFFFFFFF }; unsigned int m_flags; btScalar m_hitFraction; btTriangleRaycastCallback(const btVector3& from,const btVector3& to, unsigned int flags=0); virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex); virtual btScalar reportHit(const btVector3& hitNormalLocal, btScalar hitFraction, int partId, int triangleIndex ) = 0; }; class btTriangleConvexcastCallback : public btTriangleCallback { public: const btConvexShape* m_convexShape; btTransform m_convexShapeFrom; btTransform m_convexShapeTo; btTransform m_triangleToWorld; btScalar m_hitFraction; btScalar m_triangleCollisionMargin; btTriangleConvexcastCallback (const btConvexShape* convexShape, const btTransform& convexShapeFrom, const btTransform& convexShapeTo, const btTransform& triangleToWorld, const btScalar triangleCollisionMargin); virtual void processTriangle (btVector3* triangle, int partId, int triangleIndex); virtual btScalar reportHit (const btVector3& hitNormalLocal, const btVector3& hitPointLocal, btScalar hitFraction, int partId, int triangleIndex) = 0; }; #endif //RAYCAST_TRI_CALLBACK_H ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.cp0000644000175000017500000001170511344267705033143 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btSubSimplexConvexCast.h" #include "BulletCollision/CollisionShapes/btConvexShape.h" #include "BulletCollision/CollisionShapes/btMinkowskiSumShape.h" #include "BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h" #include "btPointCollector.h" #include "LinearMath/btTransformUtil.h" btSubsimplexConvexCast::btSubsimplexConvexCast (const btConvexShape* convexA,const btConvexShape* convexB,btSimplexSolverInterface* simplexSolver) :m_simplexSolver(simplexSolver), m_convexA(convexA),m_convexB(convexB) { } ///Typically the conservative advancement reaches solution in a few iterations, clip it to 32 for degenerate cases. ///See discussion about this here http://continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=565 #ifdef BT_USE_DOUBLE_PRECISION #define MAX_ITERATIONS 64 #else #define MAX_ITERATIONS 32 #endif bool btSubsimplexConvexCast::calcTimeOfImpact( const btTransform& fromA, const btTransform& toA, const btTransform& fromB, const btTransform& toB, CastResult& result) { m_simplexSolver->reset(); btVector3 linVelA,linVelB; linVelA = toA.getOrigin()-fromA.getOrigin(); linVelB = toB.getOrigin()-fromB.getOrigin(); btScalar lambda = btScalar(0.); btTransform interpolatedTransA = fromA; btTransform interpolatedTransB = fromB; ///take relative motion btVector3 r = (linVelA-linVelB); btVector3 v; btVector3 supVertexA = fromA(m_convexA->localGetSupportingVertex(-r*fromA.getBasis())); btVector3 supVertexB = fromB(m_convexB->localGetSupportingVertex(r*fromB.getBasis())); v = supVertexA-supVertexB; int maxIter = MAX_ITERATIONS; btVector3 n; n.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); bool hasResult = false; btVector3 c; btScalar lastLambda = lambda; btScalar dist2 = v.length2(); #ifdef BT_USE_DOUBLE_PRECISION btScalar epsilon = btScalar(0.0001); #else btScalar epsilon = btScalar(0.0001); #endif //BT_USE_DOUBLE_PRECISION btVector3 w,p; btScalar VdotR; while ( (dist2 > epsilon) && maxIter--) { supVertexA = interpolatedTransA(m_convexA->localGetSupportingVertex(-v*interpolatedTransA.getBasis())); supVertexB = interpolatedTransB(m_convexB->localGetSupportingVertex(v*interpolatedTransB.getBasis())); w = supVertexA-supVertexB; btScalar VdotW = v.dot(w); if (lambda > btScalar(1.0)) { return false; } if ( VdotW > btScalar(0.)) { VdotR = v.dot(r); if (VdotR >= -(SIMD_EPSILON*SIMD_EPSILON)) return false; else { lambda = lambda - VdotW / VdotR; //interpolate to next lambda // x = s + lambda * r; interpolatedTransA.getOrigin().setInterpolate3(fromA.getOrigin(),toA.getOrigin(),lambda); interpolatedTransB.getOrigin().setInterpolate3(fromB.getOrigin(),toB.getOrigin(),lambda); //m_simplexSolver->reset(); //check next line w = supVertexA-supVertexB; lastLambda = lambda; n = v; hasResult = true; } } ///Just like regular GJK only add the vertex if it isn't already (close) to current vertex, it would lead to divisions by zero and NaN etc. if (!m_simplexSolver->inSimplex(w)) m_simplexSolver->addVertex( w, supVertexA , supVertexB); if (m_simplexSolver->closest(v)) { dist2 = v.length2(); hasResult = true; //todo: check this normal for validity //n=v; //printf("V=%f , %f, %f\n",v[0],v[1],v[2]); //printf("DIST2=%f\n",dist2); //printf("numverts = %i\n",m_simplexSolver->numVertices()); } else { dist2 = btScalar(0.); } } //int numiter = MAX_ITERATIONS - maxIter; // printf("number of iterations: %d", numiter); //don't report a time of impact when moving 'away' from the hitnormal result.m_fraction = lambda; if (n.length2() >= (SIMD_EPSILON*SIMD_EPSILON)) result.m_normal = n.normalized(); else result.m_normal = btVector3(btScalar(0.0), btScalar(0.0), btScalar(0.0)); //don't report time of impact for motion away from the contact normal (or causes minor penetration) if (result.m_normal.dot(r)>=-result.m_allowedPenetration) return false; btVector3 hitA,hitB; m_simplexSolver->compute_points(hitA,hitB); result.m_hitPoint=hitB; return true; } ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.cp0000644000175000017500000004217311344267705033245 0ustar bobkebobke /* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. Elsevier CDROM license agreements grants nonexclusive license to use the software for any purpose, commercial or non-commercial as long as the following credit is included identifying the original source of the software: Parts of the source are "from the book Real-Time Collision Detection by Christer Ericson, published by Morgan Kaufmann Publishers, (c) 2005 Elsevier Inc." */ #include "btVoronoiSimplexSolver.h" #define VERTA 0 #define VERTB 1 #define VERTC 2 #define VERTD 3 #define CATCH_DEGENERATE_TETRAHEDRON 1 void btVoronoiSimplexSolver::removeVertex(int index) { btAssert(m_numVertices>0); m_numVertices--; m_simplexVectorW[index] = m_simplexVectorW[m_numVertices]; m_simplexPointsP[index] = m_simplexPointsP[m_numVertices]; m_simplexPointsQ[index] = m_simplexPointsQ[m_numVertices]; } void btVoronoiSimplexSolver::reduceVertices (const btUsageBitfield& usedVerts) { if ((numVertices() >= 4) && (!usedVerts.usedVertexD)) removeVertex(3); if ((numVertices() >= 3) && (!usedVerts.usedVertexC)) removeVertex(2); if ((numVertices() >= 2) && (!usedVerts.usedVertexB)) removeVertex(1); if ((numVertices() >= 1) && (!usedVerts.usedVertexA)) removeVertex(0); } //clear the simplex, remove all the vertices void btVoronoiSimplexSolver::reset() { m_cachedValidClosest = false; m_numVertices = 0; m_needsUpdate = true; m_lastW = btVector3(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); m_cachedBC.reset(); } //add a vertex void btVoronoiSimplexSolver::addVertex(const btVector3& w, const btVector3& p, const btVector3& q) { m_lastW = w; m_needsUpdate = true; m_simplexVectorW[m_numVertices] = w; m_simplexPointsP[m_numVertices] = p; m_simplexPointsQ[m_numVertices] = q; m_numVertices++; } bool btVoronoiSimplexSolver::updateClosestVectorAndPoints() { if (m_needsUpdate) { m_cachedBC.reset(); m_needsUpdate = false; switch (numVertices()) { case 0: m_cachedValidClosest = false; break; case 1: { m_cachedP1 = m_simplexPointsP[0]; m_cachedP2 = m_simplexPointsQ[0]; m_cachedV = m_cachedP1-m_cachedP2; //== m_simplexVectorW[0] m_cachedBC.reset(); m_cachedBC.setBarycentricCoordinates(btScalar(1.),btScalar(0.),btScalar(0.),btScalar(0.)); m_cachedValidClosest = m_cachedBC.isValid(); break; }; case 2: { //closest point origin from line segment const btVector3& from = m_simplexVectorW[0]; const btVector3& to = m_simplexVectorW[1]; btVector3 nearest; btVector3 p (btScalar(0.),btScalar(0.),btScalar(0.)); btVector3 diff = p - from; btVector3 v = to - from; btScalar t = v.dot(diff); if (t > 0) { btScalar dotVV = v.dot(v); if (t < dotVV) { t /= dotVV; diff -= t*v; m_cachedBC.m_usedVertices.usedVertexA = true; m_cachedBC.m_usedVertices.usedVertexB = true; } else { t = 1; diff -= v; //reduce to 1 point m_cachedBC.m_usedVertices.usedVertexB = true; } } else { t = 0; //reduce to 1 point m_cachedBC.m_usedVertices.usedVertexA = true; } m_cachedBC.setBarycentricCoordinates(1-t,t); nearest = from + t*v; m_cachedP1 = m_simplexPointsP[0] + t * (m_simplexPointsP[1] - m_simplexPointsP[0]); m_cachedP2 = m_simplexPointsQ[0] + t * (m_simplexPointsQ[1] - m_simplexPointsQ[0]); m_cachedV = m_cachedP1 - m_cachedP2; reduceVertices(m_cachedBC.m_usedVertices); m_cachedValidClosest = m_cachedBC.isValid(); break; } case 3: { //closest point origin from triangle btVector3 p (btScalar(0.),btScalar(0.),btScalar(0.)); const btVector3& a = m_simplexVectorW[0]; const btVector3& b = m_simplexVectorW[1]; const btVector3& c = m_simplexVectorW[2]; closestPtPointTriangle(p,a,b,c,m_cachedBC); m_cachedP1 = m_simplexPointsP[0] * m_cachedBC.m_barycentricCoords[0] + m_simplexPointsP[1] * m_cachedBC.m_barycentricCoords[1] + m_simplexPointsP[2] * m_cachedBC.m_barycentricCoords[2]; m_cachedP2 = m_simplexPointsQ[0] * m_cachedBC.m_barycentricCoords[0] + m_simplexPointsQ[1] * m_cachedBC.m_barycentricCoords[1] + m_simplexPointsQ[2] * m_cachedBC.m_barycentricCoords[2]; m_cachedV = m_cachedP1-m_cachedP2; reduceVertices (m_cachedBC.m_usedVertices); m_cachedValidClosest = m_cachedBC.isValid(); break; } case 4: { btVector3 p (btScalar(0.),btScalar(0.),btScalar(0.)); const btVector3& a = m_simplexVectorW[0]; const btVector3& b = m_simplexVectorW[1]; const btVector3& c = m_simplexVectorW[2]; const btVector3& d = m_simplexVectorW[3]; bool hasSeperation = closestPtPointTetrahedron(p,a,b,c,d,m_cachedBC); if (hasSeperation) { m_cachedP1 = m_simplexPointsP[0] * m_cachedBC.m_barycentricCoords[0] + m_simplexPointsP[1] * m_cachedBC.m_barycentricCoords[1] + m_simplexPointsP[2] * m_cachedBC.m_barycentricCoords[2] + m_simplexPointsP[3] * m_cachedBC.m_barycentricCoords[3]; m_cachedP2 = m_simplexPointsQ[0] * m_cachedBC.m_barycentricCoords[0] + m_simplexPointsQ[1] * m_cachedBC.m_barycentricCoords[1] + m_simplexPointsQ[2] * m_cachedBC.m_barycentricCoords[2] + m_simplexPointsQ[3] * m_cachedBC.m_barycentricCoords[3]; m_cachedV = m_cachedP1-m_cachedP2; reduceVertices (m_cachedBC.m_usedVertices); } else { // printf("sub distance got penetration\n"); if (m_cachedBC.m_degenerate) { m_cachedValidClosest = false; } else { m_cachedValidClosest = true; //degenerate case == false, penetration = true + zero m_cachedV.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); } break; } m_cachedValidClosest = m_cachedBC.isValid(); //closest point origin from tetrahedron break; } default: { m_cachedValidClosest = false; } }; } return m_cachedValidClosest; } //return/calculate the closest vertex bool btVoronoiSimplexSolver::closest(btVector3& v) { bool succes = updateClosestVectorAndPoints(); v = m_cachedV; return succes; } btScalar btVoronoiSimplexSolver::maxVertex() { int i, numverts = numVertices(); btScalar maxV = btScalar(0.); for (i=0;i= btScalar(0.0) && d4 <= d3) { result.m_closestPointOnSimplex = b; result.m_usedVertices.usedVertexB = true; result.setBarycentricCoordinates(0,1,0); return true; // b; // barycentric coordinates (0,1,0) } // Check if P in edge region of AB, if so return projection of P onto AB btScalar vc = d1*d4 - d3*d2; if (vc <= btScalar(0.0) && d1 >= btScalar(0.0) && d3 <= btScalar(0.0)) { btScalar v = d1 / (d1 - d3); result.m_closestPointOnSimplex = a + v * ab; result.m_usedVertices.usedVertexA = true; result.m_usedVertices.usedVertexB = true; result.setBarycentricCoordinates(1-v,v,0); return true; //return a + v * ab; // barycentric coordinates (1-v,v,0) } // Check if P in vertex region outside C btVector3 cp = p - c; btScalar d5 = ab.dot(cp); btScalar d6 = ac.dot(cp); if (d6 >= btScalar(0.0) && d5 <= d6) { result.m_closestPointOnSimplex = c; result.m_usedVertices.usedVertexC = true; result.setBarycentricCoordinates(0,0,1); return true;//c; // barycentric coordinates (0,0,1) } // Check if P in edge region of AC, if so return projection of P onto AC btScalar vb = d5*d2 - d1*d6; if (vb <= btScalar(0.0) && d2 >= btScalar(0.0) && d6 <= btScalar(0.0)) { btScalar w = d2 / (d2 - d6); result.m_closestPointOnSimplex = a + w * ac; result.m_usedVertices.usedVertexA = true; result.m_usedVertices.usedVertexC = true; result.setBarycentricCoordinates(1-w,0,w); return true; //return a + w * ac; // barycentric coordinates (1-w,0,w) } // Check if P in edge region of BC, if so return projection of P onto BC btScalar va = d3*d6 - d5*d4; if (va <= btScalar(0.0) && (d4 - d3) >= btScalar(0.0) && (d5 - d6) >= btScalar(0.0)) { btScalar w = (d4 - d3) / ((d4 - d3) + (d5 - d6)); result.m_closestPointOnSimplex = b + w * (c - b); result.m_usedVertices.usedVertexB = true; result.m_usedVertices.usedVertexC = true; result.setBarycentricCoordinates(0,1-w,w); return true; // return b + w * (c - b); // barycentric coordinates (0,1-w,w) } // P inside face region. Compute Q through its barycentric coordinates (u,v,w) btScalar denom = btScalar(1.0) / (va + vb + vc); btScalar v = vb * denom; btScalar w = vc * denom; result.m_closestPointOnSimplex = a + ab * v + ac * w; result.m_usedVertices.usedVertexA = true; result.m_usedVertices.usedVertexB = true; result.m_usedVertices.usedVertexC = true; result.setBarycentricCoordinates(1-v-w,v,w); return true; // return a + ab * v + ac * w; // = u*a + v*b + w*c, u = va * denom = btScalar(1.0) - v - w } /// Test if point p and d lie on opposite sides of plane through abc int btVoronoiSimplexSolver::pointOutsideOfPlane(const btVector3& p, const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d) { btVector3 normal = (b-a).cross(c-a); btScalar signp = (p - a).dot(normal); // [AP AB AC] btScalar signd = (d - a).dot( normal); // [AD AB AC] #ifdef CATCH_DEGENERATE_TETRAHEDRON #ifdef BT_USE_DOUBLE_PRECISION if (signd * signd < (btScalar(1e-8) * btScalar(1e-8))) { return -1; } #else if (signd * signd < (btScalar(1e-4) * btScalar(1e-4))) { // printf("affine dependent/degenerate\n");// return -1; } #endif #endif // Points on opposite sides if expression signs are opposite return signp * signd < btScalar(0.); } bool btVoronoiSimplexSolver::closestPtPointTetrahedron(const btVector3& p, const btVector3& a, const btVector3& b, const btVector3& c, const btVector3& d, btSubSimplexClosestResult& finalResult) { btSubSimplexClosestResult tempResult; // Start out assuming point inside all halfspaces, so closest to itself finalResult.m_closestPointOnSimplex = p; finalResult.m_usedVertices.reset(); finalResult.m_usedVertices.usedVertexA = true; finalResult.m_usedVertices.usedVertexB = true; finalResult.m_usedVertices.usedVertexC = true; finalResult.m_usedVertices.usedVertexD = true; int pointOutsideABC = pointOutsideOfPlane(p, a, b, c, d); int pointOutsideACD = pointOutsideOfPlane(p, a, c, d, b); int pointOutsideADB = pointOutsideOfPlane(p, a, d, b, c); int pointOutsideBDC = pointOutsideOfPlane(p, b, d, c, a); if (pointOutsideABC < 0 || pointOutsideACD < 0 || pointOutsideADB < 0 || pointOutsideBDC < 0) { finalResult.m_degenerate = true; return false; } if (!pointOutsideABC && !pointOutsideACD && !pointOutsideADB && !pointOutsideBDC) { return false; } btScalar bestSqDist = FLT_MAX; // If point outside face abc then compute closest point on abc if (pointOutsideABC) { closestPtPointTriangle(p, a, b, c,tempResult); btVector3 q = tempResult.m_closestPointOnSimplex; btScalar sqDist = (q - p).dot( q - p); // Update best closest point if (squared) distance is less than current best if (sqDist < bestSqDist) { bestSqDist = sqDist; finalResult.m_closestPointOnSimplex = q; //convert result bitmask! finalResult.m_usedVertices.reset(); finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA; finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexB; finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexC; finalResult.setBarycentricCoordinates( tempResult.m_barycentricCoords[VERTA], tempResult.m_barycentricCoords[VERTB], tempResult.m_barycentricCoords[VERTC], 0 ); } } // Repeat test for face acd if (pointOutsideACD) { closestPtPointTriangle(p, a, c, d,tempResult); btVector3 q = tempResult.m_closestPointOnSimplex; //convert result bitmask! btScalar sqDist = (q - p).dot( q - p); if (sqDist < bestSqDist) { bestSqDist = sqDist; finalResult.m_closestPointOnSimplex = q; finalResult.m_usedVertices.reset(); finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA; finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexB; finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexC; finalResult.setBarycentricCoordinates( tempResult.m_barycentricCoords[VERTA], 0, tempResult.m_barycentricCoords[VERTB], tempResult.m_barycentricCoords[VERTC] ); } } // Repeat test for face adb if (pointOutsideADB) { closestPtPointTriangle(p, a, d, b,tempResult); btVector3 q = tempResult.m_closestPointOnSimplex; //convert result bitmask! btScalar sqDist = (q - p).dot( q - p); if (sqDist < bestSqDist) { bestSqDist = sqDist; finalResult.m_closestPointOnSimplex = q; finalResult.m_usedVertices.reset(); finalResult.m_usedVertices.usedVertexA = tempResult.m_usedVertices.usedVertexA; finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexC; finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexB; finalResult.setBarycentricCoordinates( tempResult.m_barycentricCoords[VERTA], tempResult.m_barycentricCoords[VERTC], 0, tempResult.m_barycentricCoords[VERTB] ); } } // Repeat test for face bdc if (pointOutsideBDC) { closestPtPointTriangle(p, b, d, c,tempResult); btVector3 q = tempResult.m_closestPointOnSimplex; //convert result bitmask! btScalar sqDist = (q - p).dot( q - p); if (sqDist < bestSqDist) { bestSqDist = sqDist; finalResult.m_closestPointOnSimplex = q; finalResult.m_usedVertices.reset(); // finalResult.m_usedVertices.usedVertexB = tempResult.m_usedVertices.usedVertexA; finalResult.m_usedVertices.usedVertexC = tempResult.m_usedVertices.usedVertexC; finalResult.m_usedVertices.usedVertexD = tempResult.m_usedVertices.usedVertexB; finalResult.setBarycentricCoordinates( 0, tempResult.m_barycentricCoords[VERTA], tempResult.m_barycentricCoords[VERTC], tempResult.m_barycentricCoords[VERTB] ); } } //help! we ended up full ! if (finalResult.m_usedVertices.usedVertexA && finalResult.m_usedVertices.usedVertexB && finalResult.m_usedVertices.usedVertexC && finalResult.m_usedVertices.usedVertexD) { return true; } return true; } ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btContinuousConvexCollisi0000644000175000017500000001534611337071441033316 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btContinuousConvexCollision.h" #include "BulletCollision/CollisionShapes/btConvexShape.h" #include "BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h" #include "LinearMath/btTransformUtil.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" #include "btGjkPairDetector.h" #include "btPointCollector.h" btContinuousConvexCollision::btContinuousConvexCollision ( const btConvexShape* convexA,const btConvexShape* convexB,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* penetrationDepthSolver) :m_simplexSolver(simplexSolver), m_penetrationDepthSolver(penetrationDepthSolver), m_convexA(convexA),m_convexB(convexB) { } /// This maximum should not be necessary. It allows for untested/degenerate cases in production code. /// You don't want your game ever to lock-up. #define MAX_ITERATIONS 64 bool btContinuousConvexCollision::calcTimeOfImpact( const btTransform& fromA, const btTransform& toA, const btTransform& fromB, const btTransform& toB, CastResult& result) { m_simplexSolver->reset(); /// compute linear and angular velocity for this interval, to interpolate btVector3 linVelA,angVelA,linVelB,angVelB; btTransformUtil::calculateVelocity(fromA,toA,btScalar(1.),linVelA,angVelA); btTransformUtil::calculateVelocity(fromB,toB,btScalar(1.),linVelB,angVelB); btScalar boundingRadiusA = m_convexA->getAngularMotionDisc(); btScalar boundingRadiusB = m_convexB->getAngularMotionDisc(); btScalar maxAngularProjectedVelocity = angVelA.length() * boundingRadiusA + angVelB.length() * boundingRadiusB; btVector3 relLinVel = (linVelB-linVelA); btScalar relLinVelocLength = (linVelB-linVelA).length(); if ((relLinVelocLength+maxAngularProjectedVelocity) == 0.f) return false; btScalar radius = btScalar(0.001); btScalar lambda = btScalar(0.); btVector3 v(1,0,0); int maxIter = MAX_ITERATIONS; btVector3 n; n.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); bool hasResult = false; btVector3 c; btScalar lastLambda = lambda; //btScalar epsilon = btScalar(0.001); int numIter = 0; //first solution, using GJK btTransform identityTrans; identityTrans.setIdentity(); btSphereShape raySphere(btScalar(0.0)); raySphere.setMargin(btScalar(0.)); // result.drawCoordSystem(sphereTr); btPointCollector pointCollector1; { btGjkPairDetector gjk(m_convexA,m_convexB,m_convexA->getShapeType(),m_convexB->getShapeType(),m_convexA->getMargin(),m_convexB->getMargin(),m_simplexSolver,m_penetrationDepthSolver); btGjkPairDetector::ClosestPointInput input; //we don't use margins during CCD // gjk.setIgnoreMargin(true); input.m_transformA = fromA; input.m_transformB = fromB; gjk.getClosestPoints(input,pointCollector1,0); hasResult = pointCollector1.m_hasResult; c = pointCollector1.m_pointInWorld; } if (hasResult) { btScalar dist; dist = pointCollector1.m_distance; n = pointCollector1.m_normalOnBInWorld; btScalar projectedLinearVelocity = relLinVel.dot(n); //not close enough while (dist > radius) { if (result.m_debugDrawer) { result.m_debugDrawer->drawSphere(c,0.2f,btVector3(1,1,1)); } numIter++; if (numIter > maxIter) { return false; //todo: report a failure } btScalar dLambda = btScalar(0.); projectedLinearVelocity = relLinVel.dot(n); //calculate safe moving fraction from distance / (linear+rotational velocity) //btScalar clippedDist = GEN_min(angularConservativeRadius,dist); //btScalar clippedDist = dist; //don't report time of impact for motion away from the contact normal (or causes minor penetration) if ((projectedLinearVelocity+ maxAngularProjectedVelocity)<=SIMD_EPSILON) return false; dLambda = dist / (projectedLinearVelocity+ maxAngularProjectedVelocity); lambda = lambda + dLambda; if (lambda > btScalar(1.)) return false; if (lambda < btScalar(0.)) return false; //todo: next check with relative epsilon if (lambda <= lastLambda) { return false; //n.setValue(0,0,0); break; } lastLambda = lambda; //interpolate to next lambda btTransform interpolatedTransA,interpolatedTransB,relativeTrans; btTransformUtil::integrateTransform(fromA,linVelA,angVelA,lambda,interpolatedTransA); btTransformUtil::integrateTransform(fromB,linVelB,angVelB,lambda,interpolatedTransB); relativeTrans = interpolatedTransB.inverseTimes(interpolatedTransA); if (result.m_debugDrawer) { result.m_debugDrawer->drawSphere(interpolatedTransA.getOrigin(),0.2f,btVector3(1,0,0)); } result.DebugDraw( lambda ); btPointCollector pointCollector; btGjkPairDetector gjk(m_convexA,m_convexB,m_simplexSolver,m_penetrationDepthSolver); btGjkPairDetector::ClosestPointInput input; input.m_transformA = interpolatedTransA; input.m_transformB = interpolatedTransB; gjk.getClosestPoints(input,pointCollector,0); if (pointCollector.m_hasResult) { if (pointCollector.m_distance < btScalar(0.)) { //degenerate ?! result.m_fraction = lastLambda; n = pointCollector.m_normalOnBInWorld; result.m_normal=n;//.setValue(1,1,1);// = n; result.m_hitPoint = pointCollector.m_pointInWorld; return true; } c = pointCollector.m_pointInWorld; n = pointCollector.m_normalOnBInWorld; dist = pointCollector.m_distance; } else { //?? return false; } } if ((projectedLinearVelocity+ maxAngularProjectedVelocity)<=result.m_allowedPenetration)//SIMD_EPSILON) return false; result.m_fraction = lambda; result.m_normal = n; result.m_hitPoint = c; return true; } return false; /* //todo: //if movement away from normal, discard result btVector3 move = transBLocalTo.getOrigin() - transBLocalFrom.getOrigin(); if (result.m_fraction < btScalar(1.)) { if (move.dot(result.m_normal) <= btScalar(0.)) { } } */ } ././@LongLink0000000000000000000000000000016200000000000011564 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.hcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetect0000644000175000017500000000632111337071441033206 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 DISCRETE_COLLISION_DETECTOR1_INTERFACE_H #define DISCRETE_COLLISION_DETECTOR1_INTERFACE_H #include "LinearMath/btTransform.h" #include "LinearMath/btVector3.h" class btStackAlloc; /// This interface is made to be used by an iterative approach to do TimeOfImpact calculations /// This interface allows to query for closest points and penetration depth between two (convex) objects /// the closest point is on the second object (B), and the normal points from the surface on B towards A. /// distance is between closest points on B and closest point on A. So you can calculate closest point on A /// by taking closestPointInA = closestPointInB + m_distance * m_normalOnSurfaceB struct btDiscreteCollisionDetectorInterface { struct Result { virtual ~Result(){} ///setShapeIdentifiersA/B provides experimental support for per-triangle material / custom material combiner virtual void setShapeIdentifiersA(int partId0,int index0)=0; virtual void setShapeIdentifiersB(int partId1,int index1)=0; virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth)=0; }; struct ClosestPointInput { ClosestPointInput() :m_maximumDistanceSquared(btScalar(BT_LARGE_FLOAT)), m_stackAlloc(0) { } btTransform m_transformA; btTransform m_transformB; btScalar m_maximumDistanceSquared; btStackAlloc* m_stackAlloc; }; virtual ~btDiscreteCollisionDetectorInterface() {}; // // give either closest points (distance > 0) or penetration (distance) // the normal always points from B towards A // virtual void getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults=false) = 0; }; struct btStorageResult : public btDiscreteCollisionDetectorInterface::Result { btVector3 m_normalOnSurfaceB; btVector3 m_closestPointInB; btScalar m_distance; //negative means penetration ! btStorageResult() : m_distance(btScalar(BT_LARGE_FLOAT)) { } virtual ~btStorageResult() {}; virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth) { if (depth < m_distance) { m_normalOnSurfaceB = normalOnBInWorld; m_closestPointInB = pointInWorld; m_distance = depth; } } }; #endif //DISCRETE_COLLISION_DETECTOR_INTERFACE1_H critterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btPersistentManifold.cpp0000644000175000017500000001603711337071441033037 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btPersistentManifold.h" #include "LinearMath/btTransform.h" btScalar gContactBreakingThreshold = btScalar(0.02); ContactDestroyedCallback gContactDestroyedCallback = 0; ContactProcessedCallback gContactProcessedCallback = 0; btPersistentManifold::btPersistentManifold() :btTypedObject(BT_PERSISTENT_MANIFOLD_TYPE), m_body0(0), m_body1(0), m_cachedPoints (0), m_index1a(0) { } #ifdef DEBUG_PERSISTENCY #include void btPersistentManifold::DebugPersistency() { int i; printf("DebugPersistency : numPoints %d\n",m_cachedPoints); for (i=0;i1) printf("error in clearUserCache\n"); } } btAssert(occurance<=0); #endif //DEBUG_PERSISTENCY if (pt.m_userPersistentData && gContactDestroyedCallback) { (*gContactDestroyedCallback)(pt.m_userPersistentData); pt.m_userPersistentData = 0; } #ifdef DEBUG_PERSISTENCY DebugPersistency(); #endif } } int btPersistentManifold::sortCachedPoints(const btManifoldPoint& pt) { //calculate 4 possible cases areas, and take biggest area //also need to keep 'deepest' int maxPenetrationIndex = -1; #define KEEP_DEEPEST_POINT 1 #ifdef KEEP_DEEPEST_POINT btScalar maxPenetration = pt.getDistance(); for (int i=0;i<4;i++) { if (m_pointCache[i].getDistance() < maxPenetration) { maxPenetrationIndex = i; maxPenetration = m_pointCache[i].getDistance(); } } #endif //KEEP_DEEPEST_POINT btScalar res0(btScalar(0.)),res1(btScalar(0.)),res2(btScalar(0.)),res3(btScalar(0.)); if (maxPenetrationIndex != 0) { btVector3 a0 = pt.m_localPointA-m_pointCache[1].m_localPointA; btVector3 b0 = m_pointCache[3].m_localPointA-m_pointCache[2].m_localPointA; btVector3 cross = a0.cross(b0); res0 = cross.length2(); } if (maxPenetrationIndex != 1) { btVector3 a1 = pt.m_localPointA-m_pointCache[0].m_localPointA; btVector3 b1 = m_pointCache[3].m_localPointA-m_pointCache[2].m_localPointA; btVector3 cross = a1.cross(b1); res1 = cross.length2(); } if (maxPenetrationIndex != 2) { btVector3 a2 = pt.m_localPointA-m_pointCache[0].m_localPointA; btVector3 b2 = m_pointCache[3].m_localPointA-m_pointCache[1].m_localPointA; btVector3 cross = a2.cross(b2); res2 = cross.length2(); } if (maxPenetrationIndex != 3) { btVector3 a3 = pt.m_localPointA-m_pointCache[0].m_localPointA; btVector3 b3 = m_pointCache[2].m_localPointA-m_pointCache[1].m_localPointA; btVector3 cross = a3.cross(b3); res3 = cross.length2(); } btVector4 maxvec(res0,res1,res2,res3); int biggestarea = maxvec.closestAxis4(); return biggestarea; } int btPersistentManifold::getCacheEntry(const btManifoldPoint& newPoint) const { btScalar shortestDist = getContactBreakingThreshold() * getContactBreakingThreshold(); int size = getNumContacts(); int nearestPoint = -1; for( int i = 0; i < size; i++ ) { const btManifoldPoint &mp = m_pointCache[i]; btVector3 diffA = mp.m_localPointA- newPoint.m_localPointA; const btScalar distToManiPoint = diffA.dot(diffA); if( distToManiPoint < shortestDist ) { shortestDist = distToManiPoint; nearestPoint = i; } } return nearestPoint; } int btPersistentManifold::addManifoldPoint(const btManifoldPoint& newPoint) { btAssert(validContactDistance(newPoint)); int insertIndex = getNumContacts(); if (insertIndex == MANIFOLD_CACHE_SIZE) { #if MANIFOLD_CACHE_SIZE >= 4 //sort cache so best points come first, based on area insertIndex = sortCachedPoints(newPoint); #else insertIndex = 0; #endif clearUserCache(m_pointCache[insertIndex]); } else { m_cachedPoints++; } if (insertIndex<0) insertIndex=0; btAssert(m_pointCache[insertIndex].m_userPersistentData==0); m_pointCache[insertIndex] = newPoint; return insertIndex; } btScalar btPersistentManifold::getContactBreakingThreshold() const { return m_contactBreakingThreshold; } void btPersistentManifold::refreshContactPoints(const btTransform& trA,const btTransform& trB) { int i; #ifdef DEBUG_PERSISTENCY printf("refreshContactPoints posA = (%f,%f,%f) posB = (%f,%f,%f)\n", trA.getOrigin().getX(), trA.getOrigin().getY(), trA.getOrigin().getZ(), trB.getOrigin().getX(), trB.getOrigin().getY(), trB.getOrigin().getZ()); #endif //DEBUG_PERSISTENCY /// first refresh worldspace positions and distance for (i=getNumContacts()-1;i>=0;i--) { btManifoldPoint &manifoldPoint = m_pointCache[i]; manifoldPoint.m_positionWorldOnA = trA( manifoldPoint.m_localPointA ); manifoldPoint.m_positionWorldOnB = trB( manifoldPoint.m_localPointB ); manifoldPoint.m_distance1 = (manifoldPoint.m_positionWorldOnA - manifoldPoint.m_positionWorldOnB).dot(manifoldPoint.m_normalWorldOnB); manifoldPoint.m_lifeTime++; } /// then btScalar distance2d; btVector3 projectedDifference,projectedPoint; for (i=getNumContacts()-1;i>=0;i--) { btManifoldPoint &manifoldPoint = m_pointCache[i]; //contact becomes invalid when signed distance exceeds margin (projected on contactnormal direction) if (!validContactDistance(manifoldPoint)) { removeContactPoint(i); } else { //contact also becomes invalid when relative movement orthogonal to normal exceeds margin projectedPoint = manifoldPoint.m_positionWorldOnA - manifoldPoint.m_normalWorldOnB * manifoldPoint.m_distance1; projectedDifference = manifoldPoint.m_positionWorldOnB - projectedPoint; distance2d = projectedDifference.dot(projectedDifference); if (distance2d > getContactBreakingThreshold()*getContactBreakingThreshold() ) { removeContactPoint(i); } else { //contact point processed callback if (gContactProcessedCallback) (*gContactProcessedCallback)(manifoldPoint,m_body0,m_body1); } } } #ifdef DEBUG_PERSISTENCY DebugPersistency(); #endif // } critterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btRaycastCallback.cpp0000644000175000017500000001357411337071441032253 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 #include "BulletCollision/CollisionShapes/btConvexShape.h" #include "BulletCollision/CollisionShapes/btTriangleShape.h" #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" #include "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h" #include "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h" #include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h" #include "btRaycastCallback.h" btTriangleRaycastCallback::btTriangleRaycastCallback(const btVector3& from,const btVector3& to, unsigned int flags) : m_from(from), m_to(to), //@BP Mod m_flags(flags), m_hitFraction(btScalar(1.)) { } void btTriangleRaycastCallback::processTriangle(btVector3* triangle,int partId, int triangleIndex) { const btVector3 &vert0=triangle[0]; const btVector3 &vert1=triangle[1]; const btVector3 &vert2=triangle[2]; btVector3 v10; v10 = vert1 - vert0 ; btVector3 v20; v20 = vert2 - vert0 ; btVector3 triangleNormal; triangleNormal = v10.cross( v20 ); const btScalar dist = vert0.dot(triangleNormal); btScalar dist_a = triangleNormal.dot(m_from) ; dist_a-= dist; btScalar dist_b = triangleNormal.dot(m_to); dist_b -= dist; if ( dist_a * dist_b >= btScalar(0.0) ) { return ; // same sign } //@BP Mod - Backface filtering if (((m_flags & kF_FilterBackfaces) != 0) && (dist_a > btScalar(0.0))) { // Backface, skip check return; } const btScalar proj_length=dist_a-dist_b; const btScalar distance = (dist_a)/(proj_length); // Now we have the intersection point on the plane, we'll see if it's inside the triangle // Add an epsilon as a tolerance for the raycast, // in case the ray hits exacly on the edge of the triangle. // It must be scaled for the triangle size. if(distance < m_hitFraction) { btScalar edge_tolerance =triangleNormal.length2(); edge_tolerance *= btScalar(-0.0001); btVector3 point; point.setInterpolate3( m_from, m_to, distance); { btVector3 v0p; v0p = vert0 - point; btVector3 v1p; v1p = vert1 - point; btVector3 cp0; cp0 = v0p.cross( v1p ); if ( (btScalar)(cp0.dot(triangleNormal)) >=edge_tolerance) { btVector3 v2p; v2p = vert2 - point; btVector3 cp1; cp1 = v1p.cross( v2p); if ( (btScalar)(cp1.dot(triangleNormal)) >=edge_tolerance) { btVector3 cp2; cp2 = v2p.cross(v0p); if ( (btScalar)(cp2.dot(triangleNormal)) >=edge_tolerance) { //@BP Mod // Triangle normal isn't normalized triangleNormal.normalize(); //@BP Mod - Allow for unflipped normal when raycasting against backfaces if (((m_flags & kF_KeepUnflippedNormal) != 0) || (dist_a <= btScalar(0.0))) { m_hitFraction = reportHit(-triangleNormal,distance,partId,triangleIndex); } else { m_hitFraction = reportHit(triangleNormal,distance,partId,triangleIndex); } } } } } } } btTriangleConvexcastCallback::btTriangleConvexcastCallback (const btConvexShape* convexShape, const btTransform& convexShapeFrom, const btTransform& convexShapeTo, const btTransform& triangleToWorld, const btScalar triangleCollisionMargin) { m_convexShape = convexShape; m_convexShapeFrom = convexShapeFrom; m_convexShapeTo = convexShapeTo; m_triangleToWorld = triangleToWorld; m_hitFraction = 1.0; m_triangleCollisionMargin = triangleCollisionMargin; } void btTriangleConvexcastCallback::processTriangle (btVector3* triangle, int partId, int triangleIndex) { btTriangleShape triangleShape (triangle[0], triangle[1], triangle[2]); triangleShape.setMargin(m_triangleCollisionMargin); btVoronoiSimplexSolver simplexSolver; btGjkEpaPenetrationDepthSolver gjkEpaPenetrationSolver; //#define USE_SUBSIMPLEX_CONVEX_CAST 1 //if you reenable USE_SUBSIMPLEX_CONVEX_CAST see commented out code below #ifdef USE_SUBSIMPLEX_CONVEX_CAST btSubsimplexConvexCast convexCaster(m_convexShape, &triangleShape, &simplexSolver); #else //btGjkConvexCast convexCaster(m_convexShape,&triangleShape,&simplexSolver); btContinuousConvexCollision convexCaster(m_convexShape,&triangleShape,&simplexSolver,&gjkEpaPenetrationSolver); #endif //#USE_SUBSIMPLEX_CONVEX_CAST btConvexCast::CastResult castResult; castResult.m_fraction = btScalar(1.); if (convexCaster.calcTimeOfImpact(m_convexShapeFrom,m_convexShapeTo,m_triangleToWorld, m_triangleToWorld, castResult)) { //add hit if (castResult.m_normal.length2() > btScalar(0.0001)) { if (castResult.m_fraction < m_hitFraction) { /* btContinuousConvexCast's normal is already in world space */ /* #ifdef USE_SUBSIMPLEX_CONVEX_CAST //rotate normal into worldspace castResult.m_normal = m_convexShapeFrom.getBasis() * castResult.m_normal; #endif //USE_SUBSIMPLEX_CONVEX_CAST */ castResult.m_normal.normalize(); reportHit (castResult.m_normal, castResult.m_hitPoint, castResult.m_fraction, partId, triangleIndex); } } } } critterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h0000644000175000017500000000424211337071441032756 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 SUBSIMPLEX_CONVEX_CAST_H #define SUBSIMPLEX_CONVEX_CAST_H #include "btConvexCast.h" #include "btSimplexSolverInterface.h" class btConvexShape; /// btSubsimplexConvexCast implements Gino van den Bergens' paper ///"Ray Casting against bteral Convex Objects with Application to Continuous Collision Detection" /// GJK based Ray Cast, optimized version /// Objects should not start in overlap, otherwise results are not defined. class btSubsimplexConvexCast : public btConvexCast { btSimplexSolverInterface* m_simplexSolver; const btConvexShape* m_convexA; const btConvexShape* m_convexB; public: btSubsimplexConvexCast (const btConvexShape* shapeA,const btConvexShape* shapeB,btSimplexSolverInterface* simplexSolver); //virtual ~btSubsimplexConvexCast(); ///SimsimplexConvexCast calculateTimeOfImpact calculates the time of impact+normal for the linear cast (sweep) between two moving objects. ///Precondition is that objects should not penetration/overlap at the start from the interval. Overlap can be tested using btGjkPairDetector. virtual bool calcTimeOfImpact( const btTransform& fromA, const btTransform& toA, const btTransform& fromB, const btTransform& toB, CastResult& result); }; #endif //SUBSIMPLEX_CONVEX_CAST_H ././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthS0000644000175000017500000000460011337071441033117 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ EPA Copyright (c) Ricardo Padrela 2006 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 "BulletCollision/CollisionShapes/btConvexShape.h" #include "btGjkEpaPenetrationDepthSolver.h" #include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h" bool btGjkEpaPenetrationDepthSolver::calcPenDepth( btSimplexSolverInterface& simplexSolver, const btConvexShape* pConvexA, const btConvexShape* pConvexB, const btTransform& transformA, const btTransform& transformB, btVector3& v, btVector3& wWitnessOnA, btVector3& wWitnessOnB, class btIDebugDraw* debugDraw, btStackAlloc* stackAlloc ) { (void)debugDraw; (void)v; (void)simplexSolver; // const btScalar radialmargin(btScalar(0.)); btVector3 guessVector(transformA.getOrigin()-transformB.getOrigin()); btGjkEpaSolver2::sResults results; if(btGjkEpaSolver2::Penetration(pConvexA,transformA, pConvexB,transformB, guessVector,results)) { // debugDraw->drawLine(results.witnesses[1],results.witnesses[1]+results.normal,btVector3(255,0,0)); //resultOut->addContactPoint(results.normal,results.witnesses[1],-results.depth); wWitnessOnA = results.witnesses[0]; wWitnessOnB = results.witnesses[1]; v = results.normal; return true; } else { if(btGjkEpaSolver2::Distance(pConvexA,transformA,pConvexB,transformB,guessVector,results)) { wWitnessOnA = results.witnesses[0]; wWitnessOnB = results.witnesses[1]; v = results.normal; return false; } } return false; } critterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btConvexCast.h0000644000175000017500000000432311337071441030742 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 CONVEX_CAST_H #define CONVEX_CAST_H #include "LinearMath/btTransform.h" #include "LinearMath/btVector3.h" #include "LinearMath/btScalar.h" class btMinkowskiSumShape; #include "LinearMath/btIDebugDraw.h" /// btConvexCast is an interface for Casting class btConvexCast { public: virtual ~btConvexCast(); ///RayResult stores the closest result /// alternatively, add a callback method to decide about closest/all results struct CastResult { //virtual bool addRayResult(const btVector3& normal,btScalar fraction) = 0; virtual void DebugDraw(btScalar fraction) {(void)fraction;} virtual void drawCoordSystem(const btTransform& trans) {(void)trans;} CastResult() :m_fraction(btScalar(BT_LARGE_FLOAT)), m_debugDrawer(0), m_allowedPenetration(btScalar(0)) { } virtual ~CastResult() {}; btTransform m_hitTransformA; btTransform m_hitTransformB; btVector3 m_normal; btVector3 m_hitPoint; btScalar m_fraction; //input and output btIDebugDraw* m_debugDrawer; btScalar m_allowedPenetration; }; /// cast a convex against another convex object virtual bool calcTimeOfImpact( const btTransform& fromA, const btTransform& toA, const btTransform& fromB, const btTransform& toB, CastResult& result) = 0; }; #endif //CONVEX_CAST_H critterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btManifoldPoint.h0000644000175000017500000000746611344267705031453 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 MANIFOLD_CONTACT_POINT_H #define MANIFOLD_CONTACT_POINT_H #include "LinearMath/btVector3.h" #include "LinearMath/btTransformUtil.h" /// ManifoldContactPoint collects and maintains persistent contactpoints. /// used to improve stability and performance of rigidbody dynamics response. class btManifoldPoint { public: btManifoldPoint() :m_userPersistentData(0), m_appliedImpulse(0.f), m_lateralFrictionInitialized(false), m_appliedImpulseLateral1(0.f), m_appliedImpulseLateral2(0.f), m_contactMotion1(0.f), m_contactMotion2(0.f), m_contactCFM1(0.f), m_contactCFM2(0.f), m_lifeTime(0) { } btManifoldPoint( const btVector3 &pointA, const btVector3 &pointB, const btVector3 &normal, btScalar distance ) : m_localPointA( pointA ), m_localPointB( pointB ), m_normalWorldOnB( normal ), m_distance1( distance ), m_combinedFriction(btScalar(0.)), m_combinedRestitution(btScalar(0.)), m_userPersistentData(0), m_appliedImpulse(0.f), m_lateralFrictionInitialized(false), m_appliedImpulseLateral1(0.f), m_appliedImpulseLateral2(0.f), m_contactMotion1(0.f), m_contactMotion2(0.f), m_contactCFM1(0.f), m_contactCFM2(0.f), m_lifeTime(0) { } btVector3 m_localPointA; btVector3 m_localPointB; btVector3 m_positionWorldOnB; ///m_positionWorldOnA is redundant information, see getPositionWorldOnA(), but for clarity btVector3 m_positionWorldOnA; btVector3 m_normalWorldOnB; btScalar m_distance1; btScalar m_combinedFriction; btScalar m_combinedRestitution; //BP mod, store contact triangles. int m_partId0; int m_partId1; int m_index0; int m_index1; mutable void* m_userPersistentData; btScalar m_appliedImpulse; bool m_lateralFrictionInitialized; btScalar m_appliedImpulseLateral1; btScalar m_appliedImpulseLateral2; btScalar m_contactMotion1; btScalar m_contactMotion2; btScalar m_contactCFM1; btScalar m_contactCFM2; int m_lifeTime;//lifetime of the contactpoint in frames btVector3 m_lateralFrictionDir1; btVector3 m_lateralFrictionDir2; btScalar getDistance() const { return m_distance1; } int getLifeTime() const { return m_lifeTime; } const btVector3& getPositionWorldOnA() const { return m_positionWorldOnA; // return m_positionWorldOnB + m_normalWorldOnB * m_distance1; } const btVector3& getPositionWorldOnB() const { return m_positionWorldOnB; } void setDistance(btScalar dist) { m_distance1 = dist; } ///this returns the most recent applied impulse, to satisfy contact constraints by the constraint solver btScalar getAppliedImpulse() const { return m_appliedImpulse; } }; #endif //MANIFOLD_CONTACT_POINT_H critterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btPointCollector.h0000644000175000017500000000354511337071441031632 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 POINT_COLLECTOR_H #define POINT_COLLECTOR_H #include "btDiscreteCollisionDetectorInterface.h" struct btPointCollector : public btDiscreteCollisionDetectorInterface::Result { btVector3 m_normalOnBInWorld; btVector3 m_pointInWorld; btScalar m_distance;//negative means penetration bool m_hasResult; btPointCollector () : m_distance(btScalar(BT_LARGE_FLOAT)),m_hasResult(false) { } virtual void setShapeIdentifiersA(int partId0,int index0) { (void)partId0; (void)index0; } virtual void setShapeIdentifiersB(int partId1,int index1) { (void)partId1; (void)index1; } virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth) { if (depth< m_distance) { m_hasResult = true; m_normalOnBInWorld = normalOnBInWorld; m_pointInWorld = pointInWorld; //negative means penetration m_distance = depth; } } }; #endif //POINT_COLLECTOR_H critterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h0000644000175000017500000000642511337071441031713 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 GJK_PAIR_DETECTOR_H #define GJK_PAIR_DETECTOR_H #include "btDiscreteCollisionDetectorInterface.h" #include "BulletCollision/CollisionShapes/btCollisionMargin.h" class btConvexShape; #include "btSimplexSolverInterface.h" class btConvexPenetrationDepthSolver; /// btGjkPairDetector uses GJK to implement the btDiscreteCollisionDetectorInterface class btGjkPairDetector : public btDiscreteCollisionDetectorInterface { btVector3 m_cachedSeparatingAxis; btConvexPenetrationDepthSolver* m_penetrationDepthSolver; btSimplexSolverInterface* m_simplexSolver; const btConvexShape* m_minkowskiA; const btConvexShape* m_minkowskiB; int m_shapeTypeA; int m_shapeTypeB; btScalar m_marginA; btScalar m_marginB; bool m_ignoreMargin; btScalar m_cachedSeparatingDistance; public: //some debugging to fix degeneracy problems int m_lastUsedMethod; int m_curIter; int m_degenerateSimplex; int m_catchDegeneracies; btGjkPairDetector(const btConvexShape* objectA,const btConvexShape* objectB,btSimplexSolverInterface* simplexSolver,btConvexPenetrationDepthSolver* penetrationDepthSolver); btGjkPairDetector(const btConvexShape* objectA,const btConvexShape* objectB,int shapeTypeA,int shapeTypeB,btScalar marginA, btScalar marginB, btSimplexSolverInterface* simplexSolver,btConvexPenetrationDepthSolver* penetrationDepthSolver); virtual ~btGjkPairDetector() {}; virtual void getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults=false); void getClosestPointsNonVirtual(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw); void setMinkowskiA(btConvexShape* minkA) { m_minkowskiA = minkA; } void setMinkowskiB(btConvexShape* minkB) { m_minkowskiB = minkB; } void setCachedSeperatingAxis(const btVector3& seperatingAxis) { m_cachedSeparatingAxis = seperatingAxis; } const btVector3& getCachedSeparatingAxis() const { return m_cachedSeparatingAxis; } btScalar getCachedSeparatingDistance() const { return m_cachedSeparatingDistance; } void setPenetrationDepthSolver(btConvexPenetrationDepthSolver* penetrationDepthSolver) { m_penetrationDepthSolver = penetrationDepthSolver; } ///don't use setIgnoreMargin, it's for Bullet's internal use void setIgnoreMargin(bool ignoreMargin) { m_ignoreMargin = ignoreMargin; } }; #endif //GJK_PAIR_DETECTOR_H critterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btGjkPairDetector.cpp0000644000175000017500000003325111337071441032243 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btGjkPairDetector.h" #include "BulletCollision/CollisionShapes/btConvexShape.h" #include "BulletCollision/NarrowPhaseCollision/btSimplexSolverInterface.h" #include "BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h" #if defined(DEBUG) || defined (_DEBUG) //#define TEST_NON_VIRTUAL 1 #include //for debug printf #ifdef __SPU__ #include #define printf spu_printf //#define DEBUG_SPU_COLLISION_DETECTION 1 #endif //__SPU__ #endif //must be above the machine epsilon #define REL_ERROR2 btScalar(1.0e-6) //temp globals, to improve GJK/EPA/penetration calculations int gNumDeepPenetrationChecks = 0; int gNumGjkChecks = 0; btGjkPairDetector::btGjkPairDetector(const btConvexShape* objectA,const btConvexShape* objectB,btSimplexSolverInterface* simplexSolver,btConvexPenetrationDepthSolver* penetrationDepthSolver) :m_cachedSeparatingAxis(btScalar(0.),btScalar(1.),btScalar(0.)), m_penetrationDepthSolver(penetrationDepthSolver), m_simplexSolver(simplexSolver), m_minkowskiA(objectA), m_minkowskiB(objectB), m_shapeTypeA(objectA->getShapeType()), m_shapeTypeB(objectB->getShapeType()), m_marginA(objectA->getMargin()), m_marginB(objectB->getMargin()), m_ignoreMargin(false), m_lastUsedMethod(-1), m_catchDegeneracies(1) { } btGjkPairDetector::btGjkPairDetector(const btConvexShape* objectA,const btConvexShape* objectB,int shapeTypeA,int shapeTypeB,btScalar marginA, btScalar marginB, btSimplexSolverInterface* simplexSolver,btConvexPenetrationDepthSolver* penetrationDepthSolver) :m_cachedSeparatingAxis(btScalar(0.),btScalar(1.),btScalar(0.)), m_penetrationDepthSolver(penetrationDepthSolver), m_simplexSolver(simplexSolver), m_minkowskiA(objectA), m_minkowskiB(objectB), m_shapeTypeA(shapeTypeA), m_shapeTypeB(shapeTypeB), m_marginA(marginA), m_marginB(marginB), m_ignoreMargin(false), m_lastUsedMethod(-1), m_catchDegeneracies(1) { } void btGjkPairDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults) { (void)swapResults; getClosestPointsNonVirtual(input,output,debugDraw); } #ifdef __SPU__ void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw) #else void btGjkPairDetector::getClosestPointsNonVirtual(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw) #endif { m_cachedSeparatingDistance = 0.f; btScalar distance=btScalar(0.); btVector3 normalInB(btScalar(0.),btScalar(0.),btScalar(0.)); btVector3 pointOnA,pointOnB; btTransform localTransA = input.m_transformA; btTransform localTransB = input.m_transformB; btVector3 positionOffset = (localTransA.getOrigin() + localTransB.getOrigin()) * btScalar(0.5); localTransA.getOrigin() -= positionOffset; localTransB.getOrigin() -= positionOffset; bool check2d = m_minkowskiA->isConvex2d() && m_minkowskiB->isConvex2d(); btScalar marginA = m_marginA; btScalar marginB = m_marginB; gNumGjkChecks++; #ifdef DEBUG_SPU_COLLISION_DETECTION spu_printf("inside gjk\n"); #endif //for CCD we don't use margins if (m_ignoreMargin) { marginA = btScalar(0.); marginB = btScalar(0.); #ifdef DEBUG_SPU_COLLISION_DETECTION spu_printf("ignoring margin\n"); #endif } m_curIter = 0; int gGjkMaxIter = 1000;//this is to catch invalid input, perhaps check for #NaN? m_cachedSeparatingAxis.setValue(0,1,0); bool isValid = false; bool checkSimplex = false; bool checkPenetration = true; m_degenerateSimplex = 0; m_lastUsedMethod = -1; { btScalar squaredDistance = BT_LARGE_FLOAT; btScalar delta = btScalar(0.); btScalar margin = marginA + marginB; m_simplexSolver->reset(); for ( ; ; ) //while (true) { btVector3 seperatingAxisInA = (-m_cachedSeparatingAxis)* input.m_transformA.getBasis(); btVector3 seperatingAxisInB = m_cachedSeparatingAxis* input.m_transformB.getBasis(); #if 1 btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA); btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB); // btVector3 pInA = localGetSupportingVertexWithoutMargin(m_shapeTypeA, m_minkowskiA, seperatingAxisInA,input.m_convexVertexData[0]);//, &featureIndexA); // btVector3 qInB = localGetSupportingVertexWithoutMargin(m_shapeTypeB, m_minkowskiB, seperatingAxisInB,input.m_convexVertexData[1]);//, &featureIndexB); #else #ifdef __SPU__ btVector3 pInA = m_minkowskiA->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInA); btVector3 qInB = m_minkowskiB->localGetSupportVertexWithoutMarginNonVirtual(seperatingAxisInB); #else btVector3 pInA = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA); btVector3 qInB = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB); #ifdef TEST_NON_VIRTUAL btVector3 pInAv = m_minkowskiA->localGetSupportingVertexWithoutMargin(seperatingAxisInA); btVector3 qInBv = m_minkowskiB->localGetSupportingVertexWithoutMargin(seperatingAxisInB); btAssert((pInAv-pInA).length() < 0.0001); btAssert((qInBv-qInB).length() < 0.0001); #endif // #endif //__SPU__ #endif btVector3 pWorld = localTransA(pInA); btVector3 qWorld = localTransB(qInB); #ifdef DEBUG_SPU_COLLISION_DETECTION spu_printf("got local supporting vertices\n"); #endif if (check2d) { pWorld[2] = 0.f; qWorld[2] = 0.f; } btVector3 w = pWorld - qWorld; delta = m_cachedSeparatingAxis.dot(w); // potential exit, they don't overlap if ((delta > btScalar(0.0)) && (delta * delta > squaredDistance * input.m_maximumDistanceSquared)) { m_degenerateSimplex = 10; checkSimplex=true; //checkPenetration = false; break; } //exit 0: the new point is already in the simplex, or we didn't come any closer if (m_simplexSolver->inSimplex(w)) { m_degenerateSimplex = 1; checkSimplex = true; break; } // are we getting any closer ? btScalar f0 = squaredDistance - delta; btScalar f1 = squaredDistance * REL_ERROR2; if (f0 <= f1) { if (f0 <= btScalar(0.)) { m_degenerateSimplex = 2; } else { m_degenerateSimplex = 11; } checkSimplex = true; break; } #ifdef DEBUG_SPU_COLLISION_DETECTION spu_printf("addVertex 1\n"); #endif //add current vertex to simplex m_simplexSolver->addVertex(w, pWorld, qWorld); #ifdef DEBUG_SPU_COLLISION_DETECTION spu_printf("addVertex 2\n"); #endif btVector3 newCachedSeparatingAxis; //calculate the closest point to the origin (update vector v) if (!m_simplexSolver->closest(newCachedSeparatingAxis)) { m_degenerateSimplex = 3; checkSimplex = true; break; } if(newCachedSeparatingAxis.length2()previousSquaredDistance) { m_degenerateSimplex = 7; squaredDistance = previousSquaredDistance; checkSimplex = false; break; } #endif // m_cachedSeparatingAxis = newCachedSeparatingAxis; //redundant m_simplexSolver->compute_points(pointOnA, pointOnB); //are we getting any closer ? if (previousSquaredDistance - squaredDistance <= SIMD_EPSILON * previousSquaredDistance) { m_simplexSolver->backup_closest(m_cachedSeparatingAxis); checkSimplex = true; m_degenerateSimplex = 12; break; } //degeneracy, this is typically due to invalid/uninitialized worldtransforms for a btCollisionObject if (m_curIter++ > gGjkMaxIter) { #if defined(DEBUG) || defined (_DEBUG) || defined (DEBUG_SPU_COLLISION_DETECTION) printf("btGjkPairDetector maxIter exceeded:%i\n",m_curIter); printf("sepAxis=(%f,%f,%f), squaredDistance = %f, shapeTypeA=%i,shapeTypeB=%i\n", m_cachedSeparatingAxis.getX(), m_cachedSeparatingAxis.getY(), m_cachedSeparatingAxis.getZ(), squaredDistance, m_minkowskiA->getShapeType(), m_minkowskiB->getShapeType()); #endif break; } bool check = (!m_simplexSolver->fullSimplex()); //bool check = (!m_simplexSolver->fullSimplex() && squaredDistance > SIMD_EPSILON * m_simplexSolver->maxVertex()); if (!check) { //do we need this backup_closest here ? m_simplexSolver->backup_closest(m_cachedSeparatingAxis); m_degenerateSimplex = 13; break; } } if (checkSimplex) { m_simplexSolver->compute_points(pointOnA, pointOnB); normalInB = pointOnA-pointOnB; btScalar lenSqr =m_cachedSeparatingAxis.length2(); //valid normal if (lenSqr < 0.0001) { m_degenerateSimplex = 5; } if (lenSqr > SIMD_EPSILON*SIMD_EPSILON) { btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); normalInB *= rlen; //normalize btScalar s = btSqrt(squaredDistance); btAssert(s > btScalar(0.0)); pointOnA -= m_cachedSeparatingAxis * (marginA / s); pointOnB += m_cachedSeparatingAxis * (marginB / s); distance = ((btScalar(1.)/rlen) - margin); isValid = true; m_lastUsedMethod = 1; } else { m_lastUsedMethod = 2; } } bool catchDegeneratePenetrationCase = (m_catchDegeneracies && m_penetrationDepthSolver && m_degenerateSimplex && ((distance+margin) < 0.01)); //if (checkPenetration && !isValid) if (checkPenetration && (!isValid || catchDegeneratePenetrationCase )) { //penetration case //if there is no way to handle penetrations, bail out if (m_penetrationDepthSolver) { // Penetration depth case. btVector3 tmpPointOnA,tmpPointOnB; gNumDeepPenetrationChecks++; m_cachedSeparatingAxis.setZero(); bool isValid2 = m_penetrationDepthSolver->calcPenDepth( *m_simplexSolver, m_minkowskiA,m_minkowskiB, localTransA,localTransB, m_cachedSeparatingAxis, tmpPointOnA, tmpPointOnB, debugDraw,input.m_stackAlloc ); if (isValid2) { btVector3 tmpNormalInB = tmpPointOnB-tmpPointOnA; btScalar lenSqr = tmpNormalInB.length2(); if (lenSqr <= (SIMD_EPSILON*SIMD_EPSILON)) { tmpNormalInB = m_cachedSeparatingAxis; lenSqr = m_cachedSeparatingAxis.length2(); } if (lenSqr > (SIMD_EPSILON*SIMD_EPSILON)) { tmpNormalInB /= btSqrt(lenSqr); btScalar distance2 = -(tmpPointOnA-tmpPointOnB).length(); //only replace valid penetrations when the result is deeper (check) if (!isValid || (distance2 < distance)) { distance = distance2; pointOnA = tmpPointOnA; pointOnB = tmpPointOnB; normalInB = tmpNormalInB; isValid = true; m_lastUsedMethod = 3; } else { m_lastUsedMethod = 8; } } else { m_lastUsedMethod = 9; } } else { ///this is another degenerate case, where the initial GJK calculation reports a degenerate case ///EPA reports no penetration, and the second GJK (using the supporting vector without margin) ///reports a valid positive distance. Use the results of the second GJK instead of failing. ///thanks to Jacob.Langford for the reproduction case ///http://code.google.com/p/bullet/issues/detail?id=250 if (m_cachedSeparatingAxis.length2() > btScalar(0.)) { btScalar distance2 = (tmpPointOnA-tmpPointOnB).length()-margin; //only replace valid distances when the distance is less if (!isValid || (distance2 < distance)) { distance = distance2; pointOnA = tmpPointOnA; pointOnB = tmpPointOnB; pointOnA -= m_cachedSeparatingAxis * marginA ; pointOnB += m_cachedSeparatingAxis * marginB ; normalInB = m_cachedSeparatingAxis; normalInB.normalize(); isValid = true; m_lastUsedMethod = 6; } else { m_lastUsedMethod = 5; } } } } } } if (isValid && ((distance < 0) || (distance*distance < input.m_maximumDistanceSquared))) { #if 0 ///some debugging // if (check2d) { printf("n = %2.3f,%2.3f,%2.3f. ",normalInB[0],normalInB[1],normalInB[2]); printf("distance = %2.3f exit=%d deg=%d\n",distance,m_lastUsedMethod,m_degenerateSimplex); } #endif m_cachedSeparatingAxis = normalInB; m_cachedSeparatingDistance = distance; output.addContactPoint( normalInB, pointOnB+positionOffset, distance); } } critterding-beta12.1/src/utils/bullet/BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h0000644000175000017500000000345411337071441031402 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 GJK_CONVEX_CAST_H #define GJK_CONVEX_CAST_H #include "BulletCollision/CollisionShapes/btCollisionMargin.h" #include "LinearMath/btVector3.h" #include "btConvexCast.h" class btConvexShape; class btMinkowskiSumShape; #include "btSimplexSolverInterface.h" ///GjkConvexCast performs a raycast on a convex object using support mapping. class btGjkConvexCast : public btConvexCast { btSimplexSolverInterface* m_simplexSolver; const btConvexShape* m_convexA; const btConvexShape* m_convexB; public: btGjkConvexCast(const btConvexShape* convexA,const btConvexShape* convexB,btSimplexSolverInterface* simplexSolver); /// cast a convex against another convex object virtual bool calcTimeOfImpact( const btTransform& fromA, const btTransform& toA, const btTransform& fromB, const btTransform& toB, CastResult& result); }; #endif //GJK_CONVEX_CAST_H critterding-beta12.1/src/utils/bullet/BulletCollision/Jamfile0000644000175000017500000000060711337071441023354 0ustar bobkebobke SubDir TOP src BulletCollision ; Description bulletcollision : "Bullet Collision Detection" ; Library bulletcollision : [ Wildcard Gimpact : *.h *.cpp ] [ Wildcard BroadphaseCollision : *.h *.cpp ] [ Wildcard CollisionDispatch : *.h *.cpp ] [ Wildcard CollisionShapes : *.h *.cpp ] [ Wildcard NarrowPhaseCollision : *.h *.cpp ] ; LibDepends bulletcollision : bulletmath ; critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/0000755000175000017500000000000011347266042023447 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/btClipPolygon.h0000644000175000017500000001047311337071441026406 0ustar bobkebobke#ifndef BT_CLIP_POLYGON_H_INCLUDED #define BT_CLIP_POLYGON_H_INCLUDED /*! \file btClipPolygon.h \author Francisco Len Njera */ /* This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com 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 "LinearMath/btTransform.h" #include "LinearMath/btGeometryUtil.h" SIMD_FORCE_INLINE btScalar bt_distance_point_plane(const btVector4 & plane,const btVector3 &point) { return point.dot(plane) - plane[3]; } /*! Vector blending Takes two vectors a, b, blends them together*/ SIMD_FORCE_INLINE void bt_vec_blend(btVector3 &vr, const btVector3 &va,const btVector3 &vb, btScalar blend_factor) { vr = (1-blend_factor)*va + blend_factor*vb; } //! This function calcs the distance from a 3D plane SIMD_FORCE_INLINE void bt_plane_clip_polygon_collect( const btVector3 & point0, const btVector3 & point1, btScalar dist0, btScalar dist1, btVector3 * clipped, int & clipped_count) { bool _prevclassif = (dist0>SIMD_EPSILON); bool _classif = (dist1>SIMD_EPSILON); if(_classif!=_prevclassif) { btScalar blendfactor = -dist0/(dist1-dist0); bt_vec_blend(clipped[clipped_count],point0,point1,blendfactor); clipped_count++; } if(!_classif) { clipped[clipped_count] = point1; clipped_count++; } } //! Clips a polygon by a plane /*! *\return The count of the clipped counts */ SIMD_FORCE_INLINE int bt_plane_clip_polygon( const btVector4 & plane, const btVector3 * polygon_points, int polygon_point_count, btVector3 * clipped) { int clipped_count = 0; //clip first point btScalar firstdist = bt_distance_point_plane(plane,polygon_points[0]);; if(!(firstdist>SIMD_EPSILON)) { clipped[clipped_count] = polygon_points[0]; clipped_count++; } btScalar olddist = firstdist; for(int i=1;iSIMD_EPSILON)) { clipped[clipped_count] = point0; clipped_count++; } // point 1 btScalar olddist = firstdist; btScalar dist = bt_distance_point_plane(plane,point1); bt_plane_clip_polygon_collect( point0,point1, olddist, dist, clipped, clipped_count); olddist = dist; // point 2 dist = bt_distance_point_plane(plane,point2); bt_plane_clip_polygon_collect( point1,point2, olddist, dist, clipped, clipped_count); olddist = dist; //RETURN TO FIRST point0 bt_plane_clip_polygon_collect( point2,point0, olddist, firstdist, clipped, clipped_count); return clipped_count; } #endif // GIM_TRI_COLLISION_H_INCLUDED critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/gim_hash_table.h0000644000175000017500000005667611337071441026566 0ustar bobkebobke#ifndef GIM_HASH_TABLE_H_INCLUDED #define GIM_HASH_TABLE_H_INCLUDED /*! \file gim_trimesh_data.h \author Francisco Len Njera */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. (3) The zlib/libpng license that is included with this library in the file GIMPACT-LICENSE-ZLIB.TXT. 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 files GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "gim_radixsort.h" #define GIM_INVALID_HASH 0xffffffff //!< A very very high value #define GIM_DEFAULT_HASH_TABLE_SIZE 380 #define GIM_DEFAULT_HASH_TABLE_NODE_SIZE 4 #define GIM_HASH_TABLE_GROW_FACTOR 2 #define GIM_MIN_RADIX_SORT_SIZE 860 //!< calibrated on a PIII template struct GIM_HASH_TABLE_NODE { GUINT m_key; T m_data; GIM_HASH_TABLE_NODE() { } GIM_HASH_TABLE_NODE(const GIM_HASH_TABLE_NODE & value) { m_key = value.m_key; m_data = value.m_data; } GIM_HASH_TABLE_NODE(GUINT key, const T & data) { m_key = key; m_data = data; } bool operator <(const GIM_HASH_TABLE_NODE & other) const { ///inverse order, further objects are first if(m_key < other.m_key) return true; return false; } bool operator >(const GIM_HASH_TABLE_NODE & other) const { ///inverse order, further objects are first if(m_key > other.m_key) return true; return false; } bool operator ==(const GIM_HASH_TABLE_NODE & other) const { ///inverse order, further objects are first if(m_key == other.m_key) return true; return false; } }; ///Macro for getting the key class GIM_HASH_NODE_GET_KEY { public: template inline GUINT operator()( const T& a) { return a.m_key; } }; ///Macro for comparing the key and the element class GIM_HASH_NODE_CMP_KEY_MACRO { public: template inline int operator() ( const T& a, GUINT key) { return ((int)(a.m_key - key)); } }; ///Macro for comparing Hash nodes class GIM_HASH_NODE_CMP_MACRO { public: template inline int operator() ( const T& a, const T& b ) { return ((int)(a.m_key - b.m_key)); } }; //! Sorting for hash table /*! switch automatically between quicksort and radixsort */ template void gim_sort_hash_node_array(T * array, GUINT array_count) { if(array_count
  • if node_size = 0, then this container becomes a simple sorted array allocator. reserve_size is used for reserve memory in m_nodes. When the array size reaches the size equivalent to 'min_hash_table_size', then it becomes a hash table by calling check_for_switching_to_hashtable.
  • If node_size != 0, then this container becomes a hash table for ever
*/ template class gim_hash_table { protected: typedef GIM_HASH_TABLE_NODE _node_type; //!The nodes //array< _node_type, SuperAllocator<_node_type> > m_nodes; gim_array< _node_type > m_nodes; //SuperBufferedArray< _node_type > m_nodes; bool m_sorted; ///Hash table data management. The hash table has the indices to the corresponding m_nodes array GUINT * m_hash_table;//!< GUINT m_table_size;//!< GUINT m_node_size;//!< GUINT m_min_hash_table_size; //! Returns the cell index inline GUINT _find_cell(GUINT hashkey) { _node_type * nodesptr = m_nodes.pointer(); GUINT start_index = (hashkey%m_table_size)*m_node_size; GUINT end_index = start_index + m_node_size; while(start_index= m_nodes.size()) return false; if(m_nodes[index].m_key != GIM_INVALID_HASH) { //Search for the avaliable cell in buffer GUINT cell_index = _find_cell(m_nodes[index].m_key); btAssert(cell_index!=GIM_INVALID_HASH); btAssert(m_hash_table[cell_index]==index); m_hash_table[cell_index] = GIM_INVALID_HASH; } return this->_erase_unsorted(index); } //! erase by key in hash table inline bool _erase_hash_table(GUINT hashkey) { if(hashkey == GIM_INVALID_HASH) return false; //Search for the avaliable cell in buffer GUINT cell_index = _find_cell(hashkey); if(cell_index ==GIM_INVALID_HASH) return false; GUINT index = m_hash_table[cell_index]; m_hash_table[cell_index] = GIM_INVALID_HASH; return this->_erase_unsorted(index); } //! insert an element in hash table /*! If the element exists, this won't insert the element \return the index in the array of the existing element,or GIM_INVALID_HASH if the element has been inserted If so, the element has been inserted at the last position of the array. */ inline GUINT _insert_hash_table(GUINT hashkey, const T & value) { if(hashkey==GIM_INVALID_HASH) { //Insert anyway _insert_unsorted(hashkey,value); return GIM_INVALID_HASH; } GUINT cell_index = _assign_hash_table_cell(hashkey); GUINT value_key = m_hash_table[cell_index]; if(value_key!= GIM_INVALID_HASH) return value_key;// Not overrited m_hash_table[cell_index] = m_nodes.size(); _insert_unsorted(hashkey,value); return GIM_INVALID_HASH; } //! insert an element in hash table. /*! If the element exists, this replaces the element. \return the index in the array of the existing element,or GIM_INVALID_HASH if the element has been inserted If so, the element has been inserted at the last position of the array. */ inline GUINT _insert_hash_table_replace(GUINT hashkey, const T & value) { if(hashkey==GIM_INVALID_HASH) { //Insert anyway _insert_unsorted(hashkey,value); return GIM_INVALID_HASH; } GUINT cell_index = _assign_hash_table_cell(hashkey); GUINT value_key = m_hash_table[cell_index]; if(value_key!= GIM_INVALID_HASH) {//replaces the existing m_nodes[value_key] = _node_type(hashkey,value); return value_key;// index of the replaced element } m_hash_table[cell_index] = m_nodes.size(); _insert_unsorted(hashkey,value); return GIM_INVALID_HASH; } ///Sorted array data management. The hash table has the indices to the corresponding m_nodes array inline bool _erase_sorted(GUINT index) { if(index>=(GUINT)m_nodes.size()) return false; m_nodes.erase_sorted(index); if(m_nodes.size()<2) m_sorted = false; return true; } //! faster, but unsorted inline bool _erase_unsorted(GUINT index) { if(index>=m_nodes.size()) return false; GUINT lastindex = m_nodes.size()-1; if(indexcheck_for_switching_to_hashtable(); } //! Insert an element in an ordered array inline GUINT _insert_sorted(GUINT hashkey, const T & value) { if(hashkey==GIM_INVALID_HASH || size()==0) { m_nodes.push_back(_node_type(hashkey,value)); return GIM_INVALID_HASH; } //Insert at last position //Sort element GUINT result_ind=0; GUINT last_index = m_nodes.size()-1; _node_type * ptr = m_nodes.pointer(); bool found = gim_binary_search_ex( ptr,0,last_index,result_ind,hashkey,GIM_HASH_NODE_CMP_KEY_MACRO()); //Insert before found index if(found) { return result_ind; } else { _insert_in_pos(hashkey, value, result_ind); } return GIM_INVALID_HASH; } inline GUINT _insert_sorted_replace(GUINT hashkey, const T & value) { if(hashkey==GIM_INVALID_HASH || size()==0) { m_nodes.push_back(_node_type(hashkey,value)); return GIM_INVALID_HASH; } //Insert at last position //Sort element GUINT result_ind; GUINT last_index = m_nodes.size()-1; _node_type * ptr = m_nodes.pointer(); bool found = gim_binary_search_ex( ptr,0,last_index,result_ind,hashkey,GIM_HASH_NODE_CMP_KEY_MACRO()); //Insert before found index if(found) { m_nodes[result_ind] = _node_type(hashkey,value); } else { _insert_in_pos(hashkey, value, result_ind); } return result_ind; } //! Fast insertion in m_nodes array inline GUINT _insert_unsorted(GUINT hashkey, const T & value) { m_nodes.push_back(_node_type(hashkey,value)); m_sorted = false; return GIM_INVALID_HASH; } public: /*!
  • if node_size = 0, then this container becomes a simple sorted array allocator. reserve_size is used for reserve memory in m_nodes. When the array size reaches the size equivalent to 'min_hash_table_size', then it becomes a hash table by calling check_for_switching_to_hashtable.
  • If node_size != 0, then this container becomes a hash table for ever */ gim_hash_table(GUINT reserve_size = GIM_DEFAULT_HASH_TABLE_SIZE, GUINT node_size = GIM_DEFAULT_HASH_TABLE_NODE_SIZE, GUINT min_hash_table_size = GIM_INVALID_HASH) { m_hash_table = NULL; m_table_size = 0; m_sorted = false; m_node_size = node_size; m_min_hash_table_size = min_hash_table_size; if(m_node_size!=0) { if(reserve_size!=0) { m_nodes.reserve(reserve_size); _reserve_table_memory(reserve_size); _invalidate_keys(); } else { m_nodes.reserve(GIM_DEFAULT_HASH_TABLE_SIZE); _reserve_table_memory(GIM_DEFAULT_HASH_TABLE_SIZE); _invalidate_keys(); } } else if(reserve_size!=0) { m_nodes.reserve(reserve_size); } } ~gim_hash_table() { _destroy(); } inline bool is_hash_table() { if(m_hash_table) return true; return false; } inline bool is_sorted() { if(size()<2) return true; return m_sorted; } bool sort() { if(is_sorted()) return true; if(m_nodes.size()<2) return false; _node_type * ptr = m_nodes.pointer(); GUINT siz = m_nodes.size(); gim_sort_hash_node_array(ptr,siz); m_sorted=true; if(m_hash_table) { _rehash(); } return true; } bool switch_to_hashtable() { if(m_hash_table) return false; if(m_node_size==0) m_node_size = GIM_DEFAULT_HASH_TABLE_NODE_SIZE; if(m_nodes.size()m_hash_table) return true; if(!(m_nodes.size()< m_min_hash_table_size)) { if(m_node_size == 0) { m_node_size = GIM_DEFAULT_HASH_TABLE_NODE_SIZE; } _resize_table(m_nodes.size()+1); return true; } return false; } inline void set_sorted(bool value) { m_sorted = value; } //! Retrieves the amount of keys. inline GUINT size() const { return m_nodes.size(); } //! Retrieves the hash key. inline GUINT get_key(GUINT index) const { return m_nodes[index].m_key; } //! Retrieves the value by index /*! */ inline T * get_value_by_index(GUINT index) { return &m_nodes[index].m_data; } inline const T& operator[](GUINT index) const { return m_nodes[index].m_data; } inline T& operator[](GUINT index) { return m_nodes[index].m_data; } //! Finds the index of the element with the key /*! \return the index in the array of the existing element,or GIM_INVALID_HASH if the element has been inserted If so, the element has been inserted at the last position of the array. */ inline GUINT find(GUINT hashkey) { if(m_hash_table) { GUINT cell_index = _find_cell(hashkey); if(cell_index==GIM_INVALID_HASH) return GIM_INVALID_HASH; return m_hash_table[cell_index]; } GUINT last_index = m_nodes.size(); if(last_index<2) { if(last_index==0) return GIM_INVALID_HASH; if(m_nodes[0].m_key == hashkey) return 0; return GIM_INVALID_HASH; } else if(m_sorted) { //Binary search GUINT result_ind = 0; last_index--; _node_type * ptr = m_nodes.pointer(); bool found = gim_binary_search_ex(ptr,0,last_index,result_ind,hashkey,GIM_HASH_NODE_CMP_KEY_MACRO()); if(found) return result_ind; } return GIM_INVALID_HASH; } //! Retrieves the value associated with the index /*! \return the found element, or null */ inline T * get_value(GUINT hashkey) { GUINT index = find(hashkey); if(index == GIM_INVALID_HASH) return NULL; return &m_nodes[index].m_data; } /*! */ inline bool erase_by_index(GUINT index) { if(index > m_nodes.size()) return false; if(m_hash_table == NULL) { if(is_sorted()) { return this->_erase_sorted(index); } else { return this->_erase_unsorted(index); } } else { return this->_erase_by_index_hash_table(index); } return false; } inline bool erase_by_index_unsorted(GUINT index) { if(index > m_nodes.size()) return false; if(m_hash_table == NULL) { return this->_erase_unsorted(index); } else { return this->_erase_by_index_hash_table(index); } return false; } /*! */ inline bool erase_by_key(GUINT hashkey) { if(size()==0) return false; if(m_hash_table) { return this->_erase_hash_table(hashkey); } //Binary search if(is_sorted()==false) return false; GUINT result_ind = find(hashkey); if(result_ind!= GIM_INVALID_HASH) { return this->_erase_sorted(result_ind); } return false; } void clear() { m_nodes.clear(); if(m_hash_table==NULL) return; GUINT datasize = m_table_size*m_node_size; //Initialize the hashkeys. GUINT i; for(i=0;i_insert_hash_table(hashkey,element); } if(this->is_sorted()) { return this->_insert_sorted(hashkey,element); } return this->_insert_unsorted(hashkey,element); } //! Insert an element into the hash, and could overrite an existing object with the same hash. /*! \return If GIM_INVALID_HASH, the object has been inserted succesfully. Else it returns the position of the replaced element. */ inline GUINT insert_override(GUINT hashkey, const T & element) { if(m_hash_table) { return this->_insert_hash_table_replace(hashkey,element); } if(this->is_sorted()) { return this->_insert_sorted_replace(hashkey,element); } this->_insert_unsorted(hashkey,element); return m_nodes.size(); } //! Insert an element into the hash,But if this container is a sorted array, this inserts it unsorted /*! */ inline GUINT insert_unsorted(GUINT hashkey,const T & element) { if(m_hash_table) { return this->_insert_hash_table(hashkey,element); } return this->_insert_unsorted(hashkey,element); } }; #endif // GIM_CONTAINERS_H_INCLUDED critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/gim_linear_math.h0000644000175000017500000011216211337071441026736 0ustar bobkebobke#ifndef GIM_LINEAR_H_INCLUDED #define GIM_LINEAR_H_INCLUDED /*! \file gim_linear_math.h *\author Francisco Len Njera Type Independant Vector and matrix operations. */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. (3) The zlib/libpng license that is included with this library in the file GIMPACT-LICENSE-ZLIB.TXT. 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 files GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "gim_math.h" #include "gim_geom_types.h" //! Zero out a 2D vector #define VEC_ZERO_2(a) \ { \ (a)[0] = (a)[1] = 0.0f; \ }\ //! Zero out a 3D vector #define VEC_ZERO(a) \ { \ (a)[0] = (a)[1] = (a)[2] = 0.0f; \ }\ /// Zero out a 4D vector #define VEC_ZERO_4(a) \ { \ (a)[0] = (a)[1] = (a)[2] = (a)[3] = 0.0f; \ }\ /// Vector copy #define VEC_COPY_2(b,a) \ { \ (b)[0] = (a)[0]; \ (b)[1] = (a)[1]; \ }\ /// Copy 3D vector #define VEC_COPY(b,a) \ { \ (b)[0] = (a)[0]; \ (b)[1] = (a)[1]; \ (b)[2] = (a)[2]; \ }\ /// Copy 4D vector #define VEC_COPY_4(b,a) \ { \ (b)[0] = (a)[0]; \ (b)[1] = (a)[1]; \ (b)[2] = (a)[2]; \ (b)[3] = (a)[3]; \ }\ /// VECTOR SWAP #define VEC_SWAP(b,a) \ { \ GIM_SWAP_NUMBERS((b)[0],(a)[0]);\ GIM_SWAP_NUMBERS((b)[1],(a)[1]);\ GIM_SWAP_NUMBERS((b)[2],(a)[2]);\ }\ /// Vector difference #define VEC_DIFF_2(v21,v2,v1) \ { \ (v21)[0] = (v2)[0] - (v1)[0]; \ (v21)[1] = (v2)[1] - (v1)[1]; \ }\ /// Vector difference #define VEC_DIFF(v21,v2,v1) \ { \ (v21)[0] = (v2)[0] - (v1)[0]; \ (v21)[1] = (v2)[1] - (v1)[1]; \ (v21)[2] = (v2)[2] - (v1)[2]; \ }\ /// Vector difference #define VEC_DIFF_4(v21,v2,v1) \ { \ (v21)[0] = (v2)[0] - (v1)[0]; \ (v21)[1] = (v2)[1] - (v1)[1]; \ (v21)[2] = (v2)[2] - (v1)[2]; \ (v21)[3] = (v2)[3] - (v1)[3]; \ }\ /// Vector sum #define VEC_SUM_2(v21,v2,v1) \ { \ (v21)[0] = (v2)[0] + (v1)[0]; \ (v21)[1] = (v2)[1] + (v1)[1]; \ }\ /// Vector sum #define VEC_SUM(v21,v2,v1) \ { \ (v21)[0] = (v2)[0] + (v1)[0]; \ (v21)[1] = (v2)[1] + (v1)[1]; \ (v21)[2] = (v2)[2] + (v1)[2]; \ }\ /// Vector sum #define VEC_SUM_4(v21,v2,v1) \ { \ (v21)[0] = (v2)[0] + (v1)[0]; \ (v21)[1] = (v2)[1] + (v1)[1]; \ (v21)[2] = (v2)[2] + (v1)[2]; \ (v21)[3] = (v2)[3] + (v1)[3]; \ }\ /// scalar times vector #define VEC_SCALE_2(c,a,b) \ { \ (c)[0] = (a)*(b)[0]; \ (c)[1] = (a)*(b)[1]; \ }\ /// scalar times vector #define VEC_SCALE(c,a,b) \ { \ (c)[0] = (a)*(b)[0]; \ (c)[1] = (a)*(b)[1]; \ (c)[2] = (a)*(b)[2]; \ }\ /// scalar times vector #define VEC_SCALE_4(c,a,b) \ { \ (c)[0] = (a)*(b)[0]; \ (c)[1] = (a)*(b)[1]; \ (c)[2] = (a)*(b)[2]; \ (c)[3] = (a)*(b)[3]; \ }\ /// accumulate scaled vector #define VEC_ACCUM_2(c,a,b) \ { \ (c)[0] += (a)*(b)[0]; \ (c)[1] += (a)*(b)[1]; \ }\ /// accumulate scaled vector #define VEC_ACCUM(c,a,b) \ { \ (c)[0] += (a)*(b)[0]; \ (c)[1] += (a)*(b)[1]; \ (c)[2] += (a)*(b)[2]; \ }\ /// accumulate scaled vector #define VEC_ACCUM_4(c,a,b) \ { \ (c)[0] += (a)*(b)[0]; \ (c)[1] += (a)*(b)[1]; \ (c)[2] += (a)*(b)[2]; \ (c)[3] += (a)*(b)[3]; \ }\ /// Vector dot product #define VEC_DOT_2(a,b) ((a)[0]*(b)[0] + (a)[1]*(b)[1]) /// Vector dot product #define VEC_DOT(a,b) ((a)[0]*(b)[0] + (a)[1]*(b)[1] + (a)[2]*(b)[2]) /// Vector dot product #define VEC_DOT_4(a,b) ((a)[0]*(b)[0] + (a)[1]*(b)[1] + (a)[2]*(b)[2] + (a)[3]*(b)[3]) /// vector impact parameter (squared) #define VEC_IMPACT_SQ(bsq,direction,position) {\ GREAL _llel_ = VEC_DOT(direction, position);\ bsq = VEC_DOT(position, position) - _llel_*_llel_;\ }\ /// vector impact parameter #define VEC_IMPACT(bsq,direction,position) {\ VEC_IMPACT_SQ(bsq,direction,position); \ GIM_SQRT(bsq,bsq); \ }\ /// Vector length #define VEC_LENGTH_2(a,l)\ {\ GREAL _pp = VEC_DOT_2(a,a);\ GIM_SQRT(_pp,l);\ }\ /// Vector length #define VEC_LENGTH(a,l)\ {\ GREAL _pp = VEC_DOT(a,a);\ GIM_SQRT(_pp,l);\ }\ /// Vector length #define VEC_LENGTH_4(a,l)\ {\ GREAL _pp = VEC_DOT_4(a,a);\ GIM_SQRT(_pp,l);\ }\ /// Vector inv length #define VEC_INV_LENGTH_2(a,l)\ {\ GREAL _pp = VEC_DOT_2(a,a);\ GIM_INV_SQRT(_pp,l);\ }\ /// Vector inv length #define VEC_INV_LENGTH(a,l)\ {\ GREAL _pp = VEC_DOT(a,a);\ GIM_INV_SQRT(_pp,l);\ }\ /// Vector inv length #define VEC_INV_LENGTH_4(a,l)\ {\ GREAL _pp = VEC_DOT_4(a,a);\ GIM_INV_SQRT(_pp,l);\ }\ /// distance between two points #define VEC_DISTANCE(_len,_va,_vb) {\ vec3f _tmp_; \ VEC_DIFF(_tmp_, _vb, _va); \ VEC_LENGTH(_tmp_,_len); \ }\ /// Vector length #define VEC_CONJUGATE_LENGTH(a,l)\ {\ GREAL _pp = 1.0 - a[0]*a[0] - a[1]*a[1] - a[2]*a[2];\ GIM_SQRT(_pp,l);\ }\ /// Vector length #define VEC_NORMALIZE(a) { \ GREAL len;\ VEC_INV_LENGTH(a,len); \ if(lenA[1]?(A[0]>A[2]?0:2):(A[1]>A[2]?1:2);\ }\ //! Finds the 2 smallest cartesian coordinates from a vector #define VEC_MINOR_AXES(vec, i0, i1)\ {\ VEC_MAYOR_COORD(vec,i0);\ i0 = (i0+1)%3;\ i1 = (i0+1)%3;\ }\ #define VEC_EQUAL(v1,v2) (v1[0]==v2[0]&&v1[1]==v2[1]&&v1[2]==v2[2]) #define VEC_NEAR_EQUAL(v1,v2) (GIM_NEAR_EQUAL(v1[0],v2[0])&&GIM_NEAR_EQUAL(v1[1],v2[1])&&GIM_NEAR_EQUAL(v1[2],v2[2])) /// Vector cross #define X_AXIS_CROSS_VEC(dst,src)\ { \ dst[0] = 0.0f; \ dst[1] = -src[2]; \ dst[2] = src[1]; \ }\ #define Y_AXIS_CROSS_VEC(dst,src)\ { \ dst[0] = src[2]; \ dst[1] = 0.0f; \ dst[2] = -src[0]; \ }\ #define Z_AXIS_CROSS_VEC(dst,src)\ { \ dst[0] = -src[1]; \ dst[1] = src[0]; \ dst[2] = 0.0f; \ }\ /// initialize matrix #define IDENTIFY_MATRIX_3X3(m) \ { \ m[0][0] = 1.0; \ m[0][1] = 0.0; \ m[0][2] = 0.0; \ \ m[1][0] = 0.0; \ m[1][1] = 1.0; \ m[1][2] = 0.0; \ \ m[2][0] = 0.0; \ m[2][1] = 0.0; \ m[2][2] = 1.0; \ }\ /*! initialize matrix */ #define IDENTIFY_MATRIX_4X4(m) \ { \ m[0][0] = 1.0; \ m[0][1] = 0.0; \ m[0][2] = 0.0; \ m[0][3] = 0.0; \ \ m[1][0] = 0.0; \ m[1][1] = 1.0; \ m[1][2] = 0.0; \ m[1][3] = 0.0; \ \ m[2][0] = 0.0; \ m[2][1] = 0.0; \ m[2][2] = 1.0; \ m[2][3] = 0.0; \ \ m[3][0] = 0.0; \ m[3][1] = 0.0; \ m[3][2] = 0.0; \ m[3][3] = 1.0; \ }\ /*! initialize matrix */ #define ZERO_MATRIX_4X4(m) \ { \ m[0][0] = 0.0; \ m[0][1] = 0.0; \ m[0][2] = 0.0; \ m[0][3] = 0.0; \ \ m[1][0] = 0.0; \ m[1][1] = 0.0; \ m[1][2] = 0.0; \ m[1][3] = 0.0; \ \ m[2][0] = 0.0; \ m[2][1] = 0.0; \ m[2][2] = 0.0; \ m[2][3] = 0.0; \ \ m[3][0] = 0.0; \ m[3][1] = 0.0; \ m[3][2] = 0.0; \ m[3][3] = 0.0; \ }\ /*! matrix rotation X */ #define ROTX_CS(m,cosine,sine) \ { \ /* rotation about the x-axis */ \ \ m[0][0] = 1.0; \ m[0][1] = 0.0; \ m[0][2] = 0.0; \ m[0][3] = 0.0; \ \ m[1][0] = 0.0; \ m[1][1] = (cosine); \ m[1][2] = (sine); \ m[1][3] = 0.0; \ \ m[2][0] = 0.0; \ m[2][1] = -(sine); \ m[2][2] = (cosine); \ m[2][3] = 0.0; \ \ m[3][0] = 0.0; \ m[3][1] = 0.0; \ m[3][2] = 0.0; \ m[3][3] = 1.0; \ }\ /*! matrix rotation Y */ #define ROTY_CS(m,cosine,sine) \ { \ /* rotation about the y-axis */ \ \ m[0][0] = (cosine); \ m[0][1] = 0.0; \ m[0][2] = -(sine); \ m[0][3] = 0.0; \ \ m[1][0] = 0.0; \ m[1][1] = 1.0; \ m[1][2] = 0.0; \ m[1][3] = 0.0; \ \ m[2][0] = (sine); \ m[2][1] = 0.0; \ m[2][2] = (cosine); \ m[2][3] = 0.0; \ \ m[3][0] = 0.0; \ m[3][1] = 0.0; \ m[3][2] = 0.0; \ m[3][3] = 1.0; \ }\ /*! matrix rotation Z */ #define ROTZ_CS(m,cosine,sine) \ { \ /* rotation about the z-axis */ \ \ m[0][0] = (cosine); \ m[0][1] = (sine); \ m[0][2] = 0.0; \ m[0][3] = 0.0; \ \ m[1][0] = -(sine); \ m[1][1] = (cosine); \ m[1][2] = 0.0; \ m[1][3] = 0.0; \ \ m[2][0] = 0.0; \ m[2][1] = 0.0; \ m[2][2] = 1.0; \ m[2][3] = 0.0; \ \ m[3][0] = 0.0; \ m[3][1] = 0.0; \ m[3][2] = 0.0; \ m[3][3] = 1.0; \ }\ /*! matrix copy */ #define COPY_MATRIX_2X2(b,a) \ { \ b[0][0] = a[0][0]; \ b[0][1] = a[0][1]; \ \ b[1][0] = a[1][0]; \ b[1][1] = a[1][1]; \ \ }\ /*! matrix copy */ #define COPY_MATRIX_2X3(b,a) \ { \ b[0][0] = a[0][0]; \ b[0][1] = a[0][1]; \ b[0][2] = a[0][2]; \ \ b[1][0] = a[1][0]; \ b[1][1] = a[1][1]; \ b[1][2] = a[1][2]; \ }\ /*! matrix copy */ #define COPY_MATRIX_3X3(b,a) \ { \ b[0][0] = a[0][0]; \ b[0][1] = a[0][1]; \ b[0][2] = a[0][2]; \ \ b[1][0] = a[1][0]; \ b[1][1] = a[1][1]; \ b[1][2] = a[1][2]; \ \ b[2][0] = a[2][0]; \ b[2][1] = a[2][1]; \ b[2][2] = a[2][2]; \ }\ /*! matrix copy */ #define COPY_MATRIX_4X4(b,a) \ { \ b[0][0] = a[0][0]; \ b[0][1] = a[0][1]; \ b[0][2] = a[0][2]; \ b[0][3] = a[0][3]; \ \ b[1][0] = a[1][0]; \ b[1][1] = a[1][1]; \ b[1][2] = a[1][2]; \ b[1][3] = a[1][3]; \ \ b[2][0] = a[2][0]; \ b[2][1] = a[2][1]; \ b[2][2] = a[2][2]; \ b[2][3] = a[2][3]; \ \ b[3][0] = a[3][0]; \ b[3][1] = a[3][1]; \ b[3][2] = a[3][2]; \ b[3][3] = a[3][3]; \ }\ /*! matrix transpose */ #define TRANSPOSE_MATRIX_2X2(b,a) \ { \ b[0][0] = a[0][0]; \ b[0][1] = a[1][0]; \ \ b[1][0] = a[0][1]; \ b[1][1] = a[1][1]; \ }\ /*! matrix transpose */ #define TRANSPOSE_MATRIX_3X3(b,a) \ { \ b[0][0] = a[0][0]; \ b[0][1] = a[1][0]; \ b[0][2] = a[2][0]; \ \ b[1][0] = a[0][1]; \ b[1][1] = a[1][1]; \ b[1][2] = a[2][1]; \ \ b[2][0] = a[0][2]; \ b[2][1] = a[1][2]; \ b[2][2] = a[2][2]; \ }\ /*! matrix transpose */ #define TRANSPOSE_MATRIX_4X4(b,a) \ { \ b[0][0] = a[0][0]; \ b[0][1] = a[1][0]; \ b[0][2] = a[2][0]; \ b[0][3] = a[3][0]; \ \ b[1][0] = a[0][1]; \ b[1][1] = a[1][1]; \ b[1][2] = a[2][1]; \ b[1][3] = a[3][1]; \ \ b[2][0] = a[0][2]; \ b[2][1] = a[1][2]; \ b[2][2] = a[2][2]; \ b[2][3] = a[3][2]; \ \ b[3][0] = a[0][3]; \ b[3][1] = a[1][3]; \ b[3][2] = a[2][3]; \ b[3][3] = a[3][3]; \ }\ /*! multiply matrix by scalar */ #define SCALE_MATRIX_2X2(b,s,a) \ { \ b[0][0] = (s) * a[0][0]; \ b[0][1] = (s) * a[0][1]; \ \ b[1][0] = (s) * a[1][0]; \ b[1][1] = (s) * a[1][1]; \ }\ /*! multiply matrix by scalar */ #define SCALE_MATRIX_3X3(b,s,a) \ { \ b[0][0] = (s) * a[0][0]; \ b[0][1] = (s) * a[0][1]; \ b[0][2] = (s) * a[0][2]; \ \ b[1][0] = (s) * a[1][0]; \ b[1][1] = (s) * a[1][1]; \ b[1][2] = (s) * a[1][2]; \ \ b[2][0] = (s) * a[2][0]; \ b[2][1] = (s) * a[2][1]; \ b[2][2] = (s) * a[2][2]; \ }\ /*! multiply matrix by scalar */ #define SCALE_MATRIX_4X4(b,s,a) \ { \ b[0][0] = (s) * a[0][0]; \ b[0][1] = (s) * a[0][1]; \ b[0][2] = (s) * a[0][2]; \ b[0][3] = (s) * a[0][3]; \ \ b[1][0] = (s) * a[1][0]; \ b[1][1] = (s) * a[1][1]; \ b[1][2] = (s) * a[1][2]; \ b[1][3] = (s) * a[1][3]; \ \ b[2][0] = (s) * a[2][0]; \ b[2][1] = (s) * a[2][1]; \ b[2][2] = (s) * a[2][2]; \ b[2][3] = (s) * a[2][3]; \ \ b[3][0] = s * a[3][0]; \ b[3][1] = s * a[3][1]; \ b[3][2] = s * a[3][2]; \ b[3][3] = s * a[3][3]; \ }\ /*! multiply matrix by scalar */ #define SCALE_VEC_MATRIX_2X2(b,svec,a) \ { \ b[0][0] = svec[0] * a[0][0]; \ b[1][0] = svec[0] * a[1][0]; \ \ b[0][1] = svec[1] * a[0][1]; \ b[1][1] = svec[1] * a[1][1]; \ }\ /*! multiply matrix by scalar. Each columns is scaled by each scalar vector component */ #define SCALE_VEC_MATRIX_3X3(b,svec,a) \ { \ b[0][0] = svec[0] * a[0][0]; \ b[1][0] = svec[0] * a[1][0]; \ b[2][0] = svec[0] * a[2][0]; \ \ b[0][1] = svec[1] * a[0][1]; \ b[1][1] = svec[1] * a[1][1]; \ b[2][1] = svec[1] * a[2][1]; \ \ b[0][2] = svec[2] * a[0][2]; \ b[1][2] = svec[2] * a[1][2]; \ b[2][2] = svec[2] * a[2][2]; \ }\ /*! multiply matrix by scalar */ #define SCALE_VEC_MATRIX_4X4(b,svec,a) \ { \ b[0][0] = svec[0] * a[0][0]; \ b[1][0] = svec[0] * a[1][0]; \ b[2][0] = svec[0] * a[2][0]; \ b[3][0] = svec[0] * a[3][0]; \ \ b[0][1] = svec[1] * a[0][1]; \ b[1][1] = svec[1] * a[1][1]; \ b[2][1] = svec[1] * a[2][1]; \ b[3][1] = svec[1] * a[3][1]; \ \ b[0][2] = svec[2] * a[0][2]; \ b[1][2] = svec[2] * a[1][2]; \ b[2][2] = svec[2] * a[2][2]; \ b[3][2] = svec[2] * a[3][2]; \ \ b[0][3] = svec[3] * a[0][3]; \ b[1][3] = svec[3] * a[1][3]; \ b[2][3] = svec[3] * a[2][3]; \ b[3][3] = svec[3] * a[3][3]; \ }\ /*! multiply matrix by scalar */ #define ACCUM_SCALE_MATRIX_2X2(b,s,a) \ { \ b[0][0] += (s) * a[0][0]; \ b[0][1] += (s) * a[0][1]; \ \ b[1][0] += (s) * a[1][0]; \ b[1][1] += (s) * a[1][1]; \ }\ /*! multiply matrix by scalar */ #define ACCUM_SCALE_MATRIX_3X3(b,s,a) \ { \ b[0][0] += (s) * a[0][0]; \ b[0][1] += (s) * a[0][1]; \ b[0][2] += (s) * a[0][2]; \ \ b[1][0] += (s) * a[1][0]; \ b[1][1] += (s) * a[1][1]; \ b[1][2] += (s) * a[1][2]; \ \ b[2][0] += (s) * a[2][0]; \ b[2][1] += (s) * a[2][1]; \ b[2][2] += (s) * a[2][2]; \ }\ /*! multiply matrix by scalar */ #define ACCUM_SCALE_MATRIX_4X4(b,s,a) \ { \ b[0][0] += (s) * a[0][0]; \ b[0][1] += (s) * a[0][1]; \ b[0][2] += (s) * a[0][2]; \ b[0][3] += (s) * a[0][3]; \ \ b[1][0] += (s) * a[1][0]; \ b[1][1] += (s) * a[1][1]; \ b[1][2] += (s) * a[1][2]; \ b[1][3] += (s) * a[1][3]; \ \ b[2][0] += (s) * a[2][0]; \ b[2][1] += (s) * a[2][1]; \ b[2][2] += (s) * a[2][2]; \ b[2][3] += (s) * a[2][3]; \ \ b[3][0] += (s) * a[3][0]; \ b[3][1] += (s) * a[3][1]; \ b[3][2] += (s) * a[3][2]; \ b[3][3] += (s) * a[3][3]; \ }\ /*! matrix product */ /*! c[x][y] = a[x][0]*b[0][y]+a[x][1]*b[1][y]+a[x][2]*b[2][y]+a[x][3]*b[3][y];*/ #define MATRIX_PRODUCT_2X2(c,a,b) \ { \ c[0][0] = a[0][0]*b[0][0]+a[0][1]*b[1][0]; \ c[0][1] = a[0][0]*b[0][1]+a[0][1]*b[1][1]; \ \ c[1][0] = a[1][0]*b[0][0]+a[1][1]*b[1][0]; \ c[1][1] = a[1][0]*b[0][1]+a[1][1]*b[1][1]; \ \ }\ /*! matrix product */ /*! c[x][y] = a[x][0]*b[0][y]+a[x][1]*b[1][y]+a[x][2]*b[2][y]+a[x][3]*b[3][y];*/ #define MATRIX_PRODUCT_3X3(c,a,b) \ { \ c[0][0] = a[0][0]*b[0][0]+a[0][1]*b[1][0]+a[0][2]*b[2][0]; \ c[0][1] = a[0][0]*b[0][1]+a[0][1]*b[1][1]+a[0][2]*b[2][1]; \ c[0][2] = a[0][0]*b[0][2]+a[0][1]*b[1][2]+a[0][2]*b[2][2]; \ \ c[1][0] = a[1][0]*b[0][0]+a[1][1]*b[1][0]+a[1][2]*b[2][0]; \ c[1][1] = a[1][0]*b[0][1]+a[1][1]*b[1][1]+a[1][2]*b[2][1]; \ c[1][2] = a[1][0]*b[0][2]+a[1][1]*b[1][2]+a[1][2]*b[2][2]; \ \ c[2][0] = a[2][0]*b[0][0]+a[2][1]*b[1][0]+a[2][2]*b[2][0]; \ c[2][1] = a[2][0]*b[0][1]+a[2][1]*b[1][1]+a[2][2]*b[2][1]; \ c[2][2] = a[2][0]*b[0][2]+a[2][1]*b[1][2]+a[2][2]*b[2][2]; \ }\ /*! matrix product */ /*! c[x][y] = a[x][0]*b[0][y]+a[x][1]*b[1][y]+a[x][2]*b[2][y]+a[x][3]*b[3][y];*/ #define MATRIX_PRODUCT_4X4(c,a,b) \ { \ c[0][0] = a[0][0]*b[0][0]+a[0][1]*b[1][0]+a[0][2]*b[2][0]+a[0][3]*b[3][0];\ c[0][1] = a[0][0]*b[0][1]+a[0][1]*b[1][1]+a[0][2]*b[2][1]+a[0][3]*b[3][1];\ c[0][2] = a[0][0]*b[0][2]+a[0][1]*b[1][2]+a[0][2]*b[2][2]+a[0][3]*b[3][2];\ c[0][3] = a[0][0]*b[0][3]+a[0][1]*b[1][3]+a[0][2]*b[2][3]+a[0][3]*b[3][3];\ \ c[1][0] = a[1][0]*b[0][0]+a[1][1]*b[1][0]+a[1][2]*b[2][0]+a[1][3]*b[3][0];\ c[1][1] = a[1][0]*b[0][1]+a[1][1]*b[1][1]+a[1][2]*b[2][1]+a[1][3]*b[3][1];\ c[1][2] = a[1][0]*b[0][2]+a[1][1]*b[1][2]+a[1][2]*b[2][2]+a[1][3]*b[3][2];\ c[1][3] = a[1][0]*b[0][3]+a[1][1]*b[1][3]+a[1][2]*b[2][3]+a[1][3]*b[3][3];\ \ c[2][0] = a[2][0]*b[0][0]+a[2][1]*b[1][0]+a[2][2]*b[2][0]+a[2][3]*b[3][0];\ c[2][1] = a[2][0]*b[0][1]+a[2][1]*b[1][1]+a[2][2]*b[2][1]+a[2][3]*b[3][1];\ c[2][2] = a[2][0]*b[0][2]+a[2][1]*b[1][2]+a[2][2]*b[2][2]+a[2][3]*b[3][2];\ c[2][3] = a[2][0]*b[0][3]+a[2][1]*b[1][3]+a[2][2]*b[2][3]+a[2][3]*b[3][3];\ \ c[3][0] = a[3][0]*b[0][0]+a[3][1]*b[1][0]+a[3][2]*b[2][0]+a[3][3]*b[3][0];\ c[3][1] = a[3][0]*b[0][1]+a[3][1]*b[1][1]+a[3][2]*b[2][1]+a[3][3]*b[3][1];\ c[3][2] = a[3][0]*b[0][2]+a[3][1]*b[1][2]+a[3][2]*b[2][2]+a[3][3]*b[3][2];\ c[3][3] = a[3][0]*b[0][3]+a[3][1]*b[1][3]+a[3][2]*b[2][3]+a[3][3]*b[3][3];\ }\ /*! matrix times vector */ #define MAT_DOT_VEC_2X2(p,m,v) \ { \ p[0] = m[0][0]*v[0] + m[0][1]*v[1]; \ p[1] = m[1][0]*v[0] + m[1][1]*v[1]; \ }\ /*! matrix times vector */ #define MAT_DOT_VEC_3X3(p,m,v) \ { \ p[0] = m[0][0]*v[0] + m[0][1]*v[1] + m[0][2]*v[2]; \ p[1] = m[1][0]*v[0] + m[1][1]*v[1] + m[1][2]*v[2]; \ p[2] = m[2][0]*v[0] + m[2][1]*v[1] + m[2][2]*v[2]; \ }\ /*! matrix times vector v is a vec4f */ #define MAT_DOT_VEC_4X4(p,m,v) \ { \ p[0] = m[0][0]*v[0] + m[0][1]*v[1] + m[0][2]*v[2] + m[0][3]*v[3]; \ p[1] = m[1][0]*v[0] + m[1][1]*v[1] + m[1][2]*v[2] + m[1][3]*v[3]; \ p[2] = m[2][0]*v[0] + m[2][1]*v[1] + m[2][2]*v[2] + m[2][3]*v[3]; \ p[3] = m[3][0]*v[0] + m[3][1]*v[1] + m[3][2]*v[2] + m[3][3]*v[3]; \ }\ /*! matrix times vector v is a vec3f and m is a mat4f
    Last column is added as the position */ #define MAT_DOT_VEC_3X4(p,m,v) \ { \ p[0] = m[0][0]*v[0] + m[0][1]*v[1] + m[0][2]*v[2] + m[0][3]; \ p[1] = m[1][0]*v[0] + m[1][1]*v[1] + m[1][2]*v[2] + m[1][3]; \ p[2] = m[2][0]*v[0] + m[2][1]*v[1] + m[2][2]*v[2] + m[2][3]; \ }\ /*! vector transpose times matrix */ /*! p[j] = v[0]*m[0][j] + v[1]*m[1][j] + v[2]*m[2][j]; */ #define VEC_DOT_MAT_3X3(p,v,m) \ { \ p[0] = v[0]*m[0][0] + v[1]*m[1][0] + v[2]*m[2][0]; \ p[1] = v[0]*m[0][1] + v[1]*m[1][1] + v[2]*m[2][1]; \ p[2] = v[0]*m[0][2] + v[1]*m[1][2] + v[2]*m[2][2]; \ }\ /*! affine matrix times vector */ /** The matrix is assumed to be an affine matrix, with last two * entries representing a translation */ #define MAT_DOT_VEC_2X3(p,m,v) \ { \ p[0] = m[0][0]*v[0] + m[0][1]*v[1] + m[0][2]; \ p[1] = m[1][0]*v[0] + m[1][1]*v[1] + m[1][2]; \ }\ //! Transform a plane #define MAT_TRANSFORM_PLANE_4X4(pout,m,plane)\ { \ pout[0] = m[0][0]*plane[0] + m[0][1]*plane[1] + m[0][2]*plane[2];\ pout[1] = m[1][0]*plane[0] + m[1][1]*plane[1] + m[1][2]*plane[2];\ pout[2] = m[2][0]*plane[0] + m[2][1]*plane[1] + m[2][2]*plane[2];\ pout[3] = m[0][3]*pout[0] + m[1][3]*pout[1] + m[2][3]*pout[2] + plane[3];\ }\ /** inverse transpose of matrix times vector * * This macro computes inverse transpose of matrix m, * and multiplies vector v into it, to yeild vector p * * DANGER !!! Do Not use this on normal vectors!!! * It will leave normals the wrong length !!! * See macro below for use on normals. */ #define INV_TRANSP_MAT_DOT_VEC_2X2(p,m,v) \ { \ GREAL det; \ \ det = m[0][0]*m[1][1] - m[0][1]*m[1][0]; \ p[0] = m[1][1]*v[0] - m[1][0]*v[1]; \ p[1] = - m[0][1]*v[0] + m[0][0]*v[1]; \ \ /* if matrix not singular, and not orthonormal, then renormalize */ \ if ((det!=1.0f) && (det != 0.0f)) { \ det = 1.0f / det; \ p[0] *= det; \ p[1] *= det; \ } \ }\ /** transform normal vector by inverse transpose of matrix * and then renormalize the vector * * This macro computes inverse transpose of matrix m, * and multiplies vector v into it, to yeild vector p * Vector p is then normalized. */ #define NORM_XFORM_2X2(p,m,v) \ { \ GREAL len; \ \ /* do nothing if off-diagonals are zero and diagonals are \ * equal */ \ if ((m[0][1] != 0.0) || (m[1][0] != 0.0) || (m[0][0] != m[1][1])) { \ p[0] = m[1][1]*v[0] - m[1][0]*v[1]; \ p[1] = - m[0][1]*v[0] + m[0][0]*v[1]; \ \ len = p[0]*p[0] + p[1]*p[1]; \ GIM_INV_SQRT(len,len); \ p[0] *= len; \ p[1] *= len; \ } else { \ VEC_COPY_2 (p, v); \ } \ }\ /** outer product of vector times vector transpose * * The outer product of vector v and vector transpose t yeilds * dyadic matrix m. */ #define OUTER_PRODUCT_2X2(m,v,t) \ { \ m[0][0] = v[0] * t[0]; \ m[0][1] = v[0] * t[1]; \ \ m[1][0] = v[1] * t[0]; \ m[1][1] = v[1] * t[1]; \ }\ /** outer product of vector times vector transpose * * The outer product of vector v and vector transpose t yeilds * dyadic matrix m. */ #define OUTER_PRODUCT_3X3(m,v,t) \ { \ m[0][0] = v[0] * t[0]; \ m[0][1] = v[0] * t[1]; \ m[0][2] = v[0] * t[2]; \ \ m[1][0] = v[1] * t[0]; \ m[1][1] = v[1] * t[1]; \ m[1][2] = v[1] * t[2]; \ \ m[2][0] = v[2] * t[0]; \ m[2][1] = v[2] * t[1]; \ m[2][2] = v[2] * t[2]; \ }\ /** outer product of vector times vector transpose * * The outer product of vector v and vector transpose t yeilds * dyadic matrix m. */ #define OUTER_PRODUCT_4X4(m,v,t) \ { \ m[0][0] = v[0] * t[0]; \ m[0][1] = v[0] * t[1]; \ m[0][2] = v[0] * t[2]; \ m[0][3] = v[0] * t[3]; \ \ m[1][0] = v[1] * t[0]; \ m[1][1] = v[1] * t[1]; \ m[1][2] = v[1] * t[2]; \ m[1][3] = v[1] * t[3]; \ \ m[2][0] = v[2] * t[0]; \ m[2][1] = v[2] * t[1]; \ m[2][2] = v[2] * t[2]; \ m[2][3] = v[2] * t[3]; \ \ m[3][0] = v[3] * t[0]; \ m[3][1] = v[3] * t[1]; \ m[3][2] = v[3] * t[2]; \ m[3][3] = v[3] * t[3]; \ }\ /** outer product of vector times vector transpose * * The outer product of vector v and vector transpose t yeilds * dyadic matrix m. */ #define ACCUM_OUTER_PRODUCT_2X2(m,v,t) \ { \ m[0][0] += v[0] * t[0]; \ m[0][1] += v[0] * t[1]; \ \ m[1][0] += v[1] * t[0]; \ m[1][1] += v[1] * t[1]; \ }\ /** outer product of vector times vector transpose * * The outer product of vector v and vector transpose t yeilds * dyadic matrix m. */ #define ACCUM_OUTER_PRODUCT_3X3(m,v,t) \ { \ m[0][0] += v[0] * t[0]; \ m[0][1] += v[0] * t[1]; \ m[0][2] += v[0] * t[2]; \ \ m[1][0] += v[1] * t[0]; \ m[1][1] += v[1] * t[1]; \ m[1][2] += v[1] * t[2]; \ \ m[2][0] += v[2] * t[0]; \ m[2][1] += v[2] * t[1]; \ m[2][2] += v[2] * t[2]; \ }\ /** outer product of vector times vector transpose * * The outer product of vector v and vector transpose t yeilds * dyadic matrix m. */ #define ACCUM_OUTER_PRODUCT_4X4(m,v,t) \ { \ m[0][0] += v[0] * t[0]; \ m[0][1] += v[0] * t[1]; \ m[0][2] += v[0] * t[2]; \ m[0][3] += v[0] * t[3]; \ \ m[1][0] += v[1] * t[0]; \ m[1][1] += v[1] * t[1]; \ m[1][2] += v[1] * t[2]; \ m[1][3] += v[1] * t[3]; \ \ m[2][0] += v[2] * t[0]; \ m[2][1] += v[2] * t[1]; \ m[2][2] += v[2] * t[2]; \ m[2][3] += v[2] * t[3]; \ \ m[3][0] += v[3] * t[0]; \ m[3][1] += v[3] * t[1]; \ m[3][2] += v[3] * t[2]; \ m[3][3] += v[3] * t[3]; \ }\ /** determinant of matrix * * Computes determinant of matrix m, returning d */ #define DETERMINANT_2X2(d,m) \ { \ d = m[0][0] * m[1][1] - m[0][1] * m[1][0]; \ }\ /** determinant of matrix * * Computes determinant of matrix m, returning d */ #define DETERMINANT_3X3(d,m) \ { \ d = m[0][0] * (m[1][1]*m[2][2] - m[1][2] * m[2][1]); \ d -= m[0][1] * (m[1][0]*m[2][2] - m[1][2] * m[2][0]); \ d += m[0][2] * (m[1][0]*m[2][1] - m[1][1] * m[2][0]); \ }\ /** i,j,th cofactor of a 4x4 matrix * */ #define COFACTOR_4X4_IJ(fac,m,i,j) \ { \ GUINT __ii[4], __jj[4], __k; \ \ for (__k=0; __k */ #define INV_MAT_DOT_VEC_3X3(p,m,v) \ { \ p[0] = MAT_DOT_COL(m,v,0); \ p[1] = MAT_DOT_COL(m,v,1); \ p[2] = MAT_DOT_COL(m,v,2); \ }\ #endif // GIM_VECTOR_H_INCLUDED critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/gim_geom_types.h0000644000175000017500000000503711337071441026630 0ustar bobkebobke#ifndef GIM_GEOM_TYPES_H_INCLUDED #define GIM_GEOM_TYPES_H_INCLUDED /*! \file gim_geom_types.h \author Francisco Len Njera */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. (3) The zlib/libpng license that is included with this library in the file GIMPACT-LICENSE-ZLIB.TXT. 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 files GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "gim_math.h" //! Short Integer vector 2D typedef GSHORT vec2s[2]; //! Integer vector 3D typedef GSHORT vec3s[3]; //! Integer vector 4D typedef GSHORT vec4s[4]; //! Short Integer vector 2D typedef GUSHORT vec2us[2]; //! Integer vector 3D typedef GUSHORT vec3us[3]; //! Integer vector 4D typedef GUSHORT vec4us[4]; //! Integer vector 2D typedef GINT vec2i[2]; //! Integer vector 3D typedef GINT vec3i[3]; //! Integer vector 4D typedef GINT vec4i[4]; //! Unsigned Integer vector 2D typedef GUINT vec2ui[2]; //! Unsigned Integer vector 3D typedef GUINT vec3ui[3]; //! Unsigned Integer vector 4D typedef GUINT vec4ui[4]; //! Float vector 2D typedef GREAL vec2f[2]; //! Float vector 3D typedef GREAL vec3f[3]; //! Float vector 4D typedef GREAL vec4f[4]; //! Double vector 2D typedef GREAL2 vec2d[2]; //! Float vector 3D typedef GREAL2 vec3d[3]; //! Float vector 4D typedef GREAL2 vec4d[4]; //! Matrix 2D, row ordered typedef GREAL mat2f[2][2]; //! Matrix 3D, row ordered typedef GREAL mat3f[3][3]; //! Matrix 4D, row ordered typedef GREAL mat4f[4][4]; //! Quaternion typedef GREAL quatf[4]; //typedef struct _aabb3f aabb3f; #endif // GIM_GEOM_TYPES_H_INCLUDED critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/btTriangleShapeEx.cpp0000644000175000017500000001417011337071441027523 0ustar bobkebobke/*! \file btGImpactTriangleShape.h \author Francisco Len Njera */ /* This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com 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 "btTriangleShapeEx.h" void GIM_TRIANGLE_CONTACT::merge_points(const btVector4 & plane, btScalar margin, const btVector3 * points, int point_count) { m_point_count = 0; m_penetration_depth= -1000.0f; int point_indices[MAX_TRI_CLIPPING]; int _k; for ( _k=0;_k=0.0f) { if (_dist>m_penetration_depth) { m_penetration_depth = _dist; point_indices[0] = _k; m_point_count=1; } else if ((_dist+SIMD_EPSILON)>=m_penetration_depth) { point_indices[m_point_count] = _k; m_point_count++; } } } for ( _k=0;_k0.0f&&dis1>0.0f&&dis2>0.0f) return false; // classify points on this triangle dis0 = bt_distance_point_plane(other.m_plane,m_vertices[0]) - total_margin; dis1 = bt_distance_point_plane(other.m_plane,m_vertices[1]) - total_margin; dis2 = bt_distance_point_plane(other.m_plane,m_vertices[2]) - total_margin; if (dis0>0.0f&&dis1>0.0f&&dis2>0.0f) return false; return true; } int btPrimitiveTriangle::clip_triangle(btPrimitiveTriangle & other, btVector3 * clipped_points ) { // edge 0 btVector3 temp_points[MAX_TRI_CLIPPING]; btVector4 edgeplane; get_edge_plane(0,edgeplane); int clipped_count = bt_plane_clip_triangle( edgeplane,other.m_vertices[0],other.m_vertices[1],other.m_vertices[2],temp_points); if (clipped_count == 0) return 0; btVector3 temp_points1[MAX_TRI_CLIPPING]; // edge 1 get_edge_plane(1,edgeplane); clipped_count = bt_plane_clip_polygon(edgeplane,temp_points,clipped_count,temp_points1); if (clipped_count == 0) return 0; // edge 2 get_edge_plane(2,edgeplane); clipped_count = bt_plane_clip_polygon( edgeplane,temp_points1,clipped_count,clipped_points); return clipped_count; } bool btPrimitiveTriangle::find_triangle_collision_clip_method(btPrimitiveTriangle & other, GIM_TRIANGLE_CONTACT & contacts) { btScalar margin = m_margin + other.m_margin; btVector3 clipped_points[MAX_TRI_CLIPPING]; int clipped_count; //create planes // plane v vs U points GIM_TRIANGLE_CONTACT contacts1; contacts1.m_separating_normal = m_plane; clipped_count = clip_triangle(other,clipped_points); if (clipped_count == 0 ) { return false;//Reject } //find most deep interval face1 contacts1.merge_points(contacts1.m_separating_normal,margin,clipped_points,clipped_count); if (contacts1.m_point_count == 0) return false; // too far //Normal pointing to this triangle contacts1.m_separating_normal *= -1.f; //Clip tri1 by tri2 edges GIM_TRIANGLE_CONTACT contacts2; contacts2.m_separating_normal = other.m_plane; clipped_count = other.clip_triangle(*this,clipped_points); if (clipped_count == 0 ) { return false;//Reject } //find most deep interval face1 contacts2.merge_points(contacts2.m_separating_normal,margin,clipped_points,clipped_count); if (contacts2.m_point_count == 0) return false; // too far ////check most dir for contacts if (contacts2.m_penetration_depth0.0f&&dis1>0.0f&&dis2>0.0f) return false; // classify points on this triangle dis0 = bt_distance_point_plane(plane1,m_vertices1[0]) - total_margin; dis1 = bt_distance_point_plane(plane1,m_vertices1[1]) - total_margin; dis2 = bt_distance_point_plane(plane1,m_vertices1[2]) - total_margin; if (dis0>0.0f&&dis1>0.0f&&dis2>0.0f) return false; return true; } critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/gim_contact.h0000644000175000017500000001136311337071441026107 0ustar bobkebobke#ifndef GIM_CONTACT_H_INCLUDED #define GIM_CONTACT_H_INCLUDED /*! \file gim_contact.h \author Francisco Len Njera */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. (3) The zlib/libpng license that is included with this library in the file GIMPACT-LICENSE-ZLIB.TXT. 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 files GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "gim_geometry.h" #include "gim_radixsort.h" #include "gim_array.h" /** Configuration var for applying interpolation of contact normals */ #define NORMAL_CONTACT_AVERAGE 1 #define CONTACT_DIFF_EPSILON 0.00001f /// Structure for collision results ///Functions for managing and sorting contacts resulting from a collision query. ///Contact lists must be create by calling \ref GIM_CREATE_CONTACT_LIST ///After querys, contact lists must be destroy by calling \ref GIM_DYNARRAY_DESTROY ///Contacts can be merge for avoid duplicate results by calling \ref gim_merge_contacts class GIM_CONTACT { public: btVector3 m_point; btVector3 m_normal; GREAL m_depth;//Positive value indicates interpenetration GREAL m_distance;//Padding not for use GUINT m_feature1;//Face number GUINT m_feature2;//Face number public: GIM_CONTACT() { } GIM_CONTACT(const GIM_CONTACT & contact): m_point(contact.m_point), m_normal(contact.m_normal), m_depth(contact.m_depth), m_feature1(contact.m_feature1), m_feature2(contact.m_feature2) { m_point = contact.m_point; m_normal = contact.m_normal; m_depth = contact.m_depth; m_feature1 = contact.m_feature1; m_feature2 = contact.m_feature2; } GIM_CONTACT(const btVector3 &point,const btVector3 & normal, GREAL depth, GUINT feature1, GUINT feature2): m_point(point), m_normal(normal), m_depth(depth), m_feature1(feature1), m_feature2(feature2) { } //! Calcs key for coord classification SIMD_FORCE_INLINE GUINT calc_key_contact() const { GINT _coords[] = { (GINT)(m_point[0]*1000.0f+1.0f), (GINT)(m_point[1]*1333.0f), (GINT)(m_point[2]*2133.0f+3.0f)}; GUINT _hash=0; GUINT *_uitmp = (GUINT *)(&_coords[0]); _hash = *_uitmp; _uitmp++; _hash += (*_uitmp)<<4; _uitmp++; _hash += (*_uitmp)<<8; return _hash; } SIMD_FORCE_INLINE void interpolate_normals( btVector3 * normals,GUINT normal_count) { btVector3 vec_sum(m_normal); for(GUINT i=0;i { public: gim_contact_array():gim_array(64) { } SIMD_FORCE_INLINE void push_contact(const btVector3 &point,const btVector3 & normal, GREAL depth, GUINT feature1, GUINT feature2) { push_back_mem(); GIM_CONTACT & newele = back(); newele.m_point = point; newele.m_normal = normal; newele.m_depth = depth; newele.m_feature1 = feature1; newele.m_feature2 = feature2; } SIMD_FORCE_INLINE void push_triangle_contacts( const GIM_TRIANGLE_CONTACT_DATA & tricontact, GUINT feature1,GUINT feature2) { for(GUINT i = 0;isetMargin(margin); } m_needs_update = true; } //! Subshape member functions //!@{ //! Base method for determinig which kind of GIMPACT shape we get virtual eGIMPACT_SHAPE_TYPE getGImpactShapeType() const = 0 ; //! gets boxset SIMD_FORCE_INLINE btGImpactBoxSet * getBoxSet() { return &m_box_set; } //! Determines if this class has a hierarchy structure for sorting its primitives SIMD_FORCE_INLINE bool hasBoxSet() const { if(m_box_set.getNodeCount() == 0) return false; return true; } //! Obtains the primitive manager virtual const btPrimitiveManagerBase * getPrimitiveManager() const = 0; //! Gets the number of children virtual int getNumChildShapes() const = 0; //! if true, then its children must get transforms. virtual bool childrenHasTransform() const = 0; //! Determines if this shape has triangles virtual bool needsRetrieveTriangles() const = 0; //! Determines if this shape has tetrahedrons virtual bool needsRetrieveTetrahedrons() const = 0; virtual void getBulletTriangle(int prim_index,btTriangleShapeEx & triangle) const = 0; virtual void getBulletTetrahedron(int prim_index,btTetrahedronShapeEx & tetrahedron) const = 0; //! call when reading child shapes virtual void lockChildShapes() const { } virtual void unlockChildShapes() const { } //! if this trimesh SIMD_FORCE_INLINE void getPrimitiveTriangle(int index,btPrimitiveTriangle & triangle) const { getPrimitiveManager()->get_primitive_triangle(index,triangle); } //! Retrieves the bound from a child /*! */ virtual void getChildAabb(int child_index,const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const { btAABB child_aabb; getPrimitiveManager()->get_primitive_box(child_index,child_aabb); child_aabb.appy_transform(t); aabbMin = child_aabb.m_min; aabbMax = child_aabb.m_max; } //! Gets the children virtual btCollisionShape* getChildShape(int index) = 0; //! Gets the child virtual const btCollisionShape* getChildShape(int index) const = 0; //! Gets the children transform virtual btTransform getChildTransform(int index) const = 0; //! Sets the children transform /*! \post You must call updateBound() for update the box set. */ virtual void setChildTransform(int index, const btTransform & transform) = 0; //!@} //! virtual method for ray collision virtual void rayTest(const btVector3& rayFrom, const btVector3& rayTo, btCollisionWorld::RayResultCallback& resultCallback) const { (void) rayFrom; (void) rayTo; (void) resultCallback; } //! Function for retrieve triangles. /*! It gives the triangles in local space */ virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const { (void) callback; (void) aabbMin; (void) aabbMax; } //!@} }; //! btGImpactCompoundShape allows to handle multiple btCollisionShape objects at once /*! This class only can manage Convex subshapes */ class btGImpactCompoundShape : public btGImpactShapeInterface { public: //! compound primitive manager class CompoundPrimitiveManager:public btPrimitiveManagerBase { public: virtual ~CompoundPrimitiveManager() {} btGImpactCompoundShape * m_compoundShape; CompoundPrimitiveManager(const CompoundPrimitiveManager& compound) : btPrimitiveManagerBase() { m_compoundShape = compound.m_compoundShape; } CompoundPrimitiveManager(btGImpactCompoundShape * compoundShape) { m_compoundShape = compoundShape; } CompoundPrimitiveManager() { m_compoundShape = NULL; } virtual bool is_trimesh() const { return false; } virtual int get_primitive_count() const { return (int )m_compoundShape->getNumChildShapes(); } virtual void get_primitive_box(int prim_index ,btAABB & primbox) const { btTransform prim_trans; if(m_compoundShape->childrenHasTransform()) { prim_trans = m_compoundShape->getChildTransform(prim_index); } else { prim_trans.setIdentity(); } const btCollisionShape* shape = m_compoundShape->getChildShape(prim_index); shape->getAabb(prim_trans,primbox.m_min,primbox.m_max); } virtual void get_primitive_triangle(int prim_index,btPrimitiveTriangle & triangle) const { btAssert(0); (void) prim_index; (void) triangle; } }; protected: CompoundPrimitiveManager m_primitive_manager; btAlignedObjectArray m_childTransforms; btAlignedObjectArray m_childShapes; public: btGImpactCompoundShape(bool children_has_transform = true) { (void) children_has_transform; m_primitive_manager.m_compoundShape = this; m_box_set.setPrimitiveManager(&m_primitive_manager); } virtual ~btGImpactCompoundShape() { } //! if true, then its children must get transforms. virtual bool childrenHasTransform() const { if(m_childTransforms.size()==0) return false; return true; } //! Obtains the primitive manager virtual const btPrimitiveManagerBase * getPrimitiveManager() const { return &m_primitive_manager; } //! Obtains the compopund primitive manager SIMD_FORCE_INLINE CompoundPrimitiveManager * getCompoundPrimitiveManager() { return &m_primitive_manager; } //! Gets the number of children virtual int getNumChildShapes() const { return m_childShapes.size(); } //! Use this method for adding children. Only Convex shapes are allowed. void addChildShape(const btTransform& localTransform,btCollisionShape* shape) { btAssert(shape->isConvex()); m_childTransforms.push_back(localTransform); m_childShapes.push_back(shape); } //! Use this method for adding children. Only Convex shapes are allowed. void addChildShape(btCollisionShape* shape) { btAssert(shape->isConvex()); m_childShapes.push_back(shape); } //! Gets the children virtual btCollisionShape* getChildShape(int index) { return m_childShapes[index]; } //! Gets the children virtual const btCollisionShape* getChildShape(int index) const { return m_childShapes[index]; } //! Retrieves the bound from a child /*! */ virtual void getChildAabb(int child_index,const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const { if(childrenHasTransform()) { m_childShapes[child_index]->getAabb(t*m_childTransforms[child_index],aabbMin,aabbMax); } else { m_childShapes[child_index]->getAabb(t,aabbMin,aabbMax); } } //! Gets the children transform virtual btTransform getChildTransform(int index) const { btAssert(m_childTransforms.size() == m_childShapes.size()); return m_childTransforms[index]; } //! Sets the children transform /*! \post You must call updateBound() for update the box set. */ virtual void setChildTransform(int index, const btTransform & transform) { btAssert(m_childTransforms.size() == m_childShapes.size()); m_childTransforms[index] = transform; postUpdate(); } //! Determines if this shape has triangles virtual bool needsRetrieveTriangles() const { return false; } //! Determines if this shape has tetrahedrons virtual bool needsRetrieveTetrahedrons() const { return false; } virtual void getBulletTriangle(int prim_index,btTriangleShapeEx & triangle) const { (void) prim_index; (void) triangle; btAssert(0); } virtual void getBulletTetrahedron(int prim_index,btTetrahedronShapeEx & tetrahedron) const { (void) prim_index; (void) tetrahedron; btAssert(0); } //! Calculates the exact inertia tensor for this shape virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; virtual const char* getName()const { return "GImpactCompound"; } virtual eGIMPACT_SHAPE_TYPE getGImpactShapeType() const { return CONST_GIMPACT_COMPOUND_SHAPE; } }; //! This class manages a sub part of a mesh supplied by the btStridingMeshInterface interface. /*! - Simply create this shape by passing the btStridingMeshInterface to the constructor btGImpactMeshShapePart, then you must call updateBound() after creating the mesh - When making operations with this shape, you must call lock before accessing to the trimesh primitives, and then call unlock - You can handle deformable meshes with this shape, by calling postUpdate() every time when changing the mesh vertices. */ class btGImpactMeshShapePart : public btGImpactShapeInterface { public: //! Trimesh primitive manager /*! Manages the info from btStridingMeshInterface object and controls the Lock/Unlock mechanism */ class TrimeshPrimitiveManager:public btPrimitiveManagerBase { public: btScalar m_margin; btStridingMeshInterface * m_meshInterface; btVector3 m_scale; int m_part; int m_lock_count; const unsigned char *vertexbase; int numverts; PHY_ScalarType type; int stride; const unsigned char *indexbase; int indexstride; int numfaces; PHY_ScalarType indicestype; TrimeshPrimitiveManager() { m_meshInterface = NULL; m_part = 0; m_margin = 0.01f; m_scale = btVector3(1.f,1.f,1.f); m_lock_count = 0; vertexbase = 0; numverts = 0; stride = 0; indexbase = 0; indexstride = 0; numfaces = 0; } TrimeshPrimitiveManager(const TrimeshPrimitiveManager & manager) : btPrimitiveManagerBase() { m_meshInterface = manager.m_meshInterface; m_part = manager.m_part; m_margin = manager.m_margin; m_scale = manager.m_scale; m_lock_count = 0; vertexbase = 0; numverts = 0; stride = 0; indexbase = 0; indexstride = 0; numfaces = 0; } TrimeshPrimitiveManager( btStridingMeshInterface * meshInterface, int part) { m_meshInterface = meshInterface; m_part = part; m_scale = m_meshInterface->getScaling(); m_margin = 0.1f; m_lock_count = 0; vertexbase = 0; numverts = 0; stride = 0; indexbase = 0; indexstride = 0; numfaces = 0; } virtual ~TrimeshPrimitiveManager() {} void lock() { if(m_lock_count>0) { m_lock_count++; return; } m_meshInterface->getLockedReadOnlyVertexIndexBase( &vertexbase,numverts, type, stride,&indexbase, indexstride, numfaces,indicestype,m_part); m_lock_count = 1; } void unlock() { if(m_lock_count == 0) return; if(m_lock_count>1) { --m_lock_count; return; } m_meshInterface->unLockReadOnlyVertexBase(m_part); vertexbase = NULL; m_lock_count = 0; } virtual bool is_trimesh() const { return true; } virtual int get_primitive_count() const { return (int )numfaces; } SIMD_FORCE_INLINE int get_vertex_count() const { return (int )numverts; } SIMD_FORCE_INLINE void get_indices(int face_index,int &i0,int &i1,int &i2) const { if(indicestype == PHY_SHORT) { short * s_indices = (short *)(indexbase + face_index*indexstride); i0 = s_indices[0]; i1 = s_indices[1]; i2 = s_indices[2]; } else { int * i_indices = (int *)(indexbase + face_index*indexstride); i0 = i_indices[0]; i1 = i_indices[1]; i2 = i_indices[2]; } } SIMD_FORCE_INLINE void get_vertex(int vertex_index, btVector3 & vertex) const { if(type == PHY_DOUBLE) { double * dvertices = (double *)(vertexbase + vertex_index*stride); vertex[0] = btScalar(dvertices[0]*m_scale[0]); vertex[1] = btScalar(dvertices[1]*m_scale[1]); vertex[2] = btScalar(dvertices[2]*m_scale[2]); } else { float * svertices = (float *)(vertexbase + vertex_index*stride); vertex[0] = svertices[0]*m_scale[0]; vertex[1] = svertices[1]*m_scale[1]; vertex[2] = svertices[2]*m_scale[2]; } } virtual void get_primitive_box(int prim_index ,btAABB & primbox) const { btPrimitiveTriangle triangle; get_primitive_triangle(prim_index,triangle); primbox.calc_from_triangle_margin( triangle.m_vertices[0], triangle.m_vertices[1],triangle.m_vertices[2],triangle.m_margin); } virtual void get_primitive_triangle(int prim_index,btPrimitiveTriangle & triangle) const { int indices[3]; get_indices(prim_index,indices[0],indices[1],indices[2]); get_vertex(indices[0],triangle.m_vertices[0]); get_vertex(indices[1],triangle.m_vertices[1]); get_vertex(indices[2],triangle.m_vertices[2]); triangle.m_margin = m_margin; } SIMD_FORCE_INLINE void get_bullet_triangle(int prim_index,btTriangleShapeEx & triangle) const { int indices[3]; get_indices(prim_index,indices[0],indices[1],indices[2]); get_vertex(indices[0],triangle.m_vertices1[0]); get_vertex(indices[1],triangle.m_vertices1[1]); get_vertex(indices[2],triangle.m_vertices1[2]); triangle.setMargin(m_margin); } }; protected: TrimeshPrimitiveManager m_primitive_manager; public: btGImpactMeshShapePart() { m_box_set.setPrimitiveManager(&m_primitive_manager); } btGImpactMeshShapePart(btStridingMeshInterface * meshInterface, int part) { m_primitive_manager.m_meshInterface = meshInterface; m_primitive_manager.m_part = part; m_box_set.setPrimitiveManager(&m_primitive_manager); } virtual ~btGImpactMeshShapePart() { } //! if true, then its children must get transforms. virtual bool childrenHasTransform() const { return false; } //! call when reading child shapes virtual void lockChildShapes() const { void * dummy = (void*)(m_box_set.getPrimitiveManager()); TrimeshPrimitiveManager * dummymanager = static_cast(dummy); dummymanager->lock(); } virtual void unlockChildShapes() const { void * dummy = (void*)(m_box_set.getPrimitiveManager()); TrimeshPrimitiveManager * dummymanager = static_cast(dummy); dummymanager->unlock(); } //! Gets the number of children virtual int getNumChildShapes() const { return m_primitive_manager.get_primitive_count(); } //! Gets the children virtual btCollisionShape* getChildShape(int index) { (void) index; btAssert(0); return NULL; } //! Gets the child virtual const btCollisionShape* getChildShape(int index) const { (void) index; btAssert(0); return NULL; } //! Gets the children transform virtual btTransform getChildTransform(int index) const { (void) index; btAssert(0); return btTransform(); } //! Sets the children transform /*! \post You must call updateBound() for update the box set. */ virtual void setChildTransform(int index, const btTransform & transform) { (void) index; (void) transform; btAssert(0); } //! Obtains the primitive manager virtual const btPrimitiveManagerBase * getPrimitiveManager() const { return &m_primitive_manager; } SIMD_FORCE_INLINE TrimeshPrimitiveManager * getTrimeshPrimitiveManager() { return &m_primitive_manager; } virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; virtual const char* getName()const { return "GImpactMeshShapePart"; } virtual eGIMPACT_SHAPE_TYPE getGImpactShapeType() const { return CONST_GIMPACT_TRIMESH_SHAPE_PART; } //! Determines if this shape has triangles virtual bool needsRetrieveTriangles() const { return true; } //! Determines if this shape has tetrahedrons virtual bool needsRetrieveTetrahedrons() const { return false; } virtual void getBulletTriangle(int prim_index,btTriangleShapeEx & triangle) const { m_primitive_manager.get_bullet_triangle(prim_index,triangle); } virtual void getBulletTetrahedron(int prim_index,btTetrahedronShapeEx & tetrahedron) const { (void) prim_index; (void) tetrahedron; btAssert(0); } SIMD_FORCE_INLINE int getVertexCount() const { return m_primitive_manager.get_vertex_count(); } SIMD_FORCE_INLINE void getVertex(int vertex_index, btVector3 & vertex) const { m_primitive_manager.get_vertex(vertex_index,vertex); } SIMD_FORCE_INLINE void setMargin(btScalar margin) { m_primitive_manager.m_margin = margin; postUpdate(); } SIMD_FORCE_INLINE btScalar getMargin() const { return m_primitive_manager.m_margin; } virtual void setLocalScaling(const btVector3& scaling) { m_primitive_manager.m_scale = scaling; postUpdate(); } virtual const btVector3& getLocalScaling() const { return m_primitive_manager.m_scale; } SIMD_FORCE_INLINE int getPart() const { return (int)m_primitive_manager.m_part; } virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const; }; //! This class manages a mesh supplied by the btStridingMeshInterface interface. /*! Set of btGImpactMeshShapePart parts - Simply create this shape by passing the btStridingMeshInterface to the constructor btGImpactMeshShape, then you must call updateBound() after creating the mesh - You can handle deformable meshes with this shape, by calling postUpdate() every time when changing the mesh vertices. */ class btGImpactMeshShape : public btGImpactShapeInterface { btStridingMeshInterface* m_meshInterface; protected: btAlignedObjectArray m_mesh_parts; void buildMeshParts(btStridingMeshInterface * meshInterface) { for (int i=0;igetNumSubParts() ;++i ) { btGImpactMeshShapePart * newpart = new btGImpactMeshShapePart(meshInterface,i); m_mesh_parts.push_back(newpart); } } //! use this function for perfofm refit in bounding boxes virtual void calcLocalAABB() { m_localAABB.invalidate(); int i = m_mesh_parts.size(); while(i--) { m_mesh_parts[i]->updateBound(); m_localAABB.merge(m_mesh_parts[i]->getLocalBox()); } } public: btGImpactMeshShape(btStridingMeshInterface * meshInterface) { m_meshInterface = meshInterface; buildMeshParts(meshInterface); } virtual ~btGImpactMeshShape() { int i = m_mesh_parts.size(); while(i--) { btGImpactMeshShapePart * part = m_mesh_parts[i]; delete part; } m_mesh_parts.clear(); } btStridingMeshInterface* getMeshInterface() { return m_meshInterface; } const btStridingMeshInterface* getMeshInterface() const { return m_meshInterface; } int getMeshPartCount() const { return m_mesh_parts.size(); } btGImpactMeshShapePart * getMeshPart(int index) { return m_mesh_parts[index]; } const btGImpactMeshShapePart * getMeshPart(int index) const { return m_mesh_parts[index]; } virtual void setLocalScaling(const btVector3& scaling) { localScaling = scaling; int i = m_mesh_parts.size(); while(i--) { btGImpactMeshShapePart * part = m_mesh_parts[i]; part->setLocalScaling(scaling); } m_needs_update = true; } virtual void setMargin(btScalar margin) { m_collisionMargin = margin; int i = m_mesh_parts.size(); while(i--) { btGImpactMeshShapePart * part = m_mesh_parts[i]; part->setMargin(margin); } m_needs_update = true; } //! Tells to this object that is needed to refit all the meshes virtual void postUpdate() { int i = m_mesh_parts.size(); while(i--) { btGImpactMeshShapePart * part = m_mesh_parts[i]; part->postUpdate(); } m_needs_update = true; } virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; //! Obtains the primitive manager virtual const btPrimitiveManagerBase * getPrimitiveManager() const { btAssert(0); return NULL; } //! Gets the number of children virtual int getNumChildShapes() const { btAssert(0); return 0; } //! if true, then its children must get transforms. virtual bool childrenHasTransform() const { btAssert(0); return false; } //! Determines if this shape has triangles virtual bool needsRetrieveTriangles() const { btAssert(0); return false; } //! Determines if this shape has tetrahedrons virtual bool needsRetrieveTetrahedrons() const { btAssert(0); return false; } virtual void getBulletTriangle(int prim_index,btTriangleShapeEx & triangle) const { (void) prim_index; (void) triangle; btAssert(0); } virtual void getBulletTetrahedron(int prim_index,btTetrahedronShapeEx & tetrahedron) const { (void) prim_index; (void) tetrahedron; btAssert(0); } //! call when reading child shapes virtual void lockChildShapes() const { btAssert(0); } virtual void unlockChildShapes() const { btAssert(0); } //! Retrieves the bound from a child /*! */ virtual void getChildAabb(int child_index,const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const { (void) child_index; (void) t; (void) aabbMin; (void) aabbMax; btAssert(0); } //! Gets the children virtual btCollisionShape* getChildShape(int index) { (void) index; btAssert(0); return NULL; } //! Gets the child virtual const btCollisionShape* getChildShape(int index) const { (void) index; btAssert(0); return NULL; } //! Gets the children transform virtual btTransform getChildTransform(int index) const { (void) index; btAssert(0); return btTransform(); } //! Sets the children transform /*! \post You must call updateBound() for update the box set. */ virtual void setChildTransform(int index, const btTransform & transform) { (void) index; (void) transform; btAssert(0); } virtual eGIMPACT_SHAPE_TYPE getGImpactShapeType() const { return CONST_GIMPACT_TRIMESH_SHAPE; } virtual const char* getName()const { return "GImpactMesh"; } virtual void rayTest(const btVector3& rayFrom, const btVector3& rayTo, btCollisionWorld::RayResultCallback& resultCallback) const; //! Function for retrieve triangles. /*! It gives the triangles in local space */ virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const; virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btGImpactMeshShapeData { btCollisionShapeData m_collisionShapeData; btStridingMeshInterfaceData m_meshInterface; btVector3FloatData m_localScaling; float m_collisionMargin; int m_gimpactSubType; }; SIMD_FORCE_INLINE int btGImpactMeshShape::calculateSerializeBufferSize() const { return sizeof(btGImpactMeshShapeData); } #endif //GIMPACT_MESH_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/btGImpactShape.cpp0000644000175000017500000001237711344267705027024 0ustar bobkebobke/* This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com 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 "btGImpactShape.h" #include "btGImpactMassUtil.h" #define CALC_EXACT_INERTIA 1 void btGImpactCompoundShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const { lockChildShapes(); #ifdef CALC_EXACT_INERTIA inertia.setValue(0.f,0.f,0.f); int i = this->getNumChildShapes(); btScalar shapemass = mass/btScalar(i); while(i--) { btVector3 temp_inertia; m_childShapes[i]->calculateLocalInertia(shapemass,temp_inertia); if(childrenHasTransform()) { inertia = gim_inertia_add_transformed( inertia,temp_inertia,m_childTransforms[i]); } else { inertia = gim_inertia_add_transformed( inertia,temp_inertia,btTransform::getIdentity()); } } #else // Calc box inertia btScalar lx= m_localAABB.m_max[0] - m_localAABB.m_min[0]; btScalar ly= m_localAABB.m_max[1] - m_localAABB.m_min[1]; btScalar lz= m_localAABB.m_max[2] - m_localAABB.m_min[2]; const btScalar x2 = lx*lx; const btScalar y2 = ly*ly; const btScalar z2 = lz*lz; const btScalar scaledmass = mass * btScalar(0.08333333); inertia = scaledmass * (btVector3(y2+z2,x2+z2,x2+y2)); #endif unlockChildShapes(); } void btGImpactMeshShapePart::calculateLocalInertia(btScalar mass,btVector3& inertia) const { lockChildShapes(); #ifdef CALC_EXACT_INERTIA inertia.setValue(0.f,0.f,0.f); int i = this->getVertexCount(); btScalar pointmass = mass/btScalar(i); while(i--) { btVector3 pointintertia; this->getVertex(i,pointintertia); pointintertia = gim_get_point_inertia(pointintertia,pointmass); inertia+=pointintertia; } #else // Calc box inertia btScalar lx= m_localAABB.m_max[0] - m_localAABB.m_min[0]; btScalar ly= m_localAABB.m_max[1] - m_localAABB.m_min[1]; btScalar lz= m_localAABB.m_max[2] - m_localAABB.m_min[2]; const btScalar x2 = lx*lx; const btScalar y2 = ly*ly; const btScalar z2 = lz*lz; const btScalar scaledmass = mass * btScalar(0.08333333); inertia = scaledmass * (btVector3(y2+z2,x2+z2,x2+y2)); #endif unlockChildShapes(); } void btGImpactMeshShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const { #ifdef CALC_EXACT_INERTIA inertia.setValue(0.f,0.f,0.f); int i = this->getMeshPartCount(); btScalar partmass = mass/btScalar(i); while(i--) { btVector3 partinertia; getMeshPart(i)->calculateLocalInertia(partmass,partinertia); inertia+=partinertia; } #else // Calc box inertia btScalar lx= m_localAABB.m_max[0] - m_localAABB.m_min[0]; btScalar ly= m_localAABB.m_max[1] - m_localAABB.m_min[1]; btScalar lz= m_localAABB.m_max[2] - m_localAABB.m_min[2]; const btScalar x2 = lx*lx; const btScalar y2 = ly*ly; const btScalar z2 = lz*lz; const btScalar scaledmass = mass * btScalar(0.08333333); inertia = scaledmass * (btVector3(y2+z2,x2+z2,x2+y2)); #endif } void btGImpactMeshShape::rayTest(const btVector3& rayFrom, const btVector3& rayTo, btCollisionWorld::RayResultCallback& resultCallback) const { } void btGImpactMeshShapePart::processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const { lockChildShapes(); btAABB box; box.m_min = aabbMin; box.m_max = aabbMax; btAlignedObjectArray collided; m_box_set.boxQuery(box,collided); if(collided.size()==0) { unlockChildShapes(); return; } int part = (int)getPart(); btPrimitiveTriangle triangle; int i = collided.size(); while(i--) { this->getPrimitiveTriangle(collided[i],triangle); callback->processTriangle(triangle.m_vertices,part,collided[i]); } unlockChildShapes(); } void btGImpactMeshShape::processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const { int i = m_mesh_parts.size(); while(i--) { m_mesh_parts[i]->processAllTriangles(callback,aabbMin,aabbMax); } } ///fills the dataBuffer and returns the struct name (and 0 on failure) const char* btGImpactMeshShape::serialize(void* dataBuffer, btSerializer* serializer) const { btGImpactMeshShapeData* trimeshData = (btGImpactMeshShapeData*) dataBuffer; btCollisionShape::serialize(&trimeshData->m_collisionShapeData,serializer); m_meshInterface->serialize(&trimeshData->m_meshInterface, serializer); trimeshData->m_collisionMargin = float(m_collisionMargin); localScaling.serializeFloat(trimeshData->m_localScaling); trimeshData->m_gimpactSubType = int(getGImpactShapeType()); return "btGImpactMeshShapeData"; } critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/btTriangleShapeEx.h0000644000175000017500000001175311337071441027174 0ustar bobkebobke/*! \file btGImpactShape.h \author Francisco Len Njera */ /* This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com 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 TRIANGLE_SHAPE_EX_H #define TRIANGLE_SHAPE_EX_H #include "BulletCollision/CollisionShapes/btCollisionShape.h" #include "BulletCollision/CollisionShapes/btTriangleShape.h" #include "btBoxCollision.h" #include "btClipPolygon.h" #include "btGeometryOperations.h" #define MAX_TRI_CLIPPING 16 //! Structure for collision struct GIM_TRIANGLE_CONTACT { btScalar m_penetration_depth; int m_point_count; btVector4 m_separating_normal; btVector3 m_points[MAX_TRI_CLIPPING]; SIMD_FORCE_INLINE void copy_from(const GIM_TRIANGLE_CONTACT& other) { m_penetration_depth = other.m_penetration_depth; m_separating_normal = other.m_separating_normal; m_point_count = other.m_point_count; int i = m_point_count; while(i--) { m_points[i] = other.m_points[i]; } } GIM_TRIANGLE_CONTACT() { } GIM_TRIANGLE_CONTACT(const GIM_TRIANGLE_CONTACT& other) { copy_from(other); } //! classify points that are closer void merge_points(const btVector4 & plane, btScalar margin, const btVector3 * points, int point_count); }; class btPrimitiveTriangle { public: btVector3 m_vertices[3]; btVector4 m_plane; btScalar m_margin; btScalar m_dummy; btPrimitiveTriangle():m_margin(0.01f) { } SIMD_FORCE_INLINE void buildTriPlane() { btVector3 normal = (m_vertices[1]-m_vertices[0]).cross(m_vertices[2]-m_vertices[0]); normal.normalize(); m_plane.setValue(normal[0],normal[1],normal[2],m_vertices[0].dot(normal)); } //! Test if triangles could collide bool overlap_test_conservative(const btPrimitiveTriangle& other); //! Calcs the plane which is paralele to the edge and perpendicular to the triangle plane /*! \pre this triangle must have its plane calculated. */ SIMD_FORCE_INLINE void get_edge_plane(int edge_index, btVector4 &plane) const { const btVector3 & e0 = m_vertices[edge_index]; const btVector3 & e1 = m_vertices[(edge_index+1)%3]; bt_edge_plane(e0,e1,m_plane,plane); } void applyTransform(const btTransform& t) { m_vertices[0] = t(m_vertices[0]); m_vertices[1] = t(m_vertices[1]); m_vertices[2] = t(m_vertices[2]); } //! Clips the triangle against this /*! \pre clipped_points must have MAX_TRI_CLIPPING size, and this triangle must have its plane calculated. \return the number of clipped points */ int clip_triangle(btPrimitiveTriangle & other, btVector3 * clipped_points ); //! Find collision using the clipping method /*! \pre this triangle and other must have their triangles calculated */ bool find_triangle_collision_clip_method(btPrimitiveTriangle & other, GIM_TRIANGLE_CONTACT & contacts); }; //! Helper class for colliding Bullet Triangle Shapes /*! This class implements a better getAabb method than the previous btTriangleShape class */ class btTriangleShapeEx: public btTriangleShape { public: btTriangleShapeEx():btTriangleShape(btVector3(0,0,0),btVector3(0,0,0),btVector3(0,0,0)) { } btTriangleShapeEx(const btVector3& p0,const btVector3& p1,const btVector3& p2): btTriangleShape(p0,p1,p2) { } btTriangleShapeEx(const btTriangleShapeEx & other): btTriangleShape(other.m_vertices1[0],other.m_vertices1[1],other.m_vertices1[2]) { } virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax)const { btVector3 tv0 = t(m_vertices1[0]); btVector3 tv1 = t(m_vertices1[1]); btVector3 tv2 = t(m_vertices1[2]); btAABB trianglebox(tv0,tv1,tv2,m_collisionMargin); aabbMin = trianglebox.m_min; aabbMax = trianglebox.m_max; } void applyTransform(const btTransform& t) { m_vertices1[0] = t(m_vertices1[0]); m_vertices1[1] = t(m_vertices1[1]); m_vertices1[2] = t(m_vertices1[2]); } SIMD_FORCE_INLINE void buildTriPlane(btVector4 & plane) const { btVector3 normal = (m_vertices1[1]-m_vertices1[0]).cross(m_vertices1[2]-m_vertices1[0]); normal.normalize(); plane.setValue(normal[0],normal[1],normal[2],m_vertices1[0].dot(normal)); } bool overlap_test_conservative(const btTriangleShapeEx& other); }; #endif //TRIANGLE_MESH_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/btGImpactMassUtil.h0000644000175000017500000000406011337071441027150 0ustar bobkebobke/*! \file btGImpactMassUtil.h \author Francisco Len Njera */ /* This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com 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 GIMPACT_MASS_UTIL_H #define GIMPACT_MASS_UTIL_H #include "LinearMath/btTransform.h" SIMD_FORCE_INLINE btVector3 gim_inertia_add_transformed( const btVector3 & source_inertia, const btVector3 & added_inertia, const btTransform & transform) { btMatrix3x3 rotatedTensor = transform.getBasis().scaled(added_inertia) * transform.getBasis().transpose(); btScalar x2 = transform.getOrigin()[0]; x2*= x2; btScalar y2 = transform.getOrigin()[1]; y2*= y2; btScalar z2 = transform.getOrigin()[2]; z2*= z2; btScalar ix = rotatedTensor[0][0]*(y2+z2); btScalar iy = rotatedTensor[1][1]*(x2+z2); btScalar iz = rotatedTensor[2][2]*(x2+y2); return btVector3(source_inertia[0]+ix,source_inertia[1]+iy,source_inertia[2] + iz); } SIMD_FORCE_INLINE btVector3 gim_get_point_inertia(const btVector3 & point, btScalar mass) { btScalar x2 = point[0]*point[0]; btScalar y2 = point[1]*point[1]; btScalar z2 = point[2]*point[2]; return btVector3(mass*(y2+z2),mass*(x2+z2),mass*(x2+y2)); } #endif //GIMPACT_MESH_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/gim_box_set.h0000644000175000017500000004047211344267705026132 0ustar bobkebobke#ifndef GIM_BOX_SET_H_INCLUDED #define GIM_BOX_SET_H_INCLUDED /*! \file gim_box_set.h \author Francisco Len Njera */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. (3) The zlib/libpng license that is included with this library in the file GIMPACT-LICENSE-ZLIB.TXT. 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 files GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "gim_array.h" #include "gim_radixsort.h" #include "gim_box_collision.h" #include "gim_tri_collision.h" //! Overlapping pair struct GIM_PAIR { GUINT m_index1; GUINT m_index2; GIM_PAIR() {} GIM_PAIR(const GIM_PAIR & p) { m_index1 = p.m_index1; m_index2 = p.m_index2; } GIM_PAIR(GUINT index1, GUINT index2) { m_index1 = index1; m_index2 = index2; } }; //! A pairset array class gim_pair_set: public gim_array { public: gim_pair_set():gim_array(32) { } inline void push_pair(GUINT index1,GUINT index2) { push_back(GIM_PAIR(index1,index2)); } inline void push_pair_inv(GUINT index1,GUINT index2) { push_back(GIM_PAIR(index2,index1)); } }; //! Prototype Base class for primitive classification /*! This class is a wrapper for primitive collections. This tells relevant info for the Bounding Box set classes, which take care of space classification. This class can manage Compound shapes and trimeshes, and if it is managing trimesh then the Hierarchy Bounding Box classes will take advantage of primitive Vs Box overlapping tests for getting optimal results and less Per Box compairisons. */ class GIM_PRIMITIVE_MANAGER_PROTOTYPE { public: virtual ~GIM_PRIMITIVE_MANAGER_PROTOTYPE() {} //! determines if this manager consist on only triangles, which special case will be optimized virtual bool is_trimesh() = 0; virtual GUINT get_primitive_count() = 0; virtual void get_primitive_box(GUINT prim_index ,GIM_AABB & primbox) = 0; virtual void get_primitive_triangle(GUINT prim_index,GIM_TRIANGLE & triangle) = 0; }; struct GIM_AABB_DATA { GIM_AABB m_bound; GUINT m_data; }; //! Node Structure for trees struct GIM_BOX_TREE_NODE { GIM_AABB m_bound; GUINT m_left;//!< Left subtree GUINT m_right;//!< Right subtree GUINT m_escapeIndex;//!< Scape index for traversing GUINT m_data;//!< primitive index if apply GIM_BOX_TREE_NODE() { m_left = 0; m_right = 0; m_escapeIndex = 0; m_data = 0; } SIMD_FORCE_INLINE bool is_leaf_node() const { return (!m_left && !m_right); } }; //! Basic Box tree structure class GIM_BOX_TREE { protected: GUINT m_num_nodes; gim_array m_node_array; protected: GUINT _sort_and_calc_splitting_index( gim_array & primitive_boxes, GUINT startIndex, GUINT endIndex, GUINT splitAxis); GUINT _calc_splitting_axis(gim_array & primitive_boxes, GUINT startIndex, GUINT endIndex); void _build_sub_tree(gim_array & primitive_boxes, GUINT startIndex, GUINT endIndex); public: GIM_BOX_TREE() { m_num_nodes = 0; } //! prototype functions for box tree management //!@{ void build_tree(gim_array & primitive_boxes); SIMD_FORCE_INLINE void clearNodes() { m_node_array.clear(); m_num_nodes = 0; } //! node count SIMD_FORCE_INLINE GUINT getNodeCount() const { return m_num_nodes; } //! tells if the node is a leaf SIMD_FORCE_INLINE bool isLeafNode(GUINT nodeindex) const { return m_node_array[nodeindex].is_leaf_node(); } SIMD_FORCE_INLINE GUINT getNodeData(GUINT nodeindex) const { return m_node_array[nodeindex].m_data; } SIMD_FORCE_INLINE void getNodeBound(GUINT nodeindex, GIM_AABB & bound) const { bound = m_node_array[nodeindex].m_bound; } SIMD_FORCE_INLINE void setNodeBound(GUINT nodeindex, const GIM_AABB & bound) { m_node_array[nodeindex].m_bound = bound; } SIMD_FORCE_INLINE GUINT getLeftNodeIndex(GUINT nodeindex) const { return m_node_array[nodeindex].m_left; } SIMD_FORCE_INLINE GUINT getRightNodeIndex(GUINT nodeindex) const { return m_node_array[nodeindex].m_right; } SIMD_FORCE_INLINE GUINT getScapeNodeIndex(GUINT nodeindex) const { return m_node_array[nodeindex].m_escapeIndex; } //!@} }; //! Generic Box Tree Template /*! This class offers an structure for managing a box tree of primitives. Requires a Primitive prototype (like GIM_PRIMITIVE_MANAGER_PROTOTYPE ) and a Box tree structure ( like GIM_BOX_TREE). */ template class GIM_BOX_TREE_TEMPLATE_SET { protected: _GIM_PRIMITIVE_MANAGER_PROTOTYPE m_primitive_manager; _GIM_BOX_TREE_PROTOTYPE m_box_tree; protected: //stackless refit SIMD_FORCE_INLINE void refit() { GUINT nodecount = getNodeCount(); while(nodecount--) { if(isLeafNode(nodecount)) { GIM_AABB leafbox; m_primitive_manager.get_primitive_box(getNodeData(nodecount),leafbox); setNodeBound(nodecount,leafbox); } else { //get left bound GUINT childindex = getLeftNodeIndex(nodecount); GIM_AABB bound; getNodeBound(childindex,bound); //get right bound childindex = getRightNodeIndex(nodecount); GIM_AABB bound2; getNodeBound(childindex,bound2); bound.merge(bound2); setNodeBound(nodecount,bound); } } } public: GIM_BOX_TREE_TEMPLATE_SET() { } SIMD_FORCE_INLINE GIM_AABB getGlobalBox() const { GIM_AABB totalbox; getNodeBound(0, totalbox); return totalbox; } SIMD_FORCE_INLINE void setPrimitiveManager(const _GIM_PRIMITIVE_MANAGER_PROTOTYPE & primitive_manager) { m_primitive_manager = primitive_manager; } const _GIM_PRIMITIVE_MANAGER_PROTOTYPE & getPrimitiveManager() const { return m_primitive_manager; } _GIM_PRIMITIVE_MANAGER_PROTOTYPE & getPrimitiveManager() { return m_primitive_manager; } //! node manager prototype functions ///@{ //! this attemps to refit the box set. SIMD_FORCE_INLINE void update() { refit(); } //! this rebuild the entire set SIMD_FORCE_INLINE void buildSet() { //obtain primitive boxes gim_array primitive_boxes; primitive_boxes.resize(m_primitive_manager.get_primitive_count(),false); for (GUINT i = 0;i & collided_results) const { GUINT curIndex = 0; GUINT numNodes = getNodeCount(); while (curIndex < numNodes) { GIM_AABB bound; getNodeBound(curIndex,bound); //catch bugs in tree data bool aabbOverlap = bound.has_collision(box); bool isleafnode = isLeafNode(curIndex); if (isleafnode && aabbOverlap) { collided_results.push_back(getNodeData(curIndex)); } if (aabbOverlap || isleafnode) { //next subnode curIndex++; } else { //skip node curIndex+= getScapeNodeIndex(curIndex); } } if(collided_results.size()>0) return true; return false; } //! returns the indices of the primitives in the m_primitive_manager SIMD_FORCE_INLINE bool boxQueryTrans(const GIM_AABB & box, const btTransform & transform, gim_array & collided_results) const { GIM_AABB transbox=box; transbox.appy_transform(transform); return boxQuery(transbox,collided_results); } //! returns the indices of the primitives in the m_primitive_manager SIMD_FORCE_INLINE bool rayQuery( const btVector3 & ray_dir,const btVector3 & ray_origin , gim_array & collided_results) const { GUINT curIndex = 0; GUINT numNodes = getNodeCount(); while (curIndex < numNodes) { GIM_AABB bound; getNodeBound(curIndex,bound); //catch bugs in tree data bool aabbOverlap = bound.collide_ray(ray_origin,ray_dir); bool isleafnode = isLeafNode(curIndex); if (isleafnode && aabbOverlap) { collided_results.push_back(getNodeData( curIndex)); } if (aabbOverlap || isleafnode) { //next subnode curIndex++; } else { //skip node curIndex+= getScapeNodeIndex(curIndex); } } if(collided_results.size()>0) return true; return false; } //! tells if this set has hierarcht SIMD_FORCE_INLINE bool hasHierarchy() const { return true; } //! tells if this set is a trimesh SIMD_FORCE_INLINE bool isTrimesh() const { return m_primitive_manager.is_trimesh(); } //! node count SIMD_FORCE_INLINE GUINT getNodeCount() const { return m_box_tree.getNodeCount(); } //! tells if the node is a leaf SIMD_FORCE_INLINE bool isLeafNode(GUINT nodeindex) const { return m_box_tree.isLeafNode(nodeindex); } SIMD_FORCE_INLINE GUINT getNodeData(GUINT nodeindex) const { return m_box_tree.getNodeData(nodeindex); } SIMD_FORCE_INLINE void getNodeBound(GUINT nodeindex, GIM_AABB & bound) const { m_box_tree.getNodeBound(nodeindex, bound); } SIMD_FORCE_INLINE void setNodeBound(GUINT nodeindex, const GIM_AABB & bound) { m_box_tree.setNodeBound(nodeindex, bound); } SIMD_FORCE_INLINE GUINT getLeftNodeIndex(GUINT nodeindex) const { return m_box_tree.getLeftNodeIndex(nodeindex); } SIMD_FORCE_INLINE GUINT getRightNodeIndex(GUINT nodeindex) const { return m_box_tree.getRightNodeIndex(nodeindex); } SIMD_FORCE_INLINE GUINT getScapeNodeIndex(GUINT nodeindex) const { return m_box_tree.getScapeNodeIndex(nodeindex); } SIMD_FORCE_INLINE void getNodeTriangle(GUINT nodeindex,GIM_TRIANGLE & triangle) const { m_primitive_manager.get_primitive_triangle(getNodeData(nodeindex),triangle); } }; //! Class for Box Tree Sets /*! this has the GIM_BOX_TREE implementation for bounding boxes. */ template class GIM_BOX_TREE_SET: public GIM_BOX_TREE_TEMPLATE_SET< _GIM_PRIMITIVE_MANAGER_PROTOTYPE, GIM_BOX_TREE> { public: }; /// GIM_BOX_SET collision methods template class GIM_TREE_TREE_COLLIDER { public: gim_pair_set * m_collision_pairs; BOX_SET_CLASS0 * m_boxset0; BOX_SET_CLASS1 * m_boxset1; GUINT current_node0; GUINT current_node1; bool node0_is_leaf; bool node1_is_leaf; bool t0_is_trimesh; bool t1_is_trimesh; bool node0_has_triangle; bool node1_has_triangle; GIM_AABB m_box0; GIM_AABB m_box1; GIM_BOX_BOX_TRANSFORM_CACHE trans_cache_1to0; btTransform trans_cache_0to1; GIM_TRIANGLE m_tri0; btVector4 m_tri0_plane; GIM_TRIANGLE m_tri1; btVector4 m_tri1_plane; public: GIM_TREE_TREE_COLLIDER() { current_node0 = G_UINT_INFINITY; current_node1 = G_UINT_INFINITY; } protected: SIMD_FORCE_INLINE void retrieve_node0_triangle(GUINT node0) { if(node0_has_triangle) return; m_boxset0->getNodeTriangle(node0,m_tri0); //transform triangle m_tri0.m_vertices[0] = trans_cache_0to1(m_tri0.m_vertices[0]); m_tri0.m_vertices[1] = trans_cache_0to1(m_tri0.m_vertices[1]); m_tri0.m_vertices[2] = trans_cache_0to1(m_tri0.m_vertices[2]); m_tri0.get_plane(m_tri0_plane); node0_has_triangle = true; } SIMD_FORCE_INLINE void retrieve_node1_triangle(GUINT node1) { if(node1_has_triangle) return; m_boxset1->getNodeTriangle(node1,m_tri1); //transform triangle m_tri1.m_vertices[0] = trans_cache_1to0.transform(m_tri1.m_vertices[0]); m_tri1.m_vertices[1] = trans_cache_1to0.transform(m_tri1.m_vertices[1]); m_tri1.m_vertices[2] = trans_cache_1to0.transform(m_tri1.m_vertices[2]); m_tri1.get_plane(m_tri1_plane); node1_has_triangle = true; } SIMD_FORCE_INLINE void retrieve_node0_info(GUINT node0) { if(node0 == current_node0) return; m_boxset0->getNodeBound(node0,m_box0); node0_is_leaf = m_boxset0->isLeafNode(node0); node0_has_triangle = false; current_node0 = node0; } SIMD_FORCE_INLINE void retrieve_node1_info(GUINT node1) { if(node1 == current_node1) return; m_boxset1->getNodeBound(node1,m_box1); node1_is_leaf = m_boxset1->isLeafNode(node1); node1_has_triangle = false; current_node1 = node1; } SIMD_FORCE_INLINE bool node_collision(GUINT node0 ,GUINT node1) { retrieve_node0_info(node0); retrieve_node1_info(node1); bool result = m_box0.overlapping_trans_cache(m_box1,trans_cache_1to0,true); if(!result) return false; if(t0_is_trimesh && node0_is_leaf) { //perform primitive vs box collision retrieve_node0_triangle(node0); //do triangle vs box collision m_box1.increment_margin(m_tri0.m_margin); result = m_box1.collide_triangle_exact( m_tri0.m_vertices[0],m_tri0.m_vertices[1],m_tri0.m_vertices[2],m_tri0_plane); m_box1.increment_margin(-m_tri0.m_margin); if(!result) return false; return true; } else if(t1_is_trimesh && node1_is_leaf) { //perform primitive vs box collision retrieve_node1_triangle(node1); //do triangle vs box collision m_box0.increment_margin(m_tri1.m_margin); result = m_box0.collide_triangle_exact( m_tri1.m_vertices[0],m_tri1.m_vertices[1],m_tri1.m_vertices[2],m_tri1_plane); m_box0.increment_margin(-m_tri1.m_margin); if(!result) return false; return true; } return true; } //stackless collision routine void find_collision_pairs() { gim_pair_set stack_collisions; stack_collisions.reserve(32); //add the first pair stack_collisions.push_pair(0,0); while(stack_collisions.size()) { //retrieve the last pair and pop GUINT node0 = stack_collisions.back().m_index1; GUINT node1 = stack_collisions.back().m_index2; stack_collisions.pop_back(); if(node_collision(node0,node1)) // a collision is found { if(node0_is_leaf) { if(node1_is_leaf) { m_collision_pairs->push_pair(m_boxset0->getNodeData(node0),m_boxset1->getNodeData(node1)); } else { //collide left stack_collisions.push_pair(node0,m_boxset1->getLeftNodeIndex(node1)); //collide right stack_collisions.push_pair(node0,m_boxset1->getRightNodeIndex(node1)); } } else { if(node1_is_leaf) { //collide left stack_collisions.push_pair(m_boxset0->getLeftNodeIndex(node0),node1); //collide right stack_collisions.push_pair(m_boxset0->getRightNodeIndex(node0),node1); } else { GUINT left0 = m_boxset0->getLeftNodeIndex(node0); GUINT right0 = m_boxset0->getRightNodeIndex(node0); GUINT left1 = m_boxset1->getLeftNodeIndex(node1); GUINT right1 = m_boxset1->getRightNodeIndex(node1); //collide left stack_collisions.push_pair(left0,left1); //collide right stack_collisions.push_pair(left0,right1); //collide left stack_collisions.push_pair(right0,left1); //collide right stack_collisions.push_pair(right0,right1); }// else if node1 is not a leaf }// else if node0 is not a leaf }// if(node_collision(node0,node1)) }//while(stack_collisions.size()) } public: void find_collision(BOX_SET_CLASS0 * boxset1, const btTransform & trans1, BOX_SET_CLASS1 * boxset2, const btTransform & trans2, gim_pair_set & collision_pairs, bool complete_primitive_tests = true) { m_collision_pairs = &collision_pairs; m_boxset0 = boxset1; m_boxset1 = boxset2; trans_cache_1to0.calc_from_homogenic(trans1,trans2); trans_cache_0to1 = trans2.inverse(); trans_cache_0to1 *= trans1; if(complete_primitive_tests) { t0_is_trimesh = boxset1->getPrimitiveManager().is_trimesh(); t1_is_trimesh = boxset2->getPrimitiveManager().is_trimesh(); } else { t0_is_trimesh = false; t1_is_trimesh = false; } find_collision_pairs(); } }; #endif // GIM_BOXPRUNING_H_INCLUDED critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/gim_memory.cpp0000644000175000017500000000553411337071441026322 0ustar bobkebobke/* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. (3) The zlib/libpng license that is included with this library in the file GIMPACT-LICENSE-ZLIB.TXT. 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 files GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "gim_memory.h" #include "stdlib.h" #ifdef GIM_SIMD_MEMORY #include "LinearMath/btAlignedAllocator.h" #endif static gim_alloc_function *g_allocfn = 0; static gim_alloca_function *g_allocafn = 0; static gim_realloc_function *g_reallocfn = 0; static gim_free_function *g_freefn = 0; void gim_set_alloc_handler (gim_alloc_function *fn) { g_allocfn = fn; } void gim_set_alloca_handler (gim_alloca_function *fn) { g_allocafn = fn; } void gim_set_realloc_handler (gim_realloc_function *fn) { g_reallocfn = fn; } void gim_set_free_handler (gim_free_function *fn) { g_freefn = fn; } gim_alloc_function *gim_get_alloc_handler() { return g_allocfn; } gim_alloca_function *gim_get_alloca_handler() { return g_allocafn; } gim_realloc_function *gim_get_realloc_handler () { return g_reallocfn; } gim_free_function *gim_get_free_handler () { return g_freefn; } void * gim_alloc(size_t size) { void * ptr; if (g_allocfn) { ptr = g_allocfn(size); } else { #ifdef GIM_SIMD_MEMORY ptr = btAlignedAlloc(size,16); #else ptr = malloc(size); #endif } return ptr; } void * gim_alloca(size_t size) { if (g_allocafn) return g_allocafn(size); else return gim_alloc(size); } void * gim_realloc(void *ptr, size_t oldsize, size_t newsize) { void * newptr = gim_alloc(newsize); size_t copysize = oldsizeb?b:a) #define GIM_MAX3(a,b,c) GIM_MAX(a,GIM_MAX(b,c)) #define GIM_MIN3(a,b,c) GIM_MIN(a,GIM_MIN(b,c)) #define GIM_IS_ZERO(value) (value < G_EPSILON && value > -G_EPSILON) #define GIM_IS_NEGATIVE(value) (value <= -G_EPSILON) #define GIM_IS_POSISITVE(value) (value >= G_EPSILON) #define GIM_NEAR_EQUAL(v1,v2) GIM_IS_ZERO((v1-v2)) ///returns a clamped number #define GIM_CLAMP(number,minval,maxval) (numbermaxval?maxval:number)) #define GIM_GREATER(x, y) btFabs(x) > (y) ///Swap numbers #define GIM_SWAP_NUMBERS(a,b){ \ a = a+b; \ b = a-b; \ a = a-b; \ }\ #define GIM_INV_SQRT(va,isva)\ {\ if(va<=0.0000001f)\ {\ isva = G_REAL_INFINITY;\ }\ else\ {\ GREAL _x = va * 0.5f;\ GUINT _y = 0x5f3759df - ( GIM_IR(va) >> 1);\ isva = GIM_FR(_y);\ isva = isva * ( 1.5f - ( _x * isva * isva ) );\ }\ }\ #define GIM_SQRT(va,sva)\ {\ GIM_INV_SQRT(va,sva);\ sva = 1.0f/sva;\ }\ //! Computes 1.0f / sqrtf(x). Comes from Quake3. See http://www.magic-software.com/3DGEDInvSqrt.html inline GREAL gim_inv_sqrt(GREAL f) { GREAL r; GIM_INV_SQRT(f,r); return r; } inline GREAL gim_sqrt(GREAL f) { GREAL r; GIM_SQRT(f,r); return r; } #endif // GIM_MATH_H_INCLUDED critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/gim_contact.cpp0000644000175000017500000000735611337071441026451 0ustar bobkebobke /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. (3) The zlib/libpng license that is included with this library in the file GIMPACT-LICENSE-ZLIB.TXT. 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 files GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "gim_contact.h" #define MAX_COINCIDENT 8 void gim_contact_array::merge_contacts( const gim_contact_array & contacts, bool normal_contact_average) { clear(); if(contacts.size()==1) { push_back(contacts.back()); return; } gim_array keycontacts(contacts.size()); keycontacts.resize(contacts.size(),false); //fill key contacts GUINT i; for (i = 0;im_depth - CONTACT_DIFF_EPSILON > scontact->m_depth)//) { *pcontact = *scontact; coincident_count = 0; } else if(normal_contact_average) { if(btFabs(pcontact->m_depth - scontact->m_depth)m_normal; coincident_count++; } } } } else {//add new contact if(normal_contact_average && coincident_count>0) { pcontact->interpolate_normals(coincident_normals,coincident_count); coincident_count = 0; } push_back(*scontact); pcontact = &back(); } last_key = key; } } void gim_contact_array::merge_contacts_unique(const gim_contact_array & contacts) { clear(); if(contacts.size()==1) { push_back(contacts.back()); return; } GIM_CONTACT average_contact = contacts.back(); for (GUINT i=1;i splitValue) { //swap primitive_boxes.swap(i,splitIndex); //swapLeafNodes(i,splitIndex); splitIndex++; } } //if the splitIndex causes unbalanced trees, fix this by using the center in between startIndex and endIndex //otherwise the tree-building might fail due to stack-overflows in certain cases. //unbalanced1 is unsafe: it can cause stack overflows //bool unbalanced1 = ((splitIndex==startIndex) || (splitIndex == (endIndex-1))); //unbalanced2 should work too: always use center (perfect balanced trees) //bool unbalanced2 = true; //this should be safe too: int rangeBalancedIndices = numIndices/3; bool unbalanced = ((splitIndex<=(startIndex+rangeBalancedIndices)) || (splitIndex >=(endIndex-1-rangeBalancedIndices))); if (unbalanced) { splitIndex = startIndex+ (numIndices>>1); } btAssert(!((splitIndex==startIndex) || (splitIndex == (endIndex)))); return splitIndex; } void btBvhTree::_build_sub_tree(GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex, int endIndex) { int curIndex = m_num_nodes; m_num_nodes++; btAssert((endIndex-startIndex)>0); if ((endIndex-startIndex)==1) { //We have a leaf node setNodeBound(curIndex,primitive_boxes[startIndex].m_bound); m_node_array[curIndex].setDataIndex(primitive_boxes[startIndex].m_data); return; } //calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'. //split axis int splitIndex = _calc_splitting_axis(primitive_boxes,startIndex,endIndex); splitIndex = _sort_and_calc_splitting_index( primitive_boxes,startIndex,endIndex, splitIndex//split axis ); //calc this node bounding box btAABB node_bound; node_bound.invalidate(); for (int i=startIndex;iget_primitive_box(getNodeData(nodecount),leafbox); setNodeBound(nodecount,leafbox); } else { //const GIM_BVH_TREE_NODE * nodepointer = get_node_pointer(nodecount); //get left bound btAABB bound; bound.invalidate(); btAABB temp_box; int child_node = getLeftNode(nodecount); if(child_node) { getNodeBound(child_node,temp_box); bound.merge(temp_box); } child_node = getRightNode(nodecount); if(child_node) { getNodeBound(child_node,temp_box); bound.merge(temp_box); } setNodeBound(nodecount,bound); } } } //! this rebuild the entire set void btGImpactBvh::buildSet() { //obtain primitive boxes GIM_BVH_DATA_ARRAY primitive_boxes; primitive_boxes.resize(m_primitive_manager->get_primitive_count()); for (int i = 0;iget_primitive_box(i,primitive_boxes[i].m_bound); primitive_boxes[i].m_data = i; } m_box_tree.build_tree(primitive_boxes); } //! returns the indices of the primitives in the m_primitive_manager bool btGImpactBvh::boxQuery(const btAABB & box, btAlignedObjectArray & collided_results) const { int curIndex = 0; int numNodes = getNodeCount(); while (curIndex < numNodes) { btAABB bound; getNodeBound(curIndex,bound); //catch bugs in tree data bool aabbOverlap = bound.has_collision(box); bool isleafnode = isLeafNode(curIndex); if (isleafnode && aabbOverlap) { collided_results.push_back(getNodeData(curIndex)); } if (aabbOverlap || isleafnode) { //next subnode curIndex++; } else { //skip node curIndex+= getEscapeNodeIndex(curIndex); } } if(collided_results.size()>0) return true; return false; } //! returns the indices of the primitives in the m_primitive_manager bool btGImpactBvh::rayQuery( const btVector3 & ray_dir,const btVector3 & ray_origin , btAlignedObjectArray & collided_results) const { int curIndex = 0; int numNodes = getNodeCount(); while (curIndex < numNodes) { btAABB bound; getNodeBound(curIndex,bound); //catch bugs in tree data bool aabbOverlap = bound.collide_ray(ray_origin,ray_dir); bool isleafnode = isLeafNode(curIndex); if (isleafnode && aabbOverlap) { collided_results.push_back(getNodeData( curIndex)); } if (aabbOverlap || isleafnode) { //next subnode curIndex++; } else { //skip node curIndex+= getEscapeNodeIndex(curIndex); } } if(collided_results.size()>0) return true; return false; } SIMD_FORCE_INLINE bool _node_collision( btGImpactBvh * boxset0, btGImpactBvh * boxset1, const BT_BOX_BOX_TRANSFORM_CACHE & trans_cache_1to0, int node0 ,int node1, bool complete_primitive_tests) { btAABB box0; boxset0->getNodeBound(node0,box0); btAABB box1; boxset1->getNodeBound(node1,box1); return box0.overlapping_trans_cache(box1,trans_cache_1to0,complete_primitive_tests ); // box1.appy_transform_trans_cache(trans_cache_1to0); // return box0.has_collision(box1); } //stackless recursive collision routine static void _find_collision_pairs_recursive( btGImpactBvh * boxset0, btGImpactBvh * boxset1, btPairSet * collision_pairs, const BT_BOX_BOX_TRANSFORM_CACHE & trans_cache_1to0, int node0, int node1, bool complete_primitive_tests) { if( _node_collision( boxset0,boxset1,trans_cache_1to0, node0,node1,complete_primitive_tests) ==false) return;//avoid colliding internal nodes if(boxset0->isLeafNode(node0)) { if(boxset1->isLeafNode(node1)) { // collision result collision_pairs->push_pair( boxset0->getNodeData(node0),boxset1->getNodeData(node1)); return; } else { //collide left recursive _find_collision_pairs_recursive( boxset0,boxset1, collision_pairs,trans_cache_1to0, node0,boxset1->getLeftNode(node1),false); //collide right recursive _find_collision_pairs_recursive( boxset0,boxset1, collision_pairs,trans_cache_1to0, node0,boxset1->getRightNode(node1),false); } } else { if(boxset1->isLeafNode(node1)) { //collide left recursive _find_collision_pairs_recursive( boxset0,boxset1, collision_pairs,trans_cache_1to0, boxset0->getLeftNode(node0),node1,false); //collide right recursive _find_collision_pairs_recursive( boxset0,boxset1, collision_pairs,trans_cache_1to0, boxset0->getRightNode(node0),node1,false); } else { //collide left0 left1 _find_collision_pairs_recursive( boxset0,boxset1, collision_pairs,trans_cache_1to0, boxset0->getLeftNode(node0),boxset1->getLeftNode(node1),false); //collide left0 right1 _find_collision_pairs_recursive( boxset0,boxset1, collision_pairs,trans_cache_1to0, boxset0->getLeftNode(node0),boxset1->getRightNode(node1),false); //collide right0 left1 _find_collision_pairs_recursive( boxset0,boxset1, collision_pairs,trans_cache_1to0, boxset0->getRightNode(node0),boxset1->getLeftNode(node1),false); //collide right0 right1 _find_collision_pairs_recursive( boxset0,boxset1, collision_pairs,trans_cache_1to0, boxset0->getRightNode(node0),boxset1->getRightNode(node1),false); }// else if node1 is not a leaf }// else if node0 is not a leaf } void btGImpactBvh::find_collision(btGImpactBvh * boxset0, const btTransform & trans0, btGImpactBvh * boxset1, const btTransform & trans1, btPairSet & collision_pairs) { if(boxset0->getNodeCount()==0 || boxset1->getNodeCount()==0 ) return; BT_BOX_BOX_TRANSFORM_CACHE trans_cache_1to0; trans_cache_1to0.calc_from_homogenic(trans0,trans1); #ifdef TRI_COLLISION_PROFILING bt_begin_gim02_tree_time(); #endif //TRI_COLLISION_PROFILING _find_collision_pairs_recursive( boxset0,boxset1, &collision_pairs,trans_cache_1to0,0,0,true); #ifdef TRI_COLLISION_PROFILING bt_end_gim02_tree_time(); #endif //TRI_COLLISION_PROFILING } critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/btGenericPoolAllocator.h0000644000175000017500000000735011337071441030216 0ustar bobkebobke/*! \file btGenericPoolAllocator.h \author Francisco Len Njera. email projectileman@yahoo.com General purpose allocator class */ /* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BT_GENERIC_POOL_ALLOCATOR_H #define BT_GENERIC_POOL_ALLOCATOR_H #include #include #include #include "LinearMath/btAlignedAllocator.h" #define BT_UINT_MAX UINT_MAX #define BT_DEFAULT_MAX_POOLS 16 //! Generic Pool class class btGenericMemoryPool { public: unsigned char * m_pool; //[m_element_size*m_max_element_count]; size_t * m_free_nodes; //[m_max_element_count];//! free nodes size_t * m_allocated_sizes;//[m_max_element_count];//! Number of elements allocated per node size_t m_allocated_count; size_t m_free_nodes_count; protected: size_t m_element_size; size_t m_max_element_count; size_t allocate_from_free_nodes(size_t num_elements); size_t allocate_from_pool(size_t num_elements); public: void init_pool(size_t element_size, size_t element_count); void end_pool(); btGenericMemoryPool(size_t element_size, size_t element_count) { init_pool(element_size, element_count); } ~btGenericMemoryPool() { end_pool(); } inline size_t get_pool_capacity() { return m_element_size*m_max_element_count; } inline size_t gem_element_size() { return m_element_size; } inline size_t get_max_element_count() { return m_max_element_count; } inline size_t get_allocated_count() { return m_allocated_count; } inline size_t get_free_positions_count() { return m_free_nodes_count; } inline void * get_element_data(size_t element_index) { return &m_pool[element_index*m_element_size]; } //! Allocates memory in pool /*! \param size_bytes size in bytes of the buffer */ void * allocate(size_t size_bytes); bool freeMemory(void * pointer); }; //! Generic Allocator with pools /*! General purpose Allocator which can create Memory Pools dynamiacally as needed. */ class btGenericPoolAllocator { protected: size_t m_pool_element_size; size_t m_pool_element_count; public: btGenericMemoryPool * m_pools[BT_DEFAULT_MAX_POOLS]; size_t m_pool_count; inline size_t get_pool_capacity() { return m_pool_element_size*m_pool_element_count; } protected: // creates a pool btGenericMemoryPool * push_new_pool(); void * failback_alloc(size_t size_bytes); bool failback_free(void * pointer); public: btGenericPoolAllocator(size_t pool_element_size, size_t pool_element_count) { m_pool_count = 0; m_pool_element_size = pool_element_size; m_pool_element_count = pool_element_count; } virtual ~btGenericPoolAllocator(); //! Allocates memory in pool /*! \param size_bytes size in bytes of the buffer */ void * allocate(size_t size_bytes); bool freeMemory(void * pointer); }; void * btPoolAlloc(size_t size); void * btPoolRealloc(void *ptr, size_t oldsize, size_t newsize); void btPoolFree(void *ptr); #endif critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/gim_array.h0000644000175000017500000001376211337071441025577 0ustar bobkebobke#ifndef GIM_ARRAY_H_INCLUDED #define GIM_ARRAY_H_INCLUDED /*! \file gim_array.h \author Francisco Len Njera */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. (3) The zlib/libpng license that is included with this library in the file GIMPACT-LICENSE-ZLIB.TXT. 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 files GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "gim_memory.h" #define GIM_ARRAY_GROW_INCREMENT 2 #define GIM_ARRAY_GROW_FACTOR 2 //! Very simple array container with fast access and simd memory template class gim_array { public: //! properties //!@{ T *m_data; GUINT m_size; GUINT m_allocated_size; //!@} //! protected operations //!@{ inline void destroyData() { m_allocated_size = 0; if(m_data==NULL) return; gim_free(m_data); m_data = NULL; } inline bool resizeData(GUINT newsize) { if(newsize==0) { destroyData(); return true; } if(m_size>0) { m_data = (T*)gim_realloc(m_data,m_size*sizeof(T),newsize*sizeof(T)); } else { m_data = (T*)gim_alloc(newsize*sizeof(T)); } m_allocated_size = newsize; return true; } inline bool growingCheck() { if(m_allocated_size<=m_size) { GUINT requestsize = m_size; m_size = m_allocated_size; if(resizeData((requestsize+GIM_ARRAY_GROW_INCREMENT)*GIM_ARRAY_GROW_FACTOR)==false) return false; } return true; } //!@} //! public operations //!@{ inline bool reserve(GUINT size) { if(m_allocated_size>=size) return false; return resizeData(size); } inline void clear_range(GUINT start_range) { while(m_size>start_range) { m_data[--m_size].~T(); } } inline void clear() { if(m_size==0)return; clear_range(0); } inline void clear_memory() { clear(); destroyData(); } gim_array() { m_data = 0; m_size = 0; m_allocated_size = 0; } gim_array(GUINT reservesize) { m_data = 0; m_size = 0; m_allocated_size = 0; reserve(reservesize); } ~gim_array() { clear_memory(); } inline GUINT size() const { return m_size; } inline GUINT max_size() const { return m_allocated_size; } inline T & operator[](size_t i) { return m_data[i]; } inline const T & operator[](size_t i) const { return m_data[i]; } inline T * pointer(){ return m_data;} inline const T * pointer() const { return m_data;} inline T * get_pointer_at(GUINT i) { return m_data + i; } inline const T * get_pointer_at(GUINT i) const { return m_data + i; } inline T & at(GUINT i) { return m_data[i]; } inline const T & at(GUINT i) const { return m_data[i]; } inline T & front() { return *m_data; } inline const T & front() const { return *m_data; } inline T & back() { return m_data[m_size-1]; } inline const T & back() const { return m_data[m_size-1]; } inline void swap(GUINT i, GUINT j) { gim_swap_elements(m_data,i,j); } inline void push_back(const T & obj) { this->growingCheck(); m_data[m_size] = obj; m_size++; } //!Simply increase the m_size, doesn't call the new element constructor inline void push_back_mem() { this->growingCheck(); m_size++; } inline void push_back_memcpy(const T & obj) { this->growingCheck(); irr_simd_memcpy(&m_data[m_size],&obj,sizeof(T)); m_size++; } inline void pop_back() { m_size--; m_data[m_size].~T(); } //!Simply decrease the m_size, doesn't call the deleted element destructor inline void pop_back_mem() { m_size--; } //! fast erase inline void erase(GUINT index) { if(indexgrowingCheck(); for(GUINT i = m_size;i>index;i--) { gim_simd_memcpy(m_data+i,m_data+i-1,sizeof(T)); } m_size++; } inline void insert(const T & obj,GUINT index) { insert_mem(index); m_data[index] = obj; } inline void resize(GUINT size, bool call_constructor = true) { if(size>m_size) { reserve(size); if(call_constructor) { T obj; while(m_sizemaxval?maxval:number)) /// Calc a plane from a triangle edge an a normal. plane is a vec4f SIMD_FORCE_INLINE void bt_edge_plane(const btVector3 & e1,const btVector3 & e2, const btVector3 & normal,btVector4 & plane) { btVector3 planenormal = (e2-e1).cross(normal); planenormal.normalize(); plane.setValue(planenormal[0],planenormal[1],planenormal[2],e2.dot(planenormal)); } //***************** SEGMENT and LINE FUNCTIONS **********************************/// /*! Finds the closest point(cp) to (v) on a segment (e1,e2) */ SIMD_FORCE_INLINE void bt_closest_point_on_segment( btVector3 & cp, const btVector3 & v, const btVector3 &e1,const btVector3 &e2) { btVector3 n = e2-e1; cp = v - e1; btScalar _scalar = cp.dot(n)/n.dot(n); if(_scalar <0.0f) { cp = e1; } else if(_scalar >1.0f) { cp = e2; } else { cp = _scalar*n + e1; } } //! line plane collision /*! *\return -0 if the ray never intersects -1 if the ray collides in front -2 if the ray collides in back */ SIMD_FORCE_INLINE int bt_line_plane_collision( const btVector4 & plane, const btVector3 & vDir, const btVector3 & vPoint, btVector3 & pout, btScalar &tparam, btScalar tmin, btScalar tmax) { btScalar _dotdir = vDir.dot(plane); if(btFabs(_dotdir)tmax) { returnvalue = 0; tparam = tmax; } pout = tparam*vDir + vPoint; return returnvalue; } //! Find closest points on segments SIMD_FORCE_INLINE void bt_segment_collision( const btVector3 & vA1, const btVector3 & vA2, const btVector3 & vB1, const btVector3 & vB2, btVector3 & vPointA, btVector3 & vPointB) { btVector3 AD = vA2 - vA1; btVector3 BD = vB2 - vB1; btVector3 N = AD.cross(BD); btScalar tp = N.length2(); btVector4 _M;//plane if(tp_M[1]) { invert_b_order = true; BT_SWAP_NUMBERS(_M[0],_M[1]); } _M[2] = vA1.dot(AD); _M[3] = vA2.dot(AD); //mid points N[0] = (_M[0]+_M[1])*0.5f; N[1] = (_M[2]+_M[3])*0.5f; if(N[0] { public: btContactArray() { reserve(64); } SIMD_FORCE_INLINE void push_contact( const btVector3 &point,const btVector3 & normal, btScalar depth, int feature1, int feature2) { push_back( GIM_CONTACT(point,normal,depth,feature1,feature2) ); } SIMD_FORCE_INLINE void push_triangle_contacts( const GIM_TRIANGLE_CONTACT & tricontact, int feature1,int feature2) { for(int i = 0;ipmax) // { // GIM_SWAP_NUMBERS(pmin,pmax); // } // //find extends // const btScalar rad = extend[component_index0] * absolute_edge[dir_index0] + // extend[component_index1] * absolute_edge[dir_index1]; // // if(pmin>rad || -rad>pmax) return false; // return true; //} // //SIMD_FORCE_INLINE bool test_cross_edge_box_X_axis( // const btVector3 & edge, // const btVector3 & absolute_edge, // const btVector3 & pointa, // const btVector3 & pointb, btVector3 & extend) //{ // // return test_cross_edge_box(edge,absolute_edge,pointa,pointb,extend,2,1,1,2); //} // // //SIMD_FORCE_INLINE bool test_cross_edge_box_Y_axis( // const btVector3 & edge, // const btVector3 & absolute_edge, // const btVector3 & pointa, // const btVector3 & pointb, btVector3 & extend) //{ // // return test_cross_edge_box(edge,absolute_edge,pointa,pointb,extend,0,2,2,0); //} // //SIMD_FORCE_INLINE bool test_cross_edge_box_Z_axis( // const btVector3 & edge, // const btVector3 & absolute_edge, // const btVector3 & pointa, // const btVector3 & pointb, btVector3 & extend) //{ // // return test_cross_edge_box(edge,absolute_edge,pointa,pointb,extend,1,0,0,1); //} #define TEST_CROSS_EDGE_BOX_MCR(edge,absolute_edge,pointa,pointb,_extend,i_dir_0,i_dir_1,i_comp_0,i_comp_1)\ {\ const btScalar dir0 = -edge[i_dir_0];\ const btScalar dir1 = edge[i_dir_1];\ btScalar pmin = pointa[i_comp_0]*dir0 + pointa[i_comp_1]*dir1;\ btScalar pmax = pointb[i_comp_0]*dir0 + pointb[i_comp_1]*dir1;\ if(pmin>pmax)\ {\ GIM_SWAP_NUMBERS(pmin,pmax); \ }\ const btScalar abs_dir0 = absolute_edge[i_dir_0];\ const btScalar abs_dir1 = absolute_edge[i_dir_1];\ const btScalar rad = _extend[i_comp_0] * abs_dir0 + _extend[i_comp_1] * abs_dir1;\ if(pmin>rad || -rad>pmax) return false;\ }\ #define TEST_CROSS_EDGE_BOX_X_AXIS_MCR(edge,absolute_edge,pointa,pointb,_extend)\ {\ TEST_CROSS_EDGE_BOX_MCR(edge,absolute_edge,pointa,pointb,_extend,2,1,1,2);\ }\ #define TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(edge,absolute_edge,pointa,pointb,_extend)\ {\ TEST_CROSS_EDGE_BOX_MCR(edge,absolute_edge,pointa,pointb,_extend,0,2,2,0);\ }\ #define TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(edge,absolute_edge,pointa,pointb,_extend)\ {\ TEST_CROSS_EDGE_BOX_MCR(edge,absolute_edge,pointa,pointb,_extend,1,0,0,1);\ }\ //! Class for transforming a model1 to the space of model0 class GIM_BOX_BOX_TRANSFORM_CACHE { public: btVector3 m_T1to0;//!< Transforms translation of model1 to model 0 btMatrix3x3 m_R1to0;//!< Transforms Rotation of model1 to model 0, equal to R0' * R1 btMatrix3x3 m_AR;//!< Absolute value of m_R1to0 SIMD_FORCE_INLINE void calc_absolute_matrix() { static const btVector3 vepsi(1e-6f,1e-6f,1e-6f); m_AR[0] = vepsi + m_R1to0[0].absolute(); m_AR[1] = vepsi + m_R1to0[1].absolute(); m_AR[2] = vepsi + m_R1to0[2].absolute(); } GIM_BOX_BOX_TRANSFORM_CACHE() { } GIM_BOX_BOX_TRANSFORM_CACHE(mat4f trans1_to_0) { COPY_MATRIX_3X3(m_R1to0,trans1_to_0) MAT_GET_TRANSLATION(trans1_to_0,m_T1to0) calc_absolute_matrix(); } //! Calc the transformation relative 1 to 0. Inverts matrics by transposing SIMD_FORCE_INLINE void calc_from_homogenic(const btTransform & trans0,const btTransform & trans1) { m_R1to0 = trans0.getBasis().transpose(); m_T1to0 = m_R1to0 * (-trans0.getOrigin()); m_T1to0 += m_R1to0*trans1.getOrigin(); m_R1to0 *= trans1.getBasis(); calc_absolute_matrix(); } //! Calcs the full invertion of the matrices. Useful for scaling matrices SIMD_FORCE_INLINE void calc_from_full_invert(const btTransform & trans0,const btTransform & trans1) { m_R1to0 = trans0.getBasis().inverse(); m_T1to0 = m_R1to0 * (-trans0.getOrigin()); m_T1to0 += m_R1to0*trans1.getOrigin(); m_R1to0 *= trans1.getBasis(); calc_absolute_matrix(); } SIMD_FORCE_INLINE btVector3 transform(const btVector3 & point) { return btVector3(m_R1to0[0].dot(point) + m_T1to0.x(), m_R1to0[1].dot(point) + m_T1to0.y(), m_R1to0[2].dot(point) + m_T1to0.z()); } }; #define BOX_PLANE_EPSILON 0.000001f //! Axis aligned box class GIM_AABB { public: btVector3 m_min; btVector3 m_max; GIM_AABB() {} GIM_AABB(const btVector3 & V1, const btVector3 & V2, const btVector3 & V3) { m_min[0] = GIM_MIN3(V1[0],V2[0],V3[0]); m_min[1] = GIM_MIN3(V1[1],V2[1],V3[1]); m_min[2] = GIM_MIN3(V1[2],V2[2],V3[2]); m_max[0] = GIM_MAX3(V1[0],V2[0],V3[0]); m_max[1] = GIM_MAX3(V1[1],V2[1],V3[1]); m_max[2] = GIM_MAX3(V1[2],V2[2],V3[2]); } GIM_AABB(const btVector3 & V1, const btVector3 & V2, const btVector3 & V3, GREAL margin) { m_min[0] = GIM_MIN3(V1[0],V2[0],V3[0]); m_min[1] = GIM_MIN3(V1[1],V2[1],V3[1]); m_min[2] = GIM_MIN3(V1[2],V2[2],V3[2]); m_max[0] = GIM_MAX3(V1[0],V2[0],V3[0]); m_max[1] = GIM_MAX3(V1[1],V2[1],V3[1]); m_max[2] = GIM_MAX3(V1[2],V2[2],V3[2]); m_min[0] -= margin; m_min[1] -= margin; m_min[2] -= margin; m_max[0] += margin; m_max[1] += margin; m_max[2] += margin; } GIM_AABB(const GIM_AABB &other): m_min(other.m_min),m_max(other.m_max) { } GIM_AABB(const GIM_AABB &other,btScalar margin ): m_min(other.m_min),m_max(other.m_max) { m_min[0] -= margin; m_min[1] -= margin; m_min[2] -= margin; m_max[0] += margin; m_max[1] += margin; m_max[2] += margin; } SIMD_FORCE_INLINE void invalidate() { m_min[0] = G_REAL_INFINITY; m_min[1] = G_REAL_INFINITY; m_min[2] = G_REAL_INFINITY; m_max[0] = -G_REAL_INFINITY; m_max[1] = -G_REAL_INFINITY; m_max[2] = -G_REAL_INFINITY; } SIMD_FORCE_INLINE void increment_margin(btScalar margin) { m_min[0] -= margin; m_min[1] -= margin; m_min[2] -= margin; m_max[0] += margin; m_max[1] += margin; m_max[2] += margin; } SIMD_FORCE_INLINE void copy_with_margin(const GIM_AABB &other, btScalar margin) { m_min[0] = other.m_min[0] - margin; m_min[1] = other.m_min[1] - margin; m_min[2] = other.m_min[2] - margin; m_max[0] = other.m_max[0] + margin; m_max[1] = other.m_max[1] + margin; m_max[2] = other.m_max[2] + margin; } template SIMD_FORCE_INLINE void calc_from_triangle( const CLASS_POINT & V1, const CLASS_POINT & V2, const CLASS_POINT & V3) { m_min[0] = GIM_MIN3(V1[0],V2[0],V3[0]); m_min[1] = GIM_MIN3(V1[1],V2[1],V3[1]); m_min[2] = GIM_MIN3(V1[2],V2[2],V3[2]); m_max[0] = GIM_MAX3(V1[0],V2[0],V3[0]); m_max[1] = GIM_MAX3(V1[1],V2[1],V3[1]); m_max[2] = GIM_MAX3(V1[2],V2[2],V3[2]); } template SIMD_FORCE_INLINE void calc_from_triangle_margin( const CLASS_POINT & V1, const CLASS_POINT & V2, const CLASS_POINT & V3, btScalar margin) { m_min[0] = GIM_MIN3(V1[0],V2[0],V3[0]); m_min[1] = GIM_MIN3(V1[1],V2[1],V3[1]); m_min[2] = GIM_MIN3(V1[2],V2[2],V3[2]); m_max[0] = GIM_MAX3(V1[0],V2[0],V3[0]); m_max[1] = GIM_MAX3(V1[1],V2[1],V3[1]); m_max[2] = GIM_MAX3(V1[2],V2[2],V3[2]); m_min[0] -= margin; m_min[1] -= margin; m_min[2] -= margin; m_max[0] += margin; m_max[1] += margin; m_max[2] += margin; } //! Apply a transform to an AABB SIMD_FORCE_INLINE void appy_transform(const btTransform & trans) { btVector3 center = (m_max+m_min)*0.5f; btVector3 extends = m_max - center; // Compute new center center = trans(center); btVector3 textends(extends.dot(trans.getBasis().getRow(0).absolute()), extends.dot(trans.getBasis().getRow(1).absolute()), extends.dot(trans.getBasis().getRow(2).absolute())); m_min = center - textends; m_max = center + textends; } //! Merges a Box SIMD_FORCE_INLINE void merge(const GIM_AABB & box) { m_min[0] = GIM_MIN(m_min[0],box.m_min[0]); m_min[1] = GIM_MIN(m_min[1],box.m_min[1]); m_min[2] = GIM_MIN(m_min[2],box.m_min[2]); m_max[0] = GIM_MAX(m_max[0],box.m_max[0]); m_max[1] = GIM_MAX(m_max[1],box.m_max[1]); m_max[2] = GIM_MAX(m_max[2],box.m_max[2]); } //! Merges a point template SIMD_FORCE_INLINE void merge_point(const CLASS_POINT & point) { m_min[0] = GIM_MIN(m_min[0],point[0]); m_min[1] = GIM_MIN(m_min[1],point[1]); m_min[2] = GIM_MIN(m_min[2],point[2]); m_max[0] = GIM_MAX(m_max[0],point[0]); m_max[1] = GIM_MAX(m_max[1],point[1]); m_max[2] = GIM_MAX(m_max[2],point[2]); } //! Gets the extend and center SIMD_FORCE_INLINE void get_center_extend(btVector3 & center,btVector3 & extend) const { center = (m_max+m_min)*0.5f; extend = m_max - center; } //! Finds the intersecting box between this box and the other. SIMD_FORCE_INLINE void find_intersection(const GIM_AABB & other, GIM_AABB & intersection) const { intersection.m_min[0] = GIM_MAX(other.m_min[0],m_min[0]); intersection.m_min[1] = GIM_MAX(other.m_min[1],m_min[1]); intersection.m_min[2] = GIM_MAX(other.m_min[2],m_min[2]); intersection.m_max[0] = GIM_MIN(other.m_max[0],m_max[0]); intersection.m_max[1] = GIM_MIN(other.m_max[1],m_max[1]); intersection.m_max[2] = GIM_MIN(other.m_max[2],m_max[2]); } SIMD_FORCE_INLINE bool has_collision(const GIM_AABB & other) const { if(m_min[0] > other.m_max[0] || m_max[0] < other.m_min[0] || m_min[1] > other.m_max[1] || m_max[1] < other.m_min[1] || m_min[2] > other.m_max[2] || m_max[2] < other.m_min[2]) { return false; } return true; } /*! \brief Finds the Ray intersection parameter. \param aabb Aligned box \param vorigin A vec3f with the origin of the ray \param vdir A vec3f with the direction of the ray */ SIMD_FORCE_INLINE bool collide_ray(const btVector3 & vorigin,const btVector3 & vdir) { btVector3 extents,center; this->get_center_extend(center,extents);; btScalar Dx = vorigin[0] - center[0]; if(GIM_GREATER(Dx, extents[0]) && Dx*vdir[0]>=0.0f) return false; btScalar Dy = vorigin[1] - center[1]; if(GIM_GREATER(Dy, extents[1]) && Dy*vdir[1]>=0.0f) return false; btScalar Dz = vorigin[2] - center[2]; if(GIM_GREATER(Dz, extents[2]) && Dz*vdir[2]>=0.0f) return false; btScalar f = vdir[1] * Dz - vdir[2] * Dy; if(btFabs(f) > extents[1]*btFabs(vdir[2]) + extents[2]*btFabs(vdir[1])) return false; f = vdir[2] * Dx - vdir[0] * Dz; if(btFabs(f) > extents[0]*btFabs(vdir[2]) + extents[2]*btFabs(vdir[0]))return false; f = vdir[0] * Dy - vdir[1] * Dx; if(btFabs(f) > extents[0]*btFabs(vdir[1]) + extents[1]*btFabs(vdir[0]))return false; return true; } SIMD_FORCE_INLINE void projection_interval(const btVector3 & direction, btScalar &vmin, btScalar &vmax) const { btVector3 center = (m_max+m_min)*0.5f; btVector3 extend = m_max-center; btScalar _fOrigin = direction.dot(center); btScalar _fMaximumExtent = extend.dot(direction.absolute()); vmin = _fOrigin - _fMaximumExtent; vmax = _fOrigin + _fMaximumExtent; } SIMD_FORCE_INLINE ePLANE_INTERSECTION_TYPE plane_classify(const btVector4 &plane) const { btScalar _fmin,_fmax; this->projection_interval(plane,_fmin,_fmax); if(plane[3] > _fmax + BOX_PLANE_EPSILON) { return G_BACK_PLANE; // 0 } if(plane[3]+BOX_PLANE_EPSILON >=_fmin) { return G_COLLIDE_PLANE; //1 } return G_FRONT_PLANE;//2 } SIMD_FORCE_INLINE bool overlapping_trans_conservative(const GIM_AABB & box, btTransform & trans1_to_0) { GIM_AABB tbox = box; tbox.appy_transform(trans1_to_0); return has_collision(tbox); } //! transcache is the transformation cache from box to this AABB SIMD_FORCE_INLINE bool overlapping_trans_cache( const GIM_AABB & box,const GIM_BOX_BOX_TRANSFORM_CACHE & transcache, bool fulltest) { //Taken from OPCODE btVector3 ea,eb;//extends btVector3 ca,cb;//extends get_center_extend(ca,ea); box.get_center_extend(cb,eb); btVector3 T; btScalar t,t2; int i; // Class I : A's basis vectors for(i=0;i<3;i++) { T[i] = transcache.m_R1to0[i].dot(cb) + transcache.m_T1to0[i] - ca[i]; t = transcache.m_AR[i].dot(eb) + ea[i]; if(GIM_GREATER(T[i], t)) return false; } // Class II : B's basis vectors for(i=0;i<3;i++) { t = MAT_DOT_COL(transcache.m_R1to0,T,i); t2 = MAT_DOT_COL(transcache.m_AR,ea,i) + eb[i]; if(GIM_GREATER(t,t2)) return false; } // Class III : 9 cross products if(fulltest) { int j,m,n,o,p,q,r; for(i=0;i<3;i++) { m = (i+1)%3; n = (i+2)%3; o = i==0?1:0; p = i==2?1:2; for(j=0;j<3;j++) { q = j==2?1:2; r = j==0?1:0; t = T[n]*transcache.m_R1to0[m][j] - T[m]*transcache.m_R1to0[n][j]; t2 = ea[o]*transcache.m_AR[p][j] + ea[p]*transcache.m_AR[o][j] + eb[r]*transcache.m_AR[i][q] + eb[q]*transcache.m_AR[i][r]; if(GIM_GREATER(t,t2)) return false; } } } return true; } //! Simple test for planes. SIMD_FORCE_INLINE bool collide_plane( const btVector4 & plane) { ePLANE_INTERSECTION_TYPE classify = plane_classify(plane); return (classify == G_COLLIDE_PLANE); } //! test for a triangle, with edges SIMD_FORCE_INLINE bool collide_triangle_exact( const btVector3 & p1, const btVector3 & p2, const btVector3 & p3, const btVector4 & triangle_plane) { if(!collide_plane(triangle_plane)) return false; btVector3 center,extends; this->get_center_extend(center,extends); const btVector3 v1(p1 - center); const btVector3 v2(p2 - center); const btVector3 v3(p3 - center); //First axis btVector3 diff(v2 - v1); btVector3 abs_diff = diff.absolute(); //Test With X axis TEST_CROSS_EDGE_BOX_X_AXIS_MCR(diff,abs_diff,v1,v3,extends); //Test With Y axis TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(diff,abs_diff,v1,v3,extends); //Test With Z axis TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(diff,abs_diff,v1,v3,extends); diff = v3 - v2; abs_diff = diff.absolute(); //Test With X axis TEST_CROSS_EDGE_BOX_X_AXIS_MCR(diff,abs_diff,v2,v1,extends); //Test With Y axis TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(diff,abs_diff,v2,v1,extends); //Test With Z axis TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(diff,abs_diff,v2,v1,extends); diff = v1 - v3; abs_diff = diff.absolute(); //Test With X axis TEST_CROSS_EDGE_BOX_X_AXIS_MCR(diff,abs_diff,v3,v2,extends); //Test With Y axis TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(diff,abs_diff,v3,v2,extends); //Test With Z axis TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(diff,abs_diff,v3,v2,extends); return true; } }; //! Compairison of transformation objects SIMD_FORCE_INLINE bool btCompareTransformsEqual(const btTransform & t1,const btTransform & t2) { if(!(t1.getOrigin() == t2.getOrigin()) ) return false; if(!(t1.getBasis().getRow(0) == t2.getBasis().getRow(0)) ) return false; if(!(t1.getBasis().getRow(1) == t2.getBasis().getRow(1)) ) return false; if(!(t1.getBasis().getRow(2) == t2.getBasis().getRow(2)) ) return false; return true; } #endif // GIM_BOX_COLLISION_H_INCLUDED critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.cpp0000644000175000017500000005260711344267705031566 0ustar bobkebobke/* This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com 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. */ /* Author: Francisco Len Njera Concave-Concave Collision */ #include "BulletCollision/CollisionDispatch/btManifoldResult.h" #include "LinearMath/btIDebugDraw.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionShapes/btBoxShape.h" #include "btGImpactCollisionAlgorithm.h" #include "btContactProcessing.h" #include "LinearMath/btQuickprof.h" //! Class for accessing the plane equation class btPlaneShape : public btStaticPlaneShape { public: btPlaneShape(const btVector3& v, float f) :btStaticPlaneShape(v,f) { } void get_plane_equation(btVector4 &equation) { equation[0] = m_planeNormal[0]; equation[1] = m_planeNormal[1]; equation[2] = m_planeNormal[2]; equation[3] = m_planeConstant; } void get_plane_equation_transformed(const btTransform & trans,btVector4 &equation) { equation[0] = trans.getBasis().getRow(0).dot(m_planeNormal); equation[1] = trans.getBasis().getRow(1).dot(m_planeNormal); equation[2] = trans.getBasis().getRow(2).dot(m_planeNormal); equation[3] = trans.getOrigin().dot(m_planeNormal) + m_planeConstant; } }; ////////////////////////////////////////////////////////////////////////////////////////////// #ifdef TRI_COLLISION_PROFILING btClock g_triangle_clock; float g_accum_triangle_collision_time = 0; int g_count_triangle_collision = 0; void bt_begin_gim02_tri_time() { g_triangle_clock.reset(); } void bt_end_gim02_tri_time() { g_accum_triangle_collision_time += g_triangle_clock.getTimeMicroseconds(); g_count_triangle_collision++; } #endif //TRI_COLLISION_PROFILING //! Retrieving shapes shapes /*! Declared here due of insuficent space on Pool allocators */ //!@{ class GIM_ShapeRetriever { public: btGImpactShapeInterface * m_gim_shape; btTriangleShapeEx m_trishape; btTetrahedronShapeEx m_tetrashape; public: class ChildShapeRetriever { public: GIM_ShapeRetriever * m_parent; virtual btCollisionShape * getChildShape(int index) { return m_parent->m_gim_shape->getChildShape(index); } virtual ~ChildShapeRetriever() {} }; class TriangleShapeRetriever:public ChildShapeRetriever { public: virtual btCollisionShape * getChildShape(int index) { m_parent->m_gim_shape->getBulletTriangle(index,m_parent->m_trishape); return &m_parent->m_trishape; } virtual ~TriangleShapeRetriever() {} }; class TetraShapeRetriever:public ChildShapeRetriever { public: virtual btCollisionShape * getChildShape(int index) { m_parent->m_gim_shape->getBulletTetrahedron(index,m_parent->m_tetrashape); return &m_parent->m_tetrashape; } }; public: ChildShapeRetriever m_child_retriever; TriangleShapeRetriever m_tri_retriever; TetraShapeRetriever m_tetra_retriever; ChildShapeRetriever * m_current_retriever; GIM_ShapeRetriever(btGImpactShapeInterface * gim_shape) { m_gim_shape = gim_shape; //select retriever if(m_gim_shape->needsRetrieveTriangles()) { m_current_retriever = &m_tri_retriever; } else if(m_gim_shape->needsRetrieveTetrahedrons()) { m_current_retriever = &m_tetra_retriever; } else { m_current_retriever = &m_child_retriever; } m_current_retriever->m_parent = this; } btCollisionShape * getChildShape(int index) { return m_current_retriever->getChildShape(index); } }; //!@} #ifdef TRI_COLLISION_PROFILING //! Gets the average time in miliseconds of tree collisions float btGImpactCollisionAlgorithm::getAverageTreeCollisionTime() { return btGImpactBoxSet::getAverageTreeCollisionTime(); } //! Gets the average time in miliseconds of triangle collisions float btGImpactCollisionAlgorithm::getAverageTriangleCollisionTime() { if(g_count_triangle_collision == 0) return 0; float avgtime = g_accum_triangle_collision_time; avgtime /= (float)g_count_triangle_collision; g_accum_triangle_collision_time = 0; g_count_triangle_collision = 0; return avgtime; } #endif //TRI_COLLISION_PROFILING btGImpactCollisionAlgorithm::btGImpactCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) : btActivatingCollisionAlgorithm(ci,body0,body1) { m_manifoldPtr = NULL; m_convex_algorithm = NULL; } btGImpactCollisionAlgorithm::~btGImpactCollisionAlgorithm() { clearCache(); } void btGImpactCollisionAlgorithm::addContactPoint(btCollisionObject * body0, btCollisionObject * body1, const btVector3 & point, const btVector3 & normal, btScalar distance) { m_resultOut->setShapeIdentifiersA(m_part0,m_triface0); m_resultOut->setShapeIdentifiersB(m_part1,m_triface1); checkManifold(body0,body1); m_resultOut->addContactPoint(normal,point,distance); } void btGImpactCollisionAlgorithm::shape_vs_shape_collision( btCollisionObject * body0, btCollisionObject * body1, btCollisionShape * shape0, btCollisionShape * shape1) { btCollisionShape* tmpShape0 = body0->getCollisionShape(); btCollisionShape* tmpShape1 = body1->getCollisionShape(); body0->internalSetTemporaryCollisionShape(shape0); body1->internalSetTemporaryCollisionShape(shape1); { btCollisionAlgorithm* algor = newAlgorithm(body0,body1); // post : checkManifold is called m_resultOut->setShapeIdentifiersA(m_part0,m_triface0); m_resultOut->setShapeIdentifiersB(m_part1,m_triface1); algor->processCollision(body0,body1,*m_dispatchInfo,m_resultOut); algor->~btCollisionAlgorithm(); m_dispatcher->freeCollisionAlgorithm(algor); } body0->internalSetTemporaryCollisionShape(tmpShape0); body1->internalSetTemporaryCollisionShape(tmpShape1); } void btGImpactCollisionAlgorithm::convex_vs_convex_collision( btCollisionObject * body0, btCollisionObject * body1, btCollisionShape * shape0, btCollisionShape * shape1) { btCollisionShape* tmpShape0 = body0->getCollisionShape(); btCollisionShape* tmpShape1 = body1->getCollisionShape(); body0->internalSetTemporaryCollisionShape(shape0); body1->internalSetTemporaryCollisionShape(shape1); m_resultOut->setShapeIdentifiersA(m_part0,m_triface0); m_resultOut->setShapeIdentifiersB(m_part1,m_triface1); checkConvexAlgorithm(body0,body1); m_convex_algorithm->processCollision(body0,body1,*m_dispatchInfo,m_resultOut); body0->internalSetTemporaryCollisionShape(tmpShape0); body1->internalSetTemporaryCollisionShape(tmpShape1); } void btGImpactCollisionAlgorithm::gimpact_vs_gimpact_find_pairs( const btTransform & trans0, const btTransform & trans1, btGImpactShapeInterface * shape0, btGImpactShapeInterface * shape1,btPairSet & pairset) { if(shape0->hasBoxSet() && shape1->hasBoxSet()) { btGImpactBoxSet::find_collision(shape0->getBoxSet(),trans0,shape1->getBoxSet(),trans1,pairset); } else { btAABB boxshape0; btAABB boxshape1; int i = shape0->getNumChildShapes(); while(i--) { shape0->getChildAabb(i,trans0,boxshape0.m_min,boxshape0.m_max); int j = shape1->getNumChildShapes(); while(j--) { shape1->getChildAabb(i,trans1,boxshape1.m_min,boxshape1.m_max); if(boxshape1.has_collision(boxshape0)) { pairset.push_pair(i,j); } } } } } void btGImpactCollisionAlgorithm::gimpact_vs_shape_find_pairs( const btTransform & trans0, const btTransform & trans1, btGImpactShapeInterface * shape0, btCollisionShape * shape1, btAlignedObjectArray & collided_primitives) { btAABB boxshape; if(shape0->hasBoxSet()) { btTransform trans1to0 = trans0.inverse(); trans1to0 *= trans1; shape1->getAabb(trans1to0,boxshape.m_min,boxshape.m_max); shape0->getBoxSet()->boxQuery(boxshape, collided_primitives); } else { shape1->getAabb(trans1,boxshape.m_min,boxshape.m_max); btAABB boxshape0; int i = shape0->getNumChildShapes(); while(i--) { shape0->getChildAabb(i,trans0,boxshape0.m_min,boxshape0.m_max); if(boxshape.has_collision(boxshape0)) { collided_primitives.push_back(i); } } } } void btGImpactCollisionAlgorithm::collide_gjk_triangles(btCollisionObject * body0, btCollisionObject * body1, btGImpactMeshShapePart * shape0, btGImpactMeshShapePart * shape1, const int * pairs, int pair_count) { btTriangleShapeEx tri0; btTriangleShapeEx tri1; shape0->lockChildShapes(); shape1->lockChildShapes(); const int * pair_pointer = pairs; while(pair_count--) { m_triface0 = *(pair_pointer); m_triface1 = *(pair_pointer+1); pair_pointer+=2; shape0->getBulletTriangle(m_triface0,tri0); shape1->getBulletTriangle(m_triface1,tri1); //collide two convex shapes if(tri0.overlap_test_conservative(tri1)) { convex_vs_convex_collision(body0,body1,&tri0,&tri1); } } shape0->unlockChildShapes(); shape1->unlockChildShapes(); } void btGImpactCollisionAlgorithm::collide_sat_triangles(btCollisionObject * body0, btCollisionObject * body1, btGImpactMeshShapePart * shape0, btGImpactMeshShapePart * shape1, const int * pairs, int pair_count) { btTransform orgtrans0 = body0->getWorldTransform(); btTransform orgtrans1 = body1->getWorldTransform(); btPrimitiveTriangle ptri0; btPrimitiveTriangle ptri1; GIM_TRIANGLE_CONTACT contact_data; shape0->lockChildShapes(); shape1->lockChildShapes(); const int * pair_pointer = pairs; while(pair_count--) { m_triface0 = *(pair_pointer); m_triface1 = *(pair_pointer+1); pair_pointer+=2; shape0->getPrimitiveTriangle(m_triface0,ptri0); shape1->getPrimitiveTriangle(m_triface1,ptri1); #ifdef TRI_COLLISION_PROFILING bt_begin_gim02_tri_time(); #endif ptri0.applyTransform(orgtrans0); ptri1.applyTransform(orgtrans1); //build planes ptri0.buildTriPlane(); ptri1.buildTriPlane(); // test conservative if(ptri0.overlap_test_conservative(ptri1)) { if(ptri0.find_triangle_collision_clip_method(ptri1,contact_data)) { int j = contact_data.m_point_count; while(j--) { addContactPoint(body0, body1, contact_data.m_points[j], contact_data.m_separating_normal, -contact_data.m_penetration_depth); } } } #ifdef TRI_COLLISION_PROFILING bt_end_gim02_tri_time(); #endif } shape0->unlockChildShapes(); shape1->unlockChildShapes(); } void btGImpactCollisionAlgorithm::gimpact_vs_gimpact( btCollisionObject * body0, btCollisionObject * body1, btGImpactShapeInterface * shape0, btGImpactShapeInterface * shape1) { if(shape0->getGImpactShapeType()==CONST_GIMPACT_TRIMESH_SHAPE) { btGImpactMeshShape * meshshape0 = static_cast(shape0); m_part0 = meshshape0->getMeshPartCount(); while(m_part0--) { gimpact_vs_gimpact(body0,body1,meshshape0->getMeshPart(m_part0),shape1); } return; } if(shape1->getGImpactShapeType()==CONST_GIMPACT_TRIMESH_SHAPE) { btGImpactMeshShape * meshshape1 = static_cast(shape1); m_part1 = meshshape1->getMeshPartCount(); while(m_part1--) { gimpact_vs_gimpact(body0,body1,shape0,meshshape1->getMeshPart(m_part1)); } return; } btTransform orgtrans0 = body0->getWorldTransform(); btTransform orgtrans1 = body1->getWorldTransform(); btPairSet pairset; gimpact_vs_gimpact_find_pairs(orgtrans0,orgtrans1,shape0,shape1,pairset); if(pairset.size()== 0) return; if(shape0->getGImpactShapeType() == CONST_GIMPACT_TRIMESH_SHAPE_PART && shape1->getGImpactShapeType() == CONST_GIMPACT_TRIMESH_SHAPE_PART) { btGImpactMeshShapePart * shapepart0 = static_cast(shape0); btGImpactMeshShapePart * shapepart1 = static_cast(shape1); //specialized function #ifdef BULLET_TRIANGLE_COLLISION collide_gjk_triangles(body0,body1,shapepart0,shapepart1,&pairset[0].m_index1,pairset.size()); #else collide_sat_triangles(body0,body1,shapepart0,shapepart1,&pairset[0].m_index1,pairset.size()); #endif return; } //general function shape0->lockChildShapes(); shape1->lockChildShapes(); GIM_ShapeRetriever retriever0(shape0); GIM_ShapeRetriever retriever1(shape1); bool child_has_transform0 = shape0->childrenHasTransform(); bool child_has_transform1 = shape1->childrenHasTransform(); int i = pairset.size(); while(i--) { GIM_PAIR * pair = &pairset[i]; m_triface0 = pair->m_index1; m_triface1 = pair->m_index2; btCollisionShape * colshape0 = retriever0.getChildShape(m_triface0); btCollisionShape * colshape1 = retriever1.getChildShape(m_triface1); if(child_has_transform0) { body0->setWorldTransform(orgtrans0*shape0->getChildTransform(m_triface0)); } if(child_has_transform1) { body1->setWorldTransform(orgtrans1*shape1->getChildTransform(m_triface1)); } //collide two convex shapes convex_vs_convex_collision(body0,body1,colshape0,colshape1); if(child_has_transform0) { body0->setWorldTransform(orgtrans0); } if(child_has_transform1) { body1->setWorldTransform(orgtrans1); } } shape0->unlockChildShapes(); shape1->unlockChildShapes(); } void btGImpactCollisionAlgorithm::gimpact_vs_shape(btCollisionObject * body0, btCollisionObject * body1, btGImpactShapeInterface * shape0, btCollisionShape * shape1,bool swapped) { if(shape0->getGImpactShapeType()==CONST_GIMPACT_TRIMESH_SHAPE) { btGImpactMeshShape * meshshape0 = static_cast(shape0); int& part = swapped ? m_part1 : m_part0; part = meshshape0->getMeshPartCount(); while(part--) { gimpact_vs_shape(body0, body1, meshshape0->getMeshPart(part), shape1,swapped); } return; } #ifdef GIMPACT_VS_PLANE_COLLISION if(shape0->getGImpactShapeType() == CONST_GIMPACT_TRIMESH_SHAPE_PART && shape1->getShapeType() == STATIC_PLANE_PROXYTYPE) { btGImpactMeshShapePart * shapepart = static_cast(shape0); btStaticPlaneShape * planeshape = static_cast(shape1); gimpacttrimeshpart_vs_plane_collision(body0,body1,shapepart,planeshape,swapped); return; } #endif if(shape1->isCompound()) { btCompoundShape * compoundshape = static_cast(shape1); gimpact_vs_compoundshape(body0,body1,shape0,compoundshape,swapped); return; } else if(shape1->isConcave()) { btConcaveShape * concaveshape = static_cast(shape1); gimpact_vs_concave(body0,body1,shape0,concaveshape,swapped); return; } btTransform orgtrans0 = body0->getWorldTransform(); btTransform orgtrans1 = body1->getWorldTransform(); btAlignedObjectArray collided_results; gimpact_vs_shape_find_pairs(orgtrans0,orgtrans1,shape0,shape1,collided_results); if(collided_results.size() == 0) return; shape0->lockChildShapes(); GIM_ShapeRetriever retriever0(shape0); bool child_has_transform0 = shape0->childrenHasTransform(); int i = collided_results.size(); while(i--) { int child_index = collided_results[i]; if(swapped) m_triface1 = child_index; else m_triface0 = child_index; btCollisionShape * colshape0 = retriever0.getChildShape(child_index); if(child_has_transform0) { body0->setWorldTransform(orgtrans0*shape0->getChildTransform(child_index)); } //collide two shapes if(swapped) { shape_vs_shape_collision(body1,body0,shape1,colshape0); } else { shape_vs_shape_collision(body0,body1,colshape0,shape1); } //restore transforms if(child_has_transform0) { body0->setWorldTransform(orgtrans0); } } shape0->unlockChildShapes(); } void btGImpactCollisionAlgorithm::gimpact_vs_compoundshape(btCollisionObject * body0, btCollisionObject * body1, btGImpactShapeInterface * shape0, btCompoundShape * shape1,bool swapped) { btTransform orgtrans1 = body1->getWorldTransform(); int i = shape1->getNumChildShapes(); while(i--) { btCollisionShape * colshape1 = shape1->getChildShape(i); btTransform childtrans1 = orgtrans1*shape1->getChildTransform(i); body1->setWorldTransform(childtrans1); //collide child shape gimpact_vs_shape(body0, body1, shape0,colshape1,swapped); //restore transforms body1->setWorldTransform(orgtrans1); } } void btGImpactCollisionAlgorithm::gimpacttrimeshpart_vs_plane_collision( btCollisionObject * body0, btCollisionObject * body1, btGImpactMeshShapePart * shape0, btStaticPlaneShape * shape1,bool swapped) { btTransform orgtrans0 = body0->getWorldTransform(); btTransform orgtrans1 = body1->getWorldTransform(); btPlaneShape * planeshape = static_cast(shape1); btVector4 plane; planeshape->get_plane_equation_transformed(orgtrans1,plane); //test box against plane btAABB tribox; shape0->getAabb(orgtrans0,tribox.m_min,tribox.m_max); tribox.increment_margin(planeshape->getMargin()); if( tribox.plane_classify(plane)!= BT_CONST_COLLIDE_PLANE) return; shape0->lockChildShapes(); btScalar margin = shape0->getMargin() + planeshape->getMargin(); btVector3 vertex; int vi = shape0->getVertexCount(); while(vi--) { shape0->getVertex(vi,vertex); vertex = orgtrans0(vertex); btScalar distance = vertex.dot(plane) - plane[3] - margin; if(distance<0.0)//add contact { if(swapped) { addContactPoint(body1, body0, vertex, -plane, distance); } else { addContactPoint(body0, body1, vertex, plane, distance); } } } shape0->unlockChildShapes(); } class btGImpactTriangleCallback: public btTriangleCallback { public: btGImpactCollisionAlgorithm * algorithm; btCollisionObject * body0; btCollisionObject * body1; btGImpactShapeInterface * gimpactshape0; bool swapped; btScalar margin; virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex) { btTriangleShapeEx tri1(triangle[0],triangle[1],triangle[2]); tri1.setMargin(margin); if(swapped) { algorithm->setPart0(partId); algorithm->setFace0(triangleIndex); } else { algorithm->setPart1(partId); algorithm->setFace1(triangleIndex); } algorithm->gimpact_vs_shape( body0,body1,gimpactshape0,&tri1,swapped); } }; void btGImpactCollisionAlgorithm::gimpact_vs_concave( btCollisionObject * body0, btCollisionObject * body1, btGImpactShapeInterface * shape0, btConcaveShape * shape1,bool swapped) { //create the callback btGImpactTriangleCallback tricallback; tricallback.algorithm = this; tricallback.body0 = body0; tricallback.body1 = body1; tricallback.gimpactshape0 = shape0; tricallback.swapped = swapped; tricallback.margin = shape1->getMargin(); //getting the trimesh AABB btTransform gimpactInConcaveSpace; gimpactInConcaveSpace = body1->getWorldTransform().inverse() * body0->getWorldTransform(); btVector3 minAABB,maxAABB; shape0->getAabb(gimpactInConcaveSpace,minAABB,maxAABB); shape1->processAllTriangles(&tricallback,minAABB,maxAABB); } void btGImpactCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { clearCache(); m_resultOut = resultOut; m_dispatchInfo = &dispatchInfo; btGImpactShapeInterface * gimpactshape0; btGImpactShapeInterface * gimpactshape1; if (body0->getCollisionShape()->getShapeType()==GIMPACT_SHAPE_PROXYTYPE) { gimpactshape0 = static_cast(body0->getCollisionShape()); if( body1->getCollisionShape()->getShapeType()==GIMPACT_SHAPE_PROXYTYPE ) { gimpactshape1 = static_cast(body1->getCollisionShape()); gimpact_vs_gimpact(body0,body1,gimpactshape0,gimpactshape1); } else { gimpact_vs_shape(body0,body1,gimpactshape0,body1->getCollisionShape(),false); } } else if (body1->getCollisionShape()->getShapeType()==GIMPACT_SHAPE_PROXYTYPE ) { gimpactshape1 = static_cast(body1->getCollisionShape()); gimpact_vs_shape(body1,body0,gimpactshape1,body0->getCollisionShape(),true); } } btScalar btGImpactCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { return 1.f; } ///////////////////////////////////// REGISTERING ALGORITHM ////////////////////////////////////////////// //! Use this function for register the algorithm externally void btGImpactCollisionAlgorithm::registerAlgorithm(btCollisionDispatcher * dispatcher) { static btGImpactCollisionAlgorithm::CreateFunc s_gimpact_cf; int i; for ( i = 0;i < MAX_BROADPHASE_COLLISION_TYPES ;i++ ) { dispatcher->registerCollisionCreateFunc(GIMPACT_SHAPE_PROXYTYPE,i ,&s_gimpact_cf); } for ( i = 0;i < MAX_BROADPHASE_COLLISION_TYPES ;i++ ) { dispatcher->registerCollisionCreateFunc(i,GIMPACT_SHAPE_PROXYTYPE ,&s_gimpact_cf); } } critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/gim_memory.h0000644000175000017500000001201311344267705025765 0ustar bobkebobke#ifndef GIM_MEMORY_H_INCLUDED #define GIM_MEMORY_H_INCLUDED /*! \file gim_memory.h \author Francisco Len Njera */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. (3) The zlib/libpng license that is included with this library in the file GIMPACT-LICENSE-ZLIB.TXT. 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 files GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "gim_math.h" #include #ifdef PREFETCH #include // for prefetch #define pfval 64 #define pfval2 128 //! Prefetch 64 #define pf(_x,_i) _mm_prefetch((void *)(_x + _i + pfval), 0) //! Prefetch 128 #define pf2(_x,_i) _mm_prefetch((void *)(_x + _i + pfval2), 0) #else //! Prefetch 64 #define pf(_x,_i) //! Prefetch 128 #define pf2(_x,_i) #endif ///Functions for manip packed arrays of numbers #define GIM_COPY_ARRAYS(dest_array,source_array,element_count)\ {\ for (GUINT _i_=0;_i_=SIMD_T_SIZE) { *(ui_dst_ptr++) = *(ui_src_ptr++); copysize-=SIMD_T_SIZE; } if(copysize==0) return; */ char * c_src_ptr = (char *)src; char * c_dst_ptr = (char *)dst; while(copysize>0) { *(c_dst_ptr++) = *(c_src_ptr++); copysize--; } return; #else memcpy(dst,src,copysize); #endif } template inline void gim_swap_elements(T* _array,size_t _i,size_t _j) { T _e_tmp_ = _array[_i]; _array[_i] = _array[_j]; _array[_j] = _e_tmp_; } template inline void gim_swap_elements_memcpy(T* _array,size_t _i,size_t _j) { char _e_tmp_[sizeof(T)]; gim_simd_memcpy(_e_tmp_,&_array[_i],sizeof(T)); gim_simd_memcpy(&_array[_i],&_array[_j],sizeof(T)); gim_simd_memcpy(&_array[_j],_e_tmp_,sizeof(T)); } template inline void gim_swap_elements_ptr(char * _array,size_t _i,size_t _j) { char _e_tmp_[SIZE]; _i*=SIZE; _j*=SIZE; gim_simd_memcpy(_e_tmp_,_array+_i,SIZE); gim_simd_memcpy(_array+_i,_array+_j,SIZE); gim_simd_memcpy(_array+_j,_e_tmp_,SIZE); } #endif // GIM_MEMORY_H_INCLUDED critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/btBoxCollision.h0000644000175000017500000004271511337071441026557 0ustar bobkebobke#ifndef BT_BOX_COLLISION_H_INCLUDED #define BT_BOX_COLLISION_H_INCLUDED /*! \file gim_box_collision.h \author Francisco Len Njera */ /* This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com 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 "LinearMath/btTransform.h" ///Swap numbers #define BT_SWAP_NUMBERS(a,b){ \ a = a+b; \ b = a-b; \ a = a-b; \ }\ #define BT_MAX(a,b) (ab?b:a) #define BT_GREATER(x, y) btFabs(x) > (y) #define BT_MAX3(a,b,c) BT_MAX(a,BT_MAX(b,c)) #define BT_MIN3(a,b,c) BT_MIN(a,BT_MIN(b,c)) enum eBT_PLANE_INTERSECTION_TYPE { BT_CONST_BACK_PLANE = 0, BT_CONST_COLLIDE_PLANE, BT_CONST_FRONT_PLANE }; //SIMD_FORCE_INLINE bool test_cross_edge_box( // const btVector3 & edge, // const btVector3 & absolute_edge, // const btVector3 & pointa, // const btVector3 & pointb, const btVector3 & extend, // int dir_index0, // int dir_index1 // int component_index0, // int component_index1) //{ // // dir coords are -z and y // // const btScalar dir0 = -edge[dir_index0]; // const btScalar dir1 = edge[dir_index1]; // btScalar pmin = pointa[component_index0]*dir0 + pointa[component_index1]*dir1; // btScalar pmax = pointb[component_index0]*dir0 + pointb[component_index1]*dir1; // //find minmax // if(pmin>pmax) // { // BT_SWAP_NUMBERS(pmin,pmax); // } // //find extends // const btScalar rad = extend[component_index0] * absolute_edge[dir_index0] + // extend[component_index1] * absolute_edge[dir_index1]; // // if(pmin>rad || -rad>pmax) return false; // return true; //} // //SIMD_FORCE_INLINE bool test_cross_edge_box_X_axis( // const btVector3 & edge, // const btVector3 & absolute_edge, // const btVector3 & pointa, // const btVector3 & pointb, btVector3 & extend) //{ // // return test_cross_edge_box(edge,absolute_edge,pointa,pointb,extend,2,1,1,2); //} // // //SIMD_FORCE_INLINE bool test_cross_edge_box_Y_axis( // const btVector3 & edge, // const btVector3 & absolute_edge, // const btVector3 & pointa, // const btVector3 & pointb, btVector3 & extend) //{ // // return test_cross_edge_box(edge,absolute_edge,pointa,pointb,extend,0,2,2,0); //} // //SIMD_FORCE_INLINE bool test_cross_edge_box_Z_axis( // const btVector3 & edge, // const btVector3 & absolute_edge, // const btVector3 & pointa, // const btVector3 & pointb, btVector3 & extend) //{ // // return test_cross_edge_box(edge,absolute_edge,pointa,pointb,extend,1,0,0,1); //} #define TEST_CROSS_EDGE_BOX_MCR(edge,absolute_edge,pointa,pointb,_extend,i_dir_0,i_dir_1,i_comp_0,i_comp_1)\ {\ const btScalar dir0 = -edge[i_dir_0];\ const btScalar dir1 = edge[i_dir_1];\ btScalar pmin = pointa[i_comp_0]*dir0 + pointa[i_comp_1]*dir1;\ btScalar pmax = pointb[i_comp_0]*dir0 + pointb[i_comp_1]*dir1;\ if(pmin>pmax)\ {\ BT_SWAP_NUMBERS(pmin,pmax); \ }\ const btScalar abs_dir0 = absolute_edge[i_dir_0];\ const btScalar abs_dir1 = absolute_edge[i_dir_1];\ const btScalar rad = _extend[i_comp_0] * abs_dir0 + _extend[i_comp_1] * abs_dir1;\ if(pmin>rad || -rad>pmax) return false;\ }\ #define TEST_CROSS_EDGE_BOX_X_AXIS_MCR(edge,absolute_edge,pointa,pointb,_extend)\ {\ TEST_CROSS_EDGE_BOX_MCR(edge,absolute_edge,pointa,pointb,_extend,2,1,1,2);\ }\ #define TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(edge,absolute_edge,pointa,pointb,_extend)\ {\ TEST_CROSS_EDGE_BOX_MCR(edge,absolute_edge,pointa,pointb,_extend,0,2,2,0);\ }\ #define TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(edge,absolute_edge,pointa,pointb,_extend)\ {\ TEST_CROSS_EDGE_BOX_MCR(edge,absolute_edge,pointa,pointb,_extend,1,0,0,1);\ }\ //! Returns the dot product between a vec3f and the col of a matrix SIMD_FORCE_INLINE btScalar bt_mat3_dot_col( const btMatrix3x3 & mat, const btVector3 & vec3, int colindex) { return vec3[0]*mat[0][colindex] + vec3[1]*mat[1][colindex] + vec3[2]*mat[2][colindex]; } //! Class for transforming a model1 to the space of model0 ATTRIBUTE_ALIGNED16 (class) BT_BOX_BOX_TRANSFORM_CACHE { public: btVector3 m_T1to0;//!< Transforms translation of model1 to model 0 btMatrix3x3 m_R1to0;//!< Transforms Rotation of model1 to model 0, equal to R0' * R1 btMatrix3x3 m_AR;//!< Absolute value of m_R1to0 SIMD_FORCE_INLINE void calc_absolute_matrix() { // static const btVector3 vepsi(1e-6f,1e-6f,1e-6f); // m_AR[0] = vepsi + m_R1to0[0].absolute(); // m_AR[1] = vepsi + m_R1to0[1].absolute(); // m_AR[2] = vepsi + m_R1to0[2].absolute(); int i,j; for(i=0;i<3;i++) { for(j=0;j<3;j++ ) { m_AR[i][j] = 1e-6f + btFabs(m_R1to0[i][j]); } } } BT_BOX_BOX_TRANSFORM_CACHE() { } //! Calc the transformation relative 1 to 0. Inverts matrics by transposing SIMD_FORCE_INLINE void calc_from_homogenic(const btTransform & trans0,const btTransform & trans1) { btTransform temp_trans = trans0.inverse(); temp_trans = temp_trans * trans1; m_T1to0 = temp_trans.getOrigin(); m_R1to0 = temp_trans.getBasis(); calc_absolute_matrix(); } //! Calcs the full invertion of the matrices. Useful for scaling matrices SIMD_FORCE_INLINE void calc_from_full_invert(const btTransform & trans0,const btTransform & trans1) { m_R1to0 = trans0.getBasis().inverse(); m_T1to0 = m_R1to0 * (-trans0.getOrigin()); m_T1to0 += m_R1to0*trans1.getOrigin(); m_R1to0 *= trans1.getBasis(); calc_absolute_matrix(); } SIMD_FORCE_INLINE btVector3 transform(const btVector3 & point) const { return btVector3(m_R1to0[0].dot(point) + m_T1to0.x(), m_R1to0[1].dot(point) + m_T1to0.y(), m_R1to0[2].dot(point) + m_T1to0.z()); } }; #define BOX_PLANE_EPSILON 0.000001f //! Axis aligned box ATTRIBUTE_ALIGNED16 (class) btAABB { public: btVector3 m_min; btVector3 m_max; btAABB() {} btAABB(const btVector3 & V1, const btVector3 & V2, const btVector3 & V3) { m_min[0] = BT_MIN3(V1[0],V2[0],V3[0]); m_min[1] = BT_MIN3(V1[1],V2[1],V3[1]); m_min[2] = BT_MIN3(V1[2],V2[2],V3[2]); m_max[0] = BT_MAX3(V1[0],V2[0],V3[0]); m_max[1] = BT_MAX3(V1[1],V2[1],V3[1]); m_max[2] = BT_MAX3(V1[2],V2[2],V3[2]); } btAABB(const btVector3 & V1, const btVector3 & V2, const btVector3 & V3, btScalar margin) { m_min[0] = BT_MIN3(V1[0],V2[0],V3[0]); m_min[1] = BT_MIN3(V1[1],V2[1],V3[1]); m_min[2] = BT_MIN3(V1[2],V2[2],V3[2]); m_max[0] = BT_MAX3(V1[0],V2[0],V3[0]); m_max[1] = BT_MAX3(V1[1],V2[1],V3[1]); m_max[2] = BT_MAX3(V1[2],V2[2],V3[2]); m_min[0] -= margin; m_min[1] -= margin; m_min[2] -= margin; m_max[0] += margin; m_max[1] += margin; m_max[2] += margin; } btAABB(const btAABB &other): m_min(other.m_min),m_max(other.m_max) { } btAABB(const btAABB &other,btScalar margin ): m_min(other.m_min),m_max(other.m_max) { m_min[0] -= margin; m_min[1] -= margin; m_min[2] -= margin; m_max[0] += margin; m_max[1] += margin; m_max[2] += margin; } SIMD_FORCE_INLINE void invalidate() { m_min[0] = SIMD_INFINITY; m_min[1] = SIMD_INFINITY; m_min[2] = SIMD_INFINITY; m_max[0] = -SIMD_INFINITY; m_max[1] = -SIMD_INFINITY; m_max[2] = -SIMD_INFINITY; } SIMD_FORCE_INLINE void increment_margin(btScalar margin) { m_min[0] -= margin; m_min[1] -= margin; m_min[2] -= margin; m_max[0] += margin; m_max[1] += margin; m_max[2] += margin; } SIMD_FORCE_INLINE void copy_with_margin(const btAABB &other, btScalar margin) { m_min[0] = other.m_min[0] - margin; m_min[1] = other.m_min[1] - margin; m_min[2] = other.m_min[2] - margin; m_max[0] = other.m_max[0] + margin; m_max[1] = other.m_max[1] + margin; m_max[2] = other.m_max[2] + margin; } template SIMD_FORCE_INLINE void calc_from_triangle( const CLASS_POINT & V1, const CLASS_POINT & V2, const CLASS_POINT & V3) { m_min[0] = BT_MIN3(V1[0],V2[0],V3[0]); m_min[1] = BT_MIN3(V1[1],V2[1],V3[1]); m_min[2] = BT_MIN3(V1[2],V2[2],V3[2]); m_max[0] = BT_MAX3(V1[0],V2[0],V3[0]); m_max[1] = BT_MAX3(V1[1],V2[1],V3[1]); m_max[2] = BT_MAX3(V1[2],V2[2],V3[2]); } template SIMD_FORCE_INLINE void calc_from_triangle_margin( const CLASS_POINT & V1, const CLASS_POINT & V2, const CLASS_POINT & V3, btScalar margin) { m_min[0] = BT_MIN3(V1[0],V2[0],V3[0]); m_min[1] = BT_MIN3(V1[1],V2[1],V3[1]); m_min[2] = BT_MIN3(V1[2],V2[2],V3[2]); m_max[0] = BT_MAX3(V1[0],V2[0],V3[0]); m_max[1] = BT_MAX3(V1[1],V2[1],V3[1]); m_max[2] = BT_MAX3(V1[2],V2[2],V3[2]); m_min[0] -= margin; m_min[1] -= margin; m_min[2] -= margin; m_max[0] += margin; m_max[1] += margin; m_max[2] += margin; } //! Apply a transform to an AABB SIMD_FORCE_INLINE void appy_transform(const btTransform & trans) { btVector3 center = (m_max+m_min)*0.5f; btVector3 extends = m_max - center; // Compute new center center = trans(center); btVector3 textends(extends.dot(trans.getBasis().getRow(0).absolute()), extends.dot(trans.getBasis().getRow(1).absolute()), extends.dot(trans.getBasis().getRow(2).absolute())); m_min = center - textends; m_max = center + textends; } //! Apply a transform to an AABB SIMD_FORCE_INLINE void appy_transform_trans_cache(const BT_BOX_BOX_TRANSFORM_CACHE & trans) { btVector3 center = (m_max+m_min)*0.5f; btVector3 extends = m_max - center; // Compute new center center = trans.transform(center); btVector3 textends(extends.dot(trans.m_R1to0.getRow(0).absolute()), extends.dot(trans.m_R1to0.getRow(1).absolute()), extends.dot(trans.m_R1to0.getRow(2).absolute())); m_min = center - textends; m_max = center + textends; } //! Merges a Box SIMD_FORCE_INLINE void merge(const btAABB & box) { m_min[0] = BT_MIN(m_min[0],box.m_min[0]); m_min[1] = BT_MIN(m_min[1],box.m_min[1]); m_min[2] = BT_MIN(m_min[2],box.m_min[2]); m_max[0] = BT_MAX(m_max[0],box.m_max[0]); m_max[1] = BT_MAX(m_max[1],box.m_max[1]); m_max[2] = BT_MAX(m_max[2],box.m_max[2]); } //! Merges a point template SIMD_FORCE_INLINE void merge_point(const CLASS_POINT & point) { m_min[0] = BT_MIN(m_min[0],point[0]); m_min[1] = BT_MIN(m_min[1],point[1]); m_min[2] = BT_MIN(m_min[2],point[2]); m_max[0] = BT_MAX(m_max[0],point[0]); m_max[1] = BT_MAX(m_max[1],point[1]); m_max[2] = BT_MAX(m_max[2],point[2]); } //! Gets the extend and center SIMD_FORCE_INLINE void get_center_extend(btVector3 & center,btVector3 & extend) const { center = (m_max+m_min)*0.5f; extend = m_max - center; } //! Finds the intersecting box between this box and the other. SIMD_FORCE_INLINE void find_intersection(const btAABB & other, btAABB & intersection) const { intersection.m_min[0] = BT_MAX(other.m_min[0],m_min[0]); intersection.m_min[1] = BT_MAX(other.m_min[1],m_min[1]); intersection.m_min[2] = BT_MAX(other.m_min[2],m_min[2]); intersection.m_max[0] = BT_MIN(other.m_max[0],m_max[0]); intersection.m_max[1] = BT_MIN(other.m_max[1],m_max[1]); intersection.m_max[2] = BT_MIN(other.m_max[2],m_max[2]); } SIMD_FORCE_INLINE bool has_collision(const btAABB & other) const { if(m_min[0] > other.m_max[0] || m_max[0] < other.m_min[0] || m_min[1] > other.m_max[1] || m_max[1] < other.m_min[1] || m_min[2] > other.m_max[2] || m_max[2] < other.m_min[2]) { return false; } return true; } /*! \brief Finds the Ray intersection parameter. \param aabb Aligned box \param vorigin A vec3f with the origin of the ray \param vdir A vec3f with the direction of the ray */ SIMD_FORCE_INLINE bool collide_ray(const btVector3 & vorigin,const btVector3 & vdir) const { btVector3 extents,center; this->get_center_extend(center,extents);; btScalar Dx = vorigin[0] - center[0]; if(BT_GREATER(Dx, extents[0]) && Dx*vdir[0]>=0.0f) return false; btScalar Dy = vorigin[1] - center[1]; if(BT_GREATER(Dy, extents[1]) && Dy*vdir[1]>=0.0f) return false; btScalar Dz = vorigin[2] - center[2]; if(BT_GREATER(Dz, extents[2]) && Dz*vdir[2]>=0.0f) return false; btScalar f = vdir[1] * Dz - vdir[2] * Dy; if(btFabs(f) > extents[1]*btFabs(vdir[2]) + extents[2]*btFabs(vdir[1])) return false; f = vdir[2] * Dx - vdir[0] * Dz; if(btFabs(f) > extents[0]*btFabs(vdir[2]) + extents[2]*btFabs(vdir[0]))return false; f = vdir[0] * Dy - vdir[1] * Dx; if(btFabs(f) > extents[0]*btFabs(vdir[1]) + extents[1]*btFabs(vdir[0]))return false; return true; } SIMD_FORCE_INLINE void projection_interval(const btVector3 & direction, btScalar &vmin, btScalar &vmax) const { btVector3 center = (m_max+m_min)*0.5f; btVector3 extend = m_max-center; btScalar _fOrigin = direction.dot(center); btScalar _fMaximumExtent = extend.dot(direction.absolute()); vmin = _fOrigin - _fMaximumExtent; vmax = _fOrigin + _fMaximumExtent; } SIMD_FORCE_INLINE eBT_PLANE_INTERSECTION_TYPE plane_classify(const btVector4 &plane) const { btScalar _fmin,_fmax; this->projection_interval(plane,_fmin,_fmax); if(plane[3] > _fmax + BOX_PLANE_EPSILON) { return BT_CONST_BACK_PLANE; // 0 } if(plane[3]+BOX_PLANE_EPSILON >=_fmin) { return BT_CONST_COLLIDE_PLANE; //1 } return BT_CONST_FRONT_PLANE;//2 } SIMD_FORCE_INLINE bool overlapping_trans_conservative(const btAABB & box, btTransform & trans1_to_0) const { btAABB tbox = box; tbox.appy_transform(trans1_to_0); return has_collision(tbox); } SIMD_FORCE_INLINE bool overlapping_trans_conservative2(const btAABB & box, const BT_BOX_BOX_TRANSFORM_CACHE & trans1_to_0) const { btAABB tbox = box; tbox.appy_transform_trans_cache(trans1_to_0); return has_collision(tbox); } //! transcache is the transformation cache from box to this AABB SIMD_FORCE_INLINE bool overlapping_trans_cache( const btAABB & box,const BT_BOX_BOX_TRANSFORM_CACHE & transcache, bool fulltest) const { //Taken from OPCODE btVector3 ea,eb;//extends btVector3 ca,cb;//extends get_center_extend(ca,ea); box.get_center_extend(cb,eb); btVector3 T; btScalar t,t2; int i; // Class I : A's basis vectors for(i=0;i<3;i++) { T[i] = transcache.m_R1to0[i].dot(cb) + transcache.m_T1to0[i] - ca[i]; t = transcache.m_AR[i].dot(eb) + ea[i]; if(BT_GREATER(T[i], t)) return false; } // Class II : B's basis vectors for(i=0;i<3;i++) { t = bt_mat3_dot_col(transcache.m_R1to0,T,i); t2 = bt_mat3_dot_col(transcache.m_AR,ea,i) + eb[i]; if(BT_GREATER(t,t2)) return false; } // Class III : 9 cross products if(fulltest) { int j,m,n,o,p,q,r; for(i=0;i<3;i++) { m = (i+1)%3; n = (i+2)%3; o = i==0?1:0; p = i==2?1:2; for(j=0;j<3;j++) { q = j==2?1:2; r = j==0?1:0; t = T[n]*transcache.m_R1to0[m][j] - T[m]*transcache.m_R1to0[n][j]; t2 = ea[o]*transcache.m_AR[p][j] + ea[p]*transcache.m_AR[o][j] + eb[r]*transcache.m_AR[i][q] + eb[q]*transcache.m_AR[i][r]; if(BT_GREATER(t,t2)) return false; } } } return true; } //! Simple test for planes. SIMD_FORCE_INLINE bool collide_plane( const btVector4 & plane) const { eBT_PLANE_INTERSECTION_TYPE classify = plane_classify(plane); return (classify == BT_CONST_COLLIDE_PLANE); } //! test for a triangle, with edges SIMD_FORCE_INLINE bool collide_triangle_exact( const btVector3 & p1, const btVector3 & p2, const btVector3 & p3, const btVector4 & triangle_plane) const { if(!collide_plane(triangle_plane)) return false; btVector3 center,extends; this->get_center_extend(center,extends); const btVector3 v1(p1 - center); const btVector3 v2(p2 - center); const btVector3 v3(p3 - center); //First axis btVector3 diff(v2 - v1); btVector3 abs_diff = diff.absolute(); //Test With X axis TEST_CROSS_EDGE_BOX_X_AXIS_MCR(diff,abs_diff,v1,v3,extends); //Test With Y axis TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(diff,abs_diff,v1,v3,extends); //Test With Z axis TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(diff,abs_diff,v1,v3,extends); diff = v3 - v2; abs_diff = diff.absolute(); //Test With X axis TEST_CROSS_EDGE_BOX_X_AXIS_MCR(diff,abs_diff,v2,v1,extends); //Test With Y axis TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(diff,abs_diff,v2,v1,extends); //Test With Z axis TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(diff,abs_diff,v2,v1,extends); diff = v1 - v3; abs_diff = diff.absolute(); //Test With X axis TEST_CROSS_EDGE_BOX_X_AXIS_MCR(diff,abs_diff,v3,v2,extends); //Test With Y axis TEST_CROSS_EDGE_BOX_Y_AXIS_MCR(diff,abs_diff,v3,v2,extends); //Test With Z axis TEST_CROSS_EDGE_BOX_Z_AXIS_MCR(diff,abs_diff,v3,v2,extends); return true; } }; //! Compairison of transformation objects SIMD_FORCE_INLINE bool btCompareTransformsEqual(const btTransform & t1,const btTransform & t2) { if(!(t1.getOrigin() == t2.getOrigin()) ) return false; if(!(t1.getBasis().getRow(0) == t2.getBasis().getRow(0)) ) return false; if(!(t1.getBasis().getRow(1) == t2.getBasis().getRow(1)) ) return false; if(!(t1.getBasis().getRow(2) == t2.getBasis().getRow(2)) ) return false; return true; } #endif // GIM_BOX_COLLISION_H_INCLUDED critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/btGImpactBvh.h0000644000175000017500000002221211337071441026125 0ustar bobkebobke#ifndef GIM_BOX_SET_H_INCLUDED #define GIM_BOX_SET_H_INCLUDED /*! \file gim_box_set.h \author Francisco Len Njera */ /* This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com 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 "LinearMath/btAlignedObjectArray.h" #include "btBoxCollision.h" #include "btTriangleShapeEx.h" //! Overlapping pair struct GIM_PAIR { int m_index1; int m_index2; GIM_PAIR() {} GIM_PAIR(const GIM_PAIR & p) { m_index1 = p.m_index1; m_index2 = p.m_index2; } GIM_PAIR(int index1, int index2) { m_index1 = index1; m_index2 = index2; } }; //! A pairset array class btPairSet: public btAlignedObjectArray { public: btPairSet() { reserve(32); } inline void push_pair(int index1,int index2) { push_back(GIM_PAIR(index1,index2)); } inline void push_pair_inv(int index1,int index2) { push_back(GIM_PAIR(index2,index1)); } }; ///GIM_BVH_DATA is an internal GIMPACT collision structure to contain axis aligned bounding box struct GIM_BVH_DATA { btAABB m_bound; int m_data; }; //! Node Structure for trees class GIM_BVH_TREE_NODE { public: btAABB m_bound; protected: int m_escapeIndexOrDataIndex; public: GIM_BVH_TREE_NODE() { m_escapeIndexOrDataIndex = 0; } SIMD_FORCE_INLINE bool isLeafNode() const { //skipindex is negative (internal node), triangleindex >=0 (leafnode) return (m_escapeIndexOrDataIndex>=0); } SIMD_FORCE_INLINE int getEscapeIndex() const { //btAssert(m_escapeIndexOrDataIndex < 0); return -m_escapeIndexOrDataIndex; } SIMD_FORCE_INLINE void setEscapeIndex(int index) { m_escapeIndexOrDataIndex = -index; } SIMD_FORCE_INLINE int getDataIndex() const { //btAssert(m_escapeIndexOrDataIndex >= 0); return m_escapeIndexOrDataIndex; } SIMD_FORCE_INLINE void setDataIndex(int index) { m_escapeIndexOrDataIndex = index; } }; class GIM_BVH_DATA_ARRAY:public btAlignedObjectArray { }; class GIM_BVH_TREE_NODE_ARRAY:public btAlignedObjectArray { }; //! Basic Box tree structure class btBvhTree { protected: int m_num_nodes; GIM_BVH_TREE_NODE_ARRAY m_node_array; protected: int _sort_and_calc_splitting_index( GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex, int endIndex, int splitAxis); int _calc_splitting_axis(GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex, int endIndex); void _build_sub_tree(GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex, int endIndex); public: btBvhTree() { m_num_nodes = 0; } //! prototype functions for box tree management //!@{ void build_tree(GIM_BVH_DATA_ARRAY & primitive_boxes); SIMD_FORCE_INLINE void clearNodes() { m_node_array.clear(); m_num_nodes = 0; } //! node count SIMD_FORCE_INLINE int getNodeCount() const { return m_num_nodes; } //! tells if the node is a leaf SIMD_FORCE_INLINE bool isLeafNode(int nodeindex) const { return m_node_array[nodeindex].isLeafNode(); } SIMD_FORCE_INLINE int getNodeData(int nodeindex) const { return m_node_array[nodeindex].getDataIndex(); } SIMD_FORCE_INLINE void getNodeBound(int nodeindex, btAABB & bound) const { bound = m_node_array[nodeindex].m_bound; } SIMD_FORCE_INLINE void setNodeBound(int nodeindex, const btAABB & bound) { m_node_array[nodeindex].m_bound = bound; } SIMD_FORCE_INLINE int getLeftNode(int nodeindex) const { return nodeindex+1; } SIMD_FORCE_INLINE int getRightNode(int nodeindex) const { if(m_node_array[nodeindex+1].isLeafNode()) return nodeindex+2; return nodeindex+1 + m_node_array[nodeindex+1].getEscapeIndex(); } SIMD_FORCE_INLINE int getEscapeNodeIndex(int nodeindex) const { return m_node_array[nodeindex].getEscapeIndex(); } SIMD_FORCE_INLINE const GIM_BVH_TREE_NODE * get_node_pointer(int index = 0) const { return &m_node_array[index]; } //!@} }; //! Prototype Base class for primitive classification /*! This class is a wrapper for primitive collections. This tells relevant info for the Bounding Box set classes, which take care of space classification. This class can manage Compound shapes and trimeshes, and if it is managing trimesh then the Hierarchy Bounding Box classes will take advantage of primitive Vs Box overlapping tests for getting optimal results and less Per Box compairisons. */ class btPrimitiveManagerBase { public: virtual ~btPrimitiveManagerBase() {} //! determines if this manager consist on only triangles, which special case will be optimized virtual bool is_trimesh() const = 0; virtual int get_primitive_count() const = 0; virtual void get_primitive_box(int prim_index ,btAABB & primbox) const = 0; //! retrieves only the points of the triangle, and the collision margin virtual void get_primitive_triangle(int prim_index,btPrimitiveTriangle & triangle) const= 0; }; //! Structure for containing Boxes /*! This class offers an structure for managing a box tree of primitives. Requires a Primitive prototype (like btPrimitiveManagerBase ) */ class btGImpactBvh { protected: btBvhTree m_box_tree; btPrimitiveManagerBase * m_primitive_manager; protected: //stackless refit void refit(); public: //! this constructor doesn't build the tree. you must call buildSet btGImpactBvh() { m_primitive_manager = NULL; } //! this constructor doesn't build the tree. you must call buildSet btGImpactBvh(btPrimitiveManagerBase * primitive_manager) { m_primitive_manager = primitive_manager; } SIMD_FORCE_INLINE btAABB getGlobalBox() const { btAABB totalbox; getNodeBound(0, totalbox); return totalbox; } SIMD_FORCE_INLINE void setPrimitiveManager(btPrimitiveManagerBase * primitive_manager) { m_primitive_manager = primitive_manager; } SIMD_FORCE_INLINE btPrimitiveManagerBase * getPrimitiveManager() const { return m_primitive_manager; } //! node manager prototype functions ///@{ //! this attemps to refit the box set. SIMD_FORCE_INLINE void update() { refit(); } //! this rebuild the entire set void buildSet(); //! returns the indices of the primitives in the m_primitive_manager bool boxQuery(const btAABB & box, btAlignedObjectArray & collided_results) const; //! returns the indices of the primitives in the m_primitive_manager SIMD_FORCE_INLINE bool boxQueryTrans(const btAABB & box, const btTransform & transform, btAlignedObjectArray & collided_results) const { btAABB transbox=box; transbox.appy_transform(transform); return boxQuery(transbox,collided_results); } //! returns the indices of the primitives in the m_primitive_manager bool rayQuery( const btVector3 & ray_dir,const btVector3 & ray_origin , btAlignedObjectArray & collided_results) const; //! tells if this set has hierarcht SIMD_FORCE_INLINE bool hasHierarchy() const { return true; } //! tells if this set is a trimesh SIMD_FORCE_INLINE bool isTrimesh() const { return m_primitive_manager->is_trimesh(); } //! node count SIMD_FORCE_INLINE int getNodeCount() const { return m_box_tree.getNodeCount(); } //! tells if the node is a leaf SIMD_FORCE_INLINE bool isLeafNode(int nodeindex) const { return m_box_tree.isLeafNode(nodeindex); } SIMD_FORCE_INLINE int getNodeData(int nodeindex) const { return m_box_tree.getNodeData(nodeindex); } SIMD_FORCE_INLINE void getNodeBound(int nodeindex, btAABB & bound) const { m_box_tree.getNodeBound(nodeindex, bound); } SIMD_FORCE_INLINE void setNodeBound(int nodeindex, const btAABB & bound) { m_box_tree.setNodeBound(nodeindex, bound); } SIMD_FORCE_INLINE int getLeftNode(int nodeindex) const { return m_box_tree.getLeftNode(nodeindex); } SIMD_FORCE_INLINE int getRightNode(int nodeindex) const { return m_box_tree.getRightNode(nodeindex); } SIMD_FORCE_INLINE int getEscapeNodeIndex(int nodeindex) const { return m_box_tree.getEscapeNodeIndex(nodeindex); } SIMD_FORCE_INLINE void getNodeTriangle(int nodeindex,btPrimitiveTriangle & triangle) const { m_primitive_manager->get_primitive_triangle(getNodeData(nodeindex),triangle); } SIMD_FORCE_INLINE const GIM_BVH_TREE_NODE * get_node_pointer(int index = 0) const { return m_box_tree.get_node_pointer(index); } static float getAverageTreeCollisionTime(); static void find_collision(btGImpactBvh * boxset1, const btTransform & trans1, btGImpactBvh * boxset2, const btTransform & trans2, btPairSet & collision_pairs); }; #endif // GIM_BOXPRUNING_H_INCLUDED critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/btGImpactCollisionAlgorithm.h0000644000175000017500000002106611337071441031216 0ustar bobkebobke/*! \file btGImpactShape.h \author Francisco Len Njera */ /* This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com 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 BVH_CONCAVE_COLLISION_ALGORITHM_H #define BVH_CONCAVE_COLLISION_ALGORITHM_H #include "BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btDispatcher.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" class btDispatcher; #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "LinearMath/btAlignedObjectArray.h" #include "btGImpactShape.h" #include "BulletCollision/CollisionShapes/btStaticPlaneShape.h" #include "BulletCollision/CollisionShapes/btCompoundShape.h" #include "BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h" #include "LinearMath/btIDebugDraw.h" //! Collision Algorithm for GImpact Shapes /*! For register this algorithm in Bullet, proceed as following: \code btCollisionDispatcher * dispatcher = static_cast(m_dynamicsWorld ->getDispatcher()); btGImpactCollisionAlgorithm::registerAlgorithm(dispatcher); \endcode */ class btGImpactCollisionAlgorithm : public btActivatingCollisionAlgorithm { protected: btCollisionAlgorithm * m_convex_algorithm; btPersistentManifold * m_manifoldPtr; btManifoldResult* m_resultOut; const btDispatcherInfo * m_dispatchInfo; int m_triface0; int m_part0; int m_triface1; int m_part1; //! Creates a new contact point SIMD_FORCE_INLINE btPersistentManifold* newContactManifold(btCollisionObject* body0,btCollisionObject* body1) { m_manifoldPtr = m_dispatcher->getNewManifold(body0,body1); return m_manifoldPtr; } SIMD_FORCE_INLINE void destroyConvexAlgorithm() { if(m_convex_algorithm) { m_convex_algorithm->~btCollisionAlgorithm(); m_dispatcher->freeCollisionAlgorithm( m_convex_algorithm); m_convex_algorithm = NULL; } } SIMD_FORCE_INLINE void destroyContactManifolds() { if(m_manifoldPtr == NULL) return; m_dispatcher->releaseManifold(m_manifoldPtr); m_manifoldPtr = NULL; } SIMD_FORCE_INLINE void clearCache() { destroyContactManifolds(); destroyConvexAlgorithm(); m_triface0 = -1; m_part0 = -1; m_triface1 = -1; m_part1 = -1; } SIMD_FORCE_INLINE btPersistentManifold* getLastManifold() { return m_manifoldPtr; } // Call before process collision SIMD_FORCE_INLINE void checkManifold(btCollisionObject* body0,btCollisionObject* body1) { if(getLastManifold() == 0) { newContactManifold(body0,body1); } m_resultOut->setPersistentManifold(getLastManifold()); } // Call before process collision SIMD_FORCE_INLINE btCollisionAlgorithm * newAlgorithm(btCollisionObject* body0,btCollisionObject* body1) { checkManifold(body0,body1); btCollisionAlgorithm * convex_algorithm = m_dispatcher->findAlgorithm( body0,body1,getLastManifold()); return convex_algorithm ; } // Call before process collision SIMD_FORCE_INLINE void checkConvexAlgorithm(btCollisionObject* body0,btCollisionObject* body1) { if(m_convex_algorithm) return; m_convex_algorithm = newAlgorithm(body0,body1); } void addContactPoint(btCollisionObject * body0, btCollisionObject * body1, const btVector3 & point, const btVector3 & normal, btScalar distance); //! Collision routines //!@{ void collide_gjk_triangles(btCollisionObject * body0, btCollisionObject * body1, btGImpactMeshShapePart * shape0, btGImpactMeshShapePart * shape1, const int * pairs, int pair_count); void collide_sat_triangles(btCollisionObject * body0, btCollisionObject * body1, btGImpactMeshShapePart * shape0, btGImpactMeshShapePart * shape1, const int * pairs, int pair_count); void shape_vs_shape_collision( btCollisionObject * body0, btCollisionObject * body1, btCollisionShape * shape0, btCollisionShape * shape1); void convex_vs_convex_collision(btCollisionObject * body0, btCollisionObject * body1, btCollisionShape * shape0, btCollisionShape * shape1); void gimpact_vs_gimpact_find_pairs( const btTransform & trans0, const btTransform & trans1, btGImpactShapeInterface * shape0, btGImpactShapeInterface * shape1,btPairSet & pairset); void gimpact_vs_shape_find_pairs( const btTransform & trans0, const btTransform & trans1, btGImpactShapeInterface * shape0, btCollisionShape * shape1, btAlignedObjectArray & collided_primitives); void gimpacttrimeshpart_vs_plane_collision( btCollisionObject * body0, btCollisionObject * body1, btGImpactMeshShapePart * shape0, btStaticPlaneShape * shape1,bool swapped); public: btGImpactCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1); virtual ~btGImpactCollisionAlgorithm(); virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual void getAllContactManifolds(btManifoldArray& manifoldArray) { if (m_manifoldPtr) manifoldArray.push_back(m_manifoldPtr); } struct CreateFunc :public btCollisionAlgorithmCreateFunc { virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btGImpactCollisionAlgorithm)); return new(mem) btGImpactCollisionAlgorithm(ci,body0,body1); } }; //! Use this function for register the algorithm externally static void registerAlgorithm(btCollisionDispatcher * dispatcher); //! Gets the average time in miliseconds of tree collisions static float getAverageTreeCollisionTime(); //! Gets the average time in miliseconds of triangle collisions static float getAverageTriangleCollisionTime(); //! Collides two gimpact shapes /*! \pre shape0 and shape1 couldn't be btGImpactMeshShape objects */ void gimpact_vs_gimpact(btCollisionObject * body0, btCollisionObject * body1, btGImpactShapeInterface * shape0, btGImpactShapeInterface * shape1); void gimpact_vs_shape(btCollisionObject * body0, btCollisionObject * body1, btGImpactShapeInterface * shape0, btCollisionShape * shape1,bool swapped); void gimpact_vs_compoundshape(btCollisionObject * body0, btCollisionObject * body1, btGImpactShapeInterface * shape0, btCompoundShape * shape1,bool swapped); void gimpact_vs_concave( btCollisionObject * body0, btCollisionObject * body1, btGImpactShapeInterface * shape0, btConcaveShape * shape1,bool swapped); /// Accessor/Mutator pairs for Part and triangleID void setFace0(int value) { m_triface0 = value; } int getFace0() { return m_triface0; } void setFace1(int value) { m_triface1 = value; } int getFace1() { return m_triface1; } void setPart0(int value) { m_part0 = value; } int getPart0() { return m_part0; } void setPart1(int value) { m_part1 = value; } int getPart1() { return m_part1; } }; //algorithm details //#define BULLET_TRIANGLE_COLLISION 1 #define GIMPACT_VS_PLANE_COLLISION 1 #endif //BVH_CONCAVE_COLLISION_ALGORITHM_H critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/gim_geometry.h0000644000175000017500000000311311337071441026301 0ustar bobkebobke#ifndef GIM_GEOMETRY_H_INCLUDED #define GIM_GEOMETRY_H_INCLUDED /*! \file gim_geometry.h \author Francisco Len Njera */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. (3) The zlib/libpng license that is included with this library in the file GIMPACT-LICENSE-ZLIB.TXT. 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 files GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ ///Additional Headers for Collision #include "gim_basic_geometry_operations.h" #include "gim_clip_polygon.h" #include "gim_box_collision.h" #include "gim_tri_collision.h" #endif // GIM_VECTOR_H_INCLUDED critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/btGImpactQuantizedBvh.h0000644000175000017500000002233111337071441030014 0ustar bobkebobke#ifndef GIM_QUANTIZED_SET_H_INCLUDED #define GIM_QUANTIZED_SET_H_INCLUDED /*! \file btGImpactQuantizedBvh.h \author Francisco Len Njera */ /* This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com 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 "btGImpactBvh.h" #include "btQuantization.h" ///btQuantizedBvhNode is a compressed aabb node, 16 bytes. ///Node can be used for leafnode or internal node. Leafnodes can point to 32-bit triangle index (non-negative range). ATTRIBUTE_ALIGNED16 (struct) BT_QUANTIZED_BVH_NODE { //12 bytes unsigned short int m_quantizedAabbMin[3]; unsigned short int m_quantizedAabbMax[3]; //4 bytes int m_escapeIndexOrDataIndex; BT_QUANTIZED_BVH_NODE() { m_escapeIndexOrDataIndex = 0; } SIMD_FORCE_INLINE bool isLeafNode() const { //skipindex is negative (internal node), triangleindex >=0 (leafnode) return (m_escapeIndexOrDataIndex>=0); } SIMD_FORCE_INLINE int getEscapeIndex() const { //btAssert(m_escapeIndexOrDataIndex < 0); return -m_escapeIndexOrDataIndex; } SIMD_FORCE_INLINE void setEscapeIndex(int index) { m_escapeIndexOrDataIndex = -index; } SIMD_FORCE_INLINE int getDataIndex() const { //btAssert(m_escapeIndexOrDataIndex >= 0); return m_escapeIndexOrDataIndex; } SIMD_FORCE_INLINE void setDataIndex(int index) { m_escapeIndexOrDataIndex = index; } SIMD_FORCE_INLINE bool testQuantizedBoxOverlapp( unsigned short * quantizedMin,unsigned short * quantizedMax) const { if(m_quantizedAabbMin[0] > quantizedMax[0] || m_quantizedAabbMax[0] < quantizedMin[0] || m_quantizedAabbMin[1] > quantizedMax[1] || m_quantizedAabbMax[1] < quantizedMin[1] || m_quantizedAabbMin[2] > quantizedMax[2] || m_quantizedAabbMax[2] < quantizedMin[2]) { return false; } return true; } }; class GIM_QUANTIZED_BVH_NODE_ARRAY:public btAlignedObjectArray { }; //! Basic Box tree structure class btQuantizedBvhTree { protected: int m_num_nodes; GIM_QUANTIZED_BVH_NODE_ARRAY m_node_array; btAABB m_global_bound; btVector3 m_bvhQuantization; protected: void calc_quantization(GIM_BVH_DATA_ARRAY & primitive_boxes, btScalar boundMargin = btScalar(1.0) ); int _sort_and_calc_splitting_index( GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex, int endIndex, int splitAxis); int _calc_splitting_axis(GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex, int endIndex); void _build_sub_tree(GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex, int endIndex); public: btQuantizedBvhTree() { m_num_nodes = 0; } //! prototype functions for box tree management //!@{ void build_tree(GIM_BVH_DATA_ARRAY & primitive_boxes); SIMD_FORCE_INLINE void quantizePoint( unsigned short * quantizedpoint, const btVector3 & point) const { bt_quantize_clamp(quantizedpoint,point,m_global_bound.m_min,m_global_bound.m_max,m_bvhQuantization); } SIMD_FORCE_INLINE bool testQuantizedBoxOverlapp( int node_index, unsigned short * quantizedMin,unsigned short * quantizedMax) const { return m_node_array[node_index].testQuantizedBoxOverlapp(quantizedMin,quantizedMax); } SIMD_FORCE_INLINE void clearNodes() { m_node_array.clear(); m_num_nodes = 0; } //! node count SIMD_FORCE_INLINE int getNodeCount() const { return m_num_nodes; } //! tells if the node is a leaf SIMD_FORCE_INLINE bool isLeafNode(int nodeindex) const { return m_node_array[nodeindex].isLeafNode(); } SIMD_FORCE_INLINE int getNodeData(int nodeindex) const { return m_node_array[nodeindex].getDataIndex(); } SIMD_FORCE_INLINE void getNodeBound(int nodeindex, btAABB & bound) const { bound.m_min = bt_unquantize( m_node_array[nodeindex].m_quantizedAabbMin, m_global_bound.m_min,m_bvhQuantization); bound.m_max = bt_unquantize( m_node_array[nodeindex].m_quantizedAabbMax, m_global_bound.m_min,m_bvhQuantization); } SIMD_FORCE_INLINE void setNodeBound(int nodeindex, const btAABB & bound) { bt_quantize_clamp( m_node_array[nodeindex].m_quantizedAabbMin, bound.m_min, m_global_bound.m_min, m_global_bound.m_max, m_bvhQuantization); bt_quantize_clamp( m_node_array[nodeindex].m_quantizedAabbMax, bound.m_max, m_global_bound.m_min, m_global_bound.m_max, m_bvhQuantization); } SIMD_FORCE_INLINE int getLeftNode(int nodeindex) const { return nodeindex+1; } SIMD_FORCE_INLINE int getRightNode(int nodeindex) const { if(m_node_array[nodeindex+1].isLeafNode()) return nodeindex+2; return nodeindex+1 + m_node_array[nodeindex+1].getEscapeIndex(); } SIMD_FORCE_INLINE int getEscapeNodeIndex(int nodeindex) const { return m_node_array[nodeindex].getEscapeIndex(); } SIMD_FORCE_INLINE const BT_QUANTIZED_BVH_NODE * get_node_pointer(int index = 0) const { return &m_node_array[index]; } //!@} }; //! Structure for containing Boxes /*! This class offers an structure for managing a box tree of primitives. Requires a Primitive prototype (like btPrimitiveManagerBase ) */ class btGImpactQuantizedBvh { protected: btQuantizedBvhTree m_box_tree; btPrimitiveManagerBase * m_primitive_manager; protected: //stackless refit void refit(); public: //! this constructor doesn't build the tree. you must call buildSet btGImpactQuantizedBvh() { m_primitive_manager = NULL; } //! this constructor doesn't build the tree. you must call buildSet btGImpactQuantizedBvh(btPrimitiveManagerBase * primitive_manager) { m_primitive_manager = primitive_manager; } SIMD_FORCE_INLINE btAABB getGlobalBox() const { btAABB totalbox; getNodeBound(0, totalbox); return totalbox; } SIMD_FORCE_INLINE void setPrimitiveManager(btPrimitiveManagerBase * primitive_manager) { m_primitive_manager = primitive_manager; } SIMD_FORCE_INLINE btPrimitiveManagerBase * getPrimitiveManager() const { return m_primitive_manager; } //! node manager prototype functions ///@{ //! this attemps to refit the box set. SIMD_FORCE_INLINE void update() { refit(); } //! this rebuild the entire set void buildSet(); //! returns the indices of the primitives in the m_primitive_manager bool boxQuery(const btAABB & box, btAlignedObjectArray & collided_results) const; //! returns the indices of the primitives in the m_primitive_manager SIMD_FORCE_INLINE bool boxQueryTrans(const btAABB & box, const btTransform & transform, btAlignedObjectArray & collided_results) const { btAABB transbox=box; transbox.appy_transform(transform); return boxQuery(transbox,collided_results); } //! returns the indices of the primitives in the m_primitive_manager bool rayQuery( const btVector3 & ray_dir,const btVector3 & ray_origin , btAlignedObjectArray & collided_results) const; //! tells if this set has hierarcht SIMD_FORCE_INLINE bool hasHierarchy() const { return true; } //! tells if this set is a trimesh SIMD_FORCE_INLINE bool isTrimesh() const { return m_primitive_manager->is_trimesh(); } //! node count SIMD_FORCE_INLINE int getNodeCount() const { return m_box_tree.getNodeCount(); } //! tells if the node is a leaf SIMD_FORCE_INLINE bool isLeafNode(int nodeindex) const { return m_box_tree.isLeafNode(nodeindex); } SIMD_FORCE_INLINE int getNodeData(int nodeindex) const { return m_box_tree.getNodeData(nodeindex); } SIMD_FORCE_INLINE void getNodeBound(int nodeindex, btAABB & bound) const { m_box_tree.getNodeBound(nodeindex, bound); } SIMD_FORCE_INLINE void setNodeBound(int nodeindex, const btAABB & bound) { m_box_tree.setNodeBound(nodeindex, bound); } SIMD_FORCE_INLINE int getLeftNode(int nodeindex) const { return m_box_tree.getLeftNode(nodeindex); } SIMD_FORCE_INLINE int getRightNode(int nodeindex) const { return m_box_tree.getRightNode(nodeindex); } SIMD_FORCE_INLINE int getEscapeNodeIndex(int nodeindex) const { return m_box_tree.getEscapeNodeIndex(nodeindex); } SIMD_FORCE_INLINE void getNodeTriangle(int nodeindex,btPrimitiveTriangle & triangle) const { m_primitive_manager->get_primitive_triangle(getNodeData(nodeindex),triangle); } SIMD_FORCE_INLINE const BT_QUANTIZED_BVH_NODE * get_node_pointer(int index = 0) const { return m_box_tree.get_node_pointer(index); } static float getAverageTreeCollisionTime(); static void find_collision(btGImpactQuantizedBvh * boxset1, const btTransform & trans1, btGImpactQuantizedBvh * boxset2, const btTransform & trans2, btPairSet & collision_pairs); }; #endif // GIM_BOXPRUNING_H_INCLUDED critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/gim_radixsort.h0000644000175000017500000002250611337071441026474 0ustar bobkebobke#ifndef GIM_RADIXSORT_H_INCLUDED #define GIM_RADIXSORT_H_INCLUDED /*! \file gim_radixsort.h \author Francisco Len Njera. Based on the work of Michael Herf : "fast floating-point radix sort" Avaliable on http://www.stereopsis.com/radix.html */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. (3) The zlib/libpng license that is included with this library in the file GIMPACT-LICENSE-ZLIB.TXT. 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 files GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "gim_memory.h" ///Macros for sorting. //! Prototype for comparators class less_comparator { public: template inline int operator() ( const T& a, const Z& b ) { return ( ab?1:0)); } }; //! Prototype for comparators class integer_comparator { public: template inline int operator() ( const T& a, const T& b ) { return (int)(a-b); } }; //!Prototype for getting the integer representation of an object class uint_key_func { public: template inline GUINT operator()( const T& a) { return (GUINT)a; } }; //!Prototype for copying elements class copy_elements_func { public: template inline void operator()(T& a,T& b) { a = b; } }; //!Prototype for copying elements class memcopy_elements_func { public: template inline void operator()(T& a,T& b) { gim_simd_memcpy(&a,&b,sizeof(T)); } }; //! @{ struct GIM_RSORT_TOKEN { GUINT m_key; GUINT m_value; GIM_RSORT_TOKEN() { } GIM_RSORT_TOKEN(const GIM_RSORT_TOKEN& rtoken) { m_key = rtoken.m_key; m_value = rtoken.m_value; } inline bool operator <(const GIM_RSORT_TOKEN& other) const { return (m_key < other.m_key); } inline bool operator >(const GIM_RSORT_TOKEN& other) const { return (m_key > other.m_key); } }; //! Prototype for comparators class GIM_RSORT_TOKEN_COMPARATOR { public: inline int operator()( const GIM_RSORT_TOKEN& a, const GIM_RSORT_TOKEN& b ) { return (int)((a.m_key) - (b.m_key)); } }; #define kHist 2048 // ---- utils for accessing 11-bit quantities #define D11_0(x) (x & 0x7FF) #define D11_1(x) (x >> 11 & 0x7FF) #define D11_2(x) (x >> 22 ) ///Radix sort for unsigned integer keys inline void gim_radix_sort_rtokens( GIM_RSORT_TOKEN * array, GIM_RSORT_TOKEN * sorted, GUINT element_count) { GUINT i; GUINT b0[kHist * 3]; GUINT *b1 = b0 + kHist; GUINT *b2 = b1 + kHist; for (i = 0; i < kHist * 3; ++i) { b0[i] = 0; } GUINT fi; GUINT pos; for (i = 0; i < element_count; ++i) { fi = array[i].m_key; b0[D11_0(fi)] ++; b1[D11_1(fi)] ++; b2[D11_2(fi)] ++; } { GUINT sum0 = 0, sum1 = 0, sum2 = 0; GUINT tsum; for (i = 0; i < kHist; ++i) { tsum = b0[i] + sum0; b0[i] = sum0 - 1; sum0 = tsum; tsum = b1[i] + sum1; b1[i] = sum1 - 1; sum1 = tsum; tsum = b2[i] + sum2; b2[i] = sum2 - 1; sum2 = tsum; } } for (i = 0; i < element_count; ++i) { fi = array[i].m_key; pos = D11_0(fi); pos = ++b0[pos]; sorted[pos].m_key = array[i].m_key; sorted[pos].m_value = array[i].m_value; } for (i = 0; i < element_count; ++i) { fi = sorted[i].m_key; pos = D11_1(fi); pos = ++b1[pos]; array[pos].m_key = sorted[i].m_key; array[pos].m_value = sorted[i].m_value; } for (i = 0; i < element_count; ++i) { fi = array[i].m_key; pos = D11_2(fi); pos = ++b2[pos]; sorted[pos].m_key = array[i].m_key; sorted[pos].m_value = array[i].m_value; } } /// Get the sorted tokens from an array. For generic use. Tokens are IRR_RSORT_TOKEN /*! *\param array Array of elements to sort *\param sorted_tokens Tokens of sorted elements *\param element_count element count *\param uintkey_macro Functor which retrieves the integer representation of an array element */ template void gim_radix_sort_array_tokens( T* array , GIM_RSORT_TOKEN * sorted_tokens, GUINT element_count,GETKEY_CLASS uintkey_macro) { GIM_RSORT_TOKEN * _unsorted = (GIM_RSORT_TOKEN *) gim_alloc(sizeof(GIM_RSORT_TOKEN)*element_count); for (GUINT _i=0;_i void gim_radix_sort( T * array, GUINT element_count, GETKEY_CLASS get_uintkey_macro, COPY_CLASS copy_elements_macro) { GIM_RSORT_TOKEN * _sorted = (GIM_RSORT_TOKEN *) gim_alloc(sizeof(GIM_RSORT_TOKEN)*element_count); gim_radix_sort_array_tokens(array,_sorted,element_count,get_uintkey_macro); T * _original_array = (T *) gim_alloc(sizeof(T)*element_count); gim_simd_memcpy(_original_array,array,sizeof(T)*element_count); for (GUINT _i=0;_i bool gim_binary_search_ex( const T* _array, GUINT _start_i, GUINT _end_i,GUINT & _result_index, const KEYCLASS & _search_key, COMP_CLASS _comp_macro) { GUINT _k; int _comp_result; GUINT _i = _start_i; GUINT _j = _end_i+1; while (_i < _j) { _k = (_j+_i-1)/2; _comp_result = _comp_macro(_array[_k], _search_key); if (_comp_result == 0) { _result_index = _k; return true; } else if (_comp_result < 0) { _i = _k+1; } else { _j = _k; } } _result_index = _i; return false; } //! Failsafe Iterative binary search,Template version /*! If the element is not found, it returns the nearest upper element position, may be the further position after the last element. \param _array \param _start_i the beginning of the array \param _end_i the ending index of the array \param _search_key Value to find \param _result_index the index of the found element, or if not found then it will get the index of the closest bigger value \return true if found, else false */ template bool gim_binary_search( const T*_array,GUINT _start_i, GUINT _end_i,const T & _search_key, GUINT & _result_index) { GUINT _i = _start_i; GUINT _j = _end_i+1; GUINT _k; while(_i < _j) { _k = (_j+_i-1)/2; if(_array[_k]==_search_key) { _result_index = _k; return true; } else if (_array[_k]<_search_key) { _i = _k+1; } else { _j = _k; } } _result_index = _i; return false; } ///heap sort from http://www.csse.monash.edu.au/~lloyd/tildeAlgDS/Sort/Heap/ template void gim_down_heap(T *pArr, GUINT k, GUINT n,COMP_CLASS CompareFunc) { /* PRE: a[k+1..N] is a heap */ /* POST: a[k..N] is a heap */ T temp = pArr[k - 1]; /* k has child(s) */ while (k <= n/2) { int child = 2*k; if ((child < (int)n) && CompareFunc(pArr[child - 1] , pArr[child])<0) { child++; } /* pick larger child */ if (CompareFunc(temp , pArr[child - 1])<0) { /* move child up */ pArr[k - 1] = pArr[child - 1]; k = child; } else { break; } } pArr[k - 1] = temp; } /*downHeap*/ template void gim_heap_sort(T *pArr, GUINT element_count, COMP_CLASS CompareFunc) { /* sort a[0..N-1], N.B. 0 to N-1 */ GUINT k; GUINT n = element_count; for (k = n/2; k > 0; k--) { gim_down_heap(pArr, k, n, CompareFunc); } /* a[1..N] is now a heap */ while ( n>=2 ) { gim_swap_elements(pArr,0,n-1); /* largest of a[0..n-1] */ --n; /* restore a[1..i-1] heap */ gim_down_heap(pArr, 1, n, CompareFunc); } } #endif // GIM_RADIXSORT_H_INCLUDED critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/btGenericPoolAllocator.cpp0000644000175000017500000001515511337071441030553 0ustar bobkebobke/*! \file btGenericPoolAllocator.cpp \author Francisco Len Njera. email projectileman@yahoo.com General purpose allocator class */ /* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btGenericPoolAllocator.h" /// *************** btGenericMemoryPool ******************/////////// size_t btGenericMemoryPool::allocate_from_free_nodes(size_t num_elements) { size_t ptr = BT_UINT_MAX; if(m_free_nodes_count == 0) return BT_UINT_MAX; // find an avaliable free node with the correct size size_t revindex = m_free_nodes_count; while(revindex-- && ptr == BT_UINT_MAX) { if(m_allocated_sizes[m_free_nodes[revindex]]>=num_elements) { ptr = revindex; } } if(ptr == BT_UINT_MAX) return BT_UINT_MAX; // not found revindex = ptr; ptr = m_free_nodes[revindex]; // post: ptr contains the node index, and revindex the index in m_free_nodes size_t finalsize = m_allocated_sizes[ptr]; finalsize -= num_elements; m_allocated_sizes[ptr] = num_elements; // post: finalsize>=0, m_allocated_sizes[ptr] has the requested size if(finalsize>0) // preserve free node, there are some free memory { m_free_nodes[revindex] = ptr + num_elements; m_allocated_sizes[ptr + num_elements] = finalsize; } else // delete free node { // swap with end m_free_nodes[revindex] = m_free_nodes[m_free_nodes_count-1]; m_free_nodes_count--; } return ptr; } size_t btGenericMemoryPool::allocate_from_pool(size_t num_elements) { if(m_allocated_count+num_elements>m_max_element_count) return BT_UINT_MAX; size_t ptr = m_allocated_count; m_allocated_sizes[m_allocated_count] = num_elements; m_allocated_count+=num_elements; return ptr; } void btGenericMemoryPool::init_pool(size_t element_size, size_t element_count) { m_allocated_count = 0; m_free_nodes_count = 0; m_element_size = element_size; m_max_element_count = element_count; m_pool = (unsigned char *) btAlignedAlloc(m_element_size*m_max_element_count,16); m_free_nodes = (size_t *) btAlignedAlloc(sizeof(size_t)*m_max_element_count,16); m_allocated_sizes = (size_t *) btAlignedAlloc(sizeof(size_t)*m_max_element_count,16); for (size_t i = 0;i< m_max_element_count;i++ ) { m_allocated_sizes[i] = 0; } } void btGenericMemoryPool::end_pool() { btAlignedFree(m_pool); btAlignedFree(m_free_nodes); btAlignedFree(m_allocated_sizes); m_allocated_count = 0; m_free_nodes_count = 0; } //! Allocates memory in pool /*! \param size_bytes size in bytes of the buffer */ void * btGenericMemoryPool::allocate(size_t size_bytes) { size_t module = size_bytes%m_element_size; size_t element_count = size_bytes/m_element_size; if(module>0) element_count++; size_t alloc_pos = allocate_from_free_nodes(element_count); // a free node is found if(alloc_pos != BT_UINT_MAX) { return get_element_data(alloc_pos); } // allocate directly on pool alloc_pos = allocate_from_pool(element_count); if(alloc_pos == BT_UINT_MAX) return NULL; // not space return get_element_data(alloc_pos); } bool btGenericMemoryPool::freeMemory(void * pointer) { unsigned char * pointer_pos = (unsigned char *)pointer; unsigned char * pool_pos = (unsigned char *)m_pool; // calc offset if(pointer_pos=get_pool_capacity()) return false;// far away // find free position m_free_nodes[m_free_nodes_count] = offset/m_element_size; m_free_nodes_count++; return true; } /// *******************! btGenericPoolAllocator *******************!/// btGenericPoolAllocator::~btGenericPoolAllocator() { // destroy pools size_t i; for (i=0;iend_pool(); btAlignedFree(m_pools[i]); } } // creates a pool btGenericMemoryPool * btGenericPoolAllocator::push_new_pool() { if(m_pool_count >= BT_DEFAULT_MAX_POOLS) return NULL; btGenericMemoryPool * newptr = (btGenericMemoryPool *)btAlignedAlloc(sizeof(btGenericMemoryPool),16); m_pools[m_pool_count] = newptr; m_pools[m_pool_count]->init_pool(m_pool_element_size,m_pool_element_count); m_pool_count++; return newptr; } void * btGenericPoolAllocator::failback_alloc(size_t size_bytes) { btGenericMemoryPool * pool = NULL; if(size_bytes<=get_pool_capacity()) { pool = push_new_pool(); } if(pool==NULL) // failback { return btAlignedAlloc(size_bytes,16); } return pool->allocate(size_bytes); } bool btGenericPoolAllocator::failback_free(void * pointer) { btAlignedFree(pointer); return true; } //! Allocates memory in pool /*! \param size_bytes size in bytes of the buffer */ void * btGenericPoolAllocator::allocate(size_t size_bytes) { void * ptr = NULL; size_t i = 0; while(iallocate(size_bytes); ++i; } if(ptr) return ptr; return failback_alloc(size_bytes); } bool btGenericPoolAllocator::freeMemory(void * pointer) { bool result = false; size_t i = 0; while(ifreeMemory(pointer); ++i; } if(result) return true; return failback_free(pointer); } /// ************** STANDARD ALLOCATOR ***************************/// #define BT_DEFAULT_POOL_SIZE 32768 #define BT_DEFAULT_POOL_ELEMENT_SIZE 8 // main allocator class GIM_STANDARD_ALLOCATOR: public btGenericPoolAllocator { public: GIM_STANDARD_ALLOCATOR():btGenericPoolAllocator(BT_DEFAULT_POOL_ELEMENT_SIZE,BT_DEFAULT_POOL_SIZE) { } }; // global allocator GIM_STANDARD_ALLOCATOR g_main_allocator; void * btPoolAlloc(size_t size) { return g_main_allocator.allocate(size); } void * btPoolRealloc(void *ptr, size_t oldsize, size_t newsize) { void * newptr = btPoolAlloc(newsize); size_t copysize = oldsize inline GREAL operator()(const CLASS_PLANE & plane, const CLASS_POINT & point) { return DISTANCE_PLANE_POINT(plane, point); } }; template SIMD_FORCE_INLINE void PLANE_CLIP_POLYGON_COLLECT( const CLASS_POINT & point0, const CLASS_POINT & point1, GREAL dist0, GREAL dist1, CLASS_POINT * clipped, GUINT & clipped_count) { GUINT _prevclassif = (dist0>G_EPSILON); GUINT _classif = (dist1>G_EPSILON); if(_classif!=_prevclassif) { GREAL blendfactor = -dist0/(dist1-dist0); VEC_BLEND(clipped[clipped_count],point0,point1,blendfactor); clipped_count++; } if(!_classif) { VEC_COPY(clipped[clipped_count],point1); clipped_count++; } } //! Clips a polygon by a plane /*! *\return The count of the clipped counts */ template SIMD_FORCE_INLINE GUINT PLANE_CLIP_POLYGON_GENERIC( const CLASS_PLANE & plane, const CLASS_POINT * polygon_points, GUINT polygon_point_count, CLASS_POINT * clipped,DISTANCE_PLANE_FUNC distance_func) { GUINT clipped_count = 0; //clip first point GREAL firstdist = distance_func(plane,polygon_points[0]);; if(!(firstdist>G_EPSILON)) { VEC_COPY(clipped[clipped_count],polygon_points[0]); clipped_count++; } GREAL olddist = firstdist; for(GUINT _i=1;_i SIMD_FORCE_INLINE GUINT PLANE_CLIP_TRIANGLE_GENERIC( const CLASS_PLANE & plane, const CLASS_POINT & point0, const CLASS_POINT & point1, const CLASS_POINT & point2, CLASS_POINT * clipped,DISTANCE_PLANE_FUNC distance_func) { GUINT clipped_count = 0; //clip first point GREAL firstdist = distance_func(plane,point0);; if(!(firstdist>G_EPSILON)) { VEC_COPY(clipped[clipped_count],point0); clipped_count++; } // point 1 GREAL olddist = firstdist; GREAL dist = distance_func(plane,point1); PLANE_CLIP_POLYGON_COLLECT( point0,point1, olddist, dist, clipped, clipped_count); olddist = dist; // point 2 dist = distance_func(plane,point2); PLANE_CLIP_POLYGON_COLLECT( point1,point2, olddist, dist, clipped, clipped_count); olddist = dist; //RETURN TO FIRST point PLANE_CLIP_POLYGON_COLLECT( point2,point0, olddist, firstdist, clipped, clipped_count); return clipped_count; } template SIMD_FORCE_INLINE GUINT PLANE_CLIP_POLYGON3D( const CLASS_PLANE & plane, const CLASS_POINT * polygon_points, GUINT polygon_point_count, CLASS_POINT * clipped) { return PLANE_CLIP_POLYGON_GENERIC(plane,polygon_points,polygon_point_count,clipped,DISTANCE_PLANE_3D_FUNC()); } template SIMD_FORCE_INLINE GUINT PLANE_CLIP_TRIANGLE3D( const CLASS_PLANE & plane, const CLASS_POINT & point0, const CLASS_POINT & point1, const CLASS_POINT & point2, CLASS_POINT * clipped) { return PLANE_CLIP_TRIANGLE_GENERIC(plane,point0,point1,point2,clipped,DISTANCE_PLANE_3D_FUNC()); } #endif // GIM_TRI_COLLISION_H_INCLUDED critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/btGImpactQuantizedBvh.cpp0000644000175000017500000003147211337071441030355 0ustar bobkebobke/*! \file gim_box_set.h \author Francisco Len Njera */ /* This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com 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 "btGImpactQuantizedBvh.h" #include "LinearMath/btQuickprof.h" #ifdef TRI_COLLISION_PROFILING btClock g_q_tree_clock; float g_q_accum_tree_collision_time = 0; int g_q_count_traversing = 0; void bt_begin_gim02_q_tree_time() { g_q_tree_clock.reset(); } void bt_end_gim02_q_tree_time() { g_q_accum_tree_collision_time += g_q_tree_clock.getTimeMicroseconds(); g_q_count_traversing++; } //! Gets the average time in miliseconds of tree collisions float btGImpactQuantizedBvh::getAverageTreeCollisionTime() { if(g_q_count_traversing == 0) return 0; float avgtime = g_q_accum_tree_collision_time; avgtime /= (float)g_q_count_traversing; g_q_accum_tree_collision_time = 0; g_q_count_traversing = 0; return avgtime; // float avgtime = g_q_count_traversing; // g_q_count_traversing = 0; // return avgtime; } #endif //TRI_COLLISION_PROFILING /////////////////////// btQuantizedBvhTree ///////////////////////////////// void btQuantizedBvhTree::calc_quantization( GIM_BVH_DATA_ARRAY & primitive_boxes, btScalar boundMargin) { //calc globa box btAABB global_bound; global_bound.invalidate(); for (int i=0;i splitValue) { //swap primitive_boxes.swap(i,splitIndex); //swapLeafNodes(i,splitIndex); splitIndex++; } } //if the splitIndex causes unbalanced trees, fix this by using the center in between startIndex and endIndex //otherwise the tree-building might fail due to stack-overflows in certain cases. //unbalanced1 is unsafe: it can cause stack overflows //bool unbalanced1 = ((splitIndex==startIndex) || (splitIndex == (endIndex-1))); //unbalanced2 should work too: always use center (perfect balanced trees) //bool unbalanced2 = true; //this should be safe too: int rangeBalancedIndices = numIndices/3; bool unbalanced = ((splitIndex<=(startIndex+rangeBalancedIndices)) || (splitIndex >=(endIndex-1-rangeBalancedIndices))); if (unbalanced) { splitIndex = startIndex+ (numIndices>>1); } btAssert(!((splitIndex==startIndex) || (splitIndex == (endIndex)))); return splitIndex; } void btQuantizedBvhTree::_build_sub_tree(GIM_BVH_DATA_ARRAY & primitive_boxes, int startIndex, int endIndex) { int curIndex = m_num_nodes; m_num_nodes++; btAssert((endIndex-startIndex)>0); if ((endIndex-startIndex)==1) { //We have a leaf node setNodeBound(curIndex,primitive_boxes[startIndex].m_bound); m_node_array[curIndex].setDataIndex(primitive_boxes[startIndex].m_data); return; } //calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'. //split axis int splitIndex = _calc_splitting_axis(primitive_boxes,startIndex,endIndex); splitIndex = _sort_and_calc_splitting_index( primitive_boxes,startIndex,endIndex, splitIndex//split axis ); //calc this node bounding box btAABB node_bound; node_bound.invalidate(); for (int i=startIndex;iget_primitive_box(getNodeData(nodecount),leafbox); setNodeBound(nodecount,leafbox); } else { //const GIM_BVH_TREE_NODE * nodepointer = get_node_pointer(nodecount); //get left bound btAABB bound; bound.invalidate(); btAABB temp_box; int child_node = getLeftNode(nodecount); if(child_node) { getNodeBound(child_node,temp_box); bound.merge(temp_box); } child_node = getRightNode(nodecount); if(child_node) { getNodeBound(child_node,temp_box); bound.merge(temp_box); } setNodeBound(nodecount,bound); } } } //! this rebuild the entire set void btGImpactQuantizedBvh::buildSet() { //obtain primitive boxes GIM_BVH_DATA_ARRAY primitive_boxes; primitive_boxes.resize(m_primitive_manager->get_primitive_count()); for (int i = 0;iget_primitive_box(i,primitive_boxes[i].m_bound); primitive_boxes[i].m_data = i; } m_box_tree.build_tree(primitive_boxes); } //! returns the indices of the primitives in the m_primitive_manager bool btGImpactQuantizedBvh::boxQuery(const btAABB & box, btAlignedObjectArray & collided_results) const { int curIndex = 0; int numNodes = getNodeCount(); //quantize box unsigned short quantizedMin[3]; unsigned short quantizedMax[3]; m_box_tree.quantizePoint(quantizedMin,box.m_min); m_box_tree.quantizePoint(quantizedMax,box.m_max); while (curIndex < numNodes) { //catch bugs in tree data bool aabbOverlap = m_box_tree.testQuantizedBoxOverlapp(curIndex, quantizedMin,quantizedMax); bool isleafnode = isLeafNode(curIndex); if (isleafnode && aabbOverlap) { collided_results.push_back(getNodeData(curIndex)); } if (aabbOverlap || isleafnode) { //next subnode curIndex++; } else { //skip node curIndex+= getEscapeNodeIndex(curIndex); } } if(collided_results.size()>0) return true; return false; } //! returns the indices of the primitives in the m_primitive_manager bool btGImpactQuantizedBvh::rayQuery( const btVector3 & ray_dir,const btVector3 & ray_origin , btAlignedObjectArray & collided_results) const { int curIndex = 0; int numNodes = getNodeCount(); while (curIndex < numNodes) { btAABB bound; getNodeBound(curIndex,bound); //catch bugs in tree data bool aabbOverlap = bound.collide_ray(ray_origin,ray_dir); bool isleafnode = isLeafNode(curIndex); if (isleafnode && aabbOverlap) { collided_results.push_back(getNodeData( curIndex)); } if (aabbOverlap || isleafnode) { //next subnode curIndex++; } else { //skip node curIndex+= getEscapeNodeIndex(curIndex); } } if(collided_results.size()>0) return true; return false; } SIMD_FORCE_INLINE bool _quantized_node_collision( btGImpactQuantizedBvh * boxset0, btGImpactQuantizedBvh * boxset1, const BT_BOX_BOX_TRANSFORM_CACHE & trans_cache_1to0, int node0 ,int node1, bool complete_primitive_tests) { btAABB box0; boxset0->getNodeBound(node0,box0); btAABB box1; boxset1->getNodeBound(node1,box1); return box0.overlapping_trans_cache(box1,trans_cache_1to0,complete_primitive_tests ); // box1.appy_transform_trans_cache(trans_cache_1to0); // return box0.has_collision(box1); } //stackless recursive collision routine static void _find_quantized_collision_pairs_recursive( btGImpactQuantizedBvh * boxset0, btGImpactQuantizedBvh * boxset1, btPairSet * collision_pairs, const BT_BOX_BOX_TRANSFORM_CACHE & trans_cache_1to0, int node0, int node1, bool complete_primitive_tests) { if( _quantized_node_collision( boxset0,boxset1,trans_cache_1to0, node0,node1,complete_primitive_tests) ==false) return;//avoid colliding internal nodes if(boxset0->isLeafNode(node0)) { if(boxset1->isLeafNode(node1)) { // collision result collision_pairs->push_pair( boxset0->getNodeData(node0),boxset1->getNodeData(node1)); return; } else { //collide left recursive _find_quantized_collision_pairs_recursive( boxset0,boxset1, collision_pairs,trans_cache_1to0, node0,boxset1->getLeftNode(node1),false); //collide right recursive _find_quantized_collision_pairs_recursive( boxset0,boxset1, collision_pairs,trans_cache_1to0, node0,boxset1->getRightNode(node1),false); } } else { if(boxset1->isLeafNode(node1)) { //collide left recursive _find_quantized_collision_pairs_recursive( boxset0,boxset1, collision_pairs,trans_cache_1to0, boxset0->getLeftNode(node0),node1,false); //collide right recursive _find_quantized_collision_pairs_recursive( boxset0,boxset1, collision_pairs,trans_cache_1to0, boxset0->getRightNode(node0),node1,false); } else { //collide left0 left1 _find_quantized_collision_pairs_recursive( boxset0,boxset1, collision_pairs,trans_cache_1to0, boxset0->getLeftNode(node0),boxset1->getLeftNode(node1),false); //collide left0 right1 _find_quantized_collision_pairs_recursive( boxset0,boxset1, collision_pairs,trans_cache_1to0, boxset0->getLeftNode(node0),boxset1->getRightNode(node1),false); //collide right0 left1 _find_quantized_collision_pairs_recursive( boxset0,boxset1, collision_pairs,trans_cache_1to0, boxset0->getRightNode(node0),boxset1->getLeftNode(node1),false); //collide right0 right1 _find_quantized_collision_pairs_recursive( boxset0,boxset1, collision_pairs,trans_cache_1to0, boxset0->getRightNode(node0),boxset1->getRightNode(node1),false); }// else if node1 is not a leaf }// else if node0 is not a leaf } void btGImpactQuantizedBvh::find_collision(btGImpactQuantizedBvh * boxset0, const btTransform & trans0, btGImpactQuantizedBvh * boxset1, const btTransform & trans1, btPairSet & collision_pairs) { if(boxset0->getNodeCount()==0 || boxset1->getNodeCount()==0 ) return; BT_BOX_BOX_TRANSFORM_CACHE trans_cache_1to0; trans_cache_1to0.calc_from_homogenic(trans0,trans1); #ifdef TRI_COLLISION_PROFILING bt_begin_gim02_q_tree_time(); #endif //TRI_COLLISION_PROFILING _find_quantized_collision_pairs_recursive( boxset0,boxset1, &collision_pairs,trans_cache_1to0,0,0,true); #ifdef TRI_COLLISION_PROFILING bt_end_gim02_q_tree_time(); #endif //TRI_COLLISION_PROFILING } critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/gim_box_set.cpp0000644000175000017500000001315211337071441026450 0ustar bobkebobke /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. (3) The zlib/libpng license that is included with this library in the file GIMPACT-LICENSE-ZLIB.TXT. 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 files GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "gim_box_set.h" GUINT GIM_BOX_TREE::_calc_splitting_axis( gim_array & primitive_boxes, GUINT startIndex, GUINT endIndex) { GUINT i; btVector3 means(btScalar(0.),btScalar(0.),btScalar(0.)); btVector3 variance(btScalar(0.),btScalar(0.),btScalar(0.)); GUINT numIndices = endIndex-startIndex; for (i=startIndex;i & primitive_boxes, GUINT startIndex, GUINT endIndex, GUINT splitAxis) { GUINT i; GUINT splitIndex =startIndex; GUINT numIndices = endIndex - startIndex; // average of centers btScalar splitValue = 0.0f; for (i=startIndex;i splitValue) { //swap primitive_boxes.swap(i,splitIndex); splitIndex++; } } //if the splitIndex causes unbalanced trees, fix this by using the center in between startIndex and endIndex //otherwise the tree-building might fail due to stack-overflows in certain cases. //unbalanced1 is unsafe: it can cause stack overflows //bool unbalanced1 = ((splitIndex==startIndex) || (splitIndex == (endIndex-1))); //unbalanced2 should work too: always use center (perfect balanced trees) //bool unbalanced2 = true; //this should be safe too: GUINT rangeBalancedIndices = numIndices/3; bool unbalanced = ((splitIndex<=(startIndex+rangeBalancedIndices)) || (splitIndex >=(endIndex-1-rangeBalancedIndices))); if (unbalanced) { splitIndex = startIndex+ (numIndices>>1); } btAssert(!((splitIndex==startIndex) || (splitIndex == (endIndex)))); return splitIndex; } void GIM_BOX_TREE::_build_sub_tree(gim_array & primitive_boxes, GUINT startIndex, GUINT endIndex) { GUINT current_index = m_num_nodes++; btAssert((endIndex-startIndex)>0); if((endIndex-startIndex) == 1) //we got a leaf { m_node_array[current_index].m_left = 0; m_node_array[current_index].m_right = 0; m_node_array[current_index].m_escapeIndex = 0; m_node_array[current_index].m_bound = primitive_boxes[startIndex].m_bound; m_node_array[current_index].m_data = primitive_boxes[startIndex].m_data; return; } //configure inner node GUINT splitIndex; //calc this node bounding box m_node_array[current_index].m_bound.invalidate(); for (splitIndex=startIndex;splitIndex & primitive_boxes) { // initialize node count to 0 m_num_nodes = 0; // allocate nodes m_node_array.resize(primitive_boxes.size()*2); _build_sub_tree(primitive_boxes, 0, primitive_boxes.size()); } critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/gim_bitset.h0000644000175000017500000000534111337071441025745 0ustar bobkebobke#ifndef GIM_BITSET_H_INCLUDED #define GIM_BITSET_H_INCLUDED /*! \file gim_bitset.h \author Francisco Len Njera */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. (3) The zlib/libpng license that is included with this library in the file GIMPACT-LICENSE-ZLIB.TXT. 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 files GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "gim_array.h" #define GUINT_BIT_COUNT 32 #define GUINT_EXPONENT 5 class gim_bitset { public: gim_array m_container; gim_bitset() { } gim_bitset(GUINT bits_count) { resize(bits_count); } ~gim_bitset() { } inline bool resize(GUINT newsize) { GUINT oldsize = m_container.size(); m_container.resize(newsize/GUINT_BIT_COUNT + 1,false); while(oldsize=size()) { resize(bit_index); } m_container[bit_index >> GUINT_EXPONENT] |= (1 << (bit_index & (GUINT_BIT_COUNT-1))); } ///Return 0 or 1 inline char get(GUINT bit_index) { if(bit_index>=size()) { return 0; } char value = m_container[bit_index >> GUINT_EXPONENT] & (1 << (bit_index & (GUINT_BIT_COUNT-1))); return value; } inline void clear(GUINT bit_index) { m_container[bit_index >> GUINT_EXPONENT] &= ~(1 << (bit_index & (GUINT_BIT_COUNT-1))); } }; #endif // GIM_CONTAINERS_H_INCLUDED critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/gim_tri_collision.cpp0000644000175000017500000003706711337071441027671 0ustar bobkebobke /*! \file gim_tri_collision.h \author Francisco Len Njera */ /* ----------------------------------------------------------------------------- This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2006 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com This library is free software; you can redistribute it and/or modify it under the terms of EITHER: (1) The GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. The text of the GNU Lesser General Public License is included with this library in the file GIMPACT-LICENSE-LGPL.TXT. (2) The BSD-style license that is included with this library in the file GIMPACT-LICENSE-BSD.TXT. (3) The zlib/libpng license that is included with this library in the file GIMPACT-LICENSE-ZLIB.TXT. 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 files GIMPACT-LICENSE-LGPL.TXT, GIMPACT-LICENSE-ZLIB.TXT and GIMPACT-LICENSE-BSD.TXT for more details. ----------------------------------------------------------------------------- */ #include "gim_tri_collision.h" #define TRI_LOCAL_EPSILON 0.000001f #define MIN_EDGE_EDGE_DIS 0.00001f class GIM_TRIANGLE_CALCULATION_CACHE { public: GREAL margin; btVector3 tu_vertices[3]; btVector3 tv_vertices[3]; btVector4 tu_plane; btVector4 tv_plane; btVector3 closest_point_u; btVector3 closest_point_v; btVector3 edge_edge_dir; btVector3 distances; GREAL du[4]; GREAL du0du1; GREAL du0du2; GREAL dv[4]; GREAL dv0dv1; GREAL dv0dv2; btVector3 temp_points[MAX_TRI_CLIPPING]; btVector3 temp_points1[MAX_TRI_CLIPPING]; btVector3 contact_points[MAX_TRI_CLIPPING]; //! if returns false, the faces are paralele SIMD_FORCE_INLINE bool compute_intervals( const GREAL &D0, const GREAL &D1, const GREAL &D2, const GREAL &D0D1, const GREAL &D0D2, GREAL & scale_edge0, GREAL & scale_edge1, GUINT &edge_index0, GUINT &edge_index1) { 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 */ scale_edge0 = -D2/(D0-D2); scale_edge1 = -D1/(D2-D1); edge_index0 = 2;edge_index1 = 1; } else if(D0D2>0.0f) { /* here we know that d0d1<=0.0 */ scale_edge0 = -D0/(D1-D0); scale_edge1 = -D1/(D2-D1); edge_index0 = 0;edge_index1 = 1; } else if(D1*D2>0.0f || D0!=0.0f) { /* here we know that d0d1<=0.0 or that D0!=0.0 */ scale_edge0 = -D0/(D1-D0); scale_edge1 = -D2/(D0-D2); edge_index0 = 0 ;edge_index1 = 2; } else { return false; } return true; } //! clip triangle /*! */ SIMD_FORCE_INLINE GUINT clip_triangle( const btVector4 & tri_plane, const btVector3 * tripoints, const btVector3 * srcpoints, btVector3 * clip_points) { // edge 0 btVector4 edgeplane; EDGE_PLANE(tripoints[0],tripoints[1],tri_plane,edgeplane); GUINT clipped_count = PLANE_CLIP_TRIANGLE3D( edgeplane,srcpoints[0],srcpoints[1],srcpoints[2],temp_points); if(clipped_count == 0) return 0; // edge 1 EDGE_PLANE(tripoints[1],tripoints[2],tri_plane,edgeplane); clipped_count = PLANE_CLIP_POLYGON3D( edgeplane,temp_points,clipped_count,temp_points1); if(clipped_count == 0) return 0; // edge 2 EDGE_PLANE(tripoints[2],tripoints[0],tri_plane,edgeplane); clipped_count = PLANE_CLIP_POLYGON3D( edgeplane,temp_points1,clipped_count,clip_points); return clipped_count; /*GUINT i0 = (tri_plane.closestAxis()+1)%3; GUINT i1 = (i0+1)%3; // edge 0 btVector3 temp_points[MAX_TRI_CLIPPING]; btVector3 temp_points1[MAX_TRI_CLIPPING]; GUINT clipped_count= PLANE_CLIP_TRIANGLE_GENERIC( 0,srcpoints[0],srcpoints[1],srcpoints[2],temp_points, DISTANCE_EDGE(tripoints[0],tripoints[1],i0,i1)); if(clipped_count == 0) return 0; // edge 1 clipped_count = PLANE_CLIP_POLYGON_GENERIC( 0,temp_points,clipped_count,temp_points1, DISTANCE_EDGE(tripoints[1],tripoints[2],i0,i1)); if(clipped_count == 0) return 0; // edge 2 clipped_count = PLANE_CLIP_POLYGON_GENERIC( 0,temp_points1,clipped_count,clipped_points, DISTANCE_EDGE(tripoints[2],tripoints[0],i0,i1)); return clipped_count;*/ } SIMD_FORCE_INLINE void sort_isect( GREAL & isect0,GREAL & isect1,GUINT &e0,GUINT &e1,btVector3 & vec0,btVector3 & vec1) { if(isect1=isect_v[1]) // face U casts face V { return 1; } else if(isect_v[0]<=isect_u[0]) // face V casts face U { return 2; } // closest points closest_point_u = up_e1; closest_point_v = vp_e0; // calc edges and separation if(isect_u[1]+ MIN_EDGE_EDGE_DIS=isect_u[1]) // face V casts face U { return 2; } else if(isect_u[0]<=isect_v[0]) // face U casts face V { return 1; } // closest points closest_point_u = up_e0; closest_point_v = vp_e1; // calc edges and separation if(isect_v[1]+MIN_EDGE_EDGE_DIS0.0f && du0du2>0.0f) // same sign on all of them + not equal 0 ? { if(du[0]<0) //we need test behind the triangle plane { distances[0] = GIM_MAX3(du[0],du[1],du[2]); distances[0] = -distances[0]; if(distances[0]>margin) return false; //never intersect //reorder triangle v VEC_SWAP(tv_vertices[0],tv_vertices[1]); VEC_SCALE_4(tv_plane,-1.0f,tv_plane); } else { distances[0] = GIM_MIN3(du[0],du[1],du[2]); if(distances[0]>margin) return false; //never intersect } } else { //Look if we need to invert the triangle distances[0] = (du[0]+du[1]+du[2])/3.0f; //centroid if(distances[0]<0.0f) { //reorder triangle v VEC_SWAP(tv_vertices[0],tv_vertices[1]); VEC_SCALE_4(tv_plane,-1.0f,tv_plane); distances[0] = GIM_MAX3(du[0],du[1],du[2]); distances[0] = -distances[0]; } else { distances[0] = GIM_MIN3(du[0],du[1],du[2]); } } // plane U vs V points TRIANGLE_PLANE(tu_vertices[0],tu_vertices[1],tu_vertices[2],tu_plane); dv[0] = DISTANCE_PLANE_POINT(tu_plane,tv_vertices[0]); dv[1] = DISTANCE_PLANE_POINT(tu_plane,tv_vertices[1]); dv[2] = DISTANCE_PLANE_POINT(tu_plane,tv_vertices[2]); dv0dv1 = dv[0] * dv[1]; dv0dv2 = dv[0] * dv[2]; if(dv0dv1>0.0f && dv0dv2>0.0f) // same sign on all of them + not equal 0 ? { if(dv[0]<0) //we need test behind the triangle plane { distances[1] = GIM_MAX3(dv[0],dv[1],dv[2]); distances[1] = -distances[1]; if(distances[1]>margin) return false; //never intersect //reorder triangle u VEC_SWAP(tu_vertices[0],tu_vertices[1]); VEC_SCALE_4(tu_plane,-1.0f,tu_plane); } else { distances[1] = GIM_MIN3(dv[0],dv[1],dv[2]); if(distances[1]>margin) return false; //never intersect } } else { //Look if we need to invert the triangle distances[1] = (dv[0]+dv[1]+dv[2])/3.0f; //centroid if(distances[1]<0.0f) { //reorder triangle v VEC_SWAP(tu_vertices[0],tu_vertices[1]); VEC_SCALE_4(tu_plane,-1.0f,tu_plane); distances[1] = GIM_MAX3(dv[0],dv[1],dv[2]); distances[1] = -distances[1]; } else { distances[1] = GIM_MIN3(dv[0],dv[1],dv[2]); } } GUINT bl; /* bl = cross_line_intersection_test(); if(bl==3) { //take edge direction too bl = distances.maxAxis(); } else {*/ bl = 0; if(distances[0]margin) return false; contacts.m_penetration_depth = -distances[2] + margin; contacts.m_points[0] = closest_point_v; contacts.m_point_count = 1; VEC_COPY(contacts.m_separating_normal,edge_edge_dir); return true; } //clip face against other GUINT point_count; //TODO if(bl == 0) //clip U points against V { point_count = clip_triangle(tv_plane,tv_vertices,tu_vertices,contact_points); if(point_count == 0) return false; contacts.merge_points(tv_plane,margin,contact_points,point_count); } else //clip V points against U { point_count = clip_triangle(tu_plane,tu_vertices,tv_vertices,contact_points); if(point_count == 0) return false; contacts.merge_points(tu_plane,margin,contact_points,point_count); contacts.m_separating_normal *= -1.f; } if(contacts.m_point_count == 0) return false; return true; } }; /*class GIM_TRIANGLE_CALCULATION_CACHE { public: GREAL margin; GUINT clipped_count; btVector3 tu_vertices[3]; btVector3 tv_vertices[3]; btVector3 temp_points[MAX_TRI_CLIPPING]; btVector3 temp_points1[MAX_TRI_CLIPPING]; btVector3 clipped_points[MAX_TRI_CLIPPING]; GIM_TRIANGLE_CONTACT_DATA contacts1; GIM_TRIANGLE_CONTACT_DATA contacts2; //! clip triangle GUINT clip_triangle( const btVector4 & tri_plane, const btVector3 * tripoints, const btVector3 * srcpoints, btVector3 * clipped_points) { // edge 0 btVector4 edgeplane; EDGE_PLANE(tripoints[0],tripoints[1],tri_plane,edgeplane); GUINT clipped_count = PLANE_CLIP_TRIANGLE3D( edgeplane,srcpoints[0],srcpoints[1],srcpoints[2],temp_points); if(clipped_count == 0) return 0; // edge 1 EDGE_PLANE(tripoints[1],tripoints[2],tri_plane,edgeplane); clipped_count = PLANE_CLIP_POLYGON3D( edgeplane,temp_points,clipped_count,temp_points1); if(clipped_count == 0) return 0; // edge 2 EDGE_PLANE(tripoints[2],tripoints[0],tri_plane,edgeplane); clipped_count = PLANE_CLIP_POLYGON3D( edgeplane,temp_points1,clipped_count,clipped_points); return clipped_count; } //! collides only on one side bool triangle_collision( const btVector3 & u0, const btVector3 & u1, const btVector3 & u2, GREAL margin_u, const btVector3 & v0, const btVector3 & v1, const btVector3 & v2, GREAL margin_v, GIM_TRIANGLE_CONTACT_DATA & contacts) { margin = margin_u + margin_v; tu_vertices[0] = u0; tu_vertices[1] = u1; tu_vertices[2] = u2; tv_vertices[0] = v0; tv_vertices[1] = v1; tv_vertices[2] = v2; //create planes // plane v vs U points TRIANGLE_PLANE(tv_vertices[0],tv_vertices[1],tv_vertices[2],contacts1.m_separating_normal); clipped_count = clip_triangle( contacts1.m_separating_normal,tv_vertices,tu_vertices,clipped_points); if(clipped_count == 0 ) { return false;//Reject } //find most deep interval face1 contacts1.merge_points(contacts1.m_separating_normal,margin,clipped_points,clipped_count); if(contacts1.m_point_count == 0) return false; // too far //Normal pointing to triangle1 //contacts1.m_separating_normal *= -1.f; //Clip tri1 by tri2 edges TRIANGLE_PLANE(tu_vertices[0],tu_vertices[1],tu_vertices[2],contacts2.m_separating_normal); clipped_count = clip_triangle( contacts2.m_separating_normal,tu_vertices,tv_vertices,clipped_points); if(clipped_count == 0 ) { return false;//Reject } //find most deep interval face1 contacts2.merge_points(contacts2.m_separating_normal,margin,clipped_points,clipped_count); if(contacts2.m_point_count == 0) return false; // too far contacts2.m_separating_normal *= -1.f; ////check most dir for contacts if(contacts2.m_penetration_depth SIMD_FORCE_INLINE void mergepoints_generic(const CLASS_PLANE & plane, GREAL margin, const btVector3 * points, GUINT point_count, DISTANCE_FUNC distance_func) { m_point_count = 0; m_penetration_depth= -1000.0f; GUINT point_indices[MAX_TRI_CLIPPING]; GUINT _k; for(_k=0;_k=0.0f) { if(_dist>m_penetration_depth) { m_penetration_depth = _dist; point_indices[0] = _k; m_point_count=1; } else if((_dist+G_EPSILON)>=m_penetration_depth) { point_indices[m_point_count] = _k; m_point_count++; } } } for( _k=0;_k u*axe1[i1] + ((vecproj[i2] - u*axe1[i2])/axe2[i2])*axe2[i1] = vecproj[i1] --> u*axe1[i1] + vecproj[i2]*axe2[i1]/axe2[i2] - u*axe1[i2]*axe2[i1]/axe2[i2] = vecproj[i1] --> u*(axe1[i1] - axe1[i2]*axe2[i1]/axe2[i2]) = vecproj[i1] - vecproj[i2]*axe2[i1]/axe2[i2] --> u*((axe1[i1]*axe2[i2] - axe1[i2]*axe2[i1])/axe2[i2]) = (vecproj[i1]*axe2[i2] - vecproj[i2]*axe2[i1])/axe2[i2] --> u*(axe1[i1]*axe2[i2] - axe1[i2]*axe2[i1]) = vecproj[i1]*axe2[i2] - vecproj[i2]*axe2[i1] --> u = (vecproj[i1]*axe2[i2] - vecproj[i2]*axe2[i1]) /(axe1[i1]*axe2[i2] - axe1[i2]*axe2[i1]) if 0.0<= u+v <=1.0 then they are inside of triangle \return false if the point is outside of triangle.This function doesn't take the margin */ SIMD_FORCE_INLINE bool get_uv_parameters( const btVector3 & point, const btVector3 & tri_plane, GREAL & u, GREAL & v) const { btVector3 _axe1 = m_vertices[1]-m_vertices[0]; btVector3 _axe2 = m_vertices[2]-m_vertices[0]; btVector3 _vecproj = point - m_vertices[0]; GUINT _i1 = (tri_plane.closestAxis()+1)%3; GUINT _i2 = (_i1+1)%3; if(btFabs(_axe2[_i2])G_EPSILON) { return false; } } return true; } //! is point in triangle beam? /*! Test if point is in triangle, with m_margin tolerance */ SIMD_FORCE_INLINE bool is_point_inside(const btVector3 & point, const btVector3 & tri_normal) const { //Test with edge 0 btVector4 edge_plane; this->get_edge_plane(0,tri_normal,edge_plane); GREAL dist = DISTANCE_PLANE_POINT(edge_plane,point); if(dist-m_margin>0.0f) return false; // outside plane this->get_edge_plane(1,tri_normal,edge_plane); dist = DISTANCE_PLANE_POINT(edge_plane,point); if(dist-m_margin>0.0f) return false; // outside plane this->get_edge_plane(2,tri_normal,edge_plane); dist = DISTANCE_PLANE_POINT(edge_plane,point); if(dist-m_margin>0.0f) return false; // outside plane return true; } //! Bidireccional ray collision SIMD_FORCE_INLINE bool ray_collision( const btVector3 & vPoint, const btVector3 & vDir, btVector3 & pout, btVector3 & triangle_normal, GREAL & tparam, GREAL tmax = G_REAL_INFINITY) { btVector4 faceplane; { btVector3 dif1 = m_vertices[1] - m_vertices[0]; btVector3 dif2 = m_vertices[2] - m_vertices[0]; VEC_CROSS(faceplane,dif1,dif2); faceplane[3] = m_vertices[0].dot(faceplane); } GUINT res = LINE_PLANE_COLLISION(faceplane,vDir,vPoint,pout,tparam, btScalar(0), tmax); if(res == 0) return false; if(! is_point_inside(pout,faceplane)) return false; if(res==2) //invert normal { triangle_normal.setValue(-faceplane[0],-faceplane[1],-faceplane[2]); } else { triangle_normal.setValue(faceplane[0],faceplane[1],faceplane[2]); } VEC_NORMALIZE(triangle_normal); return true; } //! one direccion ray collision SIMD_FORCE_INLINE bool ray_collision_front_side( const btVector3 & vPoint, const btVector3 & vDir, btVector3 & pout, btVector3 & triangle_normal, GREAL & tparam, GREAL tmax = G_REAL_INFINITY) { btVector4 faceplane; { btVector3 dif1 = m_vertices[1] - m_vertices[0]; btVector3 dif2 = m_vertices[2] - m_vertices[0]; VEC_CROSS(faceplane,dif1,dif2); faceplane[3] = m_vertices[0].dot(faceplane); } GUINT res = LINE_PLANE_COLLISION(faceplane,vDir,vPoint,pout,tparam, btScalar(0), tmax); if(res != 1) return false; if(!is_point_inside(pout,faceplane)) return false; triangle_normal.setValue(faceplane[0],faceplane[1],faceplane[2]); VEC_NORMALIZE(triangle_normal); return true; } }; #endif // GIM_TRI_COLLISION_H_INCLUDED critterding-beta12.1/src/utils/bullet/BulletCollision/Gimpact/btContactProcessing.cpp0000644000175000017500000001024411337071441030126 0ustar bobkebobke /* This source file is part of GIMPACT Library. For the latest info, see http://gimpact.sourceforge.net/ Copyright (c) 2007 Francisco Leon Najera. C.C. 80087371. email: projectileman@yahoo.com 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 "btContactProcessing.h" #define MAX_COINCIDENT 8 struct CONTACT_KEY_TOKEN { unsigned int m_key; int m_value; CONTACT_KEY_TOKEN() { } CONTACT_KEY_TOKEN(unsigned int key,int token) { m_key = key; m_value = token; } CONTACT_KEY_TOKEN(const CONTACT_KEY_TOKEN& rtoken) { m_key = rtoken.m_key; m_value = rtoken.m_value; } inline bool operator <(const CONTACT_KEY_TOKEN& other) const { return (m_key < other.m_key); } inline bool operator >(const CONTACT_KEY_TOKEN& other) const { return (m_key > other.m_key); } }; class CONTACT_KEY_TOKEN_COMP { public: bool operator() ( const CONTACT_KEY_TOKEN& a, const CONTACT_KEY_TOKEN& b ) { return ( a < b ); } }; void btContactArray::merge_contacts( const btContactArray & contacts, bool normal_contact_average) { clear(); int i; if(contacts.size()==0) return; if(contacts.size()==1) { push_back(contacts[0]); return; } btAlignedObjectArray keycontacts; keycontacts.reserve(contacts.size()); //fill key contacts for ( i = 0;im_depth - CONTACT_DIFF_EPSILON > scontact->m_depth)//) { *pcontact = *scontact; coincident_count = 0; } else if(normal_contact_average) { if(btFabs(pcontact->m_depth - scontact->m_depth)m_normal; coincident_count++; } } } } else {//add new contact if(normal_contact_average && coincident_count>0) { pcontact->interpolate_normals(coincident_normals,coincident_count); coincident_count = 0; } push_back(*scontact); pcontact = &(*this)[this->size()-1]; } last_key = key; } } void btContactArray::merge_contacts_unique(const btContactArray & contacts) { clear(); if(contacts.size()==0) return; if(contacts.size()==1) { push_back(contacts[0]); return; } GIM_CONTACT average_contact = contacts[0]; for (int i=1;i SIMD_FORCE_INLINE bool POINT_IN_HULL( const CLASS_POINT& point,const CLASS_PLANE * planes,GUINT plane_count) { GREAL _dis; for (GUINT _i = 0;_i< plane_count;++_i) { _dis = DISTANCE_PLANE_POINT(planes[_i],point); if(_dis>0.0f) return false; } return true; } template SIMD_FORCE_INLINE void PLANE_CLIP_SEGMENT( const CLASS_POINT& s1, const CLASS_POINT &s2,const CLASS_PLANE &plane,CLASS_POINT &clipped) { GREAL _dis1,_dis2; _dis1 = DISTANCE_PLANE_POINT(plane,s1); VEC_DIFF(clipped,s2,s1); _dis2 = VEC_DOT(clipped,plane); VEC_SCALE(clipped,-_dis1/_dis2,clipped); VEC_SUM(clipped,clipped,s1); } enum ePLANE_INTERSECTION_TYPE { G_BACK_PLANE = 0, G_COLLIDE_PLANE, G_FRONT_PLANE }; enum eLINE_PLANE_INTERSECTION_TYPE { G_FRONT_PLANE_S1 = 0, G_FRONT_PLANE_S2, G_BACK_PLANE_S1, G_BACK_PLANE_S2, G_COLLIDE_PLANE_S1, G_COLLIDE_PLANE_S2 }; //! Confirms if the plane intersect the edge or nor /*! intersection type must have the following values
    • 0 : Segment in front of plane, s1 closest
    • 1 : Segment in front of plane, s2 closest
    • 2 : Segment in back of plane, s1 closest
    • 3 : Segment in back of plane, s2 closest
    • 4 : Segment collides plane, s1 in back
    • 5 : Segment collides plane, s2 in back
    */ template SIMD_FORCE_INLINE eLINE_PLANE_INTERSECTION_TYPE PLANE_CLIP_SEGMENT2( const CLASS_POINT& s1, const CLASS_POINT &s2, const CLASS_PLANE &plane,CLASS_POINT &clipped) { GREAL _dis1 = DISTANCE_PLANE_POINT(plane,s1); GREAL _dis2 = DISTANCE_PLANE_POINT(plane,s2); if(_dis1 >-G_EPSILON && _dis2 >-G_EPSILON) { if(_dis1<_dis2) return G_FRONT_PLANE_S1; return G_FRONT_PLANE_S2; } else if(_dis1 _dis2) return G_BACK_PLANE_S1; return G_BACK_PLANE_S2; } VEC_DIFF(clipped,s2,s1); _dis2 = VEC_DOT(clipped,plane); VEC_SCALE(clipped,-_dis1/_dis2,clipped); VEC_SUM(clipped,clipped,s1); if(_dis1<_dis2) return G_COLLIDE_PLANE_S1; return G_COLLIDE_PLANE_S2; } //! Confirms if the plane intersect the edge or not /*! clipped1 and clipped2 are the vertices behind the plane. clipped1 is the closest intersection_type must have the following values
    • 0 : Segment in front of plane, s1 closest
    • 1 : Segment in front of plane, s2 closest
    • 2 : Segment in back of plane, s1 closest
    • 3 : Segment in back of plane, s2 closest
    • 4 : Segment collides plane, s1 in back
    • 5 : Segment collides plane, s2 in back
    */ template SIMD_FORCE_INLINE eLINE_PLANE_INTERSECTION_TYPE PLANE_CLIP_SEGMENT_CLOSEST( const CLASS_POINT& s1, const CLASS_POINT &s2, const CLASS_PLANE &plane, CLASS_POINT &clipped1,CLASS_POINT &clipped2) { eLINE_PLANE_INTERSECTION_TYPE intersection_type = PLANE_CLIP_SEGMENT2(s1,s2,plane,clipped1); switch(intersection_type) { case G_FRONT_PLANE_S1: VEC_COPY(clipped1,s1); VEC_COPY(clipped2,s2); break; case G_FRONT_PLANE_S2: VEC_COPY(clipped1,s2); VEC_COPY(clipped2,s1); break; case G_BACK_PLANE_S1: VEC_COPY(clipped1,s1); VEC_COPY(clipped2,s2); break; case G_BACK_PLANE_S2: VEC_COPY(clipped1,s2); VEC_COPY(clipped2,s1); break; case G_COLLIDE_PLANE_S1: VEC_COPY(clipped2,s1); break; case G_COLLIDE_PLANE_S2: VEC_COPY(clipped2,s2); break; } return intersection_type; } //! Finds the 2 smallest cartesian coordinates of a plane normal #define PLANE_MINOR_AXES(plane, i0, i1) VEC_MINOR_AXES(plane, i0, i1) //! Ray plane collision in one way /*! Intersects plane in one way only. The ray must face the plane (normals must be in opossite directions).
    It uses the PLANEDIREPSILON constant. */ template SIMD_FORCE_INLINE bool RAY_PLANE_COLLISION( const CLASS_PLANE & plane, const CLASS_POINT & vDir, const CLASS_POINT & vPoint, CLASS_POINT & pout,T &tparam) { GREAL _dis,_dotdir; _dotdir = VEC_DOT(plane,vDir); if(_dotdir SIMD_FORCE_INLINE GUINT LINE_PLANE_COLLISION( const CLASS_PLANE & plane, const CLASS_POINT & vDir, const CLASS_POINT & vPoint, CLASS_POINT & pout, T &tparam, T tmin, T tmax) { GREAL _dis,_dotdir; _dotdir = VEC_DOT(plane,vDir); if(btFabs(_dotdir)tmax) { returnvalue = 0; tparam = tmax; } VEC_SCALE(pout,tparam,vDir); VEC_SUM(pout,vPoint,pout); return returnvalue; } /*! \brief Returns the Ray on which 2 planes intersect if they do. Written by Rodrigo Hernandez on ODE convex collision \param p1 Plane 1 \param p2 Plane 2 \param p Contains the origin of the ray upon returning if planes intersect \param d Contains the direction of the ray upon returning if planes intersect \return true if the planes intersect, 0 if paralell. */ template SIMD_FORCE_INLINE bool INTERSECT_PLANES( const CLASS_PLANE &p1, const CLASS_PLANE &p2, CLASS_POINT &p, CLASS_POINT &d) { VEC_CROSS(d,p1,p2); GREAL denom = VEC_DOT(d, d); if(GIM_IS_ZERO(denom)) return false; vec3f _n; _n[0]=p1[3]*p2[0] - p2[3]*p1[0]; _n[1]=p1[3]*p2[1] - p2[3]*p1[1]; _n[2]=p1[3]*p2[2] - p2[3]*p1[2]; VEC_CROSS(p,_n,d); p[0]/=denom; p[1]/=denom; p[2]/=denom; return true; } //***************** SEGMENT and LINE FUNCTIONS **********************************/// /*! Finds the closest point(cp) to (v) on a segment (e1,e2) */ template SIMD_FORCE_INLINE void CLOSEST_POINT_ON_SEGMENT( CLASS_POINT & cp, const CLASS_POINT & v, const CLASS_POINT &e1,const CLASS_POINT &e2) { vec3f _n; VEC_DIFF(_n,e2,e1); VEC_DIFF(cp,v,e1); GREAL _scalar = VEC_DOT(cp, _n); _scalar/= VEC_DOT(_n, _n); if(_scalar <0.0f) { VEC_COPY(cp,e1); } else if(_scalar >1.0f) { VEC_COPY(cp,e2); } else { VEC_SCALE(cp,_scalar,_n); VEC_SUM(cp,cp,e1); } } /*! \brief Finds the line params where these lines intersect. \param dir1 Direction of line 1 \param point1 Point of line 1 \param dir2 Direction of line 2 \param point2 Point of line 2 \param t1 Result Parameter for line 1 \param t2 Result Parameter for line 2 \param dointersect 0 if the lines won't intersect, else 1 */ template SIMD_FORCE_INLINE bool LINE_INTERSECTION_PARAMS( const CLASS_POINT & dir1, CLASS_POINT & point1, const CLASS_POINT & dir2, CLASS_POINT & point2, T& t1,T& t2) { GREAL det; GREAL e1e1 = VEC_DOT(dir1,dir1); GREAL e1e2 = VEC_DOT(dir1,dir2); GREAL e2e2 = VEC_DOT(dir2,dir2); vec3f p1p2; VEC_DIFF(p1p2,point1,point2); GREAL p1p2e1 = VEC_DOT(p1p2,dir1); GREAL p1p2e2 = VEC_DOT(p1p2,dir2); det = e1e2*e1e2 - e1e1*e2e2; if(GIM_IS_ZERO(det)) return false; t1 = (e1e2*p1p2e2 - e2e2*p1p2e1)/det; t2 = (e1e1*p1p2e2 - e1e2*p1p2e1)/det; return true; } //! Find closest points on segments template SIMD_FORCE_INLINE void SEGMENT_COLLISION( const CLASS_POINT & vA1, const CLASS_POINT & vA2, const CLASS_POINT & vB1, const CLASS_POINT & vB2, CLASS_POINT & vPointA, CLASS_POINT & vPointB) { CLASS_POINT _AD,_BD,_N; vec4f _M;//plane VEC_DIFF(_AD,vA2,vA1); VEC_DIFF(_BD,vB2,vB1); VEC_CROSS(_N,_AD,_BD); GREAL _tp = VEC_DOT(_N,_N); if(_tp_M[1]) { invert_b_order = true; GIM_SWAP_NUMBERS(_M[0],_M[1]); } _M[2] = VEC_DOT(vA1,_AD); _M[3] = VEC_DOT(vA2,_AD); //mid points _N[0] = (_M[0]+_M[1])*0.5f; _N[1] = (_M[2]+_M[3])*0.5f; if(_N[0]<_N[1]) { if(_M[1]<_M[2]) { vPointB = invert_b_order?vB1:vB2; vPointA = vA1; } else if(_M[1]<_M[3]) { vPointB = invert_b_order?vB1:vB2; CLOSEST_POINT_ON_SEGMENT(vPointA,vPointB,vA1,vA2); } else { vPointA = vA2; CLOSEST_POINT_ON_SEGMENT(vPointB,vPointA,vB1,vB2); } } else { if(_M[3]<_M[0]) { vPointB = invert_b_order?vB2:vB1; vPointA = vA2; } else if(_M[3]<_M[1]) { vPointA = vA2; CLOSEST_POINT_ON_SEGMENT(vPointB,vPointA,vB1,vB2); } else { vPointB = invert_b_order?vB1:vB2; CLOSEST_POINT_ON_SEGMENT(vPointA,vPointB,vA1,vA2); } } return; } VEC_CROSS(_M,_N,_BD); _M[3] = VEC_DOT(_M,vB1); LINE_PLANE_COLLISION(_M,_AD,vA1,vPointA,_tp,btScalar(0), btScalar(1)); /*Closest point on segment*/ VEC_DIFF(vPointB,vPointA,vB1); _tp = VEC_DOT(vPointB, _BD); _tp/= VEC_DOT(_BD, _BD); _tp = GIM_CLAMP(_tp,0.0f,1.0f); VEC_SCALE(vPointB,_tp,_BD); VEC_SUM(vPointB,vPointB,vB1); } //! Line box intersection in one dimension /*! *\param pos Position of the ray *\param dir Projection of the Direction of the ray *\param bmin Minimum bound of the box *\param bmax Maximum bound of the box *\param tfirst the minimum projection. Assign to 0 at first. *\param tlast the maximum projection. Assign to INFINITY at first. *\return true if there is an intersection. */ template SIMD_FORCE_INLINE bool BOX_AXIS_INTERSECT(T pos, T dir,T bmin, T bmax, T & tfirst, T & tlast) { if(GIM_IS_ZERO(dir)) { return !(pos < bmin || pos > bmax); } GREAL a0 = (bmin - pos) / dir; GREAL a1 = (bmax - pos) / dir; if(a0 > a1) GIM_SWAP_NUMBERS(a0, a1); tfirst = GIM_MAX(a0, tfirst); tlast = GIM_MIN(a1, tlast); if (tlast < tfirst) return false; return true; } //! Sorts 3 componets template SIMD_FORCE_INLINE void SORT_3_INDICES( const T * values, GUINT * order_indices) { //get minimum order_indices[0] = values[0] < values[1] ? (values[0] < values[2] ? 0 : 2) : (values[1] < values[2] ? 1 : 2); //get second and third GUINT i0 = (order_indices[0] + 1)%3; GUINT i1 = (i0 + 1)%3; if(values[i0] < values[i1]) { order_indices[1] = i0; order_indices[2] = i1; } else { order_indices[1] = i1; order_indices[2] = i0; } } #endif // GIM_VECTOR_H_INCLUDED critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/0000755000175000017500000000000011347266042026007 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btSimpleBroadphase.cpp0000644000175000017500000002250211344267705032270 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btSimpleBroadphase.h" #include "BulletCollision/BroadphaseCollision/btDispatcher.h" #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" #include "LinearMath/btVector3.h" #include "LinearMath/btTransform.h" #include "LinearMath/btMatrix3x3.h" #include "LinearMath/btAabbUtil2.h" #include extern int gOverlappingPairs; void btSimpleBroadphase::validate() { for (int i=0;i~btOverlappingPairCache(); btAlignedFree(m_pairCache); } } btBroadphaseProxy* btSimpleBroadphase::createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* /*dispatcher*/,void* multiSapProxy) { if (m_numHandles >= m_maxHandles) { btAssert(0); return 0; //should never happen, but don't let the game crash ;-) } btAssert(aabbMin[0]<= aabbMax[0] && aabbMin[1]<= aabbMax[1] && aabbMin[2]<= aabbMax[2]); int newHandleIndex = allocHandle(); btSimpleBroadphaseProxy* proxy = new (&m_pHandles[newHandleIndex])btSimpleBroadphaseProxy(aabbMin,aabbMax,shapeType,userPtr,collisionFilterGroup,collisionFilterMask,multiSapProxy); return proxy; } class RemovingOverlapCallback : public btOverlapCallback { protected: virtual bool processOverlap(btBroadphasePair& pair) { (void)pair; btAssert(0); return false; } }; class RemovePairContainingProxy { btBroadphaseProxy* m_targetProxy; public: virtual ~RemovePairContainingProxy() { } protected: virtual bool processOverlap(btBroadphasePair& pair) { btSimpleBroadphaseProxy* proxy0 = static_cast(pair.m_pProxy0); btSimpleBroadphaseProxy* proxy1 = static_cast(pair.m_pProxy1); return ((m_targetProxy == proxy0 || m_targetProxy == proxy1)); }; }; void btSimpleBroadphase::destroyProxy(btBroadphaseProxy* proxyOrg,btDispatcher* dispatcher) { btSimpleBroadphaseProxy* proxy0 = static_cast(proxyOrg); freeHandle(proxy0); m_pairCache->removeOverlappingPairsContainingProxy(proxyOrg,dispatcher); //validate(); } void btSimpleBroadphase::getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const { const btSimpleBroadphaseProxy* sbp = getSimpleProxyFromProxy(proxy); aabbMin = sbp->m_aabbMin; aabbMax = sbp->m_aabbMax; } void btSimpleBroadphase::setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* /*dispatcher*/) { btSimpleBroadphaseProxy* sbp = getSimpleProxyFromProxy(proxy); sbp->m_aabbMin = aabbMin; sbp->m_aabbMax = aabbMax; } void btSimpleBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin,const btVector3& aabbMax) { for (int i=0; i <= m_LastHandleIndex; i++) { btSimpleBroadphaseProxy* proxy = &m_pHandles[i]; if(!proxy->m_clientObject) { continue; } rayCallback.process(proxy); } } void btSimpleBroadphase::aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback) { for (int i=0; i <= m_LastHandleIndex; i++) { btSimpleBroadphaseProxy* proxy = &m_pHandles[i]; if(!proxy->m_clientObject) { continue; } if (TestAabbAgainstAabb2(aabbMin,aabbMax,proxy->m_aabbMin,proxy->m_aabbMax)) { callback.process(proxy); } } } bool btSimpleBroadphase::aabbOverlap(btSimpleBroadphaseProxy* proxy0,btSimpleBroadphaseProxy* proxy1) { return proxy0->m_aabbMin[0] <= proxy1->m_aabbMax[0] && proxy1->m_aabbMin[0] <= proxy0->m_aabbMax[0] && proxy0->m_aabbMin[1] <= proxy1->m_aabbMax[1] && proxy1->m_aabbMin[1] <= proxy0->m_aabbMax[1] && proxy0->m_aabbMin[2] <= proxy1->m_aabbMax[2] && proxy1->m_aabbMin[2] <= proxy0->m_aabbMax[2]; } //then remove non-overlapping ones class CheckOverlapCallback : public btOverlapCallback { public: virtual bool processOverlap(btBroadphasePair& pair) { return (!btSimpleBroadphase::aabbOverlap(static_cast(pair.m_pProxy0),static_cast(pair.m_pProxy1))); } }; void btSimpleBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher) { //first check for new overlapping pairs int i,j; if (m_numHandles >= 0) { int new_largest_index = -1; for (i=0; i <= m_LastHandleIndex; i++) { btSimpleBroadphaseProxy* proxy0 = &m_pHandles[i]; if(!proxy0->m_clientObject) { continue; } new_largest_index = i; for (j=i+1; j <= m_LastHandleIndex; j++) { btSimpleBroadphaseProxy* proxy1 = &m_pHandles[j]; btAssert(proxy0 != proxy1); if(!proxy1->m_clientObject) { continue; } btSimpleBroadphaseProxy* p0 = getSimpleProxyFromProxy(proxy0); btSimpleBroadphaseProxy* p1 = getSimpleProxyFromProxy(proxy1); if (aabbOverlap(p0,p1)) { if ( !m_pairCache->findPair(proxy0,proxy1)) { m_pairCache->addOverlappingPair(proxy0,proxy1); } } else { if (!m_pairCache->hasDeferredRemoval()) { if ( m_pairCache->findPair(proxy0,proxy1)) { m_pairCache->removeOverlappingPair(proxy0,proxy1,dispatcher); } } } } } m_LastHandleIndex = new_largest_index; if (m_ownsPairCache && m_pairCache->hasDeferredRemoval()) { btBroadphasePairArray& overlappingPairArray = m_pairCache->getOverlappingPairArray(); //perform a sort, to find duplicates and to sort 'invalid' pairs to the end overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); m_invalidPair = 0; btBroadphasePair previousPair; previousPair.m_pProxy0 = 0; previousPair.m_pProxy1 = 0; previousPair.m_algorithm = 0; for (i=0;iprocessOverlap(pair); } else { needsRemoval = true; } } else { //remove duplicate needsRemoval = true; //should have no algorithm btAssert(!pair.m_algorithm); } if (needsRemoval) { m_pairCache->cleanOverlappingPair(pair,dispatcher); // m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); // m_overlappingPairArray.pop_back(); pair.m_pProxy0 = 0; pair.m_pProxy1 = 0; m_invalidPair++; gOverlappingPairs--; } } ///if you don't like to skip the invalid pairs in the array, execute following code: #define CLEAN_INVALID_PAIRS 1 #ifdef CLEAN_INVALID_PAIRS //perform a sort, to sort 'invalid' pairs to the end overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); m_invalidPair = 0; #endif//CLEAN_INVALID_PAIRS } } } bool btSimpleBroadphase::testAabbOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) { btSimpleBroadphaseProxy* p0 = getSimpleProxyFromProxy(proxy0); btSimpleBroadphaseProxy* p1 = getSimpleProxyFromProxy(proxy1); return aabbOverlap(p0,p1); } void btSimpleBroadphase::resetPool(btDispatcher* dispatcher) { //not yet } critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btAxisSweep3.h0000644000175000017500000007714411344267705030522 0ustar bobkebobke//Bullet Continuous Collision Detection and Physics Library //Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ // // btAxisSweep3.h // // Copyright (c) 2006 Simon Hobbs // // 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 AXIS_SWEEP_3_H #define AXIS_SWEEP_3_H #include "LinearMath/btVector3.h" #include "btOverlappingPairCache.h" #include "btBroadphaseInterface.h" #include "btBroadphaseProxy.h" #include "btOverlappingPairCallback.h" #include "btDbvtBroadphase.h" //#define DEBUG_BROADPHASE 1 #define USE_OVERLAP_TEST_ON_REMOVES 1 /// The internal templace class btAxisSweep3Internal implements the sweep and prune broadphase. /// It uses quantized integers to represent the begin and end points for each of the 3 axis. /// Dont use this class directly, use btAxisSweep3 or bt32BitAxisSweep3 instead. template class btAxisSweep3Internal : public btBroadphaseInterface { protected: BP_FP_INT_TYPE m_bpHandleMask; BP_FP_INT_TYPE m_handleSentinel; public: BT_DECLARE_ALIGNED_ALLOCATOR(); class Edge { public: BP_FP_INT_TYPE m_pos; // low bit is min/max BP_FP_INT_TYPE m_handle; BP_FP_INT_TYPE IsMax() const {return static_cast(m_pos & 1);} }; public: class Handle : public btBroadphaseProxy { public: BT_DECLARE_ALIGNED_ALLOCATOR(); // indexes into the edge arrays BP_FP_INT_TYPE m_minEdges[3], m_maxEdges[3]; // 6 * 2 = 12 // BP_FP_INT_TYPE m_uniqueId; btBroadphaseProxy* m_dbvtProxy;//for faster raycast //void* m_pOwner; this is now in btBroadphaseProxy.m_clientObject SIMD_FORCE_INLINE void SetNextFree(BP_FP_INT_TYPE next) {m_minEdges[0] = next;} SIMD_FORCE_INLINE BP_FP_INT_TYPE GetNextFree() const {return m_minEdges[0];} }; // 24 bytes + 24 for Edge structures = 44 bytes total per entry protected: btVector3 m_worldAabbMin; // overall system bounds btVector3 m_worldAabbMax; // overall system bounds btVector3 m_quantize; // scaling factor for quantization BP_FP_INT_TYPE m_numHandles; // number of active handles BP_FP_INT_TYPE m_maxHandles; // max number of handles Handle* m_pHandles; // handles pool BP_FP_INT_TYPE m_firstFreeHandle; // free handles list Edge* m_pEdges[3]; // edge arrays for the 3 axes (each array has m_maxHandles * 2 + 2 sentinel entries) void* m_pEdgesRawPtr[3]; btOverlappingPairCache* m_pairCache; ///btOverlappingPairCallback is an additional optional user callback for adding/removing overlapping pairs, similar interface to btOverlappingPairCache. btOverlappingPairCallback* m_userPairCallback; bool m_ownsPairCache; int m_invalidPair; ///additional dynamic aabb structure, used to accelerate ray cast queries. ///can be disabled using a optional argument in the constructor btDbvtBroadphase* m_raycastAccelerator; btOverlappingPairCache* m_nullPairCache; // allocation/deallocation BP_FP_INT_TYPE allocHandle(); void freeHandle(BP_FP_INT_TYPE handle); bool testOverlap2D(const Handle* pHandleA, const Handle* pHandleB,int axis0,int axis1); #ifdef DEBUG_BROADPHASE void debugPrintAxis(int axis,bool checkCardinality=true); #endif //DEBUG_BROADPHASE //Overlap* AddOverlap(BP_FP_INT_TYPE handleA, BP_FP_INT_TYPE handleB); //void RemoveOverlap(BP_FP_INT_TYPE handleA, BP_FP_INT_TYPE handleB); void sortMinDown(int axis, BP_FP_INT_TYPE edge, btDispatcher* dispatcher, bool updateOverlaps ); void sortMinUp(int axis, BP_FP_INT_TYPE edge, btDispatcher* dispatcher, bool updateOverlaps ); void sortMaxDown(int axis, BP_FP_INT_TYPE edge, btDispatcher* dispatcher, bool updateOverlaps ); void sortMaxUp(int axis, BP_FP_INT_TYPE edge, btDispatcher* dispatcher, bool updateOverlaps ); public: btAxisSweep3Internal(const btVector3& worldAabbMin,const btVector3& worldAabbMax, BP_FP_INT_TYPE handleMask, BP_FP_INT_TYPE handleSentinel, BP_FP_INT_TYPE maxHandles = 16384, btOverlappingPairCache* pairCache=0,bool disableRaycastAccelerator = false); virtual ~btAxisSweep3Internal(); BP_FP_INT_TYPE getNumHandles() const { return m_numHandles; } virtual void calculateOverlappingPairs(btDispatcher* dispatcher); BP_FP_INT_TYPE addHandle(const btVector3& aabbMin,const btVector3& aabbMax, void* pOwner,short int collisionFilterGroup,short int collisionFilterMask,btDispatcher* dispatcher,void* multiSapProxy); void removeHandle(BP_FP_INT_TYPE handle,btDispatcher* dispatcher); void updateHandle(BP_FP_INT_TYPE handle, const btVector3& aabbMin,const btVector3& aabbMax,btDispatcher* dispatcher); SIMD_FORCE_INLINE Handle* getHandle(BP_FP_INT_TYPE index) const {return m_pHandles + index;} virtual void resetPool(btDispatcher* dispatcher); void processAllOverlappingPairs(btOverlapCallback* callback); //Broadphase Interface virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask,btDispatcher* dispatcher,void* multiSapProxy); virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax,btDispatcher* dispatcher); virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const; virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin=btVector3(0,0,0), const btVector3& aabbMax = btVector3(0,0,0)); virtual void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback); void quantize(BP_FP_INT_TYPE* out, const btVector3& point, int isMax) const; ///unQuantize should be conservative: aabbMin/aabbMax should be larger then 'getAabb' result void unQuantize(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const; bool testAabbOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); btOverlappingPairCache* getOverlappingPairCache() { return m_pairCache; } const btOverlappingPairCache* getOverlappingPairCache() const { return m_pairCache; } void setOverlappingPairUserCallback(btOverlappingPairCallback* pairCallback) { m_userPairCallback = pairCallback; } const btOverlappingPairCallback* getOverlappingPairUserCallback() const { return m_userPairCallback; } ///getAabb returns the axis aligned bounding box in the 'global' coordinate frame ///will add some transform later virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const { aabbMin = m_worldAabbMin; aabbMax = m_worldAabbMax; } virtual void printStats() { /* printf("btAxisSweep3.h\n"); printf("numHandles = %d, maxHandles = %d\n",m_numHandles,m_maxHandles); printf("aabbMin=%f,%f,%f,aabbMax=%f,%f,%f\n",m_worldAabbMin.getX(),m_worldAabbMin.getY(),m_worldAabbMin.getZ(), m_worldAabbMax.getX(),m_worldAabbMax.getY(),m_worldAabbMax.getZ()); */ } }; //////////////////////////////////////////////////////////////////// #ifdef DEBUG_BROADPHASE #include template void btAxisSweep3::debugPrintAxis(int axis, bool checkCardinality) { int numEdges = m_pHandles[0].m_maxEdges[axis]; printf("SAP Axis %d, numEdges=%d\n",axis,numEdges); int i; for (i=0;im_handle); int handleIndex = pEdge->IsMax()? pHandlePrev->m_maxEdges[axis] : pHandlePrev->m_minEdges[axis]; char beginOrEnd; beginOrEnd=pEdge->IsMax()?'E':'B'; printf(" [%c,h=%d,p=%x,i=%d]\n",beginOrEnd,pEdge->m_handle,pEdge->m_pos,handleIndex); } if (checkCardinality) btAssert(numEdges == m_numHandles*2+1); } #endif //DEBUG_BROADPHASE template btBroadphaseProxy* btAxisSweep3Internal::createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr,short int collisionFilterGroup,short int collisionFilterMask,btDispatcher* dispatcher,void* multiSapProxy) { (void)shapeType; BP_FP_INT_TYPE handleId = addHandle(aabbMin,aabbMax, userPtr,collisionFilterGroup,collisionFilterMask,dispatcher,multiSapProxy); Handle* handle = getHandle(handleId); if (m_raycastAccelerator) { btBroadphaseProxy* rayProxy = m_raycastAccelerator->createProxy(aabbMin,aabbMax,shapeType,userPtr,collisionFilterGroup,collisionFilterMask,dispatcher,0); handle->m_dbvtProxy = rayProxy; } return handle; } template void btAxisSweep3Internal::destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher) { Handle* handle = static_cast(proxy); if (m_raycastAccelerator) m_raycastAccelerator->destroyProxy(handle->m_dbvtProxy,dispatcher); removeHandle(static_cast(handle->m_uniqueId), dispatcher); } template void btAxisSweep3Internal::setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax,btDispatcher* dispatcher) { Handle* handle = static_cast(proxy); handle->m_aabbMin = aabbMin; handle->m_aabbMax = aabbMax; updateHandle(static_cast(handle->m_uniqueId), aabbMin, aabbMax,dispatcher); if (m_raycastAccelerator) m_raycastAccelerator->setAabb(handle->m_dbvtProxy,aabbMin,aabbMax,dispatcher); } template void btAxisSweep3Internal::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback,const btVector3& aabbMin,const btVector3& aabbMax) { if (m_raycastAccelerator) { m_raycastAccelerator->rayTest(rayFrom,rayTo,rayCallback,aabbMin,aabbMax); } else { //choose axis? BP_FP_INT_TYPE axis = 0; //for each proxy for (BP_FP_INT_TYPE i=1;i void btAxisSweep3Internal::aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback) { if (m_raycastAccelerator) { m_raycastAccelerator->aabbTest(aabbMin,aabbMax,callback); } else { //choose axis? BP_FP_INT_TYPE axis = 0; //for each proxy for (BP_FP_INT_TYPE i=1;im_aabbMin,handle->m_aabbMax)) { callback.process(handle); } } } } } template void btAxisSweep3Internal::getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const { Handle* pHandle = static_cast(proxy); aabbMin = pHandle->m_aabbMin; aabbMax = pHandle->m_aabbMax; } template void btAxisSweep3Internal::unQuantize(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const { Handle* pHandle = static_cast(proxy); unsigned short vecInMin[3]; unsigned short vecInMax[3]; vecInMin[0] = m_pEdges[0][pHandle->m_minEdges[0]].m_pos ; vecInMax[0] = m_pEdges[0][pHandle->m_maxEdges[0]].m_pos +1 ; vecInMin[1] = m_pEdges[1][pHandle->m_minEdges[1]].m_pos ; vecInMax[1] = m_pEdges[1][pHandle->m_maxEdges[1]].m_pos +1 ; vecInMin[2] = m_pEdges[2][pHandle->m_minEdges[2]].m_pos ; vecInMax[2] = m_pEdges[2][pHandle->m_maxEdges[2]].m_pos +1 ; aabbMin.setValue((btScalar)(vecInMin[0]) / (m_quantize.getX()),(btScalar)(vecInMin[1]) / (m_quantize.getY()),(btScalar)(vecInMin[2]) / (m_quantize.getZ())); aabbMin += m_worldAabbMin; aabbMax.setValue((btScalar)(vecInMax[0]) / (m_quantize.getX()),(btScalar)(vecInMax[1]) / (m_quantize.getY()),(btScalar)(vecInMax[2]) / (m_quantize.getZ())); aabbMax += m_worldAabbMin; } template btAxisSweep3Internal::btAxisSweep3Internal(const btVector3& worldAabbMin,const btVector3& worldAabbMax, BP_FP_INT_TYPE handleMask, BP_FP_INT_TYPE handleSentinel,BP_FP_INT_TYPE userMaxHandles, btOverlappingPairCache* pairCache , bool disableRaycastAccelerator) :m_bpHandleMask(handleMask), m_handleSentinel(handleSentinel), m_pairCache(pairCache), m_userPairCallback(0), m_ownsPairCache(false), m_invalidPair(0), m_raycastAccelerator(0) { BP_FP_INT_TYPE maxHandles = static_cast(userMaxHandles+1);//need to add one sentinel handle if (!m_pairCache) { void* ptr = btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16); m_pairCache = new(ptr) btHashedOverlappingPairCache(); m_ownsPairCache = true; } if (!disableRaycastAccelerator) { m_nullPairCache = new (btAlignedAlloc(sizeof(btNullPairCache),16)) btNullPairCache(); m_raycastAccelerator = new (btAlignedAlloc(sizeof(btDbvtBroadphase),16)) btDbvtBroadphase(m_nullPairCache);//m_pairCache); m_raycastAccelerator->m_deferedcollide = true;//don't add/remove pairs } //btAssert(bounds.HasVolume()); // init bounds m_worldAabbMin = worldAabbMin; m_worldAabbMax = worldAabbMax; btVector3 aabbSize = m_worldAabbMax - m_worldAabbMin; BP_FP_INT_TYPE maxInt = m_handleSentinel; m_quantize = btVector3(btScalar(maxInt),btScalar(maxInt),btScalar(maxInt)) / aabbSize; // allocate handles buffer, using btAlignedAlloc, and put all handles on free list m_pHandles = new Handle[maxHandles]; m_maxHandles = maxHandles; m_numHandles = 0; // handle 0 is reserved as the null index, and is also used as the sentinel m_firstFreeHandle = 1; { for (BP_FP_INT_TYPE i = m_firstFreeHandle; i < maxHandles; i++) m_pHandles[i].SetNextFree(static_cast(i + 1)); m_pHandles[maxHandles - 1].SetNextFree(0); } { // allocate edge buffers for (int i = 0; i < 3; i++) { m_pEdgesRawPtr[i] = btAlignedAlloc(sizeof(Edge)*maxHandles*2,16); m_pEdges[i] = new(m_pEdgesRawPtr[i]) Edge[maxHandles * 2]; } } //removed overlap management // make boundary sentinels m_pHandles[0].m_clientObject = 0; for (int axis = 0; axis < 3; axis++) { m_pHandles[0].m_minEdges[axis] = 0; m_pHandles[0].m_maxEdges[axis] = 1; m_pEdges[axis][0].m_pos = 0; m_pEdges[axis][0].m_handle = 0; m_pEdges[axis][1].m_pos = m_handleSentinel; m_pEdges[axis][1].m_handle = 0; #ifdef DEBUG_BROADPHASE debugPrintAxis(axis); #endif //DEBUG_BROADPHASE } } template btAxisSweep3Internal::~btAxisSweep3Internal() { if (m_raycastAccelerator) { m_nullPairCache->~btOverlappingPairCache(); btAlignedFree(m_nullPairCache); m_raycastAccelerator->~btDbvtBroadphase(); btAlignedFree (m_raycastAccelerator); } for (int i = 2; i >= 0; i--) { btAlignedFree(m_pEdgesRawPtr[i]); } delete [] m_pHandles; if (m_ownsPairCache) { m_pairCache->~btOverlappingPairCache(); btAlignedFree(m_pairCache); } } template void btAxisSweep3Internal::quantize(BP_FP_INT_TYPE* out, const btVector3& point, int isMax) const { #ifdef OLD_CLAMPING_METHOD ///problem with this clamping method is that the floating point during quantization might still go outside the range [(0|isMax) .. (m_handleSentinel&m_bpHandleMask]|isMax] ///see http://code.google.com/p/bullet/issues/detail?id=87 btVector3 clampedPoint(point); clampedPoint.setMax(m_worldAabbMin); clampedPoint.setMin(m_worldAabbMax); btVector3 v = (clampedPoint - m_worldAabbMin) * m_quantize; out[0] = (BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v.getX() & m_bpHandleMask) | isMax); out[1] = (BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v.getY() & m_bpHandleMask) | isMax); out[2] = (BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v.getZ() & m_bpHandleMask) | isMax); #else btVector3 v = (point - m_worldAabbMin) * m_quantize; out[0]=(v[0]<=0)?(BP_FP_INT_TYPE)isMax:(v[0]>=m_handleSentinel)?(BP_FP_INT_TYPE)((m_handleSentinel&m_bpHandleMask)|isMax):(BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v[0]&m_bpHandleMask)|isMax); out[1]=(v[1]<=0)?(BP_FP_INT_TYPE)isMax:(v[1]>=m_handleSentinel)?(BP_FP_INT_TYPE)((m_handleSentinel&m_bpHandleMask)|isMax):(BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v[1]&m_bpHandleMask)|isMax); out[2]=(v[2]<=0)?(BP_FP_INT_TYPE)isMax:(v[2]>=m_handleSentinel)?(BP_FP_INT_TYPE)((m_handleSentinel&m_bpHandleMask)|isMax):(BP_FP_INT_TYPE)(((BP_FP_INT_TYPE)v[2]&m_bpHandleMask)|isMax); #endif //OLD_CLAMPING_METHOD } template BP_FP_INT_TYPE btAxisSweep3Internal::allocHandle() { btAssert(m_firstFreeHandle); BP_FP_INT_TYPE handle = m_firstFreeHandle; m_firstFreeHandle = getHandle(handle)->GetNextFree(); m_numHandles++; return handle; } template void btAxisSweep3Internal::freeHandle(BP_FP_INT_TYPE handle) { btAssert(handle > 0 && handle < m_maxHandles); getHandle(handle)->SetNextFree(m_firstFreeHandle); m_firstFreeHandle = handle; m_numHandles--; } template BP_FP_INT_TYPE btAxisSweep3Internal::addHandle(const btVector3& aabbMin,const btVector3& aabbMax, void* pOwner,short int collisionFilterGroup,short int collisionFilterMask,btDispatcher* dispatcher,void* multiSapProxy) { // quantize the bounds BP_FP_INT_TYPE min[3], max[3]; quantize(min, aabbMin, 0); quantize(max, aabbMax, 1); // allocate a handle BP_FP_INT_TYPE handle = allocHandle(); Handle* pHandle = getHandle(handle); pHandle->m_uniqueId = static_cast(handle); //pHandle->m_pOverlaps = 0; pHandle->m_clientObject = pOwner; pHandle->m_collisionFilterGroup = collisionFilterGroup; pHandle->m_collisionFilterMask = collisionFilterMask; pHandle->m_multiSapParentProxy = multiSapProxy; // compute current limit of edge arrays BP_FP_INT_TYPE limit = static_cast(m_numHandles * 2); // insert new edges just inside the max boundary edge for (BP_FP_INT_TYPE axis = 0; axis < 3; axis++) { m_pHandles[0].m_maxEdges[axis] += 2; m_pEdges[axis][limit + 1] = m_pEdges[axis][limit - 1]; m_pEdges[axis][limit - 1].m_pos = min[axis]; m_pEdges[axis][limit - 1].m_handle = handle; m_pEdges[axis][limit].m_pos = max[axis]; m_pEdges[axis][limit].m_handle = handle; pHandle->m_minEdges[axis] = static_cast(limit - 1); pHandle->m_maxEdges[axis] = limit; } // now sort the new edges to their correct position sortMinDown(0, pHandle->m_minEdges[0], dispatcher,false); sortMaxDown(0, pHandle->m_maxEdges[0], dispatcher,false); sortMinDown(1, pHandle->m_minEdges[1], dispatcher,false); sortMaxDown(1, pHandle->m_maxEdges[1], dispatcher,false); sortMinDown(2, pHandle->m_minEdges[2], dispatcher,true); sortMaxDown(2, pHandle->m_maxEdges[2], dispatcher,true); return handle; } template void btAxisSweep3Internal::removeHandle(BP_FP_INT_TYPE handle,btDispatcher* dispatcher) { Handle* pHandle = getHandle(handle); //explicitly remove the pairs containing the proxy //we could do it also in the sortMinUp (passing true) ///@todo: compare performance if (!m_pairCache->hasDeferredRemoval()) { m_pairCache->removeOverlappingPairsContainingProxy(pHandle,dispatcher); } // compute current limit of edge arrays int limit = static_cast(m_numHandles * 2); int axis; for (axis = 0;axis<3;axis++) { m_pHandles[0].m_maxEdges[axis] -= 2; } // remove the edges by sorting them up to the end of the list for ( axis = 0; axis < 3; axis++) { Edge* pEdges = m_pEdges[axis]; BP_FP_INT_TYPE max = pHandle->m_maxEdges[axis]; pEdges[max].m_pos = m_handleSentinel; sortMaxUp(axis,max,dispatcher,false); BP_FP_INT_TYPE i = pHandle->m_minEdges[axis]; pEdges[i].m_pos = m_handleSentinel; sortMinUp(axis,i,dispatcher,false); pEdges[limit-1].m_handle = 0; pEdges[limit-1].m_pos = m_handleSentinel; #ifdef DEBUG_BROADPHASE debugPrintAxis(axis,false); #endif //DEBUG_BROADPHASE } // free the handle freeHandle(handle); } template void btAxisSweep3Internal::resetPool(btDispatcher* dispatcher) { if (m_numHandles == 0) { m_firstFreeHandle = 1; { for (BP_FP_INT_TYPE i = m_firstFreeHandle; i < m_maxHandles; i++) m_pHandles[i].SetNextFree(static_cast(i + 1)); m_pHandles[m_maxHandles - 1].SetNextFree(0); } } } extern int gOverlappingPairs; //#include template void btAxisSweep3Internal::calculateOverlappingPairs(btDispatcher* dispatcher) { if (m_pairCache->hasDeferredRemoval()) { btBroadphasePairArray& overlappingPairArray = m_pairCache->getOverlappingPairArray(); //perform a sort, to find duplicates and to sort 'invalid' pairs to the end overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); m_invalidPair = 0; int i; btBroadphasePair previousPair; previousPair.m_pProxy0 = 0; previousPair.m_pProxy1 = 0; previousPair.m_algorithm = 0; for (i=0;iprocessOverlap(pair); } else { needsRemoval = true; } } else { //remove duplicate needsRemoval = true; //should have no algorithm btAssert(!pair.m_algorithm); } if (needsRemoval) { m_pairCache->cleanOverlappingPair(pair,dispatcher); // m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); // m_overlappingPairArray.pop_back(); pair.m_pProxy0 = 0; pair.m_pProxy1 = 0; m_invalidPair++; gOverlappingPairs--; } } ///if you don't like to skip the invalid pairs in the array, execute following code: #define CLEAN_INVALID_PAIRS 1 #ifdef CLEAN_INVALID_PAIRS //perform a sort, to sort 'invalid' pairs to the end overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); m_invalidPair = 0; #endif//CLEAN_INVALID_PAIRS //printf("overlappingPairArray.size()=%d\n",overlappingPairArray.size()); } } template bool btAxisSweep3Internal::testAabbOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) { const Handle* pHandleA = static_cast(proxy0); const Handle* pHandleB = static_cast(proxy1); //optimization 1: check the array index (memory address), instead of the m_pos for (int axis = 0; axis < 3; axis++) { if (pHandleA->m_maxEdges[axis] < pHandleB->m_minEdges[axis] || pHandleB->m_maxEdges[axis] < pHandleA->m_minEdges[axis]) { return false; } } return true; } template bool btAxisSweep3Internal::testOverlap2D(const Handle* pHandleA, const Handle* pHandleB,int axis0,int axis1) { //optimization 1: check the array index (memory address), instead of the m_pos if (pHandleA->m_maxEdges[axis0] < pHandleB->m_minEdges[axis0] || pHandleB->m_maxEdges[axis0] < pHandleA->m_minEdges[axis0] || pHandleA->m_maxEdges[axis1] < pHandleB->m_minEdges[axis1] || pHandleB->m_maxEdges[axis1] < pHandleA->m_minEdges[axis1]) { return false; } return true; } template void btAxisSweep3Internal::updateHandle(BP_FP_INT_TYPE handle, const btVector3& aabbMin,const btVector3& aabbMax,btDispatcher* dispatcher) { // btAssert(bounds.IsFinite()); //btAssert(bounds.HasVolume()); Handle* pHandle = getHandle(handle); // quantize the new bounds BP_FP_INT_TYPE min[3], max[3]; quantize(min, aabbMin, 0); quantize(max, aabbMax, 1); // update changed edges for (int axis = 0; axis < 3; axis++) { BP_FP_INT_TYPE emin = pHandle->m_minEdges[axis]; BP_FP_INT_TYPE emax = pHandle->m_maxEdges[axis]; int dmin = (int)min[axis] - (int)m_pEdges[axis][emin].m_pos; int dmax = (int)max[axis] - (int)m_pEdges[axis][emax].m_pos; m_pEdges[axis][emin].m_pos = min[axis]; m_pEdges[axis][emax].m_pos = max[axis]; // expand (only adds overlaps) if (dmin < 0) sortMinDown(axis, emin,dispatcher,true); if (dmax > 0) sortMaxUp(axis, emax,dispatcher,true); // shrink (only removes overlaps) if (dmin > 0) sortMinUp(axis, emin,dispatcher,true); if (dmax < 0) sortMaxDown(axis, emax,dispatcher,true); #ifdef DEBUG_BROADPHASE debugPrintAxis(axis); #endif //DEBUG_BROADPHASE } } // sorting a min edge downwards can only ever *add* overlaps template void btAxisSweep3Internal::sortMinDown(int axis, BP_FP_INT_TYPE edge, btDispatcher* /* dispatcher */, bool updateOverlaps) { Edge* pEdge = m_pEdges[axis] + edge; Edge* pPrev = pEdge - 1; Handle* pHandleEdge = getHandle(pEdge->m_handle); while (pEdge->m_pos < pPrev->m_pos) { Handle* pHandlePrev = getHandle(pPrev->m_handle); if (pPrev->IsMax()) { // if previous edge is a maximum check the bounds and add an overlap if necessary const int axis1 = (1 << axis) & 3; const int axis2 = (1 << axis1) & 3; if (updateOverlaps && testOverlap2D(pHandleEdge, pHandlePrev,axis1,axis2)) { m_pairCache->addOverlappingPair(pHandleEdge,pHandlePrev); if (m_userPairCallback) m_userPairCallback->addOverlappingPair(pHandleEdge,pHandlePrev); //AddOverlap(pEdge->m_handle, pPrev->m_handle); } // update edge reference in other handle pHandlePrev->m_maxEdges[axis]++; } else pHandlePrev->m_minEdges[axis]++; pHandleEdge->m_minEdges[axis]--; // swap the edges Edge swap = *pEdge; *pEdge = *pPrev; *pPrev = swap; // decrement pEdge--; pPrev--; } #ifdef DEBUG_BROADPHASE debugPrintAxis(axis); #endif //DEBUG_BROADPHASE } // sorting a min edge upwards can only ever *remove* overlaps template void btAxisSweep3Internal::sortMinUp(int axis, BP_FP_INT_TYPE edge, btDispatcher* dispatcher, bool updateOverlaps) { Edge* pEdge = m_pEdges[axis] + edge; Edge* pNext = pEdge + 1; Handle* pHandleEdge = getHandle(pEdge->m_handle); while (pNext->m_handle && (pEdge->m_pos >= pNext->m_pos)) { Handle* pHandleNext = getHandle(pNext->m_handle); if (pNext->IsMax()) { Handle* handle0 = getHandle(pEdge->m_handle); Handle* handle1 = getHandle(pNext->m_handle); const int axis1 = (1 << axis) & 3; const int axis2 = (1 << axis1) & 3; // if next edge is maximum remove any overlap between the two handles if (updateOverlaps #ifdef USE_OVERLAP_TEST_ON_REMOVES && testOverlap2D(handle0,handle1,axis1,axis2) #endif //USE_OVERLAP_TEST_ON_REMOVES ) { m_pairCache->removeOverlappingPair(handle0,handle1,dispatcher); if (m_userPairCallback) m_userPairCallback->removeOverlappingPair(handle0,handle1,dispatcher); } // update edge reference in other handle pHandleNext->m_maxEdges[axis]--; } else pHandleNext->m_minEdges[axis]--; pHandleEdge->m_minEdges[axis]++; // swap the edges Edge swap = *pEdge; *pEdge = *pNext; *pNext = swap; // increment pEdge++; pNext++; } } // sorting a max edge downwards can only ever *remove* overlaps template void btAxisSweep3Internal::sortMaxDown(int axis, BP_FP_INT_TYPE edge, btDispatcher* dispatcher, bool updateOverlaps) { Edge* pEdge = m_pEdges[axis] + edge; Edge* pPrev = pEdge - 1; Handle* pHandleEdge = getHandle(pEdge->m_handle); while (pEdge->m_pos < pPrev->m_pos) { Handle* pHandlePrev = getHandle(pPrev->m_handle); if (!pPrev->IsMax()) { // if previous edge was a minimum remove any overlap between the two handles Handle* handle0 = getHandle(pEdge->m_handle); Handle* handle1 = getHandle(pPrev->m_handle); const int axis1 = (1 << axis) & 3; const int axis2 = (1 << axis1) & 3; if (updateOverlaps #ifdef USE_OVERLAP_TEST_ON_REMOVES && testOverlap2D(handle0,handle1,axis1,axis2) #endif //USE_OVERLAP_TEST_ON_REMOVES ) { //this is done during the overlappingpairarray iteration/narrowphase collision m_pairCache->removeOverlappingPair(handle0,handle1,dispatcher); if (m_userPairCallback) m_userPairCallback->removeOverlappingPair(handle0,handle1,dispatcher); } // update edge reference in other handle pHandlePrev->m_minEdges[axis]++;; } else pHandlePrev->m_maxEdges[axis]++; pHandleEdge->m_maxEdges[axis]--; // swap the edges Edge swap = *pEdge; *pEdge = *pPrev; *pPrev = swap; // decrement pEdge--; pPrev--; } #ifdef DEBUG_BROADPHASE debugPrintAxis(axis); #endif //DEBUG_BROADPHASE } // sorting a max edge upwards can only ever *add* overlaps template void btAxisSweep3Internal::sortMaxUp(int axis, BP_FP_INT_TYPE edge, btDispatcher* /* dispatcher */, bool updateOverlaps) { Edge* pEdge = m_pEdges[axis] + edge; Edge* pNext = pEdge + 1; Handle* pHandleEdge = getHandle(pEdge->m_handle); while (pNext->m_handle && (pEdge->m_pos >= pNext->m_pos)) { Handle* pHandleNext = getHandle(pNext->m_handle); const int axis1 = (1 << axis) & 3; const int axis2 = (1 << axis1) & 3; if (!pNext->IsMax()) { // if next edge is a minimum check the bounds and add an overlap if necessary if (updateOverlaps && testOverlap2D(pHandleEdge, pHandleNext,axis1,axis2)) { Handle* handle0 = getHandle(pEdge->m_handle); Handle* handle1 = getHandle(pNext->m_handle); m_pairCache->addOverlappingPair(handle0,handle1); if (m_userPairCallback) m_userPairCallback->addOverlappingPair(handle0,handle1); } // update edge reference in other handle pHandleNext->m_minEdges[axis]--; } else pHandleNext->m_maxEdges[axis]--; pHandleEdge->m_maxEdges[axis]++; // swap the edges Edge swap = *pEdge; *pEdge = *pNext; *pNext = swap; // increment pEdge++; pNext++; } } //////////////////////////////////////////////////////////////////// /// The btAxisSweep3 is an efficient implementation of the 3d axis sweep and prune broadphase. /// It uses arrays rather then lists for storage of the 3 axis. Also it operates using 16 bit integer coordinates instead of floats. /// For large worlds and many objects, use bt32BitAxisSweep3 or btDbvtBroadphase instead. bt32BitAxisSweep3 has higher precision and allows more then 16384 objects at the cost of more memory and bit of performance. class btAxisSweep3 : public btAxisSweep3Internal { public: btAxisSweep3(const btVector3& worldAabbMin,const btVector3& worldAabbMax, unsigned short int maxHandles = 16384, btOverlappingPairCache* pairCache = 0, bool disableRaycastAccelerator = false); }; /// The bt32BitAxisSweep3 allows higher precision quantization and more objects compared to the btAxisSweep3 sweep and prune. /// This comes at the cost of more memory per handle, and a bit slower performance. /// It uses arrays rather then lists for storage of the 3 axis. class bt32BitAxisSweep3 : public btAxisSweep3Internal { public: bt32BitAxisSweep3(const btVector3& worldAabbMin,const btVector3& worldAabbMax, unsigned int maxHandles = 1500000, btOverlappingPairCache* pairCache = 0, bool disableRaycastAccelerator = false); }; #endif critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btSimpleBroadphase.h0000644000175000017500000001235111344267705031736 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 SIMPLE_BROADPHASE_H #define SIMPLE_BROADPHASE_H #include "btOverlappingPairCache.h" struct btSimpleBroadphaseProxy : public btBroadphaseProxy { int m_nextFree; // int m_handleId; btSimpleBroadphaseProxy() {}; btSimpleBroadphaseProxy(const btVector3& minpt,const btVector3& maxpt,int shapeType,void* userPtr,short int collisionFilterGroup,short int collisionFilterMask,void* multiSapProxy) :btBroadphaseProxy(minpt,maxpt,userPtr,collisionFilterGroup,collisionFilterMask,multiSapProxy) { (void)shapeType; } SIMD_FORCE_INLINE void SetNextFree(int next) {m_nextFree = next;} SIMD_FORCE_INLINE int GetNextFree() const {return m_nextFree;} }; ///The SimpleBroadphase is just a unit-test for btAxisSweep3, bt32BitAxisSweep3, or btDbvtBroadphase, so use those classes instead. ///It is a brute force aabb culling broadphase based on O(n^2) aabb checks class btSimpleBroadphase : public btBroadphaseInterface { protected: int m_numHandles; // number of active handles int m_maxHandles; // max number of handles int m_LastHandleIndex; btSimpleBroadphaseProxy* m_pHandles; // handles pool void* m_pHandlesRawPtr; int m_firstFreeHandle; // free handles list int allocHandle() { btAssert(m_numHandles < m_maxHandles); int freeHandle = m_firstFreeHandle; m_firstFreeHandle = m_pHandles[freeHandle].GetNextFree(); m_numHandles++; if(freeHandle > m_LastHandleIndex) { m_LastHandleIndex = freeHandle; } return freeHandle; } void freeHandle(btSimpleBroadphaseProxy* proxy) { int handle = int(proxy-m_pHandles); btAssert(handle >= 0 && handle < m_maxHandles); if(handle == m_LastHandleIndex) { m_LastHandleIndex--; } proxy->SetNextFree(m_firstFreeHandle); m_firstFreeHandle = handle; proxy->m_clientObject = 0; m_numHandles--; } btOverlappingPairCache* m_pairCache; bool m_ownsPairCache; int m_invalidPair; inline btSimpleBroadphaseProxy* getSimpleProxyFromProxy(btBroadphaseProxy* proxy) { btSimpleBroadphaseProxy* proxy0 = static_cast(proxy); return proxy0; } inline const btSimpleBroadphaseProxy* getSimpleProxyFromProxy(btBroadphaseProxy* proxy) const { const btSimpleBroadphaseProxy* proxy0 = static_cast(proxy); return proxy0; } ///reset broadphase internal structures, to ensure determinism/reproducability virtual void resetPool(btDispatcher* dispatcher); void validate(); protected: public: btSimpleBroadphase(int maxProxies=16384,btOverlappingPairCache* overlappingPairCache=0); virtual ~btSimpleBroadphase(); static bool aabbOverlap(btSimpleBroadphaseProxy* proxy0,btSimpleBroadphaseProxy* proxy1); virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr ,short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy); virtual void calculateOverlappingPairs(btDispatcher* dispatcher); virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher); virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const; virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin=btVector3(0,0,0),const btVector3& aabbMax=btVector3(0,0,0)); virtual void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback); btOverlappingPairCache* getOverlappingPairCache() { return m_pairCache; } const btOverlappingPairCache* getOverlappingPairCache() const { return m_pairCache; } bool testAabbOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); ///getAabb returns the axis aligned bounding box in the 'global' coordinate frame ///will add some transform later virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const { aabbMin.setValue(-BT_LARGE_FLOAT,-BT_LARGE_FLOAT,-BT_LARGE_FLOAT); aabbMax.setValue(BT_LARGE_FLOAT,BT_LARGE_FLOAT,BT_LARGE_FLOAT); } virtual void printStats() { // printf("btSimpleBroadphase.h\n"); // printf("numHandles = %d, maxHandles = %d\n",m_numHandles,m_maxHandles); } }; #endif //SIMPLE_BROADPHASE_H critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCache.cpp0000644000175000017500000003644011344267705033102 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btOverlappingPairCache.h" #include "btDispatcher.h" #include "btCollisionAlgorithm.h" #include "LinearMath/btAabbUtil2.h" #include int gOverlappingPairs = 0; int gRemovePairs =0; int gAddedPairs =0; int gFindPairs =0; btHashedOverlappingPairCache::btHashedOverlappingPairCache(): m_overlapFilterCallback(0), m_blockedForChanges(false), m_ghostPairCallback(0) { int initialAllocatedSize= 2; m_overlappingPairArray.reserve(initialAllocatedSize); growTables(); } btHashedOverlappingPairCache::~btHashedOverlappingPairCache() { } void btHashedOverlappingPairCache::cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher) { if (pair.m_algorithm) { { pair.m_algorithm->~btCollisionAlgorithm(); dispatcher->freeCollisionAlgorithm(pair.m_algorithm); pair.m_algorithm=0; } } } void btHashedOverlappingPairCache::cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher) { class CleanPairCallback : public btOverlapCallback { btBroadphaseProxy* m_cleanProxy; btOverlappingPairCache* m_pairCache; btDispatcher* m_dispatcher; public: CleanPairCallback(btBroadphaseProxy* cleanProxy,btOverlappingPairCache* pairCache,btDispatcher* dispatcher) :m_cleanProxy(cleanProxy), m_pairCache(pairCache), m_dispatcher(dispatcher) { } virtual bool processOverlap(btBroadphasePair& pair) { if ((pair.m_pProxy0 == m_cleanProxy) || (pair.m_pProxy1 == m_cleanProxy)) { m_pairCache->cleanOverlappingPair(pair,m_dispatcher); } return false; } }; CleanPairCallback cleanPairs(proxy,this,dispatcher); processAllOverlappingPairs(&cleanPairs,dispatcher); } void btHashedOverlappingPairCache::removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher) { class RemovePairCallback : public btOverlapCallback { btBroadphaseProxy* m_obsoleteProxy; public: RemovePairCallback(btBroadphaseProxy* obsoleteProxy) :m_obsoleteProxy(obsoleteProxy) { } virtual bool processOverlap(btBroadphasePair& pair) { return ((pair.m_pProxy0 == m_obsoleteProxy) || (pair.m_pProxy1 == m_obsoleteProxy)); } }; RemovePairCallback removeCallback(proxy); processAllOverlappingPairs(&removeCallback,dispatcher); } btBroadphasePair* btHashedOverlappingPairCache::findPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) { gFindPairs++; if(proxy0->m_uniqueId>proxy1->m_uniqueId) btSwap(proxy0,proxy1); int proxyId1 = proxy0->getUid(); int proxyId2 = proxy1->getUid(); /*if (proxyId1 > proxyId2) btSwap(proxyId1, proxyId2);*/ int hash = static_cast(getHash(static_cast(proxyId1), static_cast(proxyId2)) & (m_overlappingPairArray.capacity()-1)); if (hash >= m_hashTable.size()) { return NULL; } int index = m_hashTable[hash]; while (index != BT_NULL_PAIR && equalsPair(m_overlappingPairArray[index], proxyId1, proxyId2) == false) { index = m_next[index]; } if (index == BT_NULL_PAIR) { return NULL; } btAssert(index < m_overlappingPairArray.size()); return &m_overlappingPairArray[index]; } //#include void btHashedOverlappingPairCache::growTables() { int newCapacity = m_overlappingPairArray.capacity(); if (m_hashTable.size() < newCapacity) { //grow hashtable and next table int curHashtableSize = m_hashTable.size(); m_hashTable.resize(newCapacity); m_next.resize(newCapacity); int i; for (i= 0; i < newCapacity; ++i) { m_hashTable[i] = BT_NULL_PAIR; } for (i = 0; i < newCapacity; ++i) { m_next[i] = BT_NULL_PAIR; } for(i=0;igetUid(); int proxyId2 = pair.m_pProxy1->getUid(); /*if (proxyId1 > proxyId2) btSwap(proxyId1, proxyId2);*/ int hashValue = static_cast(getHash(static_cast(proxyId1),static_cast(proxyId2)) & (m_overlappingPairArray.capacity()-1)); // New hash value with new mask m_next[i] = m_hashTable[hashValue]; m_hashTable[hashValue] = i; } } } btBroadphasePair* btHashedOverlappingPairCache::internalAddPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) { if(proxy0->m_uniqueId>proxy1->m_uniqueId) btSwap(proxy0,proxy1); int proxyId1 = proxy0->getUid(); int proxyId2 = proxy1->getUid(); /*if (proxyId1 > proxyId2) btSwap(proxyId1, proxyId2);*/ int hash = static_cast(getHash(static_cast(proxyId1),static_cast(proxyId2)) & (m_overlappingPairArray.capacity()-1)); // New hash value with new mask btBroadphasePair* pair = internalFindPair(proxy0, proxy1, hash); if (pair != NULL) { return pair; } /*for(int i=0;i%u\r\n",proxyId1,proxyId2); internalFindPair(proxy0, proxy1, hash); } }*/ int count = m_overlappingPairArray.size(); int oldCapacity = m_overlappingPairArray.capacity(); void* mem = &m_overlappingPairArray.expandNonInitializing(); //this is where we add an actual pair, so also call the 'ghost' if (m_ghostPairCallback) m_ghostPairCallback->addOverlappingPair(proxy0,proxy1); int newCapacity = m_overlappingPairArray.capacity(); if (oldCapacity < newCapacity) { growTables(); //hash with new capacity hash = static_cast(getHash(static_cast(proxyId1),static_cast(proxyId2)) & (m_overlappingPairArray.capacity()-1)); } pair = new (mem) btBroadphasePair(*proxy0,*proxy1); // pair->m_pProxy0 = proxy0; // pair->m_pProxy1 = proxy1; pair->m_algorithm = 0; pair->m_internalTmpValue = 0; m_next[count] = m_hashTable[hash]; m_hashTable[hash] = count; return pair; } void* btHashedOverlappingPairCache::removeOverlappingPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1,btDispatcher* dispatcher) { gRemovePairs++; if(proxy0->m_uniqueId>proxy1->m_uniqueId) btSwap(proxy0,proxy1); int proxyId1 = proxy0->getUid(); int proxyId2 = proxy1->getUid(); /*if (proxyId1 > proxyId2) btSwap(proxyId1, proxyId2);*/ int hash = static_cast(getHash(static_cast(proxyId1),static_cast(proxyId2)) & (m_overlappingPairArray.capacity()-1)); btBroadphasePair* pair = internalFindPair(proxy0, proxy1, hash); if (pair == NULL) { return 0; } cleanOverlappingPair(*pair,dispatcher); void* userData = pair->m_internalInfo1; btAssert(pair->m_pProxy0->getUid() == proxyId1); btAssert(pair->m_pProxy1->getUid() == proxyId2); int pairIndex = int(pair - &m_overlappingPairArray[0]); btAssert(pairIndex < m_overlappingPairArray.size()); // Remove the pair from the hash table. int index = m_hashTable[hash]; btAssert(index != BT_NULL_PAIR); int previous = BT_NULL_PAIR; while (index != pairIndex) { previous = index; index = m_next[index]; } if (previous != BT_NULL_PAIR) { btAssert(m_next[previous] == pairIndex); m_next[previous] = m_next[pairIndex]; } else { m_hashTable[hash] = m_next[pairIndex]; } // We now move the last pair into spot of the // pair being removed. We need to fix the hash // table indices to support the move. int lastPairIndex = m_overlappingPairArray.size() - 1; if (m_ghostPairCallback) m_ghostPairCallback->removeOverlappingPair(proxy0, proxy1,dispatcher); // If the removed pair is the last pair, we are done. if (lastPairIndex == pairIndex) { m_overlappingPairArray.pop_back(); return userData; } // Remove the last pair from the hash table. const btBroadphasePair* last = &m_overlappingPairArray[lastPairIndex]; /* missing swap here too, Nat. */ int lastHash = static_cast(getHash(static_cast(last->m_pProxy0->getUid()), static_cast(last->m_pProxy1->getUid())) & (m_overlappingPairArray.capacity()-1)); index = m_hashTable[lastHash]; btAssert(index != BT_NULL_PAIR); previous = BT_NULL_PAIR; while (index != lastPairIndex) { previous = index; index = m_next[index]; } if (previous != BT_NULL_PAIR) { btAssert(m_next[previous] == lastPairIndex); m_next[previous] = m_next[lastPairIndex]; } else { m_hashTable[lastHash] = m_next[lastPairIndex]; } // Copy the last pair into the remove pair's spot. m_overlappingPairArray[pairIndex] = m_overlappingPairArray[lastPairIndex]; // Insert the last pair into the hash table m_next[pairIndex] = m_hashTable[lastHash]; m_hashTable[lastHash] = pairIndex; m_overlappingPairArray.pop_back(); return userData; } //#include void btHashedOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback* callback,btDispatcher* dispatcher) { int i; // printf("m_overlappingPairArray.size()=%d\n",m_overlappingPairArray.size()); for (i=0;iprocessOverlap(*pair)) { removeOverlappingPair(pair->m_pProxy0,pair->m_pProxy1,dispatcher); gOverlappingPairs--; } else { i++; } } } void btHashedOverlappingPairCache::sortOverlappingPairs(btDispatcher* dispatcher) { ///need to keep hashmap in sync with pair address, so rebuild all btBroadphasePairArray tmpPairs; int i; for (i=0;iremoveOverlappingPair(proxy0, proxy1,dispatcher); m_overlappingPairArray.swap(findIndex,m_overlappingPairArray.capacity()-1); m_overlappingPairArray.pop_back(); return userData; } } return 0; } btBroadphasePair* btSortedOverlappingPairCache::addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) { //don't add overlap with own btAssert(proxy0 != proxy1); if (!needsBroadphaseCollision(proxy0,proxy1)) return 0; void* mem = &m_overlappingPairArray.expandNonInitializing(); btBroadphasePair* pair = new (mem) btBroadphasePair(*proxy0,*proxy1); gOverlappingPairs++; gAddedPairs++; if (m_ghostPairCallback) m_ghostPairCallback->addOverlappingPair(proxy0, proxy1); return pair; } ///this findPair becomes really slow. Either sort the list to speedup the query, or ///use a different solution. It is mainly used for Removing overlapping pairs. Removal could be delayed. ///we could keep a linked list in each proxy, and store pair in one of the proxies (with lowest memory address) ///Also we can use a 2D bitmap, which can be useful for a future GPU implementation btBroadphasePair* btSortedOverlappingPairCache::findPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) { if (!needsBroadphaseCollision(proxy0,proxy1)) return 0; btBroadphasePair tmpPair(*proxy0,*proxy1); int findIndex = m_overlappingPairArray.findLinearSearch(tmpPair); if (findIndex < m_overlappingPairArray.size()) { //btAssert(it != m_overlappingPairSet.end()); btBroadphasePair* pair = &m_overlappingPairArray[findIndex]; return pair; } return 0; } //#include void btSortedOverlappingPairCache::processAllOverlappingPairs(btOverlapCallback* callback,btDispatcher* dispatcher) { int i; for (i=0;iprocessOverlap(*pair)) { cleanOverlappingPair(*pair,dispatcher); pair->m_pProxy0 = 0; pair->m_pProxy1 = 0; m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); m_overlappingPairArray.pop_back(); gOverlappingPairs--; } else { i++; } } } btSortedOverlappingPairCache::btSortedOverlappingPairCache(): m_blockedForChanges(false), m_hasDeferredRemoval(true), m_overlapFilterCallback(0), m_ghostPairCallback(0) { int initialAllocatedSize= 2; m_overlappingPairArray.reserve(initialAllocatedSize); } btSortedOverlappingPairCache::~btSortedOverlappingPairCache() { } void btSortedOverlappingPairCache::cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher) { if (pair.m_algorithm) { { pair.m_algorithm->~btCollisionAlgorithm(); dispatcher->freeCollisionAlgorithm(pair.m_algorithm); pair.m_algorithm=0; gRemovePairs--; } } } void btSortedOverlappingPairCache::cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher) { class CleanPairCallback : public btOverlapCallback { btBroadphaseProxy* m_cleanProxy; btOverlappingPairCache* m_pairCache; btDispatcher* m_dispatcher; public: CleanPairCallback(btBroadphaseProxy* cleanProxy,btOverlappingPairCache* pairCache,btDispatcher* dispatcher) :m_cleanProxy(cleanProxy), m_pairCache(pairCache), m_dispatcher(dispatcher) { } virtual bool processOverlap(btBroadphasePair& pair) { if ((pair.m_pProxy0 == m_cleanProxy) || (pair.m_pProxy1 == m_cleanProxy)) { m_pairCache->cleanOverlappingPair(pair,m_dispatcher); } return false; } }; CleanPairCallback cleanPairs(proxy,this,dispatcher); processAllOverlappingPairs(&cleanPairs,dispatcher); } void btSortedOverlappingPairCache::removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher) { class RemovePairCallback : public btOverlapCallback { btBroadphaseProxy* m_obsoleteProxy; public: RemovePairCallback(btBroadphaseProxy* obsoleteProxy) :m_obsoleteProxy(obsoleteProxy) { } virtual bool processOverlap(btBroadphasePair& pair) { return ((pair.m_pProxy0 == m_obsoleteProxy) || (pair.m_pProxy1 == m_obsoleteProxy)); } }; RemovePairCallback removeCallback(proxy); processAllOverlappingPairs(&removeCallback,dispatcher); } void btSortedOverlappingPairCache::sortOverlappingPairs(btDispatcher* dispatcher) { //should already be sorted } critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btQuantizedBvh.h0000644000175000017500000004357311344267705031132 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 QUANTIZED_BVH_H #define QUANTIZED_BVH_H class btSerializer; //#define DEBUG_CHECK_DEQUANTIZATION 1 #ifdef DEBUG_CHECK_DEQUANTIZATION #ifdef __SPU__ #define printf spu_printf #endif //__SPU__ #include #include #endif //DEBUG_CHECK_DEQUANTIZATION #include "LinearMath/btVector3.h" #include "LinearMath/btAlignedAllocator.h" #ifdef BT_USE_DOUBLE_PRECISION #define btQuantizedBvhData btQuantizedBvhDoubleData #define btOptimizedBvhNodeData btOptimizedBvhNodeDoubleData #define btQuantizedBvhDataName "btQuantizedBvhDoubleData" #else #define btQuantizedBvhData btQuantizedBvhFloatData #define btOptimizedBvhNodeData btOptimizedBvhNodeFloatData #define btQuantizedBvhDataName "btQuantizedBvhFloatData" #endif //http://msdn.microsoft.com/library/default.asp?url=/library/en-us/vclang/html/vclrf__m128.asp //Note: currently we have 16 bytes per quantized node #define MAX_SUBTREE_SIZE_IN_BYTES 2048 // 10 gives the potential for 1024 parts, with at most 2^21 (2097152) (minus one // actually) triangles each (since the sign bit is reserved #define MAX_NUM_PARTS_IN_BITS 10 ///btQuantizedBvhNode is a compressed aabb node, 16 bytes. ///Node can be used for leafnode or internal node. Leafnodes can point to 32-bit triangle index (non-negative range). ATTRIBUTE_ALIGNED16 (struct) btQuantizedBvhNode { BT_DECLARE_ALIGNED_ALLOCATOR(); //12 bytes unsigned short int m_quantizedAabbMin[3]; unsigned short int m_quantizedAabbMax[3]; //4 bytes int m_escapeIndexOrTriangleIndex; bool isLeafNode() const { //skipindex is negative (internal node), triangleindex >=0 (leafnode) return (m_escapeIndexOrTriangleIndex >= 0); } int getEscapeIndex() const { btAssert(!isLeafNode()); return -m_escapeIndexOrTriangleIndex; } int getTriangleIndex() const { btAssert(isLeafNode()); // Get only the lower bits where the triangle index is stored return (m_escapeIndexOrTriangleIndex&~((~0)<<(31-MAX_NUM_PARTS_IN_BITS))); } int getPartId() const { btAssert(isLeafNode()); // Get only the highest bits where the part index is stored return (m_escapeIndexOrTriangleIndex>>(31-MAX_NUM_PARTS_IN_BITS)); } } ; /// btOptimizedBvhNode contains both internal and leaf node information. /// Total node size is 44 bytes / node. You can use the compressed version of 16 bytes. ATTRIBUTE_ALIGNED16 (struct) btOptimizedBvhNode { BT_DECLARE_ALIGNED_ALLOCATOR(); //32 bytes btVector3 m_aabbMinOrg; btVector3 m_aabbMaxOrg; //4 int m_escapeIndex; //8 //for child nodes int m_subPart; int m_triangleIndex; int m_padding[5];//bad, due to alignment }; ///btBvhSubtreeInfo provides info to gather a subtree of limited size ATTRIBUTE_ALIGNED16(class) btBvhSubtreeInfo { public: BT_DECLARE_ALIGNED_ALLOCATOR(); //12 bytes unsigned short int m_quantizedAabbMin[3]; unsigned short int m_quantizedAabbMax[3]; //4 bytes, points to the root of the subtree int m_rootNodeIndex; //4 bytes int m_subtreeSize; int m_padding[3]; btBvhSubtreeInfo() { //memset(&m_padding[0], 0, sizeof(m_padding)); } void setAabbFromQuantizeNode(const btQuantizedBvhNode& quantizedNode) { m_quantizedAabbMin[0] = quantizedNode.m_quantizedAabbMin[0]; m_quantizedAabbMin[1] = quantizedNode.m_quantizedAabbMin[1]; m_quantizedAabbMin[2] = quantizedNode.m_quantizedAabbMin[2]; m_quantizedAabbMax[0] = quantizedNode.m_quantizedAabbMax[0]; m_quantizedAabbMax[1] = quantizedNode.m_quantizedAabbMax[1]; m_quantizedAabbMax[2] = quantizedNode.m_quantizedAabbMax[2]; } } ; class btNodeOverlapCallback { public: virtual ~btNodeOverlapCallback() {}; virtual void processNode(int subPart, int triangleIndex) = 0; }; #include "LinearMath/btAlignedAllocator.h" #include "LinearMath/btAlignedObjectArray.h" ///for code readability: typedef btAlignedObjectArray NodeArray; typedef btAlignedObjectArray QuantizedNodeArray; typedef btAlignedObjectArray BvhSubtreeInfoArray; ///The btQuantizedBvh class stores an AABB tree that can be quickly traversed on CPU and Cell SPU. ///It is used by the btBvhTriangleMeshShape as midphase, and by the btMultiSapBroadphase. ///It is recommended to use quantization for better performance and lower memory requirements. ATTRIBUTE_ALIGNED16(class) btQuantizedBvh { public: enum btTraversalMode { TRAVERSAL_STACKLESS = 0, TRAVERSAL_STACKLESS_CACHE_FRIENDLY, TRAVERSAL_RECURSIVE }; protected: btVector3 m_bvhAabbMin; btVector3 m_bvhAabbMax; btVector3 m_bvhQuantization; int m_bulletVersion; //for serialization versioning. It could also be used to detect endianess. int m_curNodeIndex; //quantization data bool m_useQuantization; NodeArray m_leafNodes; NodeArray m_contiguousNodes; QuantizedNodeArray m_quantizedLeafNodes; QuantizedNodeArray m_quantizedContiguousNodes; btTraversalMode m_traversalMode; BvhSubtreeInfoArray m_SubtreeHeaders; //This is only used for serialization so we don't have to add serialization directly to btAlignedObjectArray mutable int m_subtreeHeaderCount; ///two versions, one for quantized and normal nodes. This allows code-reuse while maintaining readability (no template/macro!) ///this might be refactored into a virtual, it is usually not calculated at run-time void setInternalNodeAabbMin(int nodeIndex, const btVector3& aabbMin) { if (m_useQuantization) { quantize(&m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0] ,aabbMin,0); } else { m_contiguousNodes[nodeIndex].m_aabbMinOrg = aabbMin; } } void setInternalNodeAabbMax(int nodeIndex,const btVector3& aabbMax) { if (m_useQuantization) { quantize(&m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0],aabbMax,1); } else { m_contiguousNodes[nodeIndex].m_aabbMaxOrg = aabbMax; } } btVector3 getAabbMin(int nodeIndex) const { if (m_useQuantization) { return unQuantize(&m_quantizedLeafNodes[nodeIndex].m_quantizedAabbMin[0]); } //non-quantized return m_leafNodes[nodeIndex].m_aabbMinOrg; } btVector3 getAabbMax(int nodeIndex) const { if (m_useQuantization) { return unQuantize(&m_quantizedLeafNodes[nodeIndex].m_quantizedAabbMax[0]); } //non-quantized return m_leafNodes[nodeIndex].m_aabbMaxOrg; } void setInternalNodeEscapeIndex(int nodeIndex, int escapeIndex) { if (m_useQuantization) { m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex = -escapeIndex; } else { m_contiguousNodes[nodeIndex].m_escapeIndex = escapeIndex; } } void mergeInternalNodeAabb(int nodeIndex,const btVector3& newAabbMin,const btVector3& newAabbMax) { if (m_useQuantization) { unsigned short int quantizedAabbMin[3]; unsigned short int quantizedAabbMax[3]; quantize(quantizedAabbMin,newAabbMin,0); quantize(quantizedAabbMax,newAabbMax,1); for (int i=0;i<3;i++) { if (m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[i] > quantizedAabbMin[i]) m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[i] = quantizedAabbMin[i]; if (m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[i] < quantizedAabbMax[i]) m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[i] = quantizedAabbMax[i]; } } else { //non-quantized m_contiguousNodes[nodeIndex].m_aabbMinOrg.setMin(newAabbMin); m_contiguousNodes[nodeIndex].m_aabbMaxOrg.setMax(newAabbMax); } } void swapLeafNodes(int firstIndex,int secondIndex); void assignInternalNodeFromLeafNode(int internalNode,int leafNodeIndex); protected: void buildTree (int startIndex,int endIndex); int calcSplittingAxis(int startIndex,int endIndex); int sortAndCalcSplittingIndex(int startIndex,int endIndex,int splitAxis); void walkStacklessTree(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const; void walkStacklessQuantizedTreeAgainstRay(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin, const btVector3& aabbMax, int startNodeIndex,int endNodeIndex) const; void walkStacklessQuantizedTree(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax,int startNodeIndex,int endNodeIndex) const; void walkStacklessTreeAgainstRay(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin, const btVector3& aabbMax, int startNodeIndex,int endNodeIndex) const; ///tree traversal designed for small-memory processors like PS3 SPU void walkStacklessQuantizedTreeCacheFriendly(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const; ///use the 16-byte stackless 'skipindex' node tree to do a recursive traversal void walkRecursiveQuantizedTreeAgainstQueryAabb(const btQuantizedBvhNode* currentNode,btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const; ///use the 16-byte stackless 'skipindex' node tree to do a recursive traversal void walkRecursiveQuantizedTreeAgainstQuantizedTree(const btQuantizedBvhNode* treeNodeA,const btQuantizedBvhNode* treeNodeB,btNodeOverlapCallback* nodeCallback) const; void updateSubtreeHeaders(int leftChildNodexIndex,int rightChildNodexIndex); public: BT_DECLARE_ALIGNED_ALLOCATOR(); btQuantizedBvh(); virtual ~btQuantizedBvh(); ///***************************************** expert/internal use only ************************* void setQuantizationValues(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax,btScalar quantizationMargin=btScalar(1.0)); QuantizedNodeArray& getLeafNodeArray() { return m_quantizedLeafNodes; } ///buildInternal is expert use only: assumes that setQuantizationValues and LeafNodeArray are initialized void buildInternal(); ///***************************************** expert/internal use only ************************* void reportAabbOverlappingNodex(btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const; void reportRayOverlappingNodex (btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget) const; void reportBoxCastOverlappingNodex(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin,const btVector3& aabbMax) const; SIMD_FORCE_INLINE void quantize(unsigned short* out, const btVector3& point,int isMax) const { btAssert(m_useQuantization); btAssert(point.getX() <= m_bvhAabbMax.getX()); btAssert(point.getY() <= m_bvhAabbMax.getY()); btAssert(point.getZ() <= m_bvhAabbMax.getZ()); btAssert(point.getX() >= m_bvhAabbMin.getX()); btAssert(point.getY() >= m_bvhAabbMin.getY()); btAssert(point.getZ() >= m_bvhAabbMin.getZ()); btVector3 v = (point - m_bvhAabbMin) * m_bvhQuantization; ///Make sure rounding is done in a way that unQuantize(quantizeWithClamp(...)) is conservative ///end-points always set the first bit, so that they are sorted properly (so that neighbouring AABBs overlap properly) ///@todo: double-check this if (isMax) { out[0] = (unsigned short) (((unsigned short)(v.getX()+btScalar(1.)) | 1)); out[1] = (unsigned short) (((unsigned short)(v.getY()+btScalar(1.)) | 1)); out[2] = (unsigned short) (((unsigned short)(v.getZ()+btScalar(1.)) | 1)); } else { out[0] = (unsigned short) (((unsigned short)(v.getX()) & 0xfffe)); out[1] = (unsigned short) (((unsigned short)(v.getY()) & 0xfffe)); out[2] = (unsigned short) (((unsigned short)(v.getZ()) & 0xfffe)); } #ifdef DEBUG_CHECK_DEQUANTIZATION btVector3 newPoint = unQuantize(out); if (isMax) { if (newPoint.getX() < point.getX()) { printf("unconservative X, diffX = %f, oldX=%f,newX=%f\n",newPoint.getX()-point.getX(), newPoint.getX(),point.getX()); } if (newPoint.getY() < point.getY()) { printf("unconservative Y, diffY = %f, oldY=%f,newY=%f\n",newPoint.getY()-point.getY(), newPoint.getY(),point.getY()); } if (newPoint.getZ() < point.getZ()) { printf("unconservative Z, diffZ = %f, oldZ=%f,newZ=%f\n",newPoint.getZ()-point.getZ(), newPoint.getZ(),point.getZ()); } } else { if (newPoint.getX() > point.getX()) { printf("unconservative X, diffX = %f, oldX=%f,newX=%f\n",newPoint.getX()-point.getX(), newPoint.getX(),point.getX()); } if (newPoint.getY() > point.getY()) { printf("unconservative Y, diffY = %f, oldY=%f,newY=%f\n",newPoint.getY()-point.getY(), newPoint.getY(),point.getY()); } if (newPoint.getZ() > point.getZ()) { printf("unconservative Z, diffZ = %f, oldZ=%f,newZ=%f\n",newPoint.getZ()-point.getZ(), newPoint.getZ(),point.getZ()); } } #endif //DEBUG_CHECK_DEQUANTIZATION } SIMD_FORCE_INLINE void quantizeWithClamp(unsigned short* out, const btVector3& point2,int isMax) const { btAssert(m_useQuantization); btVector3 clampedPoint(point2); clampedPoint.setMax(m_bvhAabbMin); clampedPoint.setMin(m_bvhAabbMax); quantize(out,clampedPoint,isMax); } SIMD_FORCE_INLINE btVector3 unQuantize(const unsigned short* vecIn) const { btVector3 vecOut; vecOut.setValue( (btScalar)(vecIn[0]) / (m_bvhQuantization.getX()), (btScalar)(vecIn[1]) / (m_bvhQuantization.getY()), (btScalar)(vecIn[2]) / (m_bvhQuantization.getZ())); vecOut += m_bvhAabbMin; return vecOut; } ///setTraversalMode let's you choose between stackless, recursive or stackless cache friendly tree traversal. Note this is only implemented for quantized trees. void setTraversalMode(btTraversalMode traversalMode) { m_traversalMode = traversalMode; } SIMD_FORCE_INLINE QuantizedNodeArray& getQuantizedNodeArray() { return m_quantizedContiguousNodes; } SIMD_FORCE_INLINE BvhSubtreeInfoArray& getSubtreeInfoArray() { return m_SubtreeHeaders; } //////////////////////////////////////////////////////////////////// /////Calculate space needed to store BVH for serialization unsigned calculateSerializeBufferSize() const; /// Data buffer MUST be 16 byte aligned virtual bool serialize(void *o_alignedDataBuffer, unsigned i_dataBufferSize, bool i_swapEndian) const; ///deSerializeInPlace loads and initializes a BVH from a buffer in memory 'in place' static btQuantizedBvh *deSerializeInPlace(void *i_alignedDataBuffer, unsigned int i_dataBufferSize, bool i_swapEndian); static unsigned int getAlignmentSerializationPadding(); ////////////////////////////////////////////////////////////////////// virtual int calculateSerializeBufferSizeNew() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; virtual void deSerializeFloat(struct btQuantizedBvhFloatData& quantizedBvhFloatData); virtual void deSerializeDouble(struct btQuantizedBvhDoubleData& quantizedBvhDoubleData); //////////////////////////////////////////////////////////////////// SIMD_FORCE_INLINE bool isQuantized() { return m_useQuantization; } private: // Special "copy" constructor that allows for in-place deserialization // Prevents btVector3's default constructor from being called, but doesn't inialize much else // ownsMemory should most likely be false if deserializing, and if you are not, don't call this (it also changes the function signature, which we need) btQuantizedBvh(btQuantizedBvh &other, bool ownsMemory); } ; struct btBvhSubtreeInfoData { int m_rootNodeIndex; int m_subtreeSize; unsigned short m_quantizedAabbMin[3]; unsigned short m_quantizedAabbMax[3]; }; struct btOptimizedBvhNodeFloatData { btVector3FloatData m_aabbMinOrg; btVector3FloatData m_aabbMaxOrg; int m_escapeIndex; int m_subPart; int m_triangleIndex; char m_pad[4]; }; struct btOptimizedBvhNodeDoubleData { btVector3DoubleData m_aabbMinOrg; btVector3DoubleData m_aabbMaxOrg; int m_escapeIndex; int m_subPart; int m_triangleIndex; char m_pad[4]; }; struct btQuantizedBvhNodeData { unsigned short m_quantizedAabbMin[3]; unsigned short m_quantizedAabbMax[3]; int m_escapeIndexOrTriangleIndex; }; struct btQuantizedBvhFloatData { btVector3FloatData m_bvhAabbMin; btVector3FloatData m_bvhAabbMax; btVector3FloatData m_bvhQuantization; int m_curNodeIndex; int m_useQuantization; int m_numContiguousLeafNodes; int m_numQuantizedContiguousNodes; btOptimizedBvhNodeFloatData *m_contiguousNodesPtr; btQuantizedBvhNodeData *m_quantizedContiguousNodesPtr; btBvhSubtreeInfoData *m_subTreeInfoPtr; int m_traversalMode; int m_numSubtreeHeaders; }; struct btQuantizedBvhDoubleData { btVector3DoubleData m_bvhAabbMin; btVector3DoubleData m_bvhAabbMax; btVector3DoubleData m_bvhQuantization; int m_curNodeIndex; int m_useQuantization; int m_numContiguousLeafNodes; int m_numQuantizedContiguousNodes; btOptimizedBvhNodeDoubleData *m_contiguousNodesPtr; btQuantizedBvhNodeData *m_quantizedContiguousNodesPtr; int m_traversalMode; int m_numSubtreeHeaders; btBvhSubtreeInfoData *m_subTreeInfoPtr; }; SIMD_FORCE_INLINE int btQuantizedBvh::calculateSerializeBufferSizeNew() const { return sizeof(btQuantizedBvhData); } #endif //QUANTIZED_BVH_H critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.h0000644000175000017500000001241111337071441032230 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BT_MULTI_SAP_BROADPHASE #define BT_MULTI_SAP_BROADPHASE #include "btBroadphaseInterface.h" #include "LinearMath/btAlignedObjectArray.h" #include "btOverlappingPairCache.h" class btBroadphaseInterface; class btSimpleBroadphase; typedef btAlignedObjectArray btSapBroadphaseArray; ///The btMultiSapBroadphase is a research project, not recommended to use in production. Use btAxisSweep3 or btDbvtBroadphase instead. ///The btMultiSapBroadphase is a broadphase that contains multiple SAP broadphases. ///The user can add SAP broadphases that cover the world. A btBroadphaseProxy can be in multiple child broadphases at the same time. ///A btQuantizedBvh acceleration structures finds overlapping SAPs for each btBroadphaseProxy. ///See http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=328 ///and http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1329 class btMultiSapBroadphase :public btBroadphaseInterface { btSapBroadphaseArray m_sapBroadphases; btSimpleBroadphase* m_simpleBroadphase; btOverlappingPairCache* m_overlappingPairs; class btQuantizedBvh* m_optimizedAabbTree; bool m_ownsPairCache; btOverlapFilterCallback* m_filterCallback; int m_invalidPair; struct btBridgeProxy { btBroadphaseProxy* m_childProxy; btBroadphaseInterface* m_childBroadphase; }; public: struct btMultiSapProxy : public btBroadphaseProxy { ///array with all the entries that this proxy belongs to btAlignedObjectArray m_bridgeProxies; btVector3 m_aabbMin; btVector3 m_aabbMax; int m_shapeType; /* void* m_userPtr; short int m_collisionFilterGroup; short int m_collisionFilterMask; */ btMultiSapProxy(const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask) :btBroadphaseProxy(aabbMin,aabbMax,userPtr,collisionFilterGroup,collisionFilterMask), m_aabbMin(aabbMin), m_aabbMax(aabbMax), m_shapeType(shapeType) { m_multiSapParentProxy =this; } }; protected: btAlignedObjectArray m_multiSapProxies; public: btMultiSapBroadphase(int maxProxies = 16384,btOverlappingPairCache* pairCache=0); btSapBroadphaseArray& getBroadphaseArray() { return m_sapBroadphases; } const btSapBroadphaseArray& getBroadphaseArray() const { return m_sapBroadphases; } virtual ~btMultiSapBroadphase(); virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy); virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher); virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const; virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback,const btVector3& aabbMin=btVector3(0,0,0),const btVector3& aabbMax=btVector3(0,0,0)); void addToChildBroadphase(btMultiSapProxy* parentMultiSapProxy, btBroadphaseProxy* childProxy, btBroadphaseInterface* childBroadphase); ///calculateOverlappingPairs is optional: incremental algorithms (sweep and prune) might do it during the set aabb virtual void calculateOverlappingPairs(btDispatcher* dispatcher); bool testAabbOverlap(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); virtual btOverlappingPairCache* getOverlappingPairCache() { return m_overlappingPairs; } virtual const btOverlappingPairCache* getOverlappingPairCache() const { return m_overlappingPairs; } ///getAabb returns the axis aligned bounding box in the 'global' coordinate frame ///will add some transform later virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const { aabbMin.setValue(-BT_LARGE_FLOAT,-BT_LARGE_FLOAT,-BT_LARGE_FLOAT); aabbMax.setValue(BT_LARGE_FLOAT,BT_LARGE_FLOAT,BT_LARGE_FLOAT); } void buildTree(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax); virtual void printStats(); void quicksort (btBroadphasePairArray& a, int lo, int hi); ///reset broadphase internal structures, to ensure determinism/reproducability virtual void resetPool(btDispatcher* dispatcher); }; #endif //BT_MULTI_SAP_BROADPHASE critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btAxisSweep3.cpp0000644000175000017500000000353711337071441031040 0ustar bobkebobke //Bullet Continuous Collision Detection and Physics Library //Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ // // btAxisSweep3 // // Copyright (c) 2006 Simon Hobbs // // 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 "btAxisSweep3.h" btAxisSweep3::btAxisSweep3(const btVector3& worldAabbMin,const btVector3& worldAabbMax, unsigned short int maxHandles, btOverlappingPairCache* pairCache, bool disableRaycastAccelerator) :btAxisSweep3Internal(worldAabbMin,worldAabbMax,0xfffe,0xffff,maxHandles,pairCache,disableRaycastAccelerator) { // 1 handle is reserved as sentinel btAssert(maxHandles > 1 && maxHandles < 32767); } bt32BitAxisSweep3::bt32BitAxisSweep3(const btVector3& worldAabbMin,const btVector3& worldAabbMax, unsigned int maxHandles , btOverlappingPairCache* pairCache , bool disableRaycastAccelerator) :btAxisSweep3Internal(worldAabbMin,worldAabbMax,0xfffffffe,0x7fffffff,maxHandles,pairCache,disableRaycastAccelerator) { // 1 handle is reserved as sentinel btAssert(maxHandles > 1 && maxHandles < 2147483647); } critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btDispatcher.cpp0000644000175000017500000000176411337071441031133 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btDispatcher.h" btDispatcher::~btDispatcher() { } critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btBroadphaseProxy.cpp0000644000175000017500000000172511337071441032154 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btBroadphaseProxy.h" critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h0000644000175000017500000000465611337071441032317 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 COLLISION_ALGORITHM_H #define COLLISION_ALGORITHM_H #include "LinearMath/btScalar.h" #include "LinearMath/btAlignedObjectArray.h" struct btBroadphaseProxy; class btDispatcher; class btManifoldResult; class btCollisionObject; struct btDispatcherInfo; class btPersistentManifold; typedef btAlignedObjectArray btManifoldArray; struct btCollisionAlgorithmConstructionInfo { btCollisionAlgorithmConstructionInfo() :m_dispatcher1(0), m_manifold(0) { } btCollisionAlgorithmConstructionInfo(btDispatcher* dispatcher,int temp) :m_dispatcher1(dispatcher) { (void)temp; } btDispatcher* m_dispatcher1; btPersistentManifold* m_manifold; int getDispatcherId(); }; ///btCollisionAlgorithm is an collision interface that is compatible with the Broadphase and btDispatcher. ///It is persistent over frames class btCollisionAlgorithm { protected: btDispatcher* m_dispatcher; protected: int getDispatcherId(); public: btCollisionAlgorithm() {}; btCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci); virtual ~btCollisionAlgorithm() {}; virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) = 0; virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) = 0; virtual void getAllContactManifolds(btManifoldArray& manifoldArray) = 0; }; #endif //COLLISION_ALGORITHM_H critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btBroadphaseProxy.h0000644000175000017500000001723211344267705031631 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BROADPHASE_PROXY_H #define BROADPHASE_PROXY_H #include "LinearMath/btScalar.h" //for SIMD_FORCE_INLINE #include "LinearMath/btVector3.h" #include "LinearMath/btAlignedAllocator.h" /// btDispatcher uses these types /// IMPORTANT NOTE:The types are ordered polyhedral, implicit convex and concave /// to facilitate type checking /// CUSTOM_POLYHEDRAL_SHAPE_TYPE,CUSTOM_CONVEX_SHAPE_TYPE and CUSTOM_CONCAVE_SHAPE_TYPE can be used to extend Bullet without modifying source code enum BroadphaseNativeTypes { // polyhedral convex shapes BOX_SHAPE_PROXYTYPE, TRIANGLE_SHAPE_PROXYTYPE, TETRAHEDRAL_SHAPE_PROXYTYPE, CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE, CONVEX_HULL_SHAPE_PROXYTYPE, CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE, CUSTOM_POLYHEDRAL_SHAPE_TYPE, //implicit convex shapes IMPLICIT_CONVEX_SHAPES_START_HERE, SPHERE_SHAPE_PROXYTYPE, MULTI_SPHERE_SHAPE_PROXYTYPE, CAPSULE_SHAPE_PROXYTYPE, CONE_SHAPE_PROXYTYPE, CONVEX_SHAPE_PROXYTYPE, CYLINDER_SHAPE_PROXYTYPE, UNIFORM_SCALING_SHAPE_PROXYTYPE, MINKOWSKI_SUM_SHAPE_PROXYTYPE, MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE, BOX_2D_SHAPE_PROXYTYPE, CONVEX_2D_SHAPE_PROXYTYPE, CUSTOM_CONVEX_SHAPE_TYPE, //concave shapes CONCAVE_SHAPES_START_HERE, //keep all the convex shapetype below here, for the check IsConvexShape in broadphase proxy! TRIANGLE_MESH_SHAPE_PROXYTYPE, SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE, ///used for demo integration FAST/Swift collision library and Bullet FAST_CONCAVE_MESH_PROXYTYPE, //terrain TERRAIN_SHAPE_PROXYTYPE, ///Used for GIMPACT Trimesh integration GIMPACT_SHAPE_PROXYTYPE, ///Multimaterial mesh MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE, EMPTY_SHAPE_PROXYTYPE, STATIC_PLANE_PROXYTYPE, CUSTOM_CONCAVE_SHAPE_TYPE, CONCAVE_SHAPES_END_HERE, COMPOUND_SHAPE_PROXYTYPE, SOFTBODY_SHAPE_PROXYTYPE, HFFLUID_SHAPE_PROXYTYPE, HFFLUID_BUOYANT_CONVEX_SHAPE_PROXYTYPE, INVALID_SHAPE_PROXYTYPE, MAX_BROADPHASE_COLLISION_TYPES }; ///The btBroadphaseProxy is the main class that can be used with the Bullet broadphases. ///It stores collision shape type information, collision filter information and a client object, typically a btCollisionObject or btRigidBody. ATTRIBUTE_ALIGNED16(struct) btBroadphaseProxy { BT_DECLARE_ALIGNED_ALLOCATOR(); ///optional filtering to cull potential collisions enum CollisionFilterGroups { DefaultFilter = 1, StaticFilter = 2, KinematicFilter = 4, DebrisFilter = 8, SensorTrigger = 16, CharacterFilter = 32, AllFilter = -1 //all bits sets: DefaultFilter | StaticFilter | KinematicFilter | DebrisFilter | SensorTrigger }; //Usually the client btCollisionObject or Rigidbody class void* m_clientObject; short int m_collisionFilterGroup; short int m_collisionFilterMask; void* m_multiSapParentProxy; int m_uniqueId;//m_uniqueId is introduced for paircache. could get rid of this, by calculating the address offset etc. btVector3 m_aabbMin; btVector3 m_aabbMax; SIMD_FORCE_INLINE int getUid() const { return m_uniqueId; } //used for memory pools btBroadphaseProxy() :m_clientObject(0),m_multiSapParentProxy(0) { } btBroadphaseProxy(const btVector3& aabbMin,const btVector3& aabbMax,void* userPtr,short int collisionFilterGroup, short int collisionFilterMask,void* multiSapParentProxy=0) :m_clientObject(userPtr), m_collisionFilterGroup(collisionFilterGroup), m_collisionFilterMask(collisionFilterMask), m_aabbMin(aabbMin), m_aabbMax(aabbMax) { m_multiSapParentProxy = multiSapParentProxy; } static SIMD_FORCE_INLINE bool isPolyhedral(int proxyType) { return (proxyType < IMPLICIT_CONVEX_SHAPES_START_HERE); } static SIMD_FORCE_INLINE bool isConvex(int proxyType) { return (proxyType < CONCAVE_SHAPES_START_HERE); } static SIMD_FORCE_INLINE bool isNonMoving(int proxyType) { return (isConcave(proxyType) && !(proxyType==GIMPACT_SHAPE_PROXYTYPE)); } static SIMD_FORCE_INLINE bool isConcave(int proxyType) { return ((proxyType > CONCAVE_SHAPES_START_HERE) && (proxyType < CONCAVE_SHAPES_END_HERE)); } static SIMD_FORCE_INLINE bool isCompound(int proxyType) { return (proxyType == COMPOUND_SHAPE_PROXYTYPE); } static SIMD_FORCE_INLINE bool isSoftBody(int proxyType) { return (proxyType == SOFTBODY_SHAPE_PROXYTYPE); } static SIMD_FORCE_INLINE bool isInfinite(int proxyType) { return (proxyType == STATIC_PLANE_PROXYTYPE); } static SIMD_FORCE_INLINE bool isConvex2d(int proxyType) { return (proxyType == BOX_2D_SHAPE_PROXYTYPE) || (proxyType == CONVEX_2D_SHAPE_PROXYTYPE); } } ; class btCollisionAlgorithm; struct btBroadphaseProxy; ///The btBroadphasePair class contains a pair of aabb-overlapping objects. ///A btDispatcher can search a btCollisionAlgorithm that performs exact/narrowphase collision detection on the actual collision shapes. ATTRIBUTE_ALIGNED16(struct) btBroadphasePair { btBroadphasePair () : m_pProxy0(0), m_pProxy1(0), m_algorithm(0), m_internalInfo1(0) { } BT_DECLARE_ALIGNED_ALLOCATOR(); btBroadphasePair(const btBroadphasePair& other) : m_pProxy0(other.m_pProxy0), m_pProxy1(other.m_pProxy1), m_algorithm(other.m_algorithm), m_internalInfo1(other.m_internalInfo1) { } btBroadphasePair(btBroadphaseProxy& proxy0,btBroadphaseProxy& proxy1) { //keep them sorted, so the std::set operations work if (proxy0.m_uniqueId < proxy1.m_uniqueId) { m_pProxy0 = &proxy0; m_pProxy1 = &proxy1; } else { m_pProxy0 = &proxy1; m_pProxy1 = &proxy0; } m_algorithm = 0; m_internalInfo1 = 0; } btBroadphaseProxy* m_pProxy0; btBroadphaseProxy* m_pProxy1; mutable btCollisionAlgorithm* m_algorithm; union { void* m_internalInfo1; int m_internalTmpValue;};//don't use this data, it will be removed in future version. }; /* //comparison for set operation, see Solid DT_Encounter SIMD_FORCE_INLINE bool operator<(const btBroadphasePair& a, const btBroadphasePair& b) { return a.m_pProxy0 < b.m_pProxy0 || (a.m_pProxy0 == b.m_pProxy0 && a.m_pProxy1 < b.m_pProxy1); } */ class btBroadphasePairSortPredicate { public: bool operator() ( const btBroadphasePair& a, const btBroadphasePair& b ) { const int uidA0 = a.m_pProxy0 ? a.m_pProxy0->m_uniqueId : -1; const int uidB0 = b.m_pProxy0 ? b.m_pProxy0->m_uniqueId : -1; const int uidA1 = a.m_pProxy1 ? a.m_pProxy1->m_uniqueId : -1; const int uidB1 = b.m_pProxy1 ? b.m_pProxy1->m_uniqueId : -1; return uidA0 > uidB0 || (a.m_pProxy0 == b.m_pProxy0 && uidA1 > uidB1) || (a.m_pProxy0 == b.m_pProxy0 && a.m_pProxy1 == b.m_pProxy1 && a.m_algorithm > b.m_algorithm); } }; SIMD_FORCE_INLINE bool operator==(const btBroadphasePair& a, const btBroadphasePair& b) { return (a.m_pProxy0 == b.m_pProxy0) && (a.m_pProxy1 == b.m_pProxy1); } #endif //BROADPHASE_PROXY_H critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btDispatcher.h0000644000175000017500000000652411337071441030577 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 _DISPATCHER_H #define _DISPATCHER_H #include "LinearMath/btScalar.h" class btCollisionAlgorithm; struct btBroadphaseProxy; class btRigidBody; class btCollisionObject; class btOverlappingPairCache; class btPersistentManifold; class btStackAlloc; struct btDispatcherInfo { enum DispatchFunc { DISPATCH_DISCRETE = 1, DISPATCH_CONTINUOUS }; btDispatcherInfo() :m_timeStep(btScalar(0.)), m_stepCount(0), m_dispatchFunc(DISPATCH_DISCRETE), m_timeOfImpact(btScalar(1.)), m_useContinuous(false), m_debugDraw(0), m_enableSatConvex(false), m_enableSPU(true), m_useEpa(true), m_allowedCcdPenetration(btScalar(0.04)), m_useConvexConservativeDistanceUtil(false), m_convexConservativeDistanceThreshold(0.0f), m_stackAllocator(0) { } btScalar m_timeStep; int m_stepCount; int m_dispatchFunc; mutable btScalar m_timeOfImpact; bool m_useContinuous; class btIDebugDraw* m_debugDraw; bool m_enableSatConvex; bool m_enableSPU; bool m_useEpa; btScalar m_allowedCcdPenetration; bool m_useConvexConservativeDistanceUtil; btScalar m_convexConservativeDistanceThreshold; btStackAlloc* m_stackAllocator; }; ///The btDispatcher interface class can be used in combination with broadphase to dispatch calculations for overlapping pairs. ///For example for pairwise collision detection, calculating contact points stored in btPersistentManifold or user callbacks (game logic). class btDispatcher { public: virtual ~btDispatcher() ; virtual btCollisionAlgorithm* findAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold=0) = 0; virtual btPersistentManifold* getNewManifold(void* body0,void* body1)=0; virtual void releaseManifold(btPersistentManifold* manifold)=0; virtual void clearManifold(btPersistentManifold* manifold)=0; virtual bool needsCollision(btCollisionObject* body0,btCollisionObject* body1) = 0; virtual bool needsResponse(btCollisionObject* body0,btCollisionObject* body1)=0; virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher) =0; virtual int getNumManifolds() const = 0; virtual btPersistentManifold* getManifoldByIndexInternal(int index) = 0; virtual btPersistentManifold** getInternalManifoldPointer() = 0; virtual void* allocateCollisionAlgorithm(int size) = 0; virtual void freeCollisionAlgorithm(void* ptr) = 0; }; #endif //_DISPATCHER_H critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btMultiSapBroadphase.cpp0000644000175000017500000004107011337071441032566 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btMultiSapBroadphase.h" #include "btSimpleBroadphase.h" #include "LinearMath/btAabbUtil2.h" #include "btQuantizedBvh.h" /// btSapBroadphaseArray m_sapBroadphases; /// btOverlappingPairCache* m_overlappingPairs; extern int gOverlappingPairs; /* class btMultiSapSortedOverlappingPairCache : public btSortedOverlappingPairCache { public: virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) { return btSortedOverlappingPairCache::addOverlappingPair((btBroadphaseProxy*)proxy0->m_multiSapParentProxy,(btBroadphaseProxy*)proxy1->m_multiSapParentProxy); } }; */ btMultiSapBroadphase::btMultiSapBroadphase(int /*maxProxies*/,btOverlappingPairCache* pairCache) :m_overlappingPairs(pairCache), m_optimizedAabbTree(0), m_ownsPairCache(false), m_invalidPair(0) { if (!m_overlappingPairs) { m_ownsPairCache = true; void* mem = btAlignedAlloc(sizeof(btSortedOverlappingPairCache),16); m_overlappingPairs = new (mem)btSortedOverlappingPairCache(); } struct btMultiSapOverlapFilterCallback : public btOverlapFilterCallback { virtual ~btMultiSapOverlapFilterCallback() {} // return true when pairs need collision virtual bool needBroadphaseCollision(btBroadphaseProxy* childProxy0,btBroadphaseProxy* childProxy1) const { btBroadphaseProxy* multiProxy0 = (btBroadphaseProxy*)childProxy0->m_multiSapParentProxy; btBroadphaseProxy* multiProxy1 = (btBroadphaseProxy*)childProxy1->m_multiSapParentProxy; bool collides = (multiProxy0->m_collisionFilterGroup & multiProxy1->m_collisionFilterMask) != 0; collides = collides && (multiProxy1->m_collisionFilterGroup & multiProxy0->m_collisionFilterMask); return collides; } }; void* mem = btAlignedAlloc(sizeof(btMultiSapOverlapFilterCallback),16); m_filterCallback = new (mem)btMultiSapOverlapFilterCallback(); m_overlappingPairs->setOverlapFilterCallback(m_filterCallback); // mem = btAlignedAlloc(sizeof(btSimpleBroadphase),16); // m_simpleBroadphase = new (mem) btSimpleBroadphase(maxProxies,m_overlappingPairs); } btMultiSapBroadphase::~btMultiSapBroadphase() { if (m_ownsPairCache) { m_overlappingPairs->~btOverlappingPairCache(); btAlignedFree(m_overlappingPairs); } } void btMultiSapBroadphase::buildTree(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax) { m_optimizedAabbTree = new btQuantizedBvh(); m_optimizedAabbTree->setQuantizationValues(bvhAabbMin,bvhAabbMax); QuantizedNodeArray& nodes = m_optimizedAabbTree->getLeafNodeArray(); for (int i=0;igetBroadphaseAabb(aabbMin,aabbMax); m_optimizedAabbTree->quantize(&node.m_quantizedAabbMin[0],aabbMin,0); m_optimizedAabbTree->quantize(&node.m_quantizedAabbMax[0],aabbMax,1); int partId = 0; node.m_escapeIndexOrTriangleIndex = (partId<<(31-MAX_NUM_PARTS_IN_BITS)) | i; nodes.push_back(node); } m_optimizedAabbTree->buildInternal(); } btBroadphaseProxy* btMultiSapBroadphase::createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* /*ignoreMe*/) { //void* ignoreMe -> we could think of recursive multi-sap, if someone is interested void* mem = btAlignedAlloc(sizeof(btMultiSapProxy),16); btMultiSapProxy* proxy = new (mem)btMultiSapProxy(aabbMin, aabbMax,shapeType,userPtr, collisionFilterGroup,collisionFilterMask); m_multiSapProxies.push_back(proxy); ///this should deal with inserting/removal into child broadphases setAabb(proxy,aabbMin,aabbMax,dispatcher); return proxy; } void btMultiSapBroadphase::destroyProxy(btBroadphaseProxy* /*proxy*/,btDispatcher* /*dispatcher*/) { ///not yet btAssert(0); } void btMultiSapBroadphase::addToChildBroadphase(btMultiSapProxy* parentMultiSapProxy, btBroadphaseProxy* childProxy, btBroadphaseInterface* childBroadphase) { void* mem = btAlignedAlloc(sizeof(btBridgeProxy),16); btBridgeProxy* bridgeProxyRef = new(mem) btBridgeProxy; bridgeProxyRef->m_childProxy = childProxy; bridgeProxyRef->m_childBroadphase = childBroadphase; parentMultiSapProxy->m_bridgeProxies.push_back(bridgeProxyRef); } bool boxIsContainedWithinBox(const btVector3& amin,const btVector3& amax,const btVector3& bmin,const btVector3& bmax); bool boxIsContainedWithinBox(const btVector3& amin,const btVector3& amax,const btVector3& bmin,const btVector3& bmax) { return amin.getX() >= bmin.getX() && amax.getX() <= bmax.getX() && amin.getY() >= bmin.getY() && amax.getY() <= bmax.getY() && amin.getZ() >= bmin.getZ() && amax.getZ() <= bmax.getZ(); } void btMultiSapBroadphase::getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const { btMultiSapProxy* multiProxy = static_cast(proxy); aabbMin = multiProxy->m_aabbMin; aabbMax = multiProxy->m_aabbMax; } void btMultiSapBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin,const btVector3& aabbMax) { for (int i=0;i void btMultiSapBroadphase::setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher) { btMultiSapProxy* multiProxy = static_cast(proxy); multiProxy->m_aabbMin = aabbMin; multiProxy->m_aabbMax = aabbMax; // bool fullyContained = false; // bool alreadyInSimple = false; struct MyNodeOverlapCallback : public btNodeOverlapCallback { btMultiSapBroadphase* m_multiSap; btMultiSapProxy* m_multiProxy; btDispatcher* m_dispatcher; MyNodeOverlapCallback(btMultiSapBroadphase* multiSap,btMultiSapProxy* multiProxy,btDispatcher* dispatcher) :m_multiSap(multiSap), m_multiProxy(multiProxy), m_dispatcher(dispatcher) { } virtual void processNode(int /*nodeSubPart*/, int broadphaseIndex) { btBroadphaseInterface* childBroadphase = m_multiSap->getBroadphaseArray()[broadphaseIndex]; int containingBroadphaseIndex = -1; //already found? for (int i=0;im_bridgeProxies.size();i++) { if (m_multiProxy->m_bridgeProxies[i]->m_childBroadphase == childBroadphase) { containingBroadphaseIndex = i; break; } } if (containingBroadphaseIndex<0) { //add it btBroadphaseProxy* childProxy = childBroadphase->createProxy(m_multiProxy->m_aabbMin,m_multiProxy->m_aabbMax,m_multiProxy->m_shapeType,m_multiProxy->m_clientObject,m_multiProxy->m_collisionFilterGroup,m_multiProxy->m_collisionFilterMask, m_dispatcher,m_multiProxy); m_multiSap->addToChildBroadphase(m_multiProxy,childProxy,childBroadphase); } } }; MyNodeOverlapCallback myNodeCallback(this,multiProxy,dispatcher); if (m_optimizedAabbTree) m_optimizedAabbTree->reportAabbOverlappingNodex(&myNodeCallback,aabbMin,aabbMax); int i; for ( i=0;im_bridgeProxies.size();i++) { btVector3 worldAabbMin,worldAabbMax; multiProxy->m_bridgeProxies[i]->m_childBroadphase->getBroadphaseAabb(worldAabbMin,worldAabbMax); bool overlapsBroadphase = TestAabbAgainstAabb2(worldAabbMin,worldAabbMax,multiProxy->m_aabbMin,multiProxy->m_aabbMax); if (!overlapsBroadphase) { //remove it now btBridgeProxy* bridgeProxy = multiProxy->m_bridgeProxies[i]; btBroadphaseProxy* childProxy = bridgeProxy->m_childProxy; bridgeProxy->m_childBroadphase->destroyProxy(childProxy,dispatcher); multiProxy->m_bridgeProxies.swap( i,multiProxy->m_bridgeProxies.size()-1); multiProxy->m_bridgeProxies.pop_back(); } } /* if (1) { //find broadphase that contain this multiProxy int numChildBroadphases = getBroadphaseArray().size(); for (int i=0;igetBroadphaseAabb(worldAabbMin,worldAabbMax); bool overlapsBroadphase = TestAabbAgainstAabb2(worldAabbMin,worldAabbMax,multiProxy->m_aabbMin,multiProxy->m_aabbMax); // fullyContained = fullyContained || boxIsContainedWithinBox(worldAabbMin,worldAabbMax,multiProxy->m_aabbMin,multiProxy->m_aabbMax); int containingBroadphaseIndex = -1; //if already contains this for (int i=0;im_bridgeProxies.size();i++) { if (multiProxy->m_bridgeProxies[i]->m_childBroadphase == childBroadphase) { containingBroadphaseIndex = i; } alreadyInSimple = alreadyInSimple || (multiProxy->m_bridgeProxies[i]->m_childBroadphase == m_simpleBroadphase); } if (overlapsBroadphase) { if (containingBroadphaseIndex<0) { btBroadphaseProxy* childProxy = childBroadphase->createProxy(aabbMin,aabbMax,multiProxy->m_shapeType,multiProxy->m_clientObject,multiProxy->m_collisionFilterGroup,multiProxy->m_collisionFilterMask, dispatcher); childProxy->m_multiSapParentProxy = multiProxy; addToChildBroadphase(multiProxy,childProxy,childBroadphase); } } else { if (containingBroadphaseIndex>=0) { //remove btBridgeProxy* bridgeProxy = multiProxy->m_bridgeProxies[containingBroadphaseIndex]; btBroadphaseProxy* childProxy = bridgeProxy->m_childProxy; bridgeProxy->m_childBroadphase->destroyProxy(childProxy,dispatcher); multiProxy->m_bridgeProxies.swap( containingBroadphaseIndex,multiProxy->m_bridgeProxies.size()-1); multiProxy->m_bridgeProxies.pop_back(); } } } ///If we are in no other child broadphase, stick the proxy in the global 'simple' broadphase (brute force) ///hopefully we don't end up with many entries here (can assert/provide feedback on stats) if (0)//!multiProxy->m_bridgeProxies.size()) { ///we don't pass the userPtr but our multisap proxy. We need to patch this, before processing an actual collision ///this is needed to be able to calculate the aabb overlap btBroadphaseProxy* childProxy = m_simpleBroadphase->createProxy(aabbMin,aabbMax,multiProxy->m_shapeType,multiProxy->m_clientObject,multiProxy->m_collisionFilterGroup,multiProxy->m_collisionFilterMask, dispatcher); childProxy->m_multiSapParentProxy = multiProxy; addToChildBroadphase(multiProxy,childProxy,m_simpleBroadphase); } } if (!multiProxy->m_bridgeProxies.size()) { ///we don't pass the userPtr but our multisap proxy. We need to patch this, before processing an actual collision ///this is needed to be able to calculate the aabb overlap btBroadphaseProxy* childProxy = m_simpleBroadphase->createProxy(aabbMin,aabbMax,multiProxy->m_shapeType,multiProxy->m_clientObject,multiProxy->m_collisionFilterGroup,multiProxy->m_collisionFilterMask, dispatcher); childProxy->m_multiSapParentProxy = multiProxy; addToChildBroadphase(multiProxy,childProxy,m_simpleBroadphase); } */ //update for ( i=0;im_bridgeProxies.size();i++) { btBridgeProxy* bridgeProxyRef = multiProxy->m_bridgeProxies[i]; bridgeProxyRef->m_childBroadphase->setAabb(bridgeProxyRef->m_childProxy,aabbMin,aabbMax,dispatcher); } } bool stopUpdating=false; class btMultiSapBroadphasePairSortPredicate { public: bool operator() ( const btBroadphasePair& a1, const btBroadphasePair& b1 ) { btMultiSapBroadphase::btMultiSapProxy* aProxy0 = a1.m_pProxy0 ? (btMultiSapBroadphase::btMultiSapProxy*)a1.m_pProxy0->m_multiSapParentProxy : 0; btMultiSapBroadphase::btMultiSapProxy* aProxy1 = a1.m_pProxy1 ? (btMultiSapBroadphase::btMultiSapProxy*)a1.m_pProxy1->m_multiSapParentProxy : 0; btMultiSapBroadphase::btMultiSapProxy* bProxy0 = b1.m_pProxy0 ? (btMultiSapBroadphase::btMultiSapProxy*)b1.m_pProxy0->m_multiSapParentProxy : 0; btMultiSapBroadphase::btMultiSapProxy* bProxy1 = b1.m_pProxy1 ? (btMultiSapBroadphase::btMultiSapProxy*)b1.m_pProxy1->m_multiSapParentProxy : 0; return aProxy0 > bProxy0 || (aProxy0 == bProxy0 && aProxy1 > bProxy1) || (aProxy0 == bProxy0 && aProxy1 == bProxy1 && a1.m_algorithm > b1.m_algorithm); } }; ///calculateOverlappingPairs is optional: incremental algorithms (sweep and prune) might do it during the set aabb void btMultiSapBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher) { // m_simpleBroadphase->calculateOverlappingPairs(dispatcher); if (!stopUpdating && getOverlappingPairCache()->hasDeferredRemoval()) { btBroadphasePairArray& overlappingPairArray = getOverlappingPairCache()->getOverlappingPairArray(); // quicksort(overlappingPairArray,0,overlappingPairArray.size()); overlappingPairArray.quickSort(btMultiSapBroadphasePairSortPredicate()); //perform a sort, to find duplicates and to sort 'invalid' pairs to the end // overlappingPairArray.heapSort(btMultiSapBroadphasePairSortPredicate()); overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); m_invalidPair = 0; int i; btBroadphasePair previousPair; previousPair.m_pProxy0 = 0; previousPair.m_pProxy1 = 0; previousPair.m_algorithm = 0; for (i=0;im_multiSapParentProxy : 0; btMultiSapProxy* aProxy1 = pair.m_pProxy1 ? (btMultiSapProxy*)pair.m_pProxy1->m_multiSapParentProxy : 0; btMultiSapProxy* bProxy0 = previousPair.m_pProxy0 ? (btMultiSapProxy*)previousPair.m_pProxy0->m_multiSapParentProxy : 0; btMultiSapProxy* bProxy1 = previousPair.m_pProxy1 ? (btMultiSapProxy*)previousPair.m_pProxy1->m_multiSapParentProxy : 0; bool isDuplicate = (aProxy0 == bProxy0) && (aProxy1 == bProxy1); previousPair = pair; bool needsRemoval = false; if (!isDuplicate) { bool hasOverlap = testAabbOverlap(pair.m_pProxy0,pair.m_pProxy1); if (hasOverlap) { needsRemoval = false;//callback->processOverlap(pair); } else { needsRemoval = true; } } else { //remove duplicate needsRemoval = true; //should have no algorithm btAssert(!pair.m_algorithm); } if (needsRemoval) { getOverlappingPairCache()->cleanOverlappingPair(pair,dispatcher); // m_overlappingPairArray.swap(i,m_overlappingPairArray.size()-1); // m_overlappingPairArray.pop_back(); pair.m_pProxy0 = 0; pair.m_pProxy1 = 0; m_invalidPair++; gOverlappingPairs--; } } ///if you don't like to skip the invalid pairs in the array, execute following code: #define CLEAN_INVALID_PAIRS 1 #ifdef CLEAN_INVALID_PAIRS //perform a sort, to sort 'invalid' pairs to the end //overlappingPairArray.heapSort(btMultiSapBroadphasePairSortPredicate()); overlappingPairArray.quickSort(btMultiSapBroadphasePairSortPredicate()); overlappingPairArray.resize(overlappingPairArray.size() - m_invalidPair); m_invalidPair = 0; #endif//CLEAN_INVALID_PAIRS //printf("overlappingPairArray.size()=%d\n",overlappingPairArray.size()); } } bool btMultiSapBroadphase::testAabbOverlap(btBroadphaseProxy* childProxy0,btBroadphaseProxy* childProxy1) { btMultiSapProxy* multiSapProxy0 = (btMultiSapProxy*)childProxy0->m_multiSapParentProxy; btMultiSapProxy* multiSapProxy1 = (btMultiSapProxy*)childProxy1->m_multiSapParentProxy; return TestAabbAgainstAabb2(multiSapProxy0->m_aabbMin,multiSapProxy0->m_aabbMax, multiSapProxy1->m_aabbMin,multiSapProxy1->m_aabbMax); } void btMultiSapBroadphase::printStats() { /* printf("---------------------------------\n"); printf("btMultiSapBroadphase.h\n"); printf("numHandles = %d\n",m_multiSapProxies.size()); //find broadphase that contain this multiProxy int numChildBroadphases = getBroadphaseArray().size(); for (int i=0;iprintStats(); } */ } void btMultiSapBroadphase::resetPool(btDispatcher* dispatcher) { // not yet } critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btDbvt.h0000644000175000017500000007637511344267705027433 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2007 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ ///btDbvt implementation by Nathanael Presson #ifndef BT_DYNAMIC_BOUNDING_VOLUME_TREE_H #define BT_DYNAMIC_BOUNDING_VOLUME_TREE_H #include "LinearMath/btAlignedObjectArray.h" #include "LinearMath/btVector3.h" #include "LinearMath/btTransform.h" #include "LinearMath/btAabbUtil2.h" // // Compile time configuration // // Implementation profiles #define DBVT_IMPL_GENERIC 0 // Generic implementation #define DBVT_IMPL_SSE 1 // SSE // Template implementation of ICollide #ifdef _WIN32 #if (defined (_MSC_VER) && _MSC_VER >= 1400) #define DBVT_USE_TEMPLATE 1 #else #define DBVT_USE_TEMPLATE 0 #endif #else #define DBVT_USE_TEMPLATE 0 #endif // Use only intrinsics instead of inline asm #define DBVT_USE_INTRINSIC_SSE 1 // Using memmov for collideOCL #define DBVT_USE_MEMMOVE 1 // Enable benchmarking code #define DBVT_ENABLE_BENCHMARK 0 // Inlining #define DBVT_INLINE SIMD_FORCE_INLINE // Specific methods implementation //SSE gives errors on a MSVC 7.1 #if defined (BT_USE_SSE) && defined (_WIN32) #define DBVT_SELECT_IMPL DBVT_IMPL_SSE #define DBVT_MERGE_IMPL DBVT_IMPL_SSE #define DBVT_INT0_IMPL DBVT_IMPL_SSE #else #define DBVT_SELECT_IMPL DBVT_IMPL_GENERIC #define DBVT_MERGE_IMPL DBVT_IMPL_GENERIC #define DBVT_INT0_IMPL DBVT_IMPL_GENERIC #endif #if (DBVT_SELECT_IMPL==DBVT_IMPL_SSE)|| \ (DBVT_MERGE_IMPL==DBVT_IMPL_SSE)|| \ (DBVT_INT0_IMPL==DBVT_IMPL_SSE) #include #endif // // Auto config and checks // #if DBVT_USE_TEMPLATE #define DBVT_VIRTUAL #define DBVT_VIRTUAL_DTOR(a) #define DBVT_PREFIX template #define DBVT_IPOLICY T& policy #define DBVT_CHECKTYPE static const ICollide& typechecker=*(T*)1;(void)typechecker; #else #define DBVT_VIRTUAL_DTOR(a) virtual ~a() {} #define DBVT_VIRTUAL virtual #define DBVT_PREFIX #define DBVT_IPOLICY ICollide& policy #define DBVT_CHECKTYPE #endif #if DBVT_USE_MEMMOVE #if !defined( __CELLOS_LV2__) && !defined(__MWERKS__) #include #endif #include #endif #ifndef DBVT_USE_TEMPLATE #error "DBVT_USE_TEMPLATE undefined" #endif #ifndef DBVT_USE_MEMMOVE #error "DBVT_USE_MEMMOVE undefined" #endif #ifndef DBVT_ENABLE_BENCHMARK #error "DBVT_ENABLE_BENCHMARK undefined" #endif #ifndef DBVT_SELECT_IMPL #error "DBVT_SELECT_IMPL undefined" #endif #ifndef DBVT_MERGE_IMPL #error "DBVT_MERGE_IMPL undefined" #endif #ifndef DBVT_INT0_IMPL #error "DBVT_INT0_IMPL undefined" #endif // // Defaults volumes // /* btDbvtAabbMm */ struct btDbvtAabbMm { DBVT_INLINE btVector3 Center() const { return((mi+mx)/2); } DBVT_INLINE btVector3 Lengths() const { return(mx-mi); } DBVT_INLINE btVector3 Extents() const { return((mx-mi)/2); } DBVT_INLINE const btVector3& Mins() const { return(mi); } DBVT_INLINE const btVector3& Maxs() const { return(mx); } static inline btDbvtAabbMm FromCE(const btVector3& c,const btVector3& e); static inline btDbvtAabbMm FromCR(const btVector3& c,btScalar r); static inline btDbvtAabbMm FromMM(const btVector3& mi,const btVector3& mx); static inline btDbvtAabbMm FromPoints(const btVector3* pts,int n); static inline btDbvtAabbMm FromPoints(const btVector3** ppts,int n); DBVT_INLINE void Expand(const btVector3& e); DBVT_INLINE void SignedExpand(const btVector3& e); DBVT_INLINE bool Contain(const btDbvtAabbMm& a) const; DBVT_INLINE int Classify(const btVector3& n,btScalar o,int s) const; DBVT_INLINE btScalar ProjectMinimum(const btVector3& v,unsigned signs) const; DBVT_INLINE friend bool Intersect( const btDbvtAabbMm& a, const btDbvtAabbMm& b); DBVT_INLINE friend bool Intersect( const btDbvtAabbMm& a, const btVector3& b); DBVT_INLINE friend btScalar Proximity( const btDbvtAabbMm& a, const btDbvtAabbMm& b); DBVT_INLINE friend int Select( const btDbvtAabbMm& o, const btDbvtAabbMm& a, const btDbvtAabbMm& b); DBVT_INLINE friend void Merge( const btDbvtAabbMm& a, const btDbvtAabbMm& b, btDbvtAabbMm& r); DBVT_INLINE friend bool NotEqual( const btDbvtAabbMm& a, const btDbvtAabbMm& b); private: DBVT_INLINE void AddSpan(const btVector3& d,btScalar& smi,btScalar& smx) const; private: btVector3 mi,mx; }; // Types typedef btDbvtAabbMm btDbvtVolume; /* btDbvtNode */ struct btDbvtNode { btDbvtVolume volume; btDbvtNode* parent; DBVT_INLINE bool isleaf() const { return(childs[1]==0); } DBVT_INLINE bool isinternal() const { return(!isleaf()); } union { btDbvtNode* childs[2]; void* data; int dataAsInt; }; }; ///The btDbvt class implements a fast dynamic bounding volume tree based on axis aligned bounding boxes (aabb tree). ///This btDbvt is used for soft body collision detection and for the btDbvtBroadphase. It has a fast insert, remove and update of nodes. ///Unlike the btQuantizedBvh, nodes can be dynamically moved around, which allows for change in topology of the underlying data structure. struct btDbvt { /* Stack element */ struct sStkNN { const btDbvtNode* a; const btDbvtNode* b; sStkNN() {} sStkNN(const btDbvtNode* na,const btDbvtNode* nb) : a(na),b(nb) {} }; struct sStkNP { const btDbvtNode* node; int mask; sStkNP(const btDbvtNode* n,unsigned m) : node(n),mask(m) {} }; struct sStkNPS { const btDbvtNode* node; int mask; btScalar value; sStkNPS() {} sStkNPS(const btDbvtNode* n,unsigned m,btScalar v) : node(n),mask(m),value(v) {} }; struct sStkCLN { const btDbvtNode* node; btDbvtNode* parent; sStkCLN(const btDbvtNode* n,btDbvtNode* p) : node(n),parent(p) {} }; // Policies/Interfaces /* ICollide */ struct ICollide { DBVT_VIRTUAL_DTOR(ICollide) DBVT_VIRTUAL void Process(const btDbvtNode*,const btDbvtNode*) {} DBVT_VIRTUAL void Process(const btDbvtNode*) {} DBVT_VIRTUAL void Process(const btDbvtNode* n,btScalar) { Process(n); } DBVT_VIRTUAL bool Descent(const btDbvtNode*) { return(true); } DBVT_VIRTUAL bool AllLeaves(const btDbvtNode*) { return(true); } }; /* IWriter */ struct IWriter { virtual ~IWriter() {} virtual void Prepare(const btDbvtNode* root,int numnodes)=0; virtual void WriteNode(const btDbvtNode*,int index,int parent,int child0,int child1)=0; virtual void WriteLeaf(const btDbvtNode*,int index,int parent)=0; }; /* IClone */ struct IClone { virtual ~IClone() {} virtual void CloneLeaf(btDbvtNode*) {} }; // Constants enum { SIMPLE_STACKSIZE = 64, DOUBLE_STACKSIZE = SIMPLE_STACKSIZE*2 }; // Fields btDbvtNode* m_root; btDbvtNode* m_free; int m_lkhd; int m_leaves; unsigned m_opath; btAlignedObjectArray m_stkStack; // Methods btDbvt(); ~btDbvt(); void clear(); bool empty() const { return(0==m_root); } void optimizeBottomUp(); void optimizeTopDown(int bu_treshold=128); void optimizeIncremental(int passes); btDbvtNode* insert(const btDbvtVolume& box,void* data); void update(btDbvtNode* leaf,int lookahead=-1); void update(btDbvtNode* leaf,btDbvtVolume& volume); bool update(btDbvtNode* leaf,btDbvtVolume& volume,const btVector3& velocity,btScalar margin); bool update(btDbvtNode* leaf,btDbvtVolume& volume,const btVector3& velocity); bool update(btDbvtNode* leaf,btDbvtVolume& volume,btScalar margin); void remove(btDbvtNode* leaf); void write(IWriter* iwriter) const; void clone(btDbvt& dest,IClone* iclone=0) const; static int maxdepth(const btDbvtNode* node); static int countLeaves(const btDbvtNode* node); static void extractLeaves(const btDbvtNode* node,btAlignedObjectArray& leaves); #if DBVT_ENABLE_BENCHMARK static void benchmark(); #else static void benchmark(){} #endif // DBVT_IPOLICY must support ICollide policy/interface DBVT_PREFIX static void enumNodes( const btDbvtNode* root, DBVT_IPOLICY); DBVT_PREFIX static void enumLeaves( const btDbvtNode* root, DBVT_IPOLICY); DBVT_PREFIX void collideTT( const btDbvtNode* root0, const btDbvtNode* root1, DBVT_IPOLICY); DBVT_PREFIX void collideTTpersistentStack( const btDbvtNode* root0, const btDbvtNode* root1, DBVT_IPOLICY); #if 0 DBVT_PREFIX void collideTT( const btDbvtNode* root0, const btDbvtNode* root1, const btTransform& xform, DBVT_IPOLICY); DBVT_PREFIX void collideTT( const btDbvtNode* root0, const btTransform& xform0, const btDbvtNode* root1, const btTransform& xform1, DBVT_IPOLICY); #endif DBVT_PREFIX void collideTV( const btDbvtNode* root, const btDbvtVolume& volume, DBVT_IPOLICY); ///rayTest is a re-entrant ray test, and can be called in parallel as long as the btAlignedAlloc is thread-safe (uses locking etc) ///rayTest is slower than rayTestInternal, because it builds a local stack, using memory allocations, and it recomputes signs/rayDirectionInverses each time DBVT_PREFIX static void rayTest( const btDbvtNode* root, const btVector3& rayFrom, const btVector3& rayTo, DBVT_IPOLICY); ///rayTestInternal is faster than rayTest, because it uses a persistent stack (to reduce dynamic memory allocations to a minimum) and it uses precomputed signs/rayInverseDirections ///rayTestInternal is used by btDbvtBroadphase to accelerate world ray casts DBVT_PREFIX void rayTestInternal( const btDbvtNode* root, const btVector3& rayFrom, const btVector3& rayTo, const btVector3& rayDirectionInverse, unsigned int signs[3], btScalar lambda_max, const btVector3& aabbMin, const btVector3& aabbMax, DBVT_IPOLICY) const; DBVT_PREFIX static void collideKDOP(const btDbvtNode* root, const btVector3* normals, const btScalar* offsets, int count, DBVT_IPOLICY); DBVT_PREFIX static void collideOCL( const btDbvtNode* root, const btVector3* normals, const btScalar* offsets, const btVector3& sortaxis, int count, DBVT_IPOLICY, bool fullsort=true); DBVT_PREFIX static void collideTU( const btDbvtNode* root, DBVT_IPOLICY); // Helpers static DBVT_INLINE int nearest(const int* i,const btDbvt::sStkNPS* a,btScalar v,int l,int h) { int m=0; while(l>1; if(a[i[m]].value>=v) l=m+1; else h=m; } return(h); } static DBVT_INLINE int allocate( btAlignedObjectArray& ifree, btAlignedObjectArray& stock, const sStkNPS& value) { int i; if(ifree.size()>0) { i=ifree[ifree.size()-1];ifree.pop_back();stock[i]=value; } else { i=stock.size();stock.push_back(value); } return(i); } // private: btDbvt(const btDbvt&) {} }; // // Inline's // // inline btDbvtAabbMm btDbvtAabbMm::FromCE(const btVector3& c,const btVector3& e) { btDbvtAabbMm box; box.mi=c-e;box.mx=c+e; return(box); } // inline btDbvtAabbMm btDbvtAabbMm::FromCR(const btVector3& c,btScalar r) { return(FromCE(c,btVector3(r,r,r))); } // inline btDbvtAabbMm btDbvtAabbMm::FromMM(const btVector3& mi,const btVector3& mx) { btDbvtAabbMm box; box.mi=mi;box.mx=mx; return(box); } // inline btDbvtAabbMm btDbvtAabbMm::FromPoints(const btVector3* pts,int n) { btDbvtAabbMm box; box.mi=box.mx=pts[0]; for(int i=1;i0) mx.setX(mx.x()+e[0]); else mi.setX(mi.x()+e[0]); if(e.y()>0) mx.setY(mx.y()+e[1]); else mi.setY(mi.y()+e[1]); if(e.z()>0) mx.setZ(mx.z()+e[2]); else mi.setZ(mi.z()+e[2]); } // DBVT_INLINE bool btDbvtAabbMm::Contain(const btDbvtAabbMm& a) const { return( (mi.x()<=a.mi.x())&& (mi.y()<=a.mi.y())&& (mi.z()<=a.mi.z())&& (mx.x()>=a.mx.x())&& (mx.y()>=a.mx.y())&& (mx.z()>=a.mx.z())); } // DBVT_INLINE int btDbvtAabbMm::Classify(const btVector3& n,btScalar o,int s) const { btVector3 pi,px; switch(s) { case (0+0+0): px=btVector3(mi.x(),mi.y(),mi.z()); pi=btVector3(mx.x(),mx.y(),mx.z());break; case (1+0+0): px=btVector3(mx.x(),mi.y(),mi.z()); pi=btVector3(mi.x(),mx.y(),mx.z());break; case (0+2+0): px=btVector3(mi.x(),mx.y(),mi.z()); pi=btVector3(mx.x(),mi.y(),mx.z());break; case (1+2+0): px=btVector3(mx.x(),mx.y(),mi.z()); pi=btVector3(mi.x(),mi.y(),mx.z());break; case (0+0+4): px=btVector3(mi.x(),mi.y(),mx.z()); pi=btVector3(mx.x(),mx.y(),mi.z());break; case (1+0+4): px=btVector3(mx.x(),mi.y(),mx.z()); pi=btVector3(mi.x(),mx.y(),mi.z());break; case (0+2+4): px=btVector3(mi.x(),mx.y(),mx.z()); pi=btVector3(mx.x(),mi.y(),mi.z());break; case (1+2+4): px=btVector3(mx.x(),mx.y(),mx.z()); pi=btVector3(mi.x(),mi.y(),mi.z());break; } if((btDot(n,px)+o)<0) return(-1); if((btDot(n,pi)+o)>=0) return(+1); return(0); } // DBVT_INLINE btScalar btDbvtAabbMm::ProjectMinimum(const btVector3& v,unsigned signs) const { const btVector3* b[]={&mx,&mi}; const btVector3 p( b[(signs>>0)&1]->x(), b[(signs>>1)&1]->y(), b[(signs>>2)&1]->z()); return(btDot(p,v)); } // DBVT_INLINE void btDbvtAabbMm::AddSpan(const btVector3& d,btScalar& smi,btScalar& smx) const { for(int i=0;i<3;++i) { if(d[i]<0) { smi+=mx[i]*d[i];smx+=mi[i]*d[i]; } else { smi+=mi[i]*d[i];smx+=mx[i]*d[i]; } } } // DBVT_INLINE bool Intersect( const btDbvtAabbMm& a, const btDbvtAabbMm& b) { #if DBVT_INT0_IMPL == DBVT_IMPL_SSE const __m128 rt(_mm_or_ps( _mm_cmplt_ps(_mm_load_ps(b.mx),_mm_load_ps(a.mi)), _mm_cmplt_ps(_mm_load_ps(a.mx),_mm_load_ps(b.mi)))); const __int32* pu((const __int32*)&rt); return((pu[0]|pu[1]|pu[2])==0); #else return( (a.mi.x()<=b.mx.x())&& (a.mx.x()>=b.mi.x())&& (a.mi.y()<=b.mx.y())&& (a.mx.y()>=b.mi.y())&& (a.mi.z()<=b.mx.z())&& (a.mx.z()>=b.mi.z())); #endif } // DBVT_INLINE bool Intersect( const btDbvtAabbMm& a, const btVector3& b) { return( (b.x()>=a.mi.x())&& (b.y()>=a.mi.y())&& (b.z()>=a.mi.z())&& (b.x()<=a.mx.x())&& (b.y()<=a.mx.y())&& (b.z()<=a.mx.z())); } ////////////////////////////////////// // DBVT_INLINE btScalar Proximity( const btDbvtAabbMm& a, const btDbvtAabbMm& b) { const btVector3 d=(a.mi+a.mx)-(b.mi+b.mx); return(btFabs(d.x())+btFabs(d.y())+btFabs(d.z())); } // DBVT_INLINE int Select( const btDbvtAabbMm& o, const btDbvtAabbMm& a, const btDbvtAabbMm& b) { #if DBVT_SELECT_IMPL == DBVT_IMPL_SSE static ATTRIBUTE_ALIGNED16(const unsigned __int32) mask[]={0x7fffffff,0x7fffffff,0x7fffffff,0x7fffffff}; ///@todo: the intrinsic version is 11% slower #if DBVT_USE_INTRINSIC_SSE union btSSEUnion ///NOTE: if we use more intrinsics, move btSSEUnion into the LinearMath directory { __m128 ssereg; float floats[4]; int ints[4]; }; __m128 omi(_mm_load_ps(o.mi)); omi=_mm_add_ps(omi,_mm_load_ps(o.mx)); __m128 ami(_mm_load_ps(a.mi)); ami=_mm_add_ps(ami,_mm_load_ps(a.mx)); ami=_mm_sub_ps(ami,omi); ami=_mm_and_ps(ami,_mm_load_ps((const float*)mask)); __m128 bmi(_mm_load_ps(b.mi)); bmi=_mm_add_ps(bmi,_mm_load_ps(b.mx)); bmi=_mm_sub_ps(bmi,omi); bmi=_mm_and_ps(bmi,_mm_load_ps((const float*)mask)); __m128 t0(_mm_movehl_ps(ami,ami)); ami=_mm_add_ps(ami,t0); ami=_mm_add_ss(ami,_mm_shuffle_ps(ami,ami,1)); __m128 t1(_mm_movehl_ps(bmi,bmi)); bmi=_mm_add_ps(bmi,t1); bmi=_mm_add_ss(bmi,_mm_shuffle_ps(bmi,bmi,1)); btSSEUnion tmp; tmp.ssereg = _mm_cmple_ss(bmi,ami); return tmp.ints[0]&1; #else ATTRIBUTE_ALIGNED16(__int32 r[1]); __asm { mov eax,o mov ecx,a mov edx,b movaps xmm0,[eax] movaps xmm5,mask addps xmm0,[eax+16] movaps xmm1,[ecx] movaps xmm2,[edx] addps xmm1,[ecx+16] addps xmm2,[edx+16] subps xmm1,xmm0 subps xmm2,xmm0 andps xmm1,xmm5 andps xmm2,xmm5 movhlps xmm3,xmm1 movhlps xmm4,xmm2 addps xmm1,xmm3 addps xmm2,xmm4 pshufd xmm3,xmm1,1 pshufd xmm4,xmm2,1 addss xmm1,xmm3 addss xmm2,xmm4 cmpless xmm2,xmm1 movss r,xmm2 } return(r[0]&1); #endif #else return(Proximity(o,a)b.mx[i]) r.mx[i]=a.mx[i]; else r.mx[i]=b.mx[i]; } #endif } // DBVT_INLINE bool NotEqual( const btDbvtAabbMm& a, const btDbvtAabbMm& b) { return( (a.mi.x()!=b.mi.x())|| (a.mi.y()!=b.mi.y())|| (a.mi.z()!=b.mi.z())|| (a.mx.x()!=b.mx.x())|| (a.mx.y()!=b.mx.y())|| (a.mx.z()!=b.mx.z())); } // // Inline's // // DBVT_PREFIX inline void btDbvt::enumNodes( const btDbvtNode* root, DBVT_IPOLICY) { DBVT_CHECKTYPE policy.Process(root); if(root->isinternal()) { enumNodes(root->childs[0],policy); enumNodes(root->childs[1],policy); } } // DBVT_PREFIX inline void btDbvt::enumLeaves( const btDbvtNode* root, DBVT_IPOLICY) { DBVT_CHECKTYPE if(root->isinternal()) { enumLeaves(root->childs[0],policy); enumLeaves(root->childs[1],policy); } else { policy.Process(root); } } // DBVT_PREFIX inline void btDbvt::collideTT( const btDbvtNode* root0, const btDbvtNode* root1, DBVT_IPOLICY) { DBVT_CHECKTYPE if(root0&&root1) { int depth=1; int treshold=DOUBLE_STACKSIZE-4; btAlignedObjectArray stkStack; stkStack.resize(DOUBLE_STACKSIZE); stkStack[0]=sStkNN(root0,root1); do { sStkNN p=stkStack[--depth]; if(depth>treshold) { stkStack.resize(stkStack.size()*2); treshold=stkStack.size()-4; } if(p.a==p.b) { if(p.a->isinternal()) { stkStack[depth++]=sStkNN(p.a->childs[0],p.a->childs[0]); stkStack[depth++]=sStkNN(p.a->childs[1],p.a->childs[1]); stkStack[depth++]=sStkNN(p.a->childs[0],p.a->childs[1]); } } else if(Intersect(p.a->volume,p.b->volume)) { if(p.a->isinternal()) { if(p.b->isinternal()) { stkStack[depth++]=sStkNN(p.a->childs[0],p.b->childs[0]); stkStack[depth++]=sStkNN(p.a->childs[1],p.b->childs[0]); stkStack[depth++]=sStkNN(p.a->childs[0],p.b->childs[1]); stkStack[depth++]=sStkNN(p.a->childs[1],p.b->childs[1]); } else { stkStack[depth++]=sStkNN(p.a->childs[0],p.b); stkStack[depth++]=sStkNN(p.a->childs[1],p.b); } } else { if(p.b->isinternal()) { stkStack[depth++]=sStkNN(p.a,p.b->childs[0]); stkStack[depth++]=sStkNN(p.a,p.b->childs[1]); } else { policy.Process(p.a,p.b); } } } } while(depth); } } DBVT_PREFIX inline void btDbvt::collideTTpersistentStack( const btDbvtNode* root0, const btDbvtNode* root1, DBVT_IPOLICY) { DBVT_CHECKTYPE if(root0&&root1) { int depth=1; int treshold=DOUBLE_STACKSIZE-4; m_stkStack.resize(DOUBLE_STACKSIZE); m_stkStack[0]=sStkNN(root0,root1); do { sStkNN p=m_stkStack[--depth]; if(depth>treshold) { m_stkStack.resize(m_stkStack.size()*2); treshold=m_stkStack.size()-4; } if(p.a==p.b) { if(p.a->isinternal()) { m_stkStack[depth++]=sStkNN(p.a->childs[0],p.a->childs[0]); m_stkStack[depth++]=sStkNN(p.a->childs[1],p.a->childs[1]); m_stkStack[depth++]=sStkNN(p.a->childs[0],p.a->childs[1]); } } else if(Intersect(p.a->volume,p.b->volume)) { if(p.a->isinternal()) { if(p.b->isinternal()) { m_stkStack[depth++]=sStkNN(p.a->childs[0],p.b->childs[0]); m_stkStack[depth++]=sStkNN(p.a->childs[1],p.b->childs[0]); m_stkStack[depth++]=sStkNN(p.a->childs[0],p.b->childs[1]); m_stkStack[depth++]=sStkNN(p.a->childs[1],p.b->childs[1]); } else { m_stkStack[depth++]=sStkNN(p.a->childs[0],p.b); m_stkStack[depth++]=sStkNN(p.a->childs[1],p.b); } } else { if(p.b->isinternal()) { m_stkStack[depth++]=sStkNN(p.a,p.b->childs[0]); m_stkStack[depth++]=sStkNN(p.a,p.b->childs[1]); } else { policy.Process(p.a,p.b); } } } } while(depth); } } #if 0 // DBVT_PREFIX inline void btDbvt::collideTT( const btDbvtNode* root0, const btDbvtNode* root1, const btTransform& xform, DBVT_IPOLICY) { DBVT_CHECKTYPE if(root0&&root1) { int depth=1; int treshold=DOUBLE_STACKSIZE-4; btAlignedObjectArray stkStack; stkStack.resize(DOUBLE_STACKSIZE); stkStack[0]=sStkNN(root0,root1); do { sStkNN p=stkStack[--depth]; if(Intersect(p.a->volume,p.b->volume,xform)) { if(depth>treshold) { stkStack.resize(stkStack.size()*2); treshold=stkStack.size()-4; } if(p.a->isinternal()) { if(p.b->isinternal()) { stkStack[depth++]=sStkNN(p.a->childs[0],p.b->childs[0]); stkStack[depth++]=sStkNN(p.a->childs[1],p.b->childs[0]); stkStack[depth++]=sStkNN(p.a->childs[0],p.b->childs[1]); stkStack[depth++]=sStkNN(p.a->childs[1],p.b->childs[1]); } else { stkStack[depth++]=sStkNN(p.a->childs[0],p.b); stkStack[depth++]=sStkNN(p.a->childs[1],p.b); } } else { if(p.b->isinternal()) { stkStack[depth++]=sStkNN(p.a,p.b->childs[0]); stkStack[depth++]=sStkNN(p.a,p.b->childs[1]); } else { policy.Process(p.a,p.b); } } } } while(depth); } } // DBVT_PREFIX inline void btDbvt::collideTT( const btDbvtNode* root0, const btTransform& xform0, const btDbvtNode* root1, const btTransform& xform1, DBVT_IPOLICY) { const btTransform xform=xform0.inverse()*xform1; collideTT(root0,root1,xform,policy); } #endif // DBVT_PREFIX inline void btDbvt::collideTV( const btDbvtNode* root, const btDbvtVolume& vol, DBVT_IPOLICY) { DBVT_CHECKTYPE if(root) { ATTRIBUTE_ALIGNED16(btDbvtVolume) volume(vol); btAlignedObjectArray stack; stack.resize(0); stack.reserve(SIMPLE_STACKSIZE); stack.push_back(root); do { const btDbvtNode* n=stack[stack.size()-1]; stack.pop_back(); if(Intersect(n->volume,volume)) { if(n->isinternal()) { stack.push_back(n->childs[0]); stack.push_back(n->childs[1]); } else { policy.Process(n); } } } while(stack.size()>0); } } DBVT_PREFIX inline void btDbvt::rayTestInternal( const btDbvtNode* root, const btVector3& rayFrom, const btVector3& rayTo, const btVector3& rayDirectionInverse, unsigned int signs[3], btScalar lambda_max, const btVector3& aabbMin, const btVector3& aabbMax, DBVT_IPOLICY) const { (void) rayTo; DBVT_CHECKTYPE if(root) { btVector3 resultNormal; int depth=1; int treshold=DOUBLE_STACKSIZE-2; btAlignedObjectArray stack; stack.resize(DOUBLE_STACKSIZE); stack[0]=root; btVector3 bounds[2]; do { const btDbvtNode* node=stack[--depth]; bounds[0] = node->volume.Mins()-aabbMax; bounds[1] = node->volume.Maxs()-aabbMin; btScalar tmin=1.f,lambda_min=0.f; unsigned int result1=false; result1 = btRayAabb2(rayFrom,rayDirectionInverse,signs,bounds,tmin,lambda_min,lambda_max); if(result1) { if(node->isinternal()) { if(depth>treshold) { stack.resize(stack.size()*2); treshold=stack.size()-2; } stack[depth++]=node->childs[0]; stack[depth++]=node->childs[1]; } else { policy.Process(node); } } } while(depth); } } // DBVT_PREFIX inline void btDbvt::rayTest( const btDbvtNode* root, const btVector3& rayFrom, const btVector3& rayTo, DBVT_IPOLICY) { DBVT_CHECKTYPE if(root) { btVector3 rayDir = (rayTo-rayFrom); rayDir.normalize (); ///what about division by zero? --> just set rayDirection[i] to INF/BT_LARGE_FLOAT btVector3 rayDirectionInverse; rayDirectionInverse[0] = rayDir[0] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[0]; rayDirectionInverse[1] = rayDir[1] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[1]; rayDirectionInverse[2] = rayDir[2] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[2]; unsigned int signs[3] = { rayDirectionInverse[0] < 0.0, rayDirectionInverse[1] < 0.0, rayDirectionInverse[2] < 0.0}; btScalar lambda_max = rayDir.dot(rayTo-rayFrom); btVector3 resultNormal; btAlignedObjectArray stack; int depth=1; int treshold=DOUBLE_STACKSIZE-2; stack.resize(DOUBLE_STACKSIZE); stack[0]=root; btVector3 bounds[2]; do { const btDbvtNode* node=stack[--depth]; bounds[0] = node->volume.Mins(); bounds[1] = node->volume.Maxs(); btScalar tmin=1.f,lambda_min=0.f; unsigned int result1 = btRayAabb2(rayFrom,rayDirectionInverse,signs,bounds,tmin,lambda_min,lambda_max); #ifdef COMPARE_BTRAY_AABB2 btScalar param=1.f; bool result2 = btRayAabb(rayFrom,rayTo,node->volume.Mins(),node->volume.Maxs(),param,resultNormal); btAssert(result1 == result2); #endif //TEST_BTRAY_AABB2 if(result1) { if(node->isinternal()) { if(depth>treshold) { stack.resize(stack.size()*2); treshold=stack.size()-2; } stack[depth++]=node->childs[0]; stack[depth++]=node->childs[1]; } else { policy.Process(node); } } } while(depth); } } // DBVT_PREFIX inline void btDbvt::collideKDOP(const btDbvtNode* root, const btVector3* normals, const btScalar* offsets, int count, DBVT_IPOLICY) { DBVT_CHECKTYPE if(root) { const int inside=(1< stack; int signs[sizeof(unsigned)*8]; btAssert(count=0)?1:0)+ ((normals[i].y()>=0)?2:0)+ ((normals[i].z()>=0)?4:0); } stack.reserve(SIMPLE_STACKSIZE); stack.push_back(sStkNP(root,0)); do { sStkNP se=stack[stack.size()-1]; bool out=false; stack.pop_back(); for(int i=0,j=1;(!out)&&(ivolume.Classify(normals[i],offsets[i],signs[i]); switch(side) { case -1: out=true;break; case +1: se.mask|=j;break; } } } if(!out) { if((se.mask!=inside)&&(se.node->isinternal())) { stack.push_back(sStkNP(se.node->childs[0],se.mask)); stack.push_back(sStkNP(se.node->childs[1],se.mask)); } else { if(policy.AllLeaves(se.node)) enumLeaves(se.node,policy); } } } while(stack.size()); } } // DBVT_PREFIX inline void btDbvt::collideOCL( const btDbvtNode* root, const btVector3* normals, const btScalar* offsets, const btVector3& sortaxis, int count, DBVT_IPOLICY, bool fsort) { DBVT_CHECKTYPE if(root) { const unsigned srtsgns=(sortaxis[0]>=0?1:0)+ (sortaxis[1]>=0?2:0)+ (sortaxis[2]>=0?4:0); const int inside=(1< stock; btAlignedObjectArray ifree; btAlignedObjectArray stack; int signs[sizeof(unsigned)*8]; btAssert(count=0)?1:0)+ ((normals[i].y()>=0)?2:0)+ ((normals[i].z()>=0)?4:0); } stock.reserve(SIMPLE_STACKSIZE); stack.reserve(SIMPLE_STACKSIZE); ifree.reserve(SIMPLE_STACKSIZE); stack.push_back(allocate(ifree,stock,sStkNPS(root,0,root->volume.ProjectMinimum(sortaxis,srtsgns)))); do { const int id=stack[stack.size()-1]; sStkNPS se=stock[id]; stack.pop_back();ifree.push_back(id); if(se.mask!=inside) { bool out=false; for(int i=0,j=1;(!out)&&(ivolume.Classify(normals[i],offsets[i],signs[i]); switch(side) { case -1: out=true;break; case +1: se.mask|=j;break; } } } if(out) continue; } if(policy.Descent(se.node)) { if(se.node->isinternal()) { const btDbvtNode* pns[]={ se.node->childs[0],se.node->childs[1]}; sStkNPS nes[]={ sStkNPS(pns[0],se.mask,pns[0]->volume.ProjectMinimum(sortaxis,srtsgns)), sStkNPS(pns[1],se.mask,pns[1]->volume.ProjectMinimum(sortaxis,srtsgns))}; const int q=nes[0].value0)) { /* Insert 0 */ j=nearest(&stack[0],&stock[0],nes[q].value,0,stack.size()); stack.push_back(0); #if DBVT_USE_MEMMOVE memmove(&stack[j+1],&stack[j],sizeof(int)*(stack.size()-j-1)); #else for(int k=stack.size()-1;k>j;--k) stack[k]=stack[k-1]; #endif stack[j]=allocate(ifree,stock,nes[q]); /* Insert 1 */ j=nearest(&stack[0],&stock[0],nes[1-q].value,j,stack.size()); stack.push_back(0); #if DBVT_USE_MEMMOVE memmove(&stack[j+1],&stack[j],sizeof(int)*(stack.size()-j-1)); #else for(int k=stack.size()-1;k>j;--k) stack[k]=stack[k-1]; #endif stack[j]=allocate(ifree,stock,nes[1-q]); } else { stack.push_back(allocate(ifree,stock,nes[q])); stack.push_back(allocate(ifree,stock,nes[1-q])); } } else { policy.Process(se.node,se.value); } } } while(stack.size()); } } // DBVT_PREFIX inline void btDbvt::collideTU( const btDbvtNode* root, DBVT_IPOLICY) { DBVT_CHECKTYPE if(root) { btAlignedObjectArray stack; stack.reserve(SIMPLE_STACKSIZE); stack.push_back(root); do { const btDbvtNode* n=stack[stack.size()-1]; stack.pop_back(); if(policy.Descent(n)) { if(n->isinternal()) { stack.push_back(n->childs[0]);stack.push_back(n->childs[1]); } else { policy.Process(n); } } } while(stack.size()>0); } } // // PP Cleanup // #undef DBVT_USE_MEMMOVE #undef DBVT_USE_TEMPLATE #undef DBVT_VIRTUAL_DTOR #undef DBVT_VIRTUAL #undef DBVT_PREFIX #undef DBVT_IPOLICY #undef DBVT_CHECKTYPE #undef DBVT_IMPL_GENERIC #undef DBVT_IMPL_SSE #undef DBVT_USE_INTRINSIC_SSE #undef DBVT_SELECT_IMPL #undef DBVT_MERGE_IMPL #undef DBVT_INT0_IMPL #endif critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btCollisionAlgorithm.cpp0000644000175000017500000000216411337071441032642 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btCollisionAlgorithm.h" #include "btDispatcher.h" btCollisionAlgorithm::btCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) { m_dispatcher = ci.m_dispatcher1; } critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCache.h0000644000175000017500000003030111344267705032535 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 OVERLAPPING_PAIR_CACHE_H #define OVERLAPPING_PAIR_CACHE_H #include "btBroadphaseInterface.h" #include "btBroadphaseProxy.h" #include "btOverlappingPairCallback.h" #include "LinearMath/btAlignedObjectArray.h" class btDispatcher; typedef btAlignedObjectArray btBroadphasePairArray; struct btOverlapCallback { virtual ~btOverlapCallback() {} //return true for deletion of the pair virtual bool processOverlap(btBroadphasePair& pair) = 0; }; struct btOverlapFilterCallback { virtual ~btOverlapFilterCallback() {} // return true when pairs need collision virtual bool needBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const = 0; }; extern int gRemovePairs; extern int gAddedPairs; extern int gFindPairs; const int BT_NULL_PAIR=0xffffffff; ///The btOverlappingPairCache provides an interface for overlapping pair management (add, remove, storage), used by the btBroadphaseInterface broadphases. ///The btHashedOverlappingPairCache and btSortedOverlappingPairCache classes are two implementations. class btOverlappingPairCache : public btOverlappingPairCallback { public: virtual ~btOverlappingPairCache() {} // this is needed so we can get to the derived class destructor virtual btBroadphasePair* getOverlappingPairArrayPtr() = 0; virtual const btBroadphasePair* getOverlappingPairArrayPtr() const = 0; virtual btBroadphasePairArray& getOverlappingPairArray() = 0; virtual void cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher) = 0; virtual int getNumOverlappingPairs() const = 0; virtual void cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher) = 0; virtual void setOverlapFilterCallback(btOverlapFilterCallback* callback) = 0; virtual void processAllOverlappingPairs(btOverlapCallback*,btDispatcher* dispatcher) = 0; virtual btBroadphasePair* findPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1) = 0; virtual bool hasDeferredRemoval() = 0; virtual void setInternalGhostPairCallback(btOverlappingPairCallback* ghostPairCallback)=0; virtual void sortOverlappingPairs(btDispatcher* dispatcher) = 0; }; /// Hash-space based Pair Cache, thanks to Erin Catto, Box2D, http://www.box2d.org, and Pierre Terdiman, Codercorner, http://codercorner.com class btHashedOverlappingPairCache : public btOverlappingPairCache { btBroadphasePairArray m_overlappingPairArray; btOverlapFilterCallback* m_overlapFilterCallback; bool m_blockedForChanges; public: btHashedOverlappingPairCache(); virtual ~btHashedOverlappingPairCache(); void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); virtual void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher); SIMD_FORCE_INLINE bool needsBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const { if (m_overlapFilterCallback) return m_overlapFilterCallback->needBroadphaseCollision(proxy0,proxy1); bool collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0; collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask); return collides; } // Add a pair and return the new pair. If the pair already exists, // no new pair is created and the old one is returned. virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) { gAddedPairs++; if (!needsBroadphaseCollision(proxy0,proxy1)) return 0; return internalAddPair(proxy0,proxy1); } void cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher); virtual void processAllOverlappingPairs(btOverlapCallback*,btDispatcher* dispatcher); virtual btBroadphasePair* getOverlappingPairArrayPtr() { return &m_overlappingPairArray[0]; } const btBroadphasePair* getOverlappingPairArrayPtr() const { return &m_overlappingPairArray[0]; } btBroadphasePairArray& getOverlappingPairArray() { return m_overlappingPairArray; } const btBroadphasePairArray& getOverlappingPairArray() const { return m_overlappingPairArray; } void cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher); btBroadphasePair* findPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1); int GetCount() const { return m_overlappingPairArray.size(); } // btBroadphasePair* GetPairs() { return m_pairs; } btOverlapFilterCallback* getOverlapFilterCallback() { return m_overlapFilterCallback; } void setOverlapFilterCallback(btOverlapFilterCallback* callback) { m_overlapFilterCallback = callback; } int getNumOverlappingPairs() const { return m_overlappingPairArray.size(); } private: btBroadphasePair* internalAddPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); void growTables(); SIMD_FORCE_INLINE bool equalsPair(const btBroadphasePair& pair, int proxyId1, int proxyId2) { return pair.m_pProxy0->getUid() == proxyId1 && pair.m_pProxy1->getUid() == proxyId2; } /* // Thomas Wang's hash, see: http://www.concentric.net/~Ttwang/tech/inthash.htm // This assumes proxyId1 and proxyId2 are 16-bit. SIMD_FORCE_INLINE int getHash(int proxyId1, int proxyId2) { int key = (proxyId2 << 16) | proxyId1; key = ~key + (key << 15); key = key ^ (key >> 12); key = key + (key << 2); key = key ^ (key >> 4); key = key * 2057; key = key ^ (key >> 16); return key; } */ SIMD_FORCE_INLINE unsigned int getHash(unsigned int proxyId1, unsigned int proxyId2) { int key = static_cast(((unsigned int)proxyId1) | (((unsigned int)proxyId2) <<16)); // Thomas Wang's hash key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); return static_cast(key); } SIMD_FORCE_INLINE btBroadphasePair* internalFindPair(btBroadphaseProxy* proxy0, btBroadphaseProxy* proxy1, int hash) { int proxyId1 = proxy0->getUid(); int proxyId2 = proxy1->getUid(); #if 0 // wrong, 'equalsPair' use unsorted uids, copy-past devil striked again. Nat. if (proxyId1 > proxyId2) btSwap(proxyId1, proxyId2); #endif int index = m_hashTable[hash]; while( index != BT_NULL_PAIR && equalsPair(m_overlappingPairArray[index], proxyId1, proxyId2) == false) { index = m_next[index]; } if ( index == BT_NULL_PAIR ) { return NULL; } btAssert(index < m_overlappingPairArray.size()); return &m_overlappingPairArray[index]; } virtual bool hasDeferredRemoval() { return false; } virtual void setInternalGhostPairCallback(btOverlappingPairCallback* ghostPairCallback) { m_ghostPairCallback = ghostPairCallback; } virtual void sortOverlappingPairs(btDispatcher* dispatcher); protected: btAlignedObjectArray m_hashTable; btAlignedObjectArray m_next; btOverlappingPairCallback* m_ghostPairCallback; }; ///btSortedOverlappingPairCache maintains the objects with overlapping AABB ///Typically managed by the Broadphase, Axis3Sweep or btSimpleBroadphase class btSortedOverlappingPairCache : public btOverlappingPairCache { protected: //avoid brute-force finding all the time btBroadphasePairArray m_overlappingPairArray; //during the dispatch, check that user doesn't destroy/create proxy bool m_blockedForChanges; ///by default, do the removal during the pair traversal bool m_hasDeferredRemoval; //if set, use the callback instead of the built in filter in needBroadphaseCollision btOverlapFilterCallback* m_overlapFilterCallback; btOverlappingPairCallback* m_ghostPairCallback; public: btSortedOverlappingPairCache(); virtual ~btSortedOverlappingPairCache(); virtual void processAllOverlappingPairs(btOverlapCallback*,btDispatcher* dispatcher); void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher); void cleanOverlappingPair(btBroadphasePair& pair,btDispatcher* dispatcher); btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); btBroadphasePair* findPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1); void cleanProxyFromPairs(btBroadphaseProxy* proxy,btDispatcher* dispatcher); void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); inline bool needsBroadphaseCollision(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) const { if (m_overlapFilterCallback) return m_overlapFilterCallback->needBroadphaseCollision(proxy0,proxy1); bool collides = (proxy0->m_collisionFilterGroup & proxy1->m_collisionFilterMask) != 0; collides = collides && (proxy1->m_collisionFilterGroup & proxy0->m_collisionFilterMask); return collides; } btBroadphasePairArray& getOverlappingPairArray() { return m_overlappingPairArray; } const btBroadphasePairArray& getOverlappingPairArray() const { return m_overlappingPairArray; } btBroadphasePair* getOverlappingPairArrayPtr() { return &m_overlappingPairArray[0]; } const btBroadphasePair* getOverlappingPairArrayPtr() const { return &m_overlappingPairArray[0]; } int getNumOverlappingPairs() const { return m_overlappingPairArray.size(); } btOverlapFilterCallback* getOverlapFilterCallback() { return m_overlapFilterCallback; } void setOverlapFilterCallback(btOverlapFilterCallback* callback) { m_overlapFilterCallback = callback; } virtual bool hasDeferredRemoval() { return m_hasDeferredRemoval; } virtual void setInternalGhostPairCallback(btOverlappingPairCallback* ghostPairCallback) { m_ghostPairCallback = ghostPairCallback; } virtual void sortOverlappingPairs(btDispatcher* dispatcher); }; ///btNullPairCache skips add/removal of overlapping pairs. Userful for benchmarking and unit testing. class btNullPairCache : public btOverlappingPairCache { btBroadphasePairArray m_overlappingPairArray; public: virtual btBroadphasePair* getOverlappingPairArrayPtr() { return &m_overlappingPairArray[0]; } const btBroadphasePair* getOverlappingPairArrayPtr() const { return &m_overlappingPairArray[0]; } btBroadphasePairArray& getOverlappingPairArray() { return m_overlappingPairArray; } virtual void cleanOverlappingPair(btBroadphasePair& /*pair*/,btDispatcher* /*dispatcher*/) { } virtual int getNumOverlappingPairs() const { return 0; } virtual void cleanProxyFromPairs(btBroadphaseProxy* /*proxy*/,btDispatcher* /*dispatcher*/) { } virtual void setOverlapFilterCallback(btOverlapFilterCallback* /*callback*/) { } virtual void processAllOverlappingPairs(btOverlapCallback*,btDispatcher* /*dispatcher*/) { } virtual btBroadphasePair* findPair(btBroadphaseProxy* /*proxy0*/, btBroadphaseProxy* /*proxy1*/) { return 0; } virtual bool hasDeferredRemoval() { return true; } virtual void setInternalGhostPairCallback(btOverlappingPairCallback* /* ghostPairCallback */) { } virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* /*proxy0*/,btBroadphaseProxy* /*proxy1*/) { return 0; } virtual void* removeOverlappingPair(btBroadphaseProxy* /*proxy0*/,btBroadphaseProxy* /*proxy1*/,btDispatcher* /*dispatcher*/) { return 0; } virtual void removeOverlappingPairsContainingProxy(btBroadphaseProxy* /*proxy0*/,btDispatcher* /*dispatcher*/) { } virtual void sortOverlappingPairs(btDispatcher* dispatcher) { (void) dispatcher; } }; #endif //OVERLAPPING_PAIR_CACHE_H critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btDbvt.cpp0000644000175000017500000010663211337071441027744 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ ///btDbvt implementation by Nathanael Presson #include "btDbvt.h" // typedef btAlignedObjectArray tNodeArray; typedef btAlignedObjectArray tConstNodeArray; // struct btDbvtNodeEnumerator : btDbvt::ICollide { tConstNodeArray nodes; void Process(const btDbvtNode* n) { nodes.push_back(n); } }; // static DBVT_INLINE int indexof(const btDbvtNode* node) { return(node->parent->childs[1]==node); } // static DBVT_INLINE btDbvtVolume merge( const btDbvtVolume& a, const btDbvtVolume& b) { #if (DBVT_MERGE_IMPL==DBVT_IMPL_SSE) ATTRIBUTE_ALIGNED16(char locals[sizeof(btDbvtAabbMm)]); btDbvtVolume& res=*(btDbvtVolume*)locals; #else btDbvtVolume res; #endif Merge(a,b,res); return(res); } // volume+edge lengths static DBVT_INLINE btScalar size(const btDbvtVolume& a) { const btVector3 edges=a.Lengths(); return( edges.x()*edges.y()*edges.z()+ edges.x()+edges.y()+edges.z()); } // static void getmaxdepth(const btDbvtNode* node,int depth,int& maxdepth) { if(node->isinternal()) { getmaxdepth(node->childs[0],depth+1,maxdepth); getmaxdepth(node->childs[0],depth+1,maxdepth); } else maxdepth=btMax(maxdepth,depth); } // static DBVT_INLINE void deletenode( btDbvt* pdbvt, btDbvtNode* node) { btAlignedFree(pdbvt->m_free); pdbvt->m_free=node; } // static void recursedeletenode( btDbvt* pdbvt, btDbvtNode* node) { if(!node->isleaf()) { recursedeletenode(pdbvt,node->childs[0]); recursedeletenode(pdbvt,node->childs[1]); } if(node==pdbvt->m_root) pdbvt->m_root=0; deletenode(pdbvt,node); } // static DBVT_INLINE btDbvtNode* createnode( btDbvt* pdbvt, btDbvtNode* parent, void* data) { btDbvtNode* node; if(pdbvt->m_free) { node=pdbvt->m_free;pdbvt->m_free=0; } else { node=new(btAlignedAlloc(sizeof(btDbvtNode),16)) btDbvtNode(); } node->parent = parent; node->data = data; node->childs[1] = 0; return(node); } // static DBVT_INLINE btDbvtNode* createnode( btDbvt* pdbvt, btDbvtNode* parent, const btDbvtVolume& volume, void* data) { btDbvtNode* node=createnode(pdbvt,parent,data); node->volume=volume; return(node); } // static DBVT_INLINE btDbvtNode* createnode( btDbvt* pdbvt, btDbvtNode* parent, const btDbvtVolume& volume0, const btDbvtVolume& volume1, void* data) { btDbvtNode* node=createnode(pdbvt,parent,data); Merge(volume0,volume1,node->volume); return(node); } // static void insertleaf( btDbvt* pdbvt, btDbvtNode* root, btDbvtNode* leaf) { if(!pdbvt->m_root) { pdbvt->m_root = leaf; leaf->parent = 0; } else { if(!root->isleaf()) { do { root=root->childs[Select( leaf->volume, root->childs[0]->volume, root->childs[1]->volume)]; } while(!root->isleaf()); } btDbvtNode* prev=root->parent; btDbvtNode* node=createnode(pdbvt,prev,leaf->volume,root->volume,0); if(prev) { prev->childs[indexof(root)] = node; node->childs[0] = root;root->parent=node; node->childs[1] = leaf;leaf->parent=node; do { if(!prev->volume.Contain(node->volume)) Merge(prev->childs[0]->volume,prev->childs[1]->volume,prev->volume); else break; node=prev; } while(0!=(prev=node->parent)); } else { node->childs[0] = root;root->parent=node; node->childs[1] = leaf;leaf->parent=node; pdbvt->m_root = node; } } } // static btDbvtNode* removeleaf( btDbvt* pdbvt, btDbvtNode* leaf) { if(leaf==pdbvt->m_root) { pdbvt->m_root=0; return(0); } else { btDbvtNode* parent=leaf->parent; btDbvtNode* prev=parent->parent; btDbvtNode* sibling=parent->childs[1-indexof(leaf)]; if(prev) { prev->childs[indexof(parent)]=sibling; sibling->parent=prev; deletenode(pdbvt,parent); while(prev) { const btDbvtVolume pb=prev->volume; Merge(prev->childs[0]->volume,prev->childs[1]->volume,prev->volume); if(NotEqual(pb,prev->volume)) { prev=prev->parent; } else break; } return(prev?prev:pdbvt->m_root); } else { pdbvt->m_root=sibling; sibling->parent=0; deletenode(pdbvt,parent); return(pdbvt->m_root); } } } // static void fetchleaves(btDbvt* pdbvt, btDbvtNode* root, tNodeArray& leaves, int depth=-1) { if(root->isinternal()&&depth) { fetchleaves(pdbvt,root->childs[0],leaves,depth-1); fetchleaves(pdbvt,root->childs[1],leaves,depth-1); deletenode(pdbvt,root); } else { leaves.push_back(root); } } // static void split( const tNodeArray& leaves, tNodeArray& left, tNodeArray& right, const btVector3& org, const btVector3& axis) { left.resize(0); right.resize(0); for(int i=0,ni=leaves.size();ivolume.Center()-org)<0) left.push_back(leaves[i]); else right.push_back(leaves[i]); } } // static btDbvtVolume bounds( const tNodeArray& leaves) { #if DBVT_MERGE_IMPL==DBVT_IMPL_SSE ATTRIBUTE_ALIGNED16(char locals[sizeof(btDbvtVolume)]); btDbvtVolume& volume=*(btDbvtVolume*)locals; volume=leaves[0]->volume; #else btDbvtVolume volume=leaves[0]->volume; #endif for(int i=1,ni=leaves.size();ivolume,volume); } return(volume); } // static void bottomup( btDbvt* pdbvt, tNodeArray& leaves) { while(leaves.size()>1) { btScalar minsize=SIMD_INFINITY; int minidx[2]={-1,-1}; for(int i=0;ivolume,leaves[j]->volume)); if(szvolume,n[1]->volume,0); p->childs[0] = n[0]; p->childs[1] = n[1]; n[0]->parent = p; n[1]->parent = p; leaves[minidx[0]] = p; leaves.swap(minidx[1],leaves.size()-1); leaves.pop_back(); } } // static btDbvtNode* topdown(btDbvt* pdbvt, tNodeArray& leaves, int bu_treshold) { static const btVector3 axis[]={btVector3(1,0,0), btVector3(0,1,0), btVector3(0,0,1)}; if(leaves.size()>1) { if(leaves.size()>bu_treshold) { const btDbvtVolume vol=bounds(leaves); const btVector3 org=vol.Center(); tNodeArray sets[2]; int bestaxis=-1; int bestmidp=leaves.size(); int splitcount[3][2]={{0,0},{0,0},{0,0}}; int i; for( i=0;ivolume.Center()-org; for(int j=0;j<3;++j) { ++splitcount[j][btDot(x,axis[j])>0?1:0]; } } for( i=0;i<3;++i) { if((splitcount[i][0]>0)&&(splitcount[i][1]>0)) { const int midp=(int)btFabs(btScalar(splitcount[i][0]-splitcount[i][1])); if(midp=0) { sets[0].reserve(splitcount[bestaxis][0]); sets[1].reserve(splitcount[bestaxis][1]); split(leaves,sets[0],sets[1],org,axis[bestaxis]); } else { sets[0].reserve(leaves.size()/2+1); sets[1].reserve(leaves.size()/2); for(int i=0,ni=leaves.size();ichilds[0]=topdown(pdbvt,sets[0],bu_treshold); node->childs[1]=topdown(pdbvt,sets[1],bu_treshold); node->childs[0]->parent=node; node->childs[1]->parent=node; return(node); } else { bottomup(pdbvt,leaves); return(leaves[0]); } } return(leaves[0]); } // static DBVT_INLINE btDbvtNode* sort(btDbvtNode* n,btDbvtNode*& r) { btDbvtNode* p=n->parent; btAssert(n->isinternal()); if(p>n) { const int i=indexof(n); const int j=1-i; btDbvtNode* s=p->childs[j]; btDbvtNode* q=p->parent; btAssert(n==p->childs[i]); if(q) q->childs[indexof(p)]=n; else r=n; s->parent=n; p->parent=n; n->parent=q; p->childs[0]=n->childs[0]; p->childs[1]=n->childs[1]; n->childs[0]->parent=p; n->childs[1]->parent=p; n->childs[i]=p; n->childs[j]=s; btSwap(p->volume,n->volume); return(p); } return(n); } #if 0 static DBVT_INLINE btDbvtNode* walkup(btDbvtNode* n,int count) { while(n&&(count--)) n=n->parent; return(n); } #endif // // Api // // btDbvt::btDbvt() { m_root = 0; m_free = 0; m_lkhd = -1; m_leaves = 0; m_opath = 0; } // btDbvt::~btDbvt() { clear(); } // void btDbvt::clear() { if(m_root) recursedeletenode(this,m_root); btAlignedFree(m_free); m_free=0; m_lkhd = -1; m_stkStack.clear(); m_opath = 0; } // void btDbvt::optimizeBottomUp() { if(m_root) { tNodeArray leaves; leaves.reserve(m_leaves); fetchleaves(this,m_root,leaves); bottomup(this,leaves); m_root=leaves[0]; } } // void btDbvt::optimizeTopDown(int bu_treshold) { if(m_root) { tNodeArray leaves; leaves.reserve(m_leaves); fetchleaves(this,m_root,leaves); m_root=topdown(this,leaves,bu_treshold); } } // void btDbvt::optimizeIncremental(int passes) { if(passes<0) passes=m_leaves; if(m_root&&(passes>0)) { do { btDbvtNode* node=m_root; unsigned bit=0; while(node->isinternal()) { node=sort(node,m_root)->childs[(m_opath>>bit)&1]; bit=(bit+1)&(sizeof(unsigned)*8-1); } update(node); ++m_opath; } while(--passes); } } // btDbvtNode* btDbvt::insert(const btDbvtVolume& volume,void* data) { btDbvtNode* leaf=createnode(this,0,volume,data); insertleaf(this,m_root,leaf); ++m_leaves; return(leaf); } // void btDbvt::update(btDbvtNode* leaf,int lookahead) { btDbvtNode* root=removeleaf(this,leaf); if(root) { if(lookahead>=0) { for(int i=0;(iparent;++i) { root=root->parent; } } else root=m_root; } insertleaf(this,root,leaf); } // void btDbvt::update(btDbvtNode* leaf,btDbvtVolume& volume) { btDbvtNode* root=removeleaf(this,leaf); if(root) { if(m_lkhd>=0) { for(int i=0;(iparent;++i) { root=root->parent; } } else root=m_root; } leaf->volume=volume; insertleaf(this,root,leaf); } // bool btDbvt::update(btDbvtNode* leaf,btDbvtVolume& volume,const btVector3& velocity,btScalar margin) { if(leaf->volume.Contain(volume)) return(false); volume.Expand(btVector3(margin,margin,margin)); volume.SignedExpand(velocity); update(leaf,volume); return(true); } // bool btDbvt::update(btDbvtNode* leaf,btDbvtVolume& volume,const btVector3& velocity) { if(leaf->volume.Contain(volume)) return(false); volume.SignedExpand(velocity); update(leaf,volume); return(true); } // bool btDbvt::update(btDbvtNode* leaf,btDbvtVolume& volume,btScalar margin) { if(leaf->volume.Contain(volume)) return(false); volume.Expand(btVector3(margin,margin,margin)); update(leaf,volume); return(true); } // void btDbvt::remove(btDbvtNode* leaf) { removeleaf(this,leaf); deletenode(this,leaf); --m_leaves; } // void btDbvt::write(IWriter* iwriter) const { btDbvtNodeEnumerator nodes; nodes.nodes.reserve(m_leaves*2); enumNodes(m_root,nodes); iwriter->Prepare(m_root,nodes.nodes.size()); for(int i=0;iparent) p=nodes.nodes.findLinearSearch(n->parent); if(n->isinternal()) { const int c0=nodes.nodes.findLinearSearch(n->childs[0]); const int c1=nodes.nodes.findLinearSearch(n->childs[1]); iwriter->WriteNode(n,i,p,c0,c1); } else { iwriter->WriteLeaf(n,i,p); } } } // void btDbvt::clone(btDbvt& dest,IClone* iclone) const { dest.clear(); if(m_root!=0) { btAlignedObjectArray stack; stack.reserve(m_leaves); stack.push_back(sStkCLN(m_root,0)); do { const int i=stack.size()-1; const sStkCLN e=stack[i]; btDbvtNode* n=createnode(&dest,e.parent,e.node->volume,e.node->data); stack.pop_back(); if(e.parent!=0) e.parent->childs[i&1]=n; else dest.m_root=n; if(e.node->isinternal()) { stack.push_back(sStkCLN(e.node->childs[0],n)); stack.push_back(sStkCLN(e.node->childs[1],n)); } else { iclone->CloneLeaf(n); } } while(stack.size()>0); } } // int btDbvt::maxdepth(const btDbvtNode* node) { int depth=0; if(node) getmaxdepth(node,1,depth); return(depth); } // int btDbvt::countLeaves(const btDbvtNode* node) { if(node->isinternal()) return(countLeaves(node->childs[0])+countLeaves(node->childs[1])); else return(1); } // void btDbvt::extractLeaves(const btDbvtNode* node,btAlignedObjectArray& leaves) { if(node->isinternal()) { extractLeaves(node->childs[0],leaves); extractLeaves(node->childs[1],leaves); } else { leaves.push_back(node); } } // #if DBVT_ENABLE_BENCHMARK #include #include #include "LinearMath/btQuickProf.h" /* q6600,2.4ghz /Ox /Ob2 /Oi /Ot /I "." /I "..\.." /I "..\..\src" /D "NDEBUG" /D "_LIB" /D "_WINDOWS" /D "_CRT_SECURE_NO_DEPRECATE" /D "_CRT_NONSTDC_NO_DEPRECATE" /D "WIN32" /GF /FD /MT /GS- /Gy /arch:SSE2 /Zc:wchar_t- /Fp"..\..\out\release8\build\libbulletcollision\libbulletcollision.pch" /Fo"..\..\out\release8\build\libbulletcollision\\" /Fd"..\..\out\release8\build\libbulletcollision\bulletcollision.pdb" /W3 /nologo /c /Wp64 /Zi /errorReport:prompt Benchmarking dbvt... World scale: 100.000000 Extents base: 1.000000 Extents range: 4.000000 Leaves: 8192 sizeof(btDbvtVolume): 32 bytes sizeof(btDbvtNode): 44 bytes [1] btDbvtVolume intersections: 3499 ms (-1%) [2] btDbvtVolume merges: 1934 ms (0%) [3] btDbvt::collideTT: 5485 ms (-21%) [4] btDbvt::collideTT self: 2814 ms (-20%) [5] btDbvt::collideTT xform: 7379 ms (-1%) [6] btDbvt::collideTT xform,self: 7270 ms (-2%) [7] btDbvt::rayTest: 6314 ms (0%),(332143 r/s) [8] insert/remove: 2093 ms (0%),(1001983 ir/s) [9] updates (teleport): 1879 ms (-3%),(1116100 u/s) [10] updates (jitter): 1244 ms (-4%),(1685813 u/s) [11] optimize (incremental): 2514 ms (0%),(1668000 o/s) [12] btDbvtVolume notequal: 3659 ms (0%) [13] culling(OCL+fullsort): 2218 ms (0%),(461 t/s) [14] culling(OCL+qsort): 3688 ms (5%),(2221 t/s) [15] culling(KDOP+qsort): 1139 ms (-1%),(7192 t/s) [16] insert/remove batch(256): 5092 ms (0%),(823704 bir/s) [17] btDbvtVolume select: 3419 ms (0%) */ struct btDbvtBenchmark { struct NilPolicy : btDbvt::ICollide { NilPolicy() : m_pcount(0),m_depth(-SIMD_INFINITY),m_checksort(true) {} void Process(const btDbvtNode*,const btDbvtNode*) { ++m_pcount; } void Process(const btDbvtNode*) { ++m_pcount; } void Process(const btDbvtNode*,btScalar depth) { ++m_pcount; if(m_checksort) { if(depth>=m_depth) m_depth=depth; else printf("wrong depth: %f (should be >= %f)\r\n",depth,m_depth); } } int m_pcount; btScalar m_depth; bool m_checksort; }; struct P14 : btDbvt::ICollide { struct Node { const btDbvtNode* leaf; btScalar depth; }; void Process(const btDbvtNode* leaf,btScalar depth) { Node n; n.leaf = leaf; n.depth = depth; } static int sortfnc(const Node& a,const Node& b) { if(a.depthb.depth) return(-1); return(0); } btAlignedObjectArray m_nodes; }; struct P15 : btDbvt::ICollide { struct Node { const btDbvtNode* leaf; btScalar depth; }; void Process(const btDbvtNode* leaf) { Node n; n.leaf = leaf; n.depth = dot(leaf->volume.Center(),m_axis); } static int sortfnc(const Node& a,const Node& b) { if(a.depthb.depth) return(-1); return(0); } btAlignedObjectArray m_nodes; btVector3 m_axis; }; static btScalar RandUnit() { return(rand()/(btScalar)RAND_MAX); } static btVector3 RandVector3() { return(btVector3(RandUnit(),RandUnit(),RandUnit())); } static btVector3 RandVector3(btScalar cs) { return(RandVector3()*cs-btVector3(cs,cs,cs)/2); } static btDbvtVolume RandVolume(btScalar cs,btScalar eb,btScalar es) { return(btDbvtVolume::FromCE(RandVector3(cs),btVector3(eb,eb,eb)+RandVector3()*es)); } static btTransform RandTransform(btScalar cs) { btTransform t; t.setOrigin(RandVector3(cs)); t.setRotation(btQuaternion(RandUnit()*SIMD_PI*2,RandUnit()*SIMD_PI*2,RandUnit()*SIMD_PI*2).normalized()); return(t); } static void RandTree(btScalar cs,btScalar eb,btScalar es,int leaves,btDbvt& dbvt) { dbvt.clear(); for(int i=0;i volumes; btAlignedObjectArray results; volumes.resize(cfgLeaves); results.resize(cfgLeaves); for(int i=0;i volumes; btAlignedObjectArray results; volumes.resize(cfgLeaves); results.resize(cfgLeaves); for(int i=0;i transforms; btDbvtBenchmark::NilPolicy policy; transforms.resize(cfgBenchmark5_Iterations); for(int i=0;i transforms; btDbvtBenchmark::NilPolicy policy; transforms.resize(cfgBenchmark6_Iterations); for(int i=0;i rayorg; btAlignedObjectArray raydir; btDbvtBenchmark::NilPolicy policy; rayorg.resize(cfgBenchmark7_Iterations); raydir.resize(cfgBenchmark7_Iterations); for(int i=0;i leaves; btDbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt); dbvt.optimizeTopDown(); dbvt.extractLeaves(dbvt.m_root,leaves); printf("[9] updates (teleport): "); wallclock.reset(); for(int i=0;i(leaves[rand()%cfgLeaves]), btDbvtBenchmark::RandVolume(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale)); } } const int time=(int)wallclock.getTimeMilliseconds(); const int up=cfgBenchmark9_Passes*cfgBenchmark9_Iterations; printf("%u ms (%i%%),(%u u/s)\r\n",time,(time-cfgBenchmark9_Reference)*100/time,up*1000/time); } if(cfgBenchmark10_Enable) {// Benchmark 10 srand(380843); btDbvt dbvt; btAlignedObjectArray leaves; btAlignedObjectArray vectors; vectors.resize(cfgBenchmark10_Iterations); for(int i=0;i(leaves[rand()%cfgLeaves]); btDbvtVolume v=btDbvtVolume::FromMM(l->volume.Mins()+d,l->volume.Maxs()+d); dbvt.update(l,v); } } const int time=(int)wallclock.getTimeMilliseconds(); const int up=cfgBenchmark10_Passes*cfgBenchmark10_Iterations; printf("%u ms (%i%%),(%u u/s)\r\n",time,(time-cfgBenchmark10_Reference)*100/time,up*1000/time); } if(cfgBenchmark11_Enable) {// Benchmark 11 srand(380843); btDbvt dbvt; btDbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt); dbvt.optimizeTopDown(); printf("[11] optimize (incremental): "); wallclock.reset(); for(int i=0;i volumes; btAlignedObjectArray results; volumes.resize(cfgLeaves); results.resize(cfgLeaves); for(int i=0;i vectors; btDbvtBenchmark::NilPolicy policy; vectors.resize(cfgBenchmark13_Iterations); for(int i=0;i vectors; btDbvtBenchmark::P14 policy; vectors.resize(cfgBenchmark14_Iterations); for(int i=0;i vectors; btDbvtBenchmark::P15 policy; vectors.resize(cfgBenchmark15_Iterations); for(int i=0;i batch; btDbvtBenchmark::RandTree(cfgVolumeCenterScale,cfgVolumeExentsBase,cfgVolumeExentsScale,cfgLeaves,dbvt); dbvt.optimizeTopDown(); batch.reserve(cfgBenchmark16_BatchCount); printf("[16] insert/remove batch(%u): ",cfgBenchmark16_BatchCount); wallclock.reset(); for(int i=0;i volumes; btAlignedObjectArray results; btAlignedObjectArray indices; volumes.resize(cfgLeaves); results.resize(cfgLeaves); indices.resize(cfgLeaves); for(int i=0;i #endif #if DBVT_BP_PROFILE struct ProfileScope { __forceinline ProfileScope(btClock& clock,unsigned long& value) : m_clock(&clock),m_value(&value),m_base(clock.getTimeMicroseconds()) { } __forceinline ~ProfileScope() { (*m_value)+=m_clock->getTimeMicroseconds()-m_base; } btClock* m_clock; unsigned long* m_value; unsigned long m_base; }; #define SPC(_value_) ProfileScope spc_scope(m_clock,_value_) #else #define SPC(_value_) #endif // // Helpers // // template static inline void listappend(T* item,T*& list) { item->links[0]=0; item->links[1]=list; if(list) list->links[0]=item; list=item; } // template static inline void listremove(T* item,T*& list) { if(item->links[0]) item->links[0]->links[1]=item->links[1]; else list=item->links[1]; if(item->links[1]) item->links[1]->links[0]=item->links[0]; } // template static inline int listcount(T* root) { int n=0; while(root) { ++n;root=root->links[1]; } return(n); } // template static inline void clear(T& value) { static const struct ZeroDummy : T {} zerodummy; value=zerodummy; } // // Colliders // /* Tree collider */ struct btDbvtTreeCollider : btDbvt::ICollide { btDbvtBroadphase* pbp; btDbvtProxy* proxy; btDbvtTreeCollider(btDbvtBroadphase* p) : pbp(p) {} void Process(const btDbvtNode* na,const btDbvtNode* nb) { if(na!=nb) { btDbvtProxy* pa=(btDbvtProxy*)na->data; btDbvtProxy* pb=(btDbvtProxy*)nb->data; #if DBVT_BP_SORTPAIRS if(pa->m_uniqueId>pb->m_uniqueId) btSwap(pa,pb); #endif pbp->m_paircache->addOverlappingPair(pa,pb); ++pbp->m_newpairs; } } void Process(const btDbvtNode* n) { Process(n,proxy->leaf); } }; // // btDbvtBroadphase // // btDbvtBroadphase::btDbvtBroadphase(btOverlappingPairCache* paircache) { m_deferedcollide = false; m_needcleanup = true; m_releasepaircache = (paircache!=0)?false:true; m_prediction = 0; m_stageCurrent = 0; m_fixedleft = 0; m_fupdates = 1; m_dupdates = 0; m_cupdates = 10; m_newpairs = 1; m_updates_call = 0; m_updates_done = 0; m_updates_ratio = 0; m_paircache = paircache? paircache : new(btAlignedAlloc(sizeof(btHashedOverlappingPairCache),16)) btHashedOverlappingPairCache(); m_gid = 0; m_pid = 0; m_cid = 0; for(int i=0;i<=STAGECOUNT;++i) { m_stageRoots[i]=0; } #if DBVT_BP_PROFILE clear(m_profiling); #endif } // btDbvtBroadphase::~btDbvtBroadphase() { if(m_releasepaircache) { m_paircache->~btOverlappingPairCache(); btAlignedFree(m_paircache); } } // btBroadphaseProxy* btDbvtBroadphase::createProxy( const btVector3& aabbMin, const btVector3& aabbMax, int /*shapeType*/, void* userPtr, short int collisionFilterGroup, short int collisionFilterMask, btDispatcher* /*dispatcher*/, void* /*multiSapProxy*/) { btDbvtProxy* proxy=new(btAlignedAlloc(sizeof(btDbvtProxy),16)) btDbvtProxy( aabbMin,aabbMax,userPtr, collisionFilterGroup, collisionFilterMask); btDbvtAabbMm aabb = btDbvtVolume::FromMM(aabbMin,aabbMax); //bproxy->aabb = btDbvtVolume::FromMM(aabbMin,aabbMax); proxy->stage = m_stageCurrent; proxy->m_uniqueId = ++m_gid; proxy->leaf = m_sets[0].insert(aabb,proxy); listappend(proxy,m_stageRoots[m_stageCurrent]); if(!m_deferedcollide) { btDbvtTreeCollider collider(this); collider.proxy=proxy; m_sets[0].collideTV(m_sets[0].m_root,aabb,collider); m_sets[1].collideTV(m_sets[1].m_root,aabb,collider); } return(proxy); } // void btDbvtBroadphase::destroyProxy( btBroadphaseProxy* absproxy, btDispatcher* dispatcher) { btDbvtProxy* proxy=(btDbvtProxy*)absproxy; if(proxy->stage==STAGECOUNT) m_sets[1].remove(proxy->leaf); else m_sets[0].remove(proxy->leaf); listremove(proxy,m_stageRoots[proxy->stage]); m_paircache->removeOverlappingPairsContainingProxy(proxy,dispatcher); btAlignedFree(proxy); m_needcleanup=true; } void btDbvtBroadphase::getAabb(btBroadphaseProxy* absproxy,btVector3& aabbMin, btVector3& aabbMax ) const { btDbvtProxy* proxy=(btDbvtProxy*)absproxy; aabbMin = proxy->m_aabbMin; aabbMax = proxy->m_aabbMax; } struct BroadphaseRayTester : btDbvt::ICollide { btBroadphaseRayCallback& m_rayCallback; BroadphaseRayTester(btBroadphaseRayCallback& orgCallback) :m_rayCallback(orgCallback) { } void Process(const btDbvtNode* leaf) { btDbvtProxy* proxy=(btDbvtProxy*)leaf->data; m_rayCallback.process(proxy); } }; void btDbvtBroadphase::rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback,const btVector3& aabbMin,const btVector3& aabbMax) { BroadphaseRayTester callback(rayCallback); m_sets[0].rayTestInternal( m_sets[0].m_root, rayFrom, rayTo, rayCallback.m_rayDirectionInverse, rayCallback.m_signs, rayCallback.m_lambda_max, aabbMin, aabbMax, callback); m_sets[1].rayTestInternal( m_sets[1].m_root, rayFrom, rayTo, rayCallback.m_rayDirectionInverse, rayCallback.m_signs, rayCallback.m_lambda_max, aabbMin, aabbMax, callback); } struct BroadphaseAabbTester : btDbvt::ICollide { btBroadphaseAabbCallback& m_aabbCallback; BroadphaseAabbTester(btBroadphaseAabbCallback& orgCallback) :m_aabbCallback(orgCallback) { } void Process(const btDbvtNode* leaf) { btDbvtProxy* proxy=(btDbvtProxy*)leaf->data; m_aabbCallback.process(proxy); } }; void btDbvtBroadphase::aabbTest(const btVector3& aabbMin,const btVector3& aabbMax,btBroadphaseAabbCallback& aabbCallback) { BroadphaseAabbTester callback(aabbCallback); const ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds=btDbvtVolume::FromMM(aabbMin,aabbMax); //process all children, that overlap with the given AABB bounds m_sets[0].collideTV(m_sets[0].m_root,bounds,callback); m_sets[1].collideTV(m_sets[1].m_root,bounds,callback); } // void btDbvtBroadphase::setAabb( btBroadphaseProxy* absproxy, const btVector3& aabbMin, const btVector3& aabbMax, btDispatcher* /*dispatcher*/) { btDbvtProxy* proxy=(btDbvtProxy*)absproxy; ATTRIBUTE_ALIGNED16(btDbvtVolume) aabb=btDbvtVolume::FromMM(aabbMin,aabbMax); #if DBVT_BP_PREVENTFALSEUPDATE if(NotEqual(aabb,proxy->leaf->volume)) #endif { bool docollide=false; if(proxy->stage==STAGECOUNT) {/* fixed -> dynamic set */ m_sets[1].remove(proxy->leaf); proxy->leaf=m_sets[0].insert(aabb,proxy); docollide=true; } else {/* dynamic set */ ++m_updates_call; if(Intersect(proxy->leaf->volume,aabb)) {/* Moving */ const btVector3 delta=aabbMin-proxy->m_aabbMin; btVector3 velocity(((proxy->m_aabbMax-proxy->m_aabbMin)/2)*m_prediction); if(delta[0]<0) velocity[0]=-velocity[0]; if(delta[1]<0) velocity[1]=-velocity[1]; if(delta[2]<0) velocity[2]=-velocity[2]; if ( #ifdef DBVT_BP_MARGIN m_sets[0].update(proxy->leaf,aabb,velocity,DBVT_BP_MARGIN) #else m_sets[0].update(proxy->leaf,aabb,velocity) #endif ) { ++m_updates_done; docollide=true; } } else {/* Teleporting */ m_sets[0].update(proxy->leaf,aabb); ++m_updates_done; docollide=true; } } listremove(proxy,m_stageRoots[proxy->stage]); proxy->m_aabbMin = aabbMin; proxy->m_aabbMax = aabbMax; proxy->stage = m_stageCurrent; listappend(proxy,m_stageRoots[m_stageCurrent]); if(docollide) { m_needcleanup=true; if(!m_deferedcollide) { btDbvtTreeCollider collider(this); m_sets[1].collideTTpersistentStack(m_sets[1].m_root,proxy->leaf,collider); m_sets[0].collideTTpersistentStack(m_sets[0].m_root,proxy->leaf,collider); } } } } // void btDbvtBroadphase::setAabbForceUpdate( btBroadphaseProxy* absproxy, const btVector3& aabbMin, const btVector3& aabbMax, btDispatcher* /*dispatcher*/) { btDbvtProxy* proxy=(btDbvtProxy*)absproxy; ATTRIBUTE_ALIGNED16(btDbvtVolume) aabb=btDbvtVolume::FromMM(aabbMin,aabbMax); bool docollide=false; if(proxy->stage==STAGECOUNT) {/* fixed -> dynamic set */ m_sets[1].remove(proxy->leaf); proxy->leaf=m_sets[0].insert(aabb,proxy); docollide=true; } else {/* dynamic set */ ++m_updates_call; /* Teleporting */ m_sets[0].update(proxy->leaf,aabb); ++m_updates_done; docollide=true; } listremove(proxy,m_stageRoots[proxy->stage]); proxy->m_aabbMin = aabbMin; proxy->m_aabbMax = aabbMax; proxy->stage = m_stageCurrent; listappend(proxy,m_stageRoots[m_stageCurrent]); if(docollide) { m_needcleanup=true; if(!m_deferedcollide) { btDbvtTreeCollider collider(this); m_sets[1].collideTTpersistentStack(m_sets[1].m_root,proxy->leaf,collider); m_sets[0].collideTTpersistentStack(m_sets[0].m_root,proxy->leaf,collider); } } } // void btDbvtBroadphase::calculateOverlappingPairs(btDispatcher* dispatcher) { collide(dispatcher); #if DBVT_BP_PROFILE if(0==(m_pid%DBVT_BP_PROFILING_RATE)) { printf("fixed(%u) dynamics(%u) pairs(%u)\r\n",m_sets[1].m_leaves,m_sets[0].m_leaves,m_paircache->getNumOverlappingPairs()); unsigned int total=m_profiling.m_total; if(total<=0) total=1; printf("ddcollide: %u%% (%uus)\r\n",(50+m_profiling.m_ddcollide*100)/total,m_profiling.m_ddcollide/DBVT_BP_PROFILING_RATE); printf("fdcollide: %u%% (%uus)\r\n",(50+m_profiling.m_fdcollide*100)/total,m_profiling.m_fdcollide/DBVT_BP_PROFILING_RATE); printf("cleanup: %u%% (%uus)\r\n",(50+m_profiling.m_cleanup*100)/total,m_profiling.m_cleanup/DBVT_BP_PROFILING_RATE); printf("total: %uus\r\n",total/DBVT_BP_PROFILING_RATE); const unsigned long sum=m_profiling.m_ddcollide+ m_profiling.m_fdcollide+ m_profiling.m_cleanup; printf("leaked: %u%% (%uus)\r\n",100-((50+sum*100)/total),(total-sum)/DBVT_BP_PROFILING_RATE); printf("job counts: %u%%\r\n",(m_profiling.m_jobcount*100)/((m_sets[0].m_leaves+m_sets[1].m_leaves)*DBVT_BP_PROFILING_RATE)); clear(m_profiling); m_clock.reset(); } #endif performDeferredRemoval(dispatcher); } void btDbvtBroadphase::performDeferredRemoval(btDispatcher* dispatcher) { if (m_paircache->hasDeferredRemoval()) { btBroadphasePairArray& overlappingPairArray = m_paircache->getOverlappingPairArray(); //perform a sort, to find duplicates and to sort 'invalid' pairs to the end overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); int invalidPair = 0; int i; btBroadphasePair previousPair; previousPair.m_pProxy0 = 0; previousPair.m_pProxy1 = 0; previousPair.m_algorithm = 0; for (i=0;ileaf->volume,pb->leaf->volume); if (hasOverlap) { needsRemoval = false; } else { needsRemoval = true; } } else { //remove duplicate needsRemoval = true; //should have no algorithm btAssert(!pair.m_algorithm); } if (needsRemoval) { m_paircache->cleanOverlappingPair(pair,dispatcher); pair.m_pProxy0 = 0; pair.m_pProxy1 = 0; invalidPair++; } } //perform a sort, to sort 'invalid' pairs to the end overlappingPairArray.quickSort(btBroadphasePairSortPredicate()); overlappingPairArray.resize(overlappingPairArray.size() - invalidPair); } } // void btDbvtBroadphase::collide(btDispatcher* dispatcher) { /*printf("---------------------------------------------------------\n"); printf("m_sets[0].m_leaves=%d\n",m_sets[0].m_leaves); printf("m_sets[1].m_leaves=%d\n",m_sets[1].m_leaves); printf("numPairs = %d\n",getOverlappingPairCache()->getNumOverlappingPairs()); { int i; for (i=0;igetNumOverlappingPairs();i++) { printf("pair[%d]=(%d,%d),",i,getOverlappingPairCache()->getOverlappingPairArray()[i].m_pProxy0->getUid(), getOverlappingPairCache()->getOverlappingPairArray()[i].m_pProxy1->getUid()); } printf("\n"); } */ SPC(m_profiling.m_total); /* optimize */ m_sets[0].optimizeIncremental(1+(m_sets[0].m_leaves*m_dupdates)/100); if(m_fixedleft) { const int count=1+(m_sets[1].m_leaves*m_fupdates)/100; m_sets[1].optimizeIncremental(1+(m_sets[1].m_leaves*m_fupdates)/100); m_fixedleft=btMax(0,m_fixedleft-count); } /* dynamic -> fixed set */ m_stageCurrent=(m_stageCurrent+1)%STAGECOUNT; btDbvtProxy* current=m_stageRoots[m_stageCurrent]; if(current) { btDbvtTreeCollider collider(this); do { btDbvtProxy* next=current->links[1]; listremove(current,m_stageRoots[current->stage]); listappend(current,m_stageRoots[STAGECOUNT]); #if DBVT_BP_ACCURATESLEEPING m_paircache->removeOverlappingPairsContainingProxy(current,dispatcher); collider.proxy=current; btDbvt::collideTV(m_sets[0].m_root,current->aabb,collider); btDbvt::collideTV(m_sets[1].m_root,current->aabb,collider); #endif m_sets[0].remove(current->leaf); ATTRIBUTE_ALIGNED16(btDbvtVolume) curAabb=btDbvtVolume::FromMM(current->m_aabbMin,current->m_aabbMax); current->leaf = m_sets[1].insert(curAabb,current); current->stage = STAGECOUNT; current = next; } while(current); m_fixedleft=m_sets[1].m_leaves; m_needcleanup=true; } /* collide dynamics */ { btDbvtTreeCollider collider(this); if(m_deferedcollide) { SPC(m_profiling.m_fdcollide); m_sets[0].collideTTpersistentStack(m_sets[0].m_root,m_sets[1].m_root,collider); } if(m_deferedcollide) { SPC(m_profiling.m_ddcollide); m_sets[0].collideTTpersistentStack(m_sets[0].m_root,m_sets[0].m_root,collider); } } /* clean up */ if(m_needcleanup) { SPC(m_profiling.m_cleanup); btBroadphasePairArray& pairs=m_paircache->getOverlappingPairArray(); if(pairs.size()>0) { int ni=btMin(pairs.size(),btMax(m_newpairs,(pairs.size()*m_cupdates)/100)); for(int i=0;ileaf->volume,pb->leaf->volume)) { #if DBVT_BP_SORTPAIRS if(pa->m_uniqueId>pb->m_uniqueId) btSwap(pa,pb); #endif m_paircache->removeOverlappingPair(pa,pb,dispatcher); --ni;--i; } } if(pairs.size()>0) m_cid=(m_cid+ni)%pairs.size(); else m_cid=0; } } ++m_pid; m_newpairs=1; m_needcleanup=false; if(m_updates_call>0) { m_updates_ratio=m_updates_done/(btScalar)m_updates_call; } else { m_updates_ratio=0; } m_updates_done/=2; m_updates_call/=2; } // void btDbvtBroadphase::optimize() { m_sets[0].optimizeTopDown(); m_sets[1].optimizeTopDown(); } // btOverlappingPairCache* btDbvtBroadphase::getOverlappingPairCache() { return(m_paircache); } // const btOverlappingPairCache* btDbvtBroadphase::getOverlappingPairCache() const { return(m_paircache); } // void btDbvtBroadphase::getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const { ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds; if(!m_sets[0].empty()) if(!m_sets[1].empty()) Merge( m_sets[0].m_root->volume, m_sets[1].m_root->volume,bounds); else bounds=m_sets[0].m_root->volume; else if(!m_sets[1].empty()) bounds=m_sets[1].m_root->volume; else bounds=btDbvtVolume::FromCR(btVector3(0,0,0),0); aabbMin=bounds.Mins(); aabbMax=bounds.Maxs(); } void btDbvtBroadphase::resetPool(btDispatcher* dispatcher) { int totalObjects = m_sets[0].m_leaves + m_sets[1].m_leaves; if (!totalObjects) { //reset internal dynamic tree data structures m_sets[0].clear(); m_sets[1].clear(); m_deferedcollide = false; m_needcleanup = true; m_stageCurrent = 0; m_fixedleft = 0; m_fupdates = 1; m_dupdates = 0; m_cupdates = 10; m_newpairs = 1; m_updates_call = 0; m_updates_done = 0; m_updates_ratio = 0; m_gid = 0; m_pid = 0; m_cid = 0; for(int i=0;i<=STAGECOUNT;++i) { m_stageRoots[i]=0; } } } // void btDbvtBroadphase::printStats() {} // #if DBVT_BP_ENABLE_BENCHMARK struct btBroadphaseBenchmark { struct Experiment { const char* name; int object_count; int update_count; int spawn_count; int iterations; btScalar speed; btScalar amplitude; }; struct Object { btVector3 center; btVector3 extents; btBroadphaseProxy* proxy; btScalar time; void update(btScalar speed,btScalar amplitude,btBroadphaseInterface* pbi) { time += speed; center[0] = btCos(time*(btScalar)2.17)*amplitude+ btSin(time)*amplitude/2; center[1] = btCos(time*(btScalar)1.38)*amplitude+ btSin(time)*amplitude; center[2] = btSin(time*(btScalar)0.777)*amplitude; pbi->setAabb(proxy,center-extents,center+extents,0); } }; static int UnsignedRand(int range=RAND_MAX-1) { return(rand()%(range+1)); } static btScalar UnitRand() { return(UnsignedRand(16384)/(btScalar)16384); } static void OutputTime(const char* name,btClock& c,unsigned count=0) { const unsigned long us=c.getTimeMicroseconds(); const unsigned long ms=(us+500)/1000; const btScalar sec=us/(btScalar)(1000*1000); if(count>0) printf("%s : %u us (%u ms), %.2f/s\r\n",name,us,ms,count/sec); else printf("%s : %u us (%u ms)\r\n",name,us,ms); } }; void btDbvtBroadphase::benchmark(btBroadphaseInterface* pbi) { static const btBroadphaseBenchmark::Experiment experiments[]= { {"1024o.10%",1024,10,0,8192,(btScalar)0.005,(btScalar)100}, /*{"4096o.10%",4096,10,0,8192,(btScalar)0.005,(btScalar)100}, {"8192o.10%",8192,10,0,8192,(btScalar)0.005,(btScalar)100},*/ }; static const int nexperiments=sizeof(experiments)/sizeof(experiments[0]); btAlignedObjectArray objects; btClock wallclock; /* Begin */ for(int iexp=0;iexpcenter[0]=btBroadphaseBenchmark::UnitRand()*50; po->center[1]=btBroadphaseBenchmark::UnitRand()*50; po->center[2]=btBroadphaseBenchmark::UnitRand()*50; po->extents[0]=btBroadphaseBenchmark::UnitRand()*2+2; po->extents[1]=btBroadphaseBenchmark::UnitRand()*2+2; po->extents[2]=btBroadphaseBenchmark::UnitRand()*2+2; po->time=btBroadphaseBenchmark::UnitRand()*2000; po->proxy=pbi->createProxy(po->center-po->extents,po->center+po->extents,0,po,1,1,0,0); objects.push_back(po); } btBroadphaseBenchmark::OutputTime("\tInitialization",wallclock); /* First update */ wallclock.reset(); for(int i=0;iupdate(speed,amplitude,pbi); } btBroadphaseBenchmark::OutputTime("\tFirst update",wallclock); /* Updates */ wallclock.reset(); for(int i=0;iupdate(speed,amplitude,pbi); } pbi->calculateOverlappingPairs(0); } btBroadphaseBenchmark::OutputTime("\tUpdate",wallclock,experiment.iterations); /* Clean up */ wallclock.reset(); for(int i=0;idestroyProxy(objects[i]->proxy,0); delete objects[i]; } objects.resize(0); btBroadphaseBenchmark::OutputTime("\tRelease",wallclock); } } #else void btDbvtBroadphase::benchmark(btBroadphaseInterface*) {} #endif #if DBVT_BP_PROFILE #undef SPC #endif ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCallback.hcritterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btOverlappingPairCallback.0000644000175000017500000000325611337071441033057 0ustar bobkebobke /* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 OVERLAPPING_PAIR_CALLBACK_H #define OVERLAPPING_PAIR_CALLBACK_H class btDispatcher; struct btBroadphasePair; ///The btOverlappingPairCallback class is an additional optional broadphase user callback for adding/removing overlapping pairs, similar interface to btOverlappingPairCache. class btOverlappingPairCallback { public: virtual ~btOverlappingPairCallback() { } virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) = 0; virtual void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher) = 0; virtual void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy0,btDispatcher* dispatcher) = 0; }; #endif //OVERLAPPING_PAIR_CALLBACK_H critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btQuantizedBvh.cpp0000644000175000017500000014245511344267705031464 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btQuantizedBvh.h" #include "LinearMath/btAabbUtil2.h" #include "LinearMath/btIDebugDraw.h" #include "LinearMath/btSerializer.h" #define RAYAABB2 btQuantizedBvh::btQuantizedBvh() : m_bulletVersion(BT_BULLET_VERSION), m_useQuantization(false), //m_traversalMode(TRAVERSAL_STACKLESS_CACHE_FRIENDLY) m_traversalMode(TRAVERSAL_STACKLESS) //m_traversalMode(TRAVERSAL_RECURSIVE) ,m_subtreeHeaderCount(0) //PCK: add this line { m_bvhAabbMin.setValue(-SIMD_INFINITY,-SIMD_INFINITY,-SIMD_INFINITY); m_bvhAabbMax.setValue(SIMD_INFINITY,SIMD_INFINITY,SIMD_INFINITY); } void btQuantizedBvh::buildInternal() { ///assumes that caller filled in the m_quantizedLeafNodes m_useQuantization = true; int numLeafNodes = 0; if (m_useQuantization) { //now we have an array of leafnodes in m_leafNodes numLeafNodes = m_quantizedLeafNodes.size(); m_quantizedContiguousNodes.resize(2*numLeafNodes); } m_curNodeIndex = 0; buildTree(0,numLeafNodes); ///if the entire tree is small then subtree size, we need to create a header info for the tree if(m_useQuantization && !m_SubtreeHeaders.size()) { btBvhSubtreeInfo& subtree = m_SubtreeHeaders.expand(); subtree.setAabbFromQuantizeNode(m_quantizedContiguousNodes[0]); subtree.m_rootNodeIndex = 0; subtree.m_subtreeSize = m_quantizedContiguousNodes[0].isLeafNode() ? 1 : m_quantizedContiguousNodes[0].getEscapeIndex(); } //PCK: update the copy of the size m_subtreeHeaderCount = m_SubtreeHeaders.size(); //PCK: clear m_quantizedLeafNodes and m_leafNodes, they are temporary m_quantizedLeafNodes.clear(); m_leafNodes.clear(); } ///just for debugging, to visualize the individual patches/subtrees #ifdef DEBUG_PATCH_COLORS btVector3 color[4]= { btVector3(1,0,0), btVector3(0,1,0), btVector3(0,0,1), btVector3(0,1,1) }; #endif //DEBUG_PATCH_COLORS void btQuantizedBvh::setQuantizationValues(const btVector3& bvhAabbMin,const btVector3& bvhAabbMax,btScalar quantizationMargin) { //enlarge the AABB to avoid division by zero when initializing the quantization values btVector3 clampValue(quantizationMargin,quantizationMargin,quantizationMargin); m_bvhAabbMin = bvhAabbMin - clampValue; m_bvhAabbMax = bvhAabbMax + clampValue; btVector3 aabbSize = m_bvhAabbMax - m_bvhAabbMin; m_bvhQuantization = btVector3(btScalar(65533.0),btScalar(65533.0),btScalar(65533.0)) / aabbSize; m_useQuantization = true; } btQuantizedBvh::~btQuantizedBvh() { } #ifdef DEBUG_TREE_BUILDING int gStackDepth = 0; int gMaxStackDepth = 0; #endif //DEBUG_TREE_BUILDING void btQuantizedBvh::buildTree (int startIndex,int endIndex) { #ifdef DEBUG_TREE_BUILDING gStackDepth++; if (gStackDepth > gMaxStackDepth) gMaxStackDepth = gStackDepth; #endif //DEBUG_TREE_BUILDING int splitAxis, splitIndex, i; int numIndices =endIndex-startIndex; int curIndex = m_curNodeIndex; btAssert(numIndices>0); if (numIndices==1) { #ifdef DEBUG_TREE_BUILDING gStackDepth--; #endif //DEBUG_TREE_BUILDING assignInternalNodeFromLeafNode(m_curNodeIndex,startIndex); m_curNodeIndex++; return; } //calculate Best Splitting Axis and where to split it. Sort the incoming 'leafNodes' array within range 'startIndex/endIndex'. splitAxis = calcSplittingAxis(startIndex,endIndex); splitIndex = sortAndCalcSplittingIndex(startIndex,endIndex,splitAxis); int internalNodeIndex = m_curNodeIndex; //set the min aabb to 'inf' or a max value, and set the max aabb to a -inf/minimum value. //the aabb will be expanded during buildTree/mergeInternalNodeAabb with actual node values setInternalNodeAabbMin(m_curNodeIndex,m_bvhAabbMax);//can't use btVector3(SIMD_INFINITY,SIMD_INFINITY,SIMD_INFINITY)) because of quantization setInternalNodeAabbMax(m_curNodeIndex,m_bvhAabbMin);//can't use btVector3(-SIMD_INFINITY,-SIMD_INFINITY,-SIMD_INFINITY)) because of quantization for (i=startIndex;im_escapeIndex; int leftChildNodexIndex = m_curNodeIndex; //build left child tree buildTree(startIndex,splitIndex); int rightChildNodexIndex = m_curNodeIndex; //build right child tree buildTree(splitIndex,endIndex); #ifdef DEBUG_TREE_BUILDING gStackDepth--; #endif //DEBUG_TREE_BUILDING int escapeIndex = m_curNodeIndex - curIndex; if (m_useQuantization) { //escapeIndex is the number of nodes of this subtree const int sizeQuantizedNode =sizeof(btQuantizedBvhNode); const int treeSizeInBytes = escapeIndex * sizeQuantizedNode; if (treeSizeInBytes > MAX_SUBTREE_SIZE_IN_BYTES) { updateSubtreeHeaders(leftChildNodexIndex,rightChildNodexIndex); } } else { } setInternalNodeEscapeIndex(internalNodeIndex,escapeIndex); } void btQuantizedBvh::updateSubtreeHeaders(int leftChildNodexIndex,int rightChildNodexIndex) { btAssert(m_useQuantization); btQuantizedBvhNode& leftChildNode = m_quantizedContiguousNodes[leftChildNodexIndex]; int leftSubTreeSize = leftChildNode.isLeafNode() ? 1 : leftChildNode.getEscapeIndex(); int leftSubTreeSizeInBytes = leftSubTreeSize * static_cast(sizeof(btQuantizedBvhNode)); btQuantizedBvhNode& rightChildNode = m_quantizedContiguousNodes[rightChildNodexIndex]; int rightSubTreeSize = rightChildNode.isLeafNode() ? 1 : rightChildNode.getEscapeIndex(); int rightSubTreeSizeInBytes = rightSubTreeSize * static_cast(sizeof(btQuantizedBvhNode)); if(leftSubTreeSizeInBytes <= MAX_SUBTREE_SIZE_IN_BYTES) { btBvhSubtreeInfo& subtree = m_SubtreeHeaders.expand(); subtree.setAabbFromQuantizeNode(leftChildNode); subtree.m_rootNodeIndex = leftChildNodexIndex; subtree.m_subtreeSize = leftSubTreeSize; } if(rightSubTreeSizeInBytes <= MAX_SUBTREE_SIZE_IN_BYTES) { btBvhSubtreeInfo& subtree = m_SubtreeHeaders.expand(); subtree.setAabbFromQuantizeNode(rightChildNode); subtree.m_rootNodeIndex = rightChildNodexIndex; subtree.m_subtreeSize = rightSubTreeSize; } //PCK: update the copy of the size m_subtreeHeaderCount = m_SubtreeHeaders.size(); } int btQuantizedBvh::sortAndCalcSplittingIndex(int startIndex,int endIndex,int splitAxis) { int i; int splitIndex =startIndex; int numIndices = endIndex - startIndex; btScalar splitValue; btVector3 means(btScalar(0.),btScalar(0.),btScalar(0.)); for (i=startIndex;i splitValue) { //swap swapLeafNodes(i,splitIndex); splitIndex++; } } //if the splitIndex causes unbalanced trees, fix this by using the center in between startIndex and endIndex //otherwise the tree-building might fail due to stack-overflows in certain cases. //unbalanced1 is unsafe: it can cause stack overflows //bool unbalanced1 = ((splitIndex==startIndex) || (splitIndex == (endIndex-1))); //unbalanced2 should work too: always use center (perfect balanced trees) //bool unbalanced2 = true; //this should be safe too: int rangeBalancedIndices = numIndices/3; bool unbalanced = ((splitIndex<=(startIndex+rangeBalancedIndices)) || (splitIndex >=(endIndex-1-rangeBalancedIndices))); if (unbalanced) { splitIndex = startIndex+ (numIndices>>1); } bool unbal = (splitIndex==startIndex) || (splitIndex == (endIndex)); (void)unbal; btAssert(!unbal); return splitIndex; } int btQuantizedBvh::calcSplittingAxis(int startIndex,int endIndex) { int i; btVector3 means(btScalar(0.),btScalar(0.),btScalar(0.)); btVector3 variance(btScalar(0.),btScalar(0.),btScalar(0.)); int numIndices = endIndex-startIndex; for (i=startIndex;im_aabbMinOrg,rootNode->m_aabbMaxOrg); isLeafNode = rootNode->m_escapeIndex == -1; //PCK: unsigned instead of bool if (isLeafNode && (aabbOverlap != 0)) { nodeCallback->processNode(rootNode->m_subPart,rootNode->m_triangleIndex); } //PCK: unsigned instead of bool if ((aabbOverlap != 0) || isLeafNode) { rootNode++; curIndex++; } else { escapeIndex = rootNode->m_escapeIndex; rootNode += escapeIndex; curIndex += escapeIndex; } } if (maxIterations < walkIterations) maxIterations = walkIterations; } /* ///this was the original recursive traversal, before we optimized towards stackless traversal void btQuantizedBvh::walkTree(btOptimizedBvhNode* rootNode,btNodeOverlapCallback* nodeCallback,const btVector3& aabbMin,const btVector3& aabbMax) const { bool isLeafNode, aabbOverlap = TestAabbAgainstAabb2(aabbMin,aabbMax,rootNode->m_aabbMin,rootNode->m_aabbMax); if (aabbOverlap) { isLeafNode = (!rootNode->m_leftChild && !rootNode->m_rightChild); if (isLeafNode) { nodeCallback->processNode(rootNode); } else { walkTree(rootNode->m_leftChild,nodeCallback,aabbMin,aabbMax); walkTree(rootNode->m_rightChild,nodeCallback,aabbMin,aabbMax); } } } */ void btQuantizedBvh::walkRecursiveQuantizedTreeAgainstQueryAabb(const btQuantizedBvhNode* currentNode,btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const { btAssert(m_useQuantization); bool isLeafNode; //PCK: unsigned instead of bool unsigned aabbOverlap; //PCK: unsigned instead of bool aabbOverlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,currentNode->m_quantizedAabbMin,currentNode->m_quantizedAabbMax); isLeafNode = currentNode->isLeafNode(); //PCK: unsigned instead of bool if (aabbOverlap != 0) { if (isLeafNode) { nodeCallback->processNode(currentNode->getPartId(),currentNode->getTriangleIndex()); } else { //process left and right children const btQuantizedBvhNode* leftChildNode = currentNode+1; walkRecursiveQuantizedTreeAgainstQueryAabb(leftChildNode,nodeCallback,quantizedQueryAabbMin,quantizedQueryAabbMax); const btQuantizedBvhNode* rightChildNode = leftChildNode->isLeafNode() ? leftChildNode+1:leftChildNode+leftChildNode->getEscapeIndex(); walkRecursiveQuantizedTreeAgainstQueryAabb(rightChildNode,nodeCallback,quantizedQueryAabbMin,quantizedQueryAabbMax); } } } void btQuantizedBvh::walkStacklessTreeAgainstRay(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin, const btVector3& aabbMax, int startNodeIndex,int endNodeIndex) const { btAssert(!m_useQuantization); const btOptimizedBvhNode* rootNode = &m_contiguousNodes[0]; int escapeIndex, curIndex = 0; int walkIterations = 0; bool isLeafNode; //PCK: unsigned instead of bool unsigned aabbOverlap=0; unsigned rayBoxOverlap=0; btScalar lambda_max = 1.0; /* Quick pruning by quantized box */ btVector3 rayAabbMin = raySource; btVector3 rayAabbMax = raySource; rayAabbMin.setMin(rayTarget); rayAabbMax.setMax(rayTarget); /* Add box cast extents to bounding box */ rayAabbMin += aabbMin; rayAabbMax += aabbMax; #ifdef RAYAABB2 btVector3 rayDir = (rayTarget-raySource); rayDir.normalize (); lambda_max = rayDir.dot(rayTarget-raySource); ///what about division by zero? --> just set rayDirection[i] to 1.0 btVector3 rayDirectionInverse; rayDirectionInverse[0] = rayDir[0] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[0]; rayDirectionInverse[1] = rayDir[1] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[1]; rayDirectionInverse[2] = rayDir[2] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[2]; unsigned int sign[3] = { rayDirectionInverse[0] < 0.0, rayDirectionInverse[1] < 0.0, rayDirectionInverse[2] < 0.0}; #endif btVector3 bounds[2]; while (curIndex < m_curNodeIndex) { btScalar param = 1.0; //catch bugs in tree data btAssert (walkIterations < m_curNodeIndex); walkIterations++; bounds[0] = rootNode->m_aabbMinOrg; bounds[1] = rootNode->m_aabbMaxOrg; /* Add box cast extents */ bounds[0] -= aabbMax; bounds[1] -= aabbMin; aabbOverlap = TestAabbAgainstAabb2(rayAabbMin,rayAabbMax,rootNode->m_aabbMinOrg,rootNode->m_aabbMaxOrg); //perhaps profile if it is worth doing the aabbOverlap test first #ifdef RAYAABB2 ///careful with this check: need to check division by zero (above) and fix the unQuantize method ///thanks Joerg/hiker for the reproduction case! ///http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=1858 rayBoxOverlap = aabbOverlap ? btRayAabb2 (raySource, rayDirectionInverse, sign, bounds, param, 0.0f, lambda_max) : false; #else btVector3 normal; rayBoxOverlap = btRayAabb(raySource, rayTarget,bounds[0],bounds[1],param, normal); #endif isLeafNode = rootNode->m_escapeIndex == -1; //PCK: unsigned instead of bool if (isLeafNode && (rayBoxOverlap != 0)) { nodeCallback->processNode(rootNode->m_subPart,rootNode->m_triangleIndex); } //PCK: unsigned instead of bool if ((rayBoxOverlap != 0) || isLeafNode) { rootNode++; curIndex++; } else { escapeIndex = rootNode->m_escapeIndex; rootNode += escapeIndex; curIndex += escapeIndex; } } if (maxIterations < walkIterations) maxIterations = walkIterations; } void btQuantizedBvh::walkStacklessQuantizedTreeAgainstRay(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin, const btVector3& aabbMax, int startNodeIndex,int endNodeIndex) const { btAssert(m_useQuantization); int curIndex = startNodeIndex; int walkIterations = 0; int subTreeSize = endNodeIndex - startNodeIndex; (void)subTreeSize; const btQuantizedBvhNode* rootNode = &m_quantizedContiguousNodes[startNodeIndex]; int escapeIndex; bool isLeafNode; //PCK: unsigned instead of bool unsigned boxBoxOverlap = 0; unsigned rayBoxOverlap = 0; btScalar lambda_max = 1.0; #ifdef RAYAABB2 btVector3 rayDirection = (rayTarget-raySource); rayDirection.normalize (); lambda_max = rayDirection.dot(rayTarget-raySource); ///what about division by zero? --> just set rayDirection[i] to 1.0 rayDirection[0] = rayDirection[0] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDirection[0]; rayDirection[1] = rayDirection[1] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDirection[1]; rayDirection[2] = rayDirection[2] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDirection[2]; unsigned int sign[3] = { rayDirection[0] < 0.0, rayDirection[1] < 0.0, rayDirection[2] < 0.0}; #endif /* Quick pruning by quantized box */ btVector3 rayAabbMin = raySource; btVector3 rayAabbMax = raySource; rayAabbMin.setMin(rayTarget); rayAabbMax.setMax(rayTarget); /* Add box cast extents to bounding box */ rayAabbMin += aabbMin; rayAabbMax += aabbMax; unsigned short int quantizedQueryAabbMin[3]; unsigned short int quantizedQueryAabbMax[3]; quantizeWithClamp(quantizedQueryAabbMin,rayAabbMin,0); quantizeWithClamp(quantizedQueryAabbMax,rayAabbMax,1); while (curIndex < endNodeIndex) { //#define VISUALLY_ANALYZE_BVH 1 #ifdef VISUALLY_ANALYZE_BVH //some code snippet to debugDraw aabb, to visually analyze bvh structure static int drawPatch = 0; //need some global access to a debugDrawer extern btIDebugDraw* debugDrawerPtr; if (curIndex==drawPatch) { btVector3 aabbMin,aabbMax; aabbMin = unQuantize(rootNode->m_quantizedAabbMin); aabbMax = unQuantize(rootNode->m_quantizedAabbMax); btVector3 color(1,0,0); debugDrawerPtr->drawAabb(aabbMin,aabbMax,color); } #endif//VISUALLY_ANALYZE_BVH //catch bugs in tree data btAssert (walkIterations < subTreeSize); walkIterations++; //PCK: unsigned instead of bool // only interested if this is closer than any previous hit btScalar param = 1.0; rayBoxOverlap = 0; boxBoxOverlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,rootNode->m_quantizedAabbMin,rootNode->m_quantizedAabbMax); isLeafNode = rootNode->isLeafNode(); if (boxBoxOverlap) { btVector3 bounds[2]; bounds[0] = unQuantize(rootNode->m_quantizedAabbMin); bounds[1] = unQuantize(rootNode->m_quantizedAabbMax); /* Add box cast extents */ bounds[0] -= aabbMax; bounds[1] -= aabbMin; btVector3 normal; #if 0 bool ra2 = btRayAabb2 (raySource, rayDirection, sign, bounds, param, 0.0, lambda_max); bool ra = btRayAabb (raySource, rayTarget, bounds[0], bounds[1], param, normal); if (ra2 != ra) { printf("functions don't match\n"); } #endif #ifdef RAYAABB2 ///careful with this check: need to check division by zero (above) and fix the unQuantize method ///thanks Joerg/hiker for the reproduction case! ///http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=9&t=1858 //BT_PROFILE("btRayAabb2"); rayBoxOverlap = btRayAabb2 (raySource, rayDirection, sign, bounds, param, 0.0f, lambda_max); #else rayBoxOverlap = true;//btRayAabb(raySource, rayTarget, bounds[0], bounds[1], param, normal); #endif } if (isLeafNode && rayBoxOverlap) { nodeCallback->processNode(rootNode->getPartId(),rootNode->getTriangleIndex()); } //PCK: unsigned instead of bool if ((rayBoxOverlap != 0) || isLeafNode) { rootNode++; curIndex++; } else { escapeIndex = rootNode->getEscapeIndex(); rootNode += escapeIndex; curIndex += escapeIndex; } } if (maxIterations < walkIterations) maxIterations = walkIterations; } void btQuantizedBvh::walkStacklessQuantizedTree(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax,int startNodeIndex,int endNodeIndex) const { btAssert(m_useQuantization); int curIndex = startNodeIndex; int walkIterations = 0; int subTreeSize = endNodeIndex - startNodeIndex; (void)subTreeSize; const btQuantizedBvhNode* rootNode = &m_quantizedContiguousNodes[startNodeIndex]; int escapeIndex; bool isLeafNode; //PCK: unsigned instead of bool unsigned aabbOverlap; while (curIndex < endNodeIndex) { //#define VISUALLY_ANALYZE_BVH 1 #ifdef VISUALLY_ANALYZE_BVH //some code snippet to debugDraw aabb, to visually analyze bvh structure static int drawPatch = 0; //need some global access to a debugDrawer extern btIDebugDraw* debugDrawerPtr; if (curIndex==drawPatch) { btVector3 aabbMin,aabbMax; aabbMin = unQuantize(rootNode->m_quantizedAabbMin); aabbMax = unQuantize(rootNode->m_quantizedAabbMax); btVector3 color(1,0,0); debugDrawerPtr->drawAabb(aabbMin,aabbMax,color); } #endif//VISUALLY_ANALYZE_BVH //catch bugs in tree data btAssert (walkIterations < subTreeSize); walkIterations++; //PCK: unsigned instead of bool aabbOverlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,rootNode->m_quantizedAabbMin,rootNode->m_quantizedAabbMax); isLeafNode = rootNode->isLeafNode(); if (isLeafNode && aabbOverlap) { nodeCallback->processNode(rootNode->getPartId(),rootNode->getTriangleIndex()); } //PCK: unsigned instead of bool if ((aabbOverlap != 0) || isLeafNode) { rootNode++; curIndex++; } else { escapeIndex = rootNode->getEscapeIndex(); rootNode += escapeIndex; curIndex += escapeIndex; } } if (maxIterations < walkIterations) maxIterations = walkIterations; } //This traversal can be called from Playstation 3 SPU void btQuantizedBvh::walkStacklessQuantizedTreeCacheFriendly(btNodeOverlapCallback* nodeCallback,unsigned short int* quantizedQueryAabbMin,unsigned short int* quantizedQueryAabbMax) const { btAssert(m_useQuantization); int i; for (i=0;im_SubtreeHeaders.size();i++) { const btBvhSubtreeInfo& subtree = m_SubtreeHeaders[i]; //PCK: unsigned instead of bool unsigned overlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,subtree.m_quantizedAabbMin,subtree.m_quantizedAabbMax); if (overlap != 0) { walkStacklessQuantizedTree(nodeCallback,quantizedQueryAabbMin,quantizedQueryAabbMax, subtree.m_rootNodeIndex, subtree.m_rootNodeIndex+subtree.m_subtreeSize); } } } void btQuantizedBvh::reportRayOverlappingNodex (btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget) const { reportBoxCastOverlappingNodex(nodeCallback,raySource,rayTarget,btVector3(0,0,0),btVector3(0,0,0)); } void btQuantizedBvh::reportBoxCastOverlappingNodex(btNodeOverlapCallback* nodeCallback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin,const btVector3& aabbMax) const { //always use stackless if (m_useQuantization) { walkStacklessQuantizedTreeAgainstRay(nodeCallback, raySource, rayTarget, aabbMin, aabbMax, 0, m_curNodeIndex); } else { walkStacklessTreeAgainstRay(nodeCallback, raySource, rayTarget, aabbMin, aabbMax, 0, m_curNodeIndex); } /* { //recursive traversal btVector3 qaabbMin = raySource; btVector3 qaabbMax = raySource; qaabbMin.setMin(rayTarget); qaabbMax.setMax(rayTarget); qaabbMin += aabbMin; qaabbMax += aabbMax; reportAabbOverlappingNodex(nodeCallback,qaabbMin,qaabbMax); } */ } void btQuantizedBvh::swapLeafNodes(int i,int splitIndex) { if (m_useQuantization) { btQuantizedBvhNode tmp = m_quantizedLeafNodes[i]; m_quantizedLeafNodes[i] = m_quantizedLeafNodes[splitIndex]; m_quantizedLeafNodes[splitIndex] = tmp; } else { btOptimizedBvhNode tmp = m_leafNodes[i]; m_leafNodes[i] = m_leafNodes[splitIndex]; m_leafNodes[splitIndex] = tmp; } } void btQuantizedBvh::assignInternalNodeFromLeafNode(int internalNode,int leafNodeIndex) { if (m_useQuantization) { m_quantizedContiguousNodes[internalNode] = m_quantizedLeafNodes[leafNodeIndex]; } else { m_contiguousNodes[internalNode] = m_leafNodes[leafNodeIndex]; } } //PCK: include #include #if 0 //PCK: consts static const unsigned BVH_ALIGNMENT = 16; static const unsigned BVH_ALIGNMENT_MASK = BVH_ALIGNMENT-1; static const unsigned BVH_ALIGNMENT_BLOCKS = 2; #endif unsigned int btQuantizedBvh::getAlignmentSerializationPadding() { // I changed this to 0 since the extra padding is not needed or used. return 0;//BVH_ALIGNMENT_BLOCKS * BVH_ALIGNMENT; } unsigned btQuantizedBvh::calculateSerializeBufferSize() const { unsigned baseSize = sizeof(btQuantizedBvh) + getAlignmentSerializationPadding(); baseSize += sizeof(btBvhSubtreeInfo) * m_subtreeHeaderCount; if (m_useQuantization) { return baseSize + m_curNodeIndex * sizeof(btQuantizedBvhNode); } return baseSize + m_curNodeIndex * sizeof(btOptimizedBvhNode); } bool btQuantizedBvh::serialize(void *o_alignedDataBuffer, unsigned /*i_dataBufferSize */, bool i_swapEndian) const { btAssert(m_subtreeHeaderCount == m_SubtreeHeaders.size()); m_subtreeHeaderCount = m_SubtreeHeaders.size(); /* if (i_dataBufferSize < calculateSerializeBufferSize() || o_alignedDataBuffer == NULL || (((unsigned)o_alignedDataBuffer & BVH_ALIGNMENT_MASK) != 0)) { ///check alignedment for buffer? btAssert(0); return false; } */ btQuantizedBvh *targetBvh = (btQuantizedBvh *)o_alignedDataBuffer; // construct the class so the virtual function table, etc will be set up // Also, m_leafNodes and m_quantizedLeafNodes will be initialized to default values by the constructor new (targetBvh) btQuantizedBvh; if (i_swapEndian) { targetBvh->m_curNodeIndex = static_cast(btSwapEndian(m_curNodeIndex)); btSwapVector3Endian(m_bvhAabbMin,targetBvh->m_bvhAabbMin); btSwapVector3Endian(m_bvhAabbMax,targetBvh->m_bvhAabbMax); btSwapVector3Endian(m_bvhQuantization,targetBvh->m_bvhQuantization); targetBvh->m_traversalMode = (btTraversalMode)btSwapEndian(m_traversalMode); targetBvh->m_subtreeHeaderCount = static_cast(btSwapEndian(m_subtreeHeaderCount)); } else { targetBvh->m_curNodeIndex = m_curNodeIndex; targetBvh->m_bvhAabbMin = m_bvhAabbMin; targetBvh->m_bvhAabbMax = m_bvhAabbMax; targetBvh->m_bvhQuantization = m_bvhQuantization; targetBvh->m_traversalMode = m_traversalMode; targetBvh->m_subtreeHeaderCount = m_subtreeHeaderCount; } targetBvh->m_useQuantization = m_useQuantization; unsigned char *nodeData = (unsigned char *)targetBvh; nodeData += sizeof(btQuantizedBvh); unsigned sizeToAdd = 0;//(BVH_ALIGNMENT-((unsigned)nodeData & BVH_ALIGNMENT_MASK))&BVH_ALIGNMENT_MASK; nodeData += sizeToAdd; int nodeCount = m_curNodeIndex; if (m_useQuantization) { targetBvh->m_quantizedContiguousNodes.initializeFromBuffer(nodeData, nodeCount, nodeCount); if (i_swapEndian) { for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++) { targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0] = btSwapEndian(m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0]); targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[1] = btSwapEndian(m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[1]); targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[2] = btSwapEndian(m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[2]); targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0] = btSwapEndian(m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0]); targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[1] = btSwapEndian(m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[1]); targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[2] = btSwapEndian(m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[2]); targetBvh->m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex = static_cast(btSwapEndian(m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex)); } } else { for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++) { targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0] = m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0]; targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[1] = m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[1]; targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[2] = m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[2]; targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0] = m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0]; targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[1] = m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[1]; targetBvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[2] = m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[2]; targetBvh->m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex = m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex; } } nodeData += sizeof(btQuantizedBvhNode) * nodeCount; // this clears the pointer in the member variable it doesn't really do anything to the data // it does call the destructor on the contained objects, but they are all classes with no destructor defined // so the memory (which is not freed) is left alone targetBvh->m_quantizedContiguousNodes.initializeFromBuffer(NULL, 0, 0); } else { targetBvh->m_contiguousNodes.initializeFromBuffer(nodeData, nodeCount, nodeCount); if (i_swapEndian) { for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++) { btSwapVector3Endian(m_contiguousNodes[nodeIndex].m_aabbMinOrg, targetBvh->m_contiguousNodes[nodeIndex].m_aabbMinOrg); btSwapVector3Endian(m_contiguousNodes[nodeIndex].m_aabbMaxOrg, targetBvh->m_contiguousNodes[nodeIndex].m_aabbMaxOrg); targetBvh->m_contiguousNodes[nodeIndex].m_escapeIndex = static_cast(btSwapEndian(m_contiguousNodes[nodeIndex].m_escapeIndex)); targetBvh->m_contiguousNodes[nodeIndex].m_subPart = static_cast(btSwapEndian(m_contiguousNodes[nodeIndex].m_subPart)); targetBvh->m_contiguousNodes[nodeIndex].m_triangleIndex = static_cast(btSwapEndian(m_contiguousNodes[nodeIndex].m_triangleIndex)); } } else { for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++) { targetBvh->m_contiguousNodes[nodeIndex].m_aabbMinOrg = m_contiguousNodes[nodeIndex].m_aabbMinOrg; targetBvh->m_contiguousNodes[nodeIndex].m_aabbMaxOrg = m_contiguousNodes[nodeIndex].m_aabbMaxOrg; targetBvh->m_contiguousNodes[nodeIndex].m_escapeIndex = m_contiguousNodes[nodeIndex].m_escapeIndex; targetBvh->m_contiguousNodes[nodeIndex].m_subPart = m_contiguousNodes[nodeIndex].m_subPart; targetBvh->m_contiguousNodes[nodeIndex].m_triangleIndex = m_contiguousNodes[nodeIndex].m_triangleIndex; } } nodeData += sizeof(btOptimizedBvhNode) * nodeCount; // this clears the pointer in the member variable it doesn't really do anything to the data // it does call the destructor on the contained objects, but they are all classes with no destructor defined // so the memory (which is not freed) is left alone targetBvh->m_contiguousNodes.initializeFromBuffer(NULL, 0, 0); } sizeToAdd = 0;//(BVH_ALIGNMENT-((unsigned)nodeData & BVH_ALIGNMENT_MASK))&BVH_ALIGNMENT_MASK; nodeData += sizeToAdd; // Now serialize the subtree headers targetBvh->m_SubtreeHeaders.initializeFromBuffer(nodeData, m_subtreeHeaderCount, m_subtreeHeaderCount); if (i_swapEndian) { for (int i = 0; i < m_subtreeHeaderCount; i++) { targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMin[0] = btSwapEndian(m_SubtreeHeaders[i].m_quantizedAabbMin[0]); targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMin[1] = btSwapEndian(m_SubtreeHeaders[i].m_quantizedAabbMin[1]); targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMin[2] = btSwapEndian(m_SubtreeHeaders[i].m_quantizedAabbMin[2]); targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMax[0] = btSwapEndian(m_SubtreeHeaders[i].m_quantizedAabbMax[0]); targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMax[1] = btSwapEndian(m_SubtreeHeaders[i].m_quantizedAabbMax[1]); targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMax[2] = btSwapEndian(m_SubtreeHeaders[i].m_quantizedAabbMax[2]); targetBvh->m_SubtreeHeaders[i].m_rootNodeIndex = static_cast(btSwapEndian(m_SubtreeHeaders[i].m_rootNodeIndex)); targetBvh->m_SubtreeHeaders[i].m_subtreeSize = static_cast(btSwapEndian(m_SubtreeHeaders[i].m_subtreeSize)); } } else { for (int i = 0; i < m_subtreeHeaderCount; i++) { targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMin[0] = (m_SubtreeHeaders[i].m_quantizedAabbMin[0]); targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMin[1] = (m_SubtreeHeaders[i].m_quantizedAabbMin[1]); targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMin[2] = (m_SubtreeHeaders[i].m_quantizedAabbMin[2]); targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMax[0] = (m_SubtreeHeaders[i].m_quantizedAabbMax[0]); targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMax[1] = (m_SubtreeHeaders[i].m_quantizedAabbMax[1]); targetBvh->m_SubtreeHeaders[i].m_quantizedAabbMax[2] = (m_SubtreeHeaders[i].m_quantizedAabbMax[2]); targetBvh->m_SubtreeHeaders[i].m_rootNodeIndex = (m_SubtreeHeaders[i].m_rootNodeIndex); targetBvh->m_SubtreeHeaders[i].m_subtreeSize = (m_SubtreeHeaders[i].m_subtreeSize); // need to clear padding in destination buffer targetBvh->m_SubtreeHeaders[i].m_padding[0] = 0; targetBvh->m_SubtreeHeaders[i].m_padding[1] = 0; targetBvh->m_SubtreeHeaders[i].m_padding[2] = 0; } } nodeData += sizeof(btBvhSubtreeInfo) * m_subtreeHeaderCount; // this clears the pointer in the member variable it doesn't really do anything to the data // it does call the destructor on the contained objects, but they are all classes with no destructor defined // so the memory (which is not freed) is left alone targetBvh->m_SubtreeHeaders.initializeFromBuffer(NULL, 0, 0); // this wipes the virtual function table pointer at the start of the buffer for the class *((void**)o_alignedDataBuffer) = NULL; return true; } btQuantizedBvh *btQuantizedBvh::deSerializeInPlace(void *i_alignedDataBuffer, unsigned int i_dataBufferSize, bool i_swapEndian) { if (i_alignedDataBuffer == NULL)// || (((unsigned)i_alignedDataBuffer & BVH_ALIGNMENT_MASK) != 0)) { return NULL; } btQuantizedBvh *bvh = (btQuantizedBvh *)i_alignedDataBuffer; if (i_swapEndian) { bvh->m_curNodeIndex = static_cast(btSwapEndian(bvh->m_curNodeIndex)); btUnSwapVector3Endian(bvh->m_bvhAabbMin); btUnSwapVector3Endian(bvh->m_bvhAabbMax); btUnSwapVector3Endian(bvh->m_bvhQuantization); bvh->m_traversalMode = (btTraversalMode)btSwapEndian(bvh->m_traversalMode); bvh->m_subtreeHeaderCount = static_cast(btSwapEndian(bvh->m_subtreeHeaderCount)); } unsigned int calculatedBufSize = bvh->calculateSerializeBufferSize(); btAssert(calculatedBufSize <= i_dataBufferSize); if (calculatedBufSize > i_dataBufferSize) { return NULL; } unsigned char *nodeData = (unsigned char *)bvh; nodeData += sizeof(btQuantizedBvh); unsigned sizeToAdd = 0;//(BVH_ALIGNMENT-((unsigned)nodeData & BVH_ALIGNMENT_MASK))&BVH_ALIGNMENT_MASK; nodeData += sizeToAdd; int nodeCount = bvh->m_curNodeIndex; // Must call placement new to fill in virtual function table, etc, but we don't want to overwrite most data, so call a special version of the constructor // Also, m_leafNodes and m_quantizedLeafNodes will be initialized to default values by the constructor new (bvh) btQuantizedBvh(*bvh, false); if (bvh->m_useQuantization) { bvh->m_quantizedContiguousNodes.initializeFromBuffer(nodeData, nodeCount, nodeCount); if (i_swapEndian) { for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++) { bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0] = btSwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[0]); bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[1] = btSwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[1]); bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[2] = btSwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMin[2]); bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0] = btSwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[0]); bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[1] = btSwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[1]); bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[2] = btSwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_quantizedAabbMax[2]); bvh->m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex = static_cast(btSwapEndian(bvh->m_quantizedContiguousNodes[nodeIndex].m_escapeIndexOrTriangleIndex)); } } nodeData += sizeof(btQuantizedBvhNode) * nodeCount; } else { bvh->m_contiguousNodes.initializeFromBuffer(nodeData, nodeCount, nodeCount); if (i_swapEndian) { for (int nodeIndex = 0; nodeIndex < nodeCount; nodeIndex++) { btUnSwapVector3Endian(bvh->m_contiguousNodes[nodeIndex].m_aabbMinOrg); btUnSwapVector3Endian(bvh->m_contiguousNodes[nodeIndex].m_aabbMaxOrg); bvh->m_contiguousNodes[nodeIndex].m_escapeIndex = static_cast(btSwapEndian(bvh->m_contiguousNodes[nodeIndex].m_escapeIndex)); bvh->m_contiguousNodes[nodeIndex].m_subPart = static_cast(btSwapEndian(bvh->m_contiguousNodes[nodeIndex].m_subPart)); bvh->m_contiguousNodes[nodeIndex].m_triangleIndex = static_cast(btSwapEndian(bvh->m_contiguousNodes[nodeIndex].m_triangleIndex)); } } nodeData += sizeof(btOptimizedBvhNode) * nodeCount; } sizeToAdd = 0;//(BVH_ALIGNMENT-((unsigned)nodeData & BVH_ALIGNMENT_MASK))&BVH_ALIGNMENT_MASK; nodeData += sizeToAdd; // Now serialize the subtree headers bvh->m_SubtreeHeaders.initializeFromBuffer(nodeData, bvh->m_subtreeHeaderCount, bvh->m_subtreeHeaderCount); if (i_swapEndian) { for (int i = 0; i < bvh->m_subtreeHeaderCount; i++) { bvh->m_SubtreeHeaders[i].m_quantizedAabbMin[0] = btSwapEndian(bvh->m_SubtreeHeaders[i].m_quantizedAabbMin[0]); bvh->m_SubtreeHeaders[i].m_quantizedAabbMin[1] = btSwapEndian(bvh->m_SubtreeHeaders[i].m_quantizedAabbMin[1]); bvh->m_SubtreeHeaders[i].m_quantizedAabbMin[2] = btSwapEndian(bvh->m_SubtreeHeaders[i].m_quantizedAabbMin[2]); bvh->m_SubtreeHeaders[i].m_quantizedAabbMax[0] = btSwapEndian(bvh->m_SubtreeHeaders[i].m_quantizedAabbMax[0]); bvh->m_SubtreeHeaders[i].m_quantizedAabbMax[1] = btSwapEndian(bvh->m_SubtreeHeaders[i].m_quantizedAabbMax[1]); bvh->m_SubtreeHeaders[i].m_quantizedAabbMax[2] = btSwapEndian(bvh->m_SubtreeHeaders[i].m_quantizedAabbMax[2]); bvh->m_SubtreeHeaders[i].m_rootNodeIndex = static_cast(btSwapEndian(bvh->m_SubtreeHeaders[i].m_rootNodeIndex)); bvh->m_SubtreeHeaders[i].m_subtreeSize = static_cast(btSwapEndian(bvh->m_SubtreeHeaders[i].m_subtreeSize)); } } return bvh; } // Constructor that prevents btVector3's default constructor from being called btQuantizedBvh::btQuantizedBvh(btQuantizedBvh &self, bool /* ownsMemory */) : m_bvhAabbMin(self.m_bvhAabbMin), m_bvhAabbMax(self.m_bvhAabbMax), m_bvhQuantization(self.m_bvhQuantization), m_bulletVersion(BT_BULLET_VERSION) { } void btQuantizedBvh::deSerializeFloat(struct btQuantizedBvhFloatData& quantizedBvhFloatData) { m_bvhAabbMax.deSerializeFloat(quantizedBvhFloatData.m_bvhAabbMax); m_bvhAabbMin.deSerializeFloat(quantizedBvhFloatData.m_bvhAabbMin); m_bvhQuantization.deSerializeFloat(quantizedBvhFloatData.m_bvhQuantization); m_curNodeIndex = quantizedBvhFloatData.m_curNodeIndex; m_useQuantization = quantizedBvhFloatData.m_useQuantization!=0; { int numElem = quantizedBvhFloatData.m_numContiguousLeafNodes; m_contiguousNodes.resize(numElem); if (numElem) { btOptimizedBvhNodeFloatData* memPtr = quantizedBvhFloatData.m_contiguousNodesPtr; for (int i=0;im_aabbMaxOrg); m_contiguousNodes[i].m_aabbMinOrg.deSerializeFloat(memPtr->m_aabbMinOrg); m_contiguousNodes[i].m_escapeIndex = memPtr->m_escapeIndex; m_contiguousNodes[i].m_subPart = memPtr->m_subPart; m_contiguousNodes[i].m_triangleIndex = memPtr->m_triangleIndex; } } } { int numElem = quantizedBvhFloatData.m_numQuantizedContiguousNodes; m_quantizedContiguousNodes.resize(numElem); if (numElem) { btQuantizedBvhNodeData* memPtr = quantizedBvhFloatData.m_quantizedContiguousNodesPtr; for (int i=0;im_escapeIndexOrTriangleIndex; m_quantizedContiguousNodes[i].m_quantizedAabbMax[0] = memPtr->m_quantizedAabbMax[0]; m_quantizedContiguousNodes[i].m_quantizedAabbMax[1] = memPtr->m_quantizedAabbMax[1]; m_quantizedContiguousNodes[i].m_quantizedAabbMax[2] = memPtr->m_quantizedAabbMax[2]; m_quantizedContiguousNodes[i].m_quantizedAabbMin[0] = memPtr->m_quantizedAabbMin[0]; m_quantizedContiguousNodes[i].m_quantizedAabbMin[1] = memPtr->m_quantizedAabbMin[1]; m_quantizedContiguousNodes[i].m_quantizedAabbMin[2] = memPtr->m_quantizedAabbMin[2]; } } } m_traversalMode = btTraversalMode(quantizedBvhFloatData.m_traversalMode); { int numElem = quantizedBvhFloatData.m_numSubtreeHeaders; m_SubtreeHeaders.resize(numElem); if (numElem) { btBvhSubtreeInfoData* memPtr = quantizedBvhFloatData.m_subTreeInfoPtr; for (int i=0;im_quantizedAabbMax[0] ; m_SubtreeHeaders[i].m_quantizedAabbMax[1] = memPtr->m_quantizedAabbMax[1]; m_SubtreeHeaders[i].m_quantizedAabbMax[2] = memPtr->m_quantizedAabbMax[2]; m_SubtreeHeaders[i].m_quantizedAabbMin[0] = memPtr->m_quantizedAabbMin[0]; m_SubtreeHeaders[i].m_quantizedAabbMin[1] = memPtr->m_quantizedAabbMin[1]; m_SubtreeHeaders[i].m_quantizedAabbMin[2] = memPtr->m_quantizedAabbMin[2]; m_SubtreeHeaders[i].m_rootNodeIndex = memPtr->m_rootNodeIndex; m_SubtreeHeaders[i].m_subtreeSize = memPtr->m_subtreeSize; } } } } void btQuantizedBvh::deSerializeDouble(struct btQuantizedBvhDoubleData& quantizedBvhDoubleData) { m_bvhAabbMax.deSerializeDouble(quantizedBvhDoubleData.m_bvhAabbMax); m_bvhAabbMin.deSerializeDouble(quantizedBvhDoubleData.m_bvhAabbMin); m_bvhQuantization.deSerializeDouble(quantizedBvhDoubleData.m_bvhQuantization); m_curNodeIndex = quantizedBvhDoubleData.m_curNodeIndex; m_useQuantization = quantizedBvhDoubleData.m_useQuantization!=0; { int numElem = quantizedBvhDoubleData.m_numContiguousLeafNodes; m_contiguousNodes.resize(numElem); if (numElem) { btOptimizedBvhNodeDoubleData* memPtr = quantizedBvhDoubleData.m_contiguousNodesPtr; for (int i=0;im_aabbMaxOrg); m_contiguousNodes[i].m_aabbMinOrg.deSerializeDouble(memPtr->m_aabbMinOrg); m_contiguousNodes[i].m_escapeIndex = memPtr->m_escapeIndex; m_contiguousNodes[i].m_subPart = memPtr->m_subPart; m_contiguousNodes[i].m_triangleIndex = memPtr->m_triangleIndex; } } } { int numElem = quantizedBvhDoubleData.m_numQuantizedContiguousNodes; m_quantizedContiguousNodes.resize(numElem); if (numElem) { btQuantizedBvhNodeData* memPtr = quantizedBvhDoubleData.m_quantizedContiguousNodesPtr; for (int i=0;im_escapeIndexOrTriangleIndex; m_quantizedContiguousNodes[i].m_quantizedAabbMax[0] = memPtr->m_quantizedAabbMax[0]; m_quantizedContiguousNodes[i].m_quantizedAabbMax[1] = memPtr->m_quantizedAabbMax[1]; m_quantizedContiguousNodes[i].m_quantizedAabbMax[2] = memPtr->m_quantizedAabbMax[2]; m_quantizedContiguousNodes[i].m_quantizedAabbMin[0] = memPtr->m_quantizedAabbMin[0]; m_quantizedContiguousNodes[i].m_quantizedAabbMin[1] = memPtr->m_quantizedAabbMin[1]; m_quantizedContiguousNodes[i].m_quantizedAabbMin[2] = memPtr->m_quantizedAabbMin[2]; } } } m_traversalMode = btTraversalMode(quantizedBvhDoubleData.m_traversalMode); { int numElem = quantizedBvhDoubleData.m_numSubtreeHeaders; m_SubtreeHeaders.resize(numElem); if (numElem) { btBvhSubtreeInfoData* memPtr = quantizedBvhDoubleData.m_subTreeInfoPtr; for (int i=0;im_quantizedAabbMax[0] ; m_SubtreeHeaders[i].m_quantizedAabbMax[1] = memPtr->m_quantizedAabbMax[1]; m_SubtreeHeaders[i].m_quantizedAabbMax[2] = memPtr->m_quantizedAabbMax[2]; m_SubtreeHeaders[i].m_quantizedAabbMin[0] = memPtr->m_quantizedAabbMin[0]; m_SubtreeHeaders[i].m_quantizedAabbMin[1] = memPtr->m_quantizedAabbMin[1]; m_SubtreeHeaders[i].m_quantizedAabbMin[2] = memPtr->m_quantizedAabbMin[2]; m_SubtreeHeaders[i].m_rootNodeIndex = memPtr->m_rootNodeIndex; m_SubtreeHeaders[i].m_subtreeSize = memPtr->m_subtreeSize; } } } } ///fills the dataBuffer and returns the struct name (and 0 on failure) const char* btQuantizedBvh::serialize(void* dataBuffer, btSerializer* serializer) const { btQuantizedBvhData* quantizedData = (btQuantizedBvhData*)dataBuffer; m_bvhAabbMax.serialize(quantizedData->m_bvhAabbMax); m_bvhAabbMin.serialize(quantizedData->m_bvhAabbMin); m_bvhQuantization.serialize(quantizedData->m_bvhQuantization); quantizedData->m_curNodeIndex = m_curNodeIndex; quantizedData->m_useQuantization = m_useQuantization; quantizedData->m_numContiguousLeafNodes = m_contiguousNodes.size(); quantizedData->m_contiguousNodesPtr = (btOptimizedBvhNodeData*) (m_contiguousNodes.size() ? serializer->getUniquePointer((void*)&m_contiguousNodes[0]) : 0); if (quantizedData->m_contiguousNodesPtr) { int sz = sizeof(btOptimizedBvhNodeData); int numElem = m_contiguousNodes.size(); btChunk* chunk = serializer->allocate(sz,numElem); btOptimizedBvhNodeData* memPtr = (btOptimizedBvhNodeData*)chunk->m_oldPtr; for (int i=0;im_aabbMaxOrg); m_contiguousNodes[i].m_aabbMinOrg.serialize(memPtr->m_aabbMinOrg); memPtr->m_escapeIndex = m_contiguousNodes[i].m_escapeIndex; memPtr->m_subPart = m_contiguousNodes[i].m_subPart; memPtr->m_triangleIndex = m_contiguousNodes[i].m_triangleIndex; } serializer->finalizeChunk(chunk,"btOptimizedBvhNodeData",BT_ARRAY_CODE,(void*)&m_contiguousNodes[0]); } quantizedData->m_numQuantizedContiguousNodes = m_quantizedContiguousNodes.size(); // printf("quantizedData->m_numQuantizedContiguousNodes=%d\n",quantizedData->m_numQuantizedContiguousNodes); quantizedData->m_quantizedContiguousNodesPtr =(btQuantizedBvhNodeData*) (m_quantizedContiguousNodes.size() ? serializer->getUniquePointer((void*)&m_quantizedContiguousNodes[0]) : 0); if (quantizedData->m_quantizedContiguousNodesPtr) { int sz = sizeof(btQuantizedBvhNodeData); int numElem = m_quantizedContiguousNodes.size(); btChunk* chunk = serializer->allocate(sz,numElem); btQuantizedBvhNodeData* memPtr = (btQuantizedBvhNodeData*)chunk->m_oldPtr; for (int i=0;im_escapeIndexOrTriangleIndex = m_quantizedContiguousNodes[i].m_escapeIndexOrTriangleIndex; memPtr->m_quantizedAabbMax[0] = m_quantizedContiguousNodes[i].m_quantizedAabbMax[0]; memPtr->m_quantizedAabbMax[1] = m_quantizedContiguousNodes[i].m_quantizedAabbMax[1]; memPtr->m_quantizedAabbMax[2] = m_quantizedContiguousNodes[i].m_quantizedAabbMax[2]; memPtr->m_quantizedAabbMin[0] = m_quantizedContiguousNodes[i].m_quantizedAabbMin[0]; memPtr->m_quantizedAabbMin[1] = m_quantizedContiguousNodes[i].m_quantizedAabbMin[1]; memPtr->m_quantizedAabbMin[2] = m_quantizedContiguousNodes[i].m_quantizedAabbMin[2]; } serializer->finalizeChunk(chunk,"btQuantizedBvhNodeData",BT_ARRAY_CODE,(void*)&m_quantizedContiguousNodes[0]); } quantizedData->m_traversalMode = int(m_traversalMode); quantizedData->m_numSubtreeHeaders = m_SubtreeHeaders.size(); quantizedData->m_subTreeInfoPtr = (btBvhSubtreeInfoData*) (m_SubtreeHeaders.size() ? serializer->getUniquePointer((void*)&m_SubtreeHeaders[0]) : 0); if (quantizedData->m_subTreeInfoPtr) { int sz = sizeof(btBvhSubtreeInfoData); int numElem = m_SubtreeHeaders.size(); btChunk* chunk = serializer->allocate(sz,numElem); btBvhSubtreeInfoData* memPtr = (btBvhSubtreeInfoData*)chunk->m_oldPtr; for (int i=0;im_quantizedAabbMax[0] = m_SubtreeHeaders[i].m_quantizedAabbMax[0]; memPtr->m_quantizedAabbMax[1] = m_SubtreeHeaders[i].m_quantizedAabbMax[1]; memPtr->m_quantizedAabbMax[2] = m_SubtreeHeaders[i].m_quantizedAabbMax[2]; memPtr->m_quantizedAabbMin[0] = m_SubtreeHeaders[i].m_quantizedAabbMin[0]; memPtr->m_quantizedAabbMin[1] = m_SubtreeHeaders[i].m_quantizedAabbMin[1]; memPtr->m_quantizedAabbMin[2] = m_SubtreeHeaders[i].m_quantizedAabbMin[2]; memPtr->m_rootNodeIndex = m_SubtreeHeaders[i].m_rootNodeIndex; memPtr->m_subtreeSize = m_SubtreeHeaders[i].m_subtreeSize; } serializer->finalizeChunk(chunk,"btBvhSubtreeInfoData",BT_ARRAY_CODE,(void*)&m_SubtreeHeaders[0]); } return btQuantizedBvhDataName; } critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btBroadphaseInterface.h0000644000175000017500000000677211344267705032417 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BROADPHASE_INTERFACE_H #define BROADPHASE_INTERFACE_H struct btDispatcherInfo; class btDispatcher; #include "btBroadphaseProxy.h" class btOverlappingPairCache; struct btBroadphaseAabbCallback { virtual ~btBroadphaseAabbCallback() {} virtual bool process(const btBroadphaseProxy* proxy) = 0; }; struct btBroadphaseRayCallback : public btBroadphaseAabbCallback { ///added some cached data to accelerate ray-AABB tests btVector3 m_rayDirectionInverse; unsigned int m_signs[3]; btScalar m_lambda_max; virtual ~btBroadphaseRayCallback() {} }; #include "LinearMath/btVector3.h" ///The btBroadphaseInterface class provides an interface to detect aabb-overlapping object pairs. ///Some implementations for this broadphase interface include btAxisSweep3, bt32BitAxisSweep3 and btDbvtBroadphase. ///The actual overlapping pair management, storage, adding and removing of pairs is dealt by the btOverlappingPairCache class. class btBroadphaseInterface { public: virtual ~btBroadphaseInterface() {} virtual btBroadphaseProxy* createProxy( const btVector3& aabbMin, const btVector3& aabbMax,int shapeType,void* userPtr, short int collisionFilterGroup,short int collisionFilterMask, btDispatcher* dispatcher,void* multiSapProxy) =0; virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher)=0; virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax, btDispatcher* dispatcher)=0; virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const =0; virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin=btVector3(0,0,0), const btVector3& aabbMax = btVector3(0,0,0)) = 0; virtual void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback) = 0; ///calculateOverlappingPairs is optional: incremental algorithms (sweep and prune) might do it during the set aabb virtual void calculateOverlappingPairs(btDispatcher* dispatcher)=0; virtual btOverlappingPairCache* getOverlappingPairCache()=0; virtual const btOverlappingPairCache* getOverlappingPairCache() const =0; ///getAabb returns the axis aligned bounding box in the 'global' coordinate frame ///will add some transform later virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const =0; ///reset broadphase internal structures, to ensure determinism/reproducability virtual void resetPool(btDispatcher* dispatcher) { (void) dispatcher; }; virtual void printStats() = 0; }; #endif //BROADPHASE_INTERFACE_H critterding-beta12.1/src/utils/bullet/BulletCollision/BroadphaseCollision/btDbvtBroadphase.h0000644000175000017500000001413211344267705031403 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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. */ ///btDbvtBroadphase implementation by Nathanael Presson #ifndef BT_DBVT_BROADPHASE_H #define BT_DBVT_BROADPHASE_H #include "BulletCollision/BroadphaseCollision/btDbvt.h" #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" // // Compile time config // #define DBVT_BP_PROFILE 0 //#define DBVT_BP_SORTPAIRS 1 #define DBVT_BP_PREVENTFALSEUPDATE 0 #define DBVT_BP_ACCURATESLEEPING 0 #define DBVT_BP_ENABLE_BENCHMARK 0 #define DBVT_BP_MARGIN (btScalar)0.05 #if DBVT_BP_PROFILE #define DBVT_BP_PROFILING_RATE 256 #include "LinearMath/btQuickprof.h" #endif // // btDbvtProxy // struct btDbvtProxy : btBroadphaseProxy { /* Fields */ //btDbvtAabbMm aabb; btDbvtNode* leaf; btDbvtProxy* links[2]; int stage; /* ctor */ btDbvtProxy(const btVector3& aabbMin,const btVector3& aabbMax,void* userPtr,short int collisionFilterGroup, short int collisionFilterMask) : btBroadphaseProxy(aabbMin,aabbMax,userPtr,collisionFilterGroup,collisionFilterMask) { links[0]=links[1]=0; } }; typedef btAlignedObjectArray btDbvtProxyArray; ///The btDbvtBroadphase implements a broadphase using two dynamic AABB bounding volume hierarchies/trees (see btDbvt). ///One tree is used for static/non-moving objects, and another tree is used for dynamic objects. Objects can move from one tree to the other. ///This is a very fast broadphase, especially for very dynamic worlds where many objects are moving. Its insert/add and remove of objects is generally faster than the sweep and prune broadphases btAxisSweep3 and bt32BitAxisSweep3. struct btDbvtBroadphase : btBroadphaseInterface { /* Config */ enum { DYNAMIC_SET = 0, /* Dynamic set index */ FIXED_SET = 1, /* Fixed set index */ STAGECOUNT = 2 /* Number of stages */ }; /* Fields */ btDbvt m_sets[2]; // Dbvt sets btDbvtProxy* m_stageRoots[STAGECOUNT+1]; // Stages list btOverlappingPairCache* m_paircache; // Pair cache btScalar m_prediction; // Velocity prediction int m_stageCurrent; // Current stage int m_fupdates; // % of fixed updates per frame int m_dupdates; // % of dynamic updates per frame int m_cupdates; // % of cleanup updates per frame int m_newpairs; // Number of pairs created int m_fixedleft; // Fixed optimization left unsigned m_updates_call; // Number of updates call unsigned m_updates_done; // Number of updates done btScalar m_updates_ratio; // m_updates_done/m_updates_call int m_pid; // Parse id int m_cid; // Cleanup index int m_gid; // Gen id bool m_releasepaircache; // Release pair cache on delete bool m_deferedcollide; // Defere dynamic/static collision to collide call bool m_needcleanup; // Need to run cleanup? #if DBVT_BP_PROFILE btClock m_clock; struct { unsigned long m_total; unsigned long m_ddcollide; unsigned long m_fdcollide; unsigned long m_cleanup; unsigned long m_jobcount; } m_profiling; #endif /* Methods */ btDbvtBroadphase(btOverlappingPairCache* paircache=0); ~btDbvtBroadphase(); void collide(btDispatcher* dispatcher); void optimize(); /* btBroadphaseInterface Implementation */ btBroadphaseProxy* createProxy(const btVector3& aabbMin,const btVector3& aabbMax,int shapeType,void* userPtr,short int collisionFilterGroup,short int collisionFilterMask,btDispatcher* dispatcher,void* multiSapProxy); virtual void destroyProxy(btBroadphaseProxy* proxy,btDispatcher* dispatcher); virtual void setAabb(btBroadphaseProxy* proxy,const btVector3& aabbMin,const btVector3& aabbMax,btDispatcher* dispatcher); virtual void rayTest(const btVector3& rayFrom,const btVector3& rayTo, btBroadphaseRayCallback& rayCallback, const btVector3& aabbMin=btVector3(0,0,0), const btVector3& aabbMax = btVector3(0,0,0)); virtual void aabbTest(const btVector3& aabbMin, const btVector3& aabbMax, btBroadphaseAabbCallback& callback); virtual void getAabb(btBroadphaseProxy* proxy,btVector3& aabbMin, btVector3& aabbMax ) const; virtual void calculateOverlappingPairs(btDispatcher* dispatcher); virtual btOverlappingPairCache* getOverlappingPairCache(); virtual const btOverlappingPairCache* getOverlappingPairCache() const; virtual void getBroadphaseAabb(btVector3& aabbMin,btVector3& aabbMax) const; virtual void printStats(); ///reset broadphase internal structures, to ensure determinism/reproducability virtual void resetPool(btDispatcher* dispatcher); void performDeferredRemoval(btDispatcher* dispatcher); void setVelocityPrediction(btScalar prediction) { m_prediction = prediction; } btScalar getVelocityPrediction() const { return m_prediction; } ///this setAabbForceUpdate is similar to setAabb but always forces the aabb update. ///it is not part of the btBroadphaseInterface but specific to btDbvtBroadphase. ///it bypasses certain optimizations that prevent aabb updates (when the aabb shrinks), see ///http://code.google.com/p/bullet/issues/detail?id=223 void setAabbForceUpdate( btBroadphaseProxy* absproxy,const btVector3& aabbMin,const btVector3& aabbMax,btDispatcher* /*dispatcher*/); static void benchmark(btBroadphaseInterface*); }; #endif critterding-beta12.1/src/utils/bullet/BulletCollision/Doxyfile0000644000175000017500000007156711337071441023605 0ustar bobkebobke# Doxyfile 1.2.4 # This file describes the settings to be used by doxygen for a project # # All text after a hash (#) is considered a comment and will be ignored # The format is: # TAG = value [value, ...] # For lists items can also be appended using: # TAG += value [value, ...] # Values that contain spaces should be placed between quotes (" ") #--------------------------------------------------------------------------- # General configuration options #--------------------------------------------------------------------------- # The PROJECT_NAME tag is a single word (or a sequence of words surrounded # by quotes) that should identify the project. PROJECT_NAME = "Bullet Continuous Collision Detection Library" # The PROJECT_NUMBER tag can be used to enter a project or revision number. # This could be handy for archiving the generated documentation or # if some version control system is used. PROJECT_NUMBER = # The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) # base path where the generated documentation will be put. # If a relative path is entered, it will be relative to the location # where doxygen was started. If left blank the current directory will be used. OUTPUT_DIRECTORY = # The OUTPUT_LANGUAGE tag is used to specify the language in which all # documentation generated by doxygen is written. Doxygen will use this # information to generate all constant output in the proper language. # The default language is English, other supported languages are: # Dutch, French, Italian, Czech, Swedish, German, Finnish, Japanese, # Korean, Hungarian, Norwegian, Spanish, Romanian, Russian, Croatian, # Polish, Portuguese and Slovene. OUTPUT_LANGUAGE = English # If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in # documentation are documented, even if no documentation was available. # Private class members and static file members will be hidden unless # the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES EXTRACT_ALL = YES # If the EXTRACT_PRIVATE tag is set to YES all private members of a class # will be included in the documentation. EXTRACT_PRIVATE = YES # If the EXTRACT_STATIC tag is set to YES all static members of a file # will be included in the documentation. EXTRACT_STATIC = YES # If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all # undocumented members of documented classes, files or namespaces. # If set to NO (the default) these members will be included in the # various overviews, but no documentation section is generated. # This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_MEMBERS = NO # If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all # undocumented classes that are normally visible in the class hierarchy. # If set to NO (the default) these class will be included in the various # overviews. This option has no effect if EXTRACT_ALL is enabled. HIDE_UNDOC_CLASSES = NO # If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will # include brief member descriptions after the members that are listed in # the file and class documentation (similar to JavaDoc). # Set to NO to disable this. BRIEF_MEMBER_DESC = YES # If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend # the brief description of a member or function before the detailed description. # Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the # brief descriptions will be completely suppressed. REPEAT_BRIEF = YES # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # Doxygen will generate a detailed section even if there is only a brief # description. ALWAYS_DETAILED_SEC = NO # If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full # path before files name in the file list and in the header files. If set # to NO the shortest path that makes the file name unique will be used. FULL_PATH_NAMES = NO # If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag # can be used to strip a user defined part of the path. Stripping is # only done if one of the specified strings matches the left-hand part of # the path. It is allowed to use relative paths in the argument list. STRIP_FROM_PATH = # The INTERNAL_DOCS tag determines if documentation # that is typed after a \internal command is included. If the tag is set # to NO (the default) then the documentation will be excluded. # Set it to YES to include the internal documentation. INTERNAL_DOCS = NO # If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will # generate a class diagram (in Html and LaTeX) for classes with base or # super classes. Setting the tag to NO turns the diagrams off. CLASS_DIAGRAMS = YES # If the SOURCE_BROWSER tag is set to YES then a list of source files will # be generated. Documented entities will be cross-referenced with these sources. SOURCE_BROWSER = YES # Setting the INLINE_SOURCES tag to YES will include the body # of functions and classes directly in the documentation. INLINE_SOURCES = NO # Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct # doxygen to hide any special comment blocks from generated source code # fragments. Normal C and C++ comments will always remain visible. STRIP_CODE_COMMENTS = YES # If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate # file names in lower case letters. If set to YES upper case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows # users are adviced to set this option to NO. CASE_SENSE_NAMES = YES # If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen # will show members with their full class and namespace scopes in the # documentation. If set to YES the scope will be hidden. HIDE_SCOPE_NAMES = NO # If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen # will generate a verbatim copy of the header file for each class for # which an include is specified. Set to NO to disable this. VERBATIM_HEADERS = YES # If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen # will put list of the files that are included by a file in the documentation # of that file. SHOW_INCLUDE_FILES = YES # If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen # will interpret the first line (until the first dot) of a JavaDoc-style # comment as the brief description. If set to NO, the JavaDoc # comments will behave just like the Qt-style comments (thus requiring an # explict @brief command for a brief description. JAVADOC_AUTOBRIEF = YES # If the INHERIT_DOCS tag is set to YES (the default) then an undocumented # member inherits the documentation from any documented member that it # reimplements. INHERIT_DOCS = YES # If the INLINE_INFO tag is set to YES (the default) then a tag [inline] # is inserted in the documentation for inline members. INLINE_INFO = YES # If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen # will sort the (detailed) documentation of file and class members # alphabetically by member name. If set to NO the members will appear in # declaration order. SORT_MEMBER_DOCS = YES # If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC # tag is set to YES, then doxygen will reuse the documentation of the first # member in the group (if any) for the other members of the group. By default # all members of a group must be documented explicitly. DISTRIBUTE_GROUP_DOC = NO # The TAB_SIZE tag can be used to set the number of spaces in a tab. # Doxygen uses this value to replace tabs by spaces in code fragments. TAB_SIZE = 8 # The ENABLE_SECTIONS tag can be used to enable conditional # documentation sections, marked by \if sectionname ... \endif. ENABLED_SECTIONS = # The GENERATE_TODOLIST tag can be used to enable (YES) or # disable (NO) the todo list. This list is created by putting \todo # commands in the documentation. GENERATE_TODOLIST = YES # The GENERATE_TESTLIST tag can be used to enable (YES) or # disable (NO) the test list. This list is created by putting \test # commands in the documentation. GENERATE_TESTLIST = YES # This tag can be used to specify a number of aliases that acts # as commands in the documentation. An alias has the form "name=value". # For example adding "sideeffect=\par Side Effects:\n" will allow you to # put the command \sideeffect (or @sideeffect) in the documentation, which # will result in a user defined paragraph with heading "Side Effects:". # You can put \n's in the value part of an alias to insert newlines. ALIASES = #--------------------------------------------------------------------------- # configuration options related to warning and progress messages #--------------------------------------------------------------------------- # The QUIET tag can be used to turn on/off the messages that are generated # by doxygen. Possible values are YES and NO. If left blank NO is used. QUIET = NO # The WARNINGS tag can be used to turn on/off the warning messages that are # generated by doxygen. Possible values are YES and NO. If left blank # NO is used. WARNINGS = YES # If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings # for undocumented members. If EXTRACT_ALL is set to YES then this flag will # automatically be disabled. WARN_IF_UNDOCUMENTED = YES # The WARN_FORMAT tag determines the format of the warning messages that # doxygen can produce. The string should contain the $file, $line, and $text # tags, which will be replaced by the file and line number from which the # warning originated and the warning text. WARN_FORMAT = "$file:$line: $text" # The WARN_LOGFILE tag can be used to specify a file to which warning # and error messages should be written. If left blank the output is written # to stderr. WARN_LOGFILE = #--------------------------------------------------------------------------- # configuration options related to the input files #--------------------------------------------------------------------------- # The INPUT tag can be used to specify the files and/or directories that contain # documented source files. You may enter file names like "myfile.cpp" or # directories like "/usr/src/myproject". Separate the files or directories # with spaces. INPUT = . # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. FILE_PATTERNS = *.h *.cpp *.c # The RECURSIVE tag can be used to turn specify whether or not subdirectories # should be searched for input files as well. Possible values are YES and NO. # If left blank NO is used. RECURSIVE = YES # The EXCLUDE tag can be used to specify files and/or directories that should # excluded from the INPUT source files. This way you can easily exclude a # subdirectory from a directory tree whose root is specified with the INPUT tag. EXCLUDE = # If the value of the INPUT tag contains directories, you can use the # EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude # certain files from those directories. EXCLUDE_PATTERNS = # The EXAMPLE_PATH tag can be used to specify one or more files or # directories that contain example code fragments that are included (see # the \include command). EXAMPLE_PATH = # If the value of the EXAMPLE_PATH tag contains directories, you can use the # EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp # and *.h) to filter out the source-files in the directories. If left # blank all files are included. EXAMPLE_PATTERNS = # The IMAGE_PATH tag can be used to specify one or more files or # directories that contain image that are included in the documentation (see # the \image command). IMAGE_PATH = # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program # by executing (via popen()) the command , where # is the value of the INPUT_FILTER tag, and is the name of an # input file. Doxygen will then use the output that the filter program writes # to standard output. INPUT_FILTER = # If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using # INPUT_FILTER) will be used to filter the input files when producing source # files to browse. FILTER_SOURCE_FILES = NO #--------------------------------------------------------------------------- # configuration options related to the alphabetical class index #--------------------------------------------------------------------------- # If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index # of all compounds will be generated. Enable this if the project # contains a lot of classes, structs, unions or interfaces. ALPHABETICAL_INDEX = NO # If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then # the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns # in which this list will be split (can be a number in the range [1..20]) COLS_IN_ALPHA_INDEX = 5 # In case all classes in a project start with a common prefix, all # classes will be put under the same header in the alphabetical index. # The IGNORE_PREFIX tag can be used to specify one or more prefixes that # should be ignored while generating the index headers. IGNORE_PREFIX = #--------------------------------------------------------------------------- # configuration options related to the HTML output #--------------------------------------------------------------------------- # If the GENERATE_HTML tag is set to YES (the default) Doxygen will # generate HTML output. GENERATE_HTML = YES # The HTML_OUTPUT tag is used to specify where the HTML docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `html' will be used as the default path. HTML_OUTPUT = html # The HTML_HEADER tag can be used to specify a personal HTML header for # each generated HTML page. If it is left blank doxygen will generate a # standard header. HTML_HEADER = # The HTML_FOOTER tag can be used to specify a personal HTML footer for # each generated HTML page. If it is left blank doxygen will generate a # standard footer. HTML_FOOTER = # The HTML_STYLESHEET tag can be used to specify a user defined cascading # style sheet that is used by each HTML page. It can be used to # fine-tune the look of the HTML output. If the tag is left blank doxygen # will generate a default style sheet HTML_STYLESHEET = # If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes, # files or namespaces will be aligned in HTML using tables. If set to # NO a bullet list will be used. HTML_ALIGN_MEMBERS = YES # If the GENERATE_HTMLHELP tag is set to YES, additional index files # will be generated that can be used as input for tools like the # Microsoft HTML help workshop to generate a compressed HTML help file (.chm) # of the generated HTML documentation. GENERATE_HTMLHELP = NO # The DISABLE_INDEX tag can be used to turn on/off the condensed index at # top of each HTML page. The value NO (the default) enables the index and # the value YES disables it. DISABLE_INDEX = NO # This tag can be used to set the number of enum values (range [1..20]) # that doxygen will group on one line in the generated HTML documentation. ENUM_VALUES_PER_LINE = 4 # If the GENERATE_TREEVIEW tag is set to YES, a side pannel will be # generated containing a tree-like index structure (just like the one that # is generated for HTML Help). For this to work a browser that supports # JavaScript and frames is required (for instance Netscape 4.0+ # or Internet explorer 4.0+). GENERATE_TREEVIEW = NO # If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be # used to set the initial width (in pixels) of the frame in which the tree # is shown. TREEVIEW_WIDTH = 250 #--------------------------------------------------------------------------- # configuration options related to the LaTeX output #--------------------------------------------------------------------------- # If the GENERATE_LATEX tag is set to YES (the default) Doxygen will # generate Latex output. GENERATE_LATEX = NO # The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `latex' will be used as the default path. LATEX_OUTPUT = latex # If the COMPACT_LATEX tag is set to YES Doxygen generates more compact # LaTeX documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_LATEX = NO # The PAPER_TYPE tag can be used to set the paper type that is used # by the printer. Possible values are: a4, a4wide, letter, legal and # executive. If left blank a4wide will be used. PAPER_TYPE = a4wide # The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX # packages that should be included in the LaTeX output. EXTRA_PACKAGES = # The LATEX_HEADER tag can be used to specify a personal LaTeX header for # the generated latex document. The header should contain everything until # the first chapter. If it is left blank doxygen will generate a # standard header. Notice: only use this tag if you know what you are doing! LATEX_HEADER = # If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated # is prepared for conversion to pdf (using ps2pdf). The pdf file will # contain links (just like the HTML output) instead of page references # This makes the output suitable for online browsing using a pdf viewer. PDF_HYPERLINKS = NO # If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of # plain latex in the generated Makefile. Set this option to YES to get a # higher quality PDF documentation. USE_PDFLATEX = NO # If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode. # command to the generated LaTeX files. This will instruct LaTeX to keep # running if errors occur, instead of asking the user for help. # This option is also used when generating formulas in HTML. LATEX_BATCHMODE = NO #--------------------------------------------------------------------------- # configuration options related to the RTF output #--------------------------------------------------------------------------- # If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output # The RTF output is optimised for Word 97 and may not look very pretty with # other RTF readers or editors. GENERATE_RTF = NO # The RTF_OUTPUT tag is used to specify where the RTF docs will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `rtf' will be used as the default path. RTF_OUTPUT = rtf # If the COMPACT_RTF tag is set to YES Doxygen generates more compact # RTF documents. This may be useful for small projects and may help to # save some trees in general. COMPACT_RTF = NO # If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated # will contain hyperlink fields. The RTF file will # contain links (just like the HTML output) instead of page references. # This makes the output suitable for online browsing using a WORD or other. # programs which support those fields. # Note: wordpad (write) and others do not support links. RTF_HYPERLINKS = NO # Load stylesheet definitions from file. Syntax is similar to doxygen's # config file, i.e. a series of assigments. You only have to provide # replacements, missing definitions are set to their default value. RTF_STYLESHEET_FILE = #--------------------------------------------------------------------------- # configuration options related to the man page output #--------------------------------------------------------------------------- # If the GENERATE_MAN tag is set to YES (the default) Doxygen will # generate man pages GENERATE_MAN = NO # The MAN_OUTPUT tag is used to specify where the man pages will be put. # If a relative path is entered the value of OUTPUT_DIRECTORY will be # put in front of it. If left blank `man' will be used as the default path. MAN_OUTPUT = man # The MAN_EXTENSION tag determines the extension that is added to # the generated man pages (default is the subroutine's section .3) MAN_EXTENSION = .3 #--------------------------------------------------------------------------- # configuration options related to the XML output #--------------------------------------------------------------------------- # If the GENERATE_XML tag is set to YES Doxygen will # generate an XML file that captures the structure of # the code including all documentation. Warning: This feature # is still experimental and very incomplete. GENERATE_XML = NO #--------------------------------------------------------------------------- # Configuration options related to the preprocessor #--------------------------------------------------------------------------- # If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will # evaluate all C-preprocessor directives found in the sources and include # files. ENABLE_PREPROCESSING = YES # If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro # names in the source code. If set to NO (the default) only conditional # compilation will be performed. Macro expansion can be done in a controlled # way by setting EXPAND_ONLY_PREDEF to YES. MACRO_EXPANSION = NO # If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES # then the macro expansion is limited to the macros specified with the # PREDEFINED and EXPAND_AS_PREDEFINED tags. EXPAND_ONLY_PREDEF = NO # If the SEARCH_INCLUDES tag is set to YES (the default) the includes files # in the INCLUDE_PATH (see below) will be search if a #include is found. SEARCH_INCLUDES = YES # The INCLUDE_PATH tag can be used to specify one or more directories that # contain include files that are not input files but should be processed by # the preprocessor. INCLUDE_PATH = ../../generic/extern # You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard # patterns (like *.h and *.hpp) to filter out the header-files in the # directories. If left blank, the patterns specified with FILE_PATTERNS will # be used. INCLUDE_FILE_PATTERNS = # The PREDEFINED tag can be used to specify one or more macro names that # are defined before the preprocessor is started (similar to the -D option of # gcc). The argument of the tag is a list of macros of the form: name # or name=definition (no spaces). If the definition and the = are # omitted =1 is assumed. PREDEFINED = # If the MACRO_EXPANSION and EXPAND_PREDEF_ONLY tags are set to YES then # this tag can be used to specify a list of macro names that should be expanded. # The macro definition that is found in the sources will be used. # Use the PREDEFINED tag if you want to use a different macro definition. EXPAND_AS_DEFINED = #--------------------------------------------------------------------------- # Configuration::addtions related to external references #--------------------------------------------------------------------------- # The TAGFILES tag can be used to specify one or more tagfiles. TAGFILES = # When a file name is specified after GENERATE_TAGFILE, doxygen will create # a tag file that is based on the input files it reads. GENERATE_TAGFILE = # If the ALLEXTERNALS tag is set to YES all external classes will be listed # in the class index. If set to NO only the inherited external classes # will be listed. ALLEXTERNALS = NO # The PERL_PATH should be the absolute path and name of the perl script # interpreter (i.e. the result of `which perl'). PERL_PATH = /usr/bin/perl #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- # If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is # available from the path. This tool is part of Graphviz, a graph visualization # toolkit from AT&T and Lucent Bell Labs. The other options in this section # have no effect if this option is set to NO (the default) HAVE_DOT = YES # If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect inheritance relations. Setting this tag to YES will force the # the CLASS_DIAGRAMS tag to NO. CLASS_GRAPH = YES # If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen # will generate a graph for each documented class showing the direct and # indirect implementation dependencies (inheritance, containment, and # class references variables) of the class with other documented classes. COLLABORATION_GRAPH = YES # If the ENABLE_PREPROCESSING, INCLUDE_GRAPH, and HAVE_DOT tags are set to # YES then doxygen will generate a graph for each documented file showing # the direct and indirect include dependencies of the file with other # documented files. INCLUDE_GRAPH = YES # If the ENABLE_PREPROCESSING, INCLUDED_BY_GRAPH, and HAVE_DOT tags are set to # YES then doxygen will generate a graph for each documented header file showing # the documented files that directly or indirectly include this file INCLUDED_BY_GRAPH = YES # If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen # will graphical hierarchy of all classes instead of a textual one. GRAPHICAL_HIERARCHY = YES # The tag DOT_PATH can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found on the path. DOT_PATH = # The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_WIDTH = 1024 # The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height # (in pixels) of the graphs generated by dot. If a graph becomes larger than # this value, doxygen will try to truncate the graph, so that it fits within # the specified constraint. Beware that most browsers cannot cope with very # large images. MAX_DOT_GRAPH_HEIGHT = 1024 # If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will # generate a legend page explaining the meaning of the various boxes and # arrows in the dot generated graphs. GENERATE_LEGEND = YES #--------------------------------------------------------------------------- # Configuration::addtions related to the search engine #--------------------------------------------------------------------------- # The SEARCHENGINE tag specifies whether or not a search engine should be # used. If set to NO the values of all tags below this one will be ignored. SEARCHENGINE = NO # The CGI_NAME tag should be the name of the CGI script that # starts the search engine (doxysearch) with the correct parameters. # A script with this name will be generated by doxygen. CGI_NAME = search.cgi # The CGI_URL tag should be the absolute URL to the directory where the # cgi binaries are located. See the documentation of your http daemon for # details. CGI_URL = # The DOC_URL tag should be the absolute URL to the directory where the # documentation is located. If left blank the absolute path to the # documentation, with file:// prepended to it, will be used. DOC_URL = # The DOC_ABSPATH tag should be the absolute path to the directory where the # documentation is located. If left blank the directory on the local machine # will be used. DOC_ABSPATH = # The BIN_ABSPATH tag must point to the directory where the doxysearch binary # is installed. BIN_ABSPATH = c:\program files\doxygen\bin # The EXT_DOC_PATHS tag can be used to specify one or more paths to # documentation generated for other projects. This allows doxysearch to search # the documentation for these projects as well. EXT_DOC_PATHS = critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/0000755000175000017500000000000011347266042025476 5ustar bobkebobke././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.hcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgo0000644000175000017500000001030311337071441033160 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 CONVEX_CONCAVE_COLLISION_ALGORITHM_H #define CONVEX_CONCAVE_COLLISION_ALGORITHM_H #include "btActivatingCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btDispatcher.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" #include "BulletCollision/CollisionShapes/btTriangleCallback.h" #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" class btDispatcher; #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "btCollisionCreateFunc.h" ///For each triangle in the concave mesh that overlaps with the AABB of a convex (m_convexProxy), processTriangle is called. class btConvexTriangleCallback : public btTriangleCallback { btCollisionObject* m_convexBody; btCollisionObject* m_triBody; btVector3 m_aabbMin; btVector3 m_aabbMax ; btManifoldResult* m_resultOut; btDispatcher* m_dispatcher; const btDispatcherInfo* m_dispatchInfoPtr; btScalar m_collisionMarginTriangle; public: int m_triangleCount; btPersistentManifold* m_manifoldPtr; btConvexTriangleCallback(btDispatcher* dispatcher,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped); void setTimeStepAndCounters(btScalar collisionMarginTriangle,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual ~btConvexTriangleCallback(); virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex); void clearCache(); SIMD_FORCE_INLINE const btVector3& getAabbMin() const { return m_aabbMin; } SIMD_FORCE_INLINE const btVector3& getAabbMax() const { return m_aabbMax; } }; /// btConvexConcaveCollisionAlgorithm supports collision between convex shapes and (concave) trianges meshes. class btConvexConcaveCollisionAlgorithm : public btActivatingCollisionAlgorithm { bool m_isSwapped; btConvexTriangleCallback m_btConvexTriangleCallback; public: btConvexConcaveCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped); virtual ~btConvexConcaveCollisionAlgorithm(); virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual void getAllContactManifolds(btManifoldArray& manifoldArray); void clearCache(); struct CreateFunc :public btCollisionAlgorithmCreateFunc { virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexConcaveCollisionAlgorithm)); return new(mem) btConvexConcaveCollisionAlgorithm(ci,body0,body1,false); } }; struct SwappedCreateFunc :public btCollisionAlgorithmCreateFunc { virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexConcaveCollisionAlgorithm)); return new(mem) btConvexConcaveCollisionAlgorithm(ci,body0,body1,true); } }; }; #endif //CONVEX_CONCAVE_COLLISION_ALGORITHM_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.cpp0000644000175000017500000005745411344271164032472 0ustar bobkebobke#include "btInternalEdgeUtility.h" #include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" #include "BulletCollision/CollisionShapes/btTriangleShape.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/NarrowPhaseCollision/btManifoldPoint.h" #include "LinearMath/btIDebugDraw.h" //#define DEBUG_INTERNAL_EDGE #ifdef DEBUG_INTERNAL_EDGE #include #endif //DEBUG_INTERNAL_EDGE #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW static btIDebugDraw* gDebugDrawer = 0; void btSetDebugDrawer(btIDebugDraw* debugDrawer) { gDebugDrawer = debugDrawer; } static void btDebugDrawLine(const btVector3& from,const btVector3& to, const btVector3& color) { if (gDebugDrawer) gDebugDrawer->drawLine(from,to,color); } #endif //BT_INTERNAL_EDGE_DEBUG_DRAW static int btGetHash(int partId, int triangleIndex) { int hash = (partId<<(31-MAX_NUM_PARTS_IN_BITS)) | triangleIndex; return hash; } static btScalar btGetAngle(const btVector3& edgeA, const btVector3& normalA,const btVector3& normalB) { const btVector3 refAxis0 = edgeA; const btVector3 refAxis1 = normalA; const btVector3 swingAxis = normalB; btScalar angle = btAtan2(swingAxis.dot(refAxis0), swingAxis.dot(refAxis1)); return angle; } struct btConnectivityProcessor : public btTriangleCallback { int m_partIdA; int m_triangleIndexA; btVector3* m_triangleVerticesA; btTriangleInfoMap* m_triangleInfoMap; virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex) { //skip self-collisions if ((m_partIdA == partId) && (m_triangleIndexA == triangleIndex)) return; //skip duplicates (disabled for now) //if ((m_partIdA <= partId) && (m_triangleIndexA <= triangleIndex)) // return; //search for shared vertices and edges int numshared = 0; int sharedVertsA[3]={-1,-1,-1}; int sharedVertsB[3]={-1,-1,-1}; ///skip degenerate triangles btScalar crossBSqr = ((triangle[1]-triangle[0]).cross(triangle[2]-triangle[0])).length2(); if (crossBSqr < m_triangleInfoMap->m_equalVertexThreshold) return; btScalar crossASqr = ((m_triangleVerticesA[1]-m_triangleVerticesA[0]).cross(m_triangleVerticesA[2]-m_triangleVerticesA[0])).length2(); ///skip degenerate triangles if (crossASqr< m_triangleInfoMap->m_equalVertexThreshold) return; #if 0 printf("triangle A[0] = (%f,%f,%f)\ntriangle A[1] = (%f,%f,%f)\ntriangle A[2] = (%f,%f,%f)\n", m_triangleVerticesA[0].getX(),m_triangleVerticesA[0].getY(),m_triangleVerticesA[0].getZ(), m_triangleVerticesA[1].getX(),m_triangleVerticesA[1].getY(),m_triangleVerticesA[1].getZ(), m_triangleVerticesA[2].getX(),m_triangleVerticesA[2].getY(),m_triangleVerticesA[2].getZ()); printf("partId=%d, triangleIndex=%d\n",partId,triangleIndex); printf("triangle B[0] = (%f,%f,%f)\ntriangle B[1] = (%f,%f,%f)\ntriangle B[2] = (%f,%f,%f)\n", triangle[0].getX(),triangle[0].getY(),triangle[0].getZ(), triangle[1].getX(),triangle[1].getY(),triangle[1].getZ(), triangle[2].getX(),triangle[2].getY(),triangle[2].getZ()); #endif for (int i=0;i<3;i++) { for (int j=0;j<3;j++) { if ( (m_triangleVerticesA[i]-triangle[j]).length2() < m_triangleInfoMap->m_equalVertexThreshold) { sharedVertsA[numshared] = i; sharedVertsB[numshared] = j; numshared++; ///degenerate case if(numshared >= 3) return; } } ///degenerate case if(numshared >= 3) return; } switch (numshared) { case 0: { break; } case 1: { //shared vertex break; } case 2: { //shared edge //we need to make sure the edge is in the order V2V0 and not V0V2 so that the signs are correct if (sharedVertsA[0] == 0 && sharedVertsA[1] == 2) { sharedVertsA[0] = 2; sharedVertsA[1] = 0; int tmp = sharedVertsB[1]; sharedVertsB[1] = sharedVertsB[0]; sharedVertsB[0] = tmp; } int hash = btGetHash(m_partIdA,m_triangleIndexA); btTriangleInfo* info = m_triangleInfoMap->find(hash); if (!info) { btTriangleInfo tmp; m_triangleInfoMap->insert(hash,tmp); info = m_triangleInfoMap->find(hash); } int sumvertsA = sharedVertsA[0]+sharedVertsA[1]; int otherIndexA = 3-sumvertsA; btVector3 edge(m_triangleVerticesA[sharedVertsA[1]]-m_triangleVerticesA[sharedVertsA[0]]); btTriangleShape tA(m_triangleVerticesA[0],m_triangleVerticesA[1],m_triangleVerticesA[2]); int otherIndexB = 3-(sharedVertsB[0]+sharedVertsB[1]); btTriangleShape tB(triangle[sharedVertsB[1]],triangle[sharedVertsB[0]],triangle[otherIndexB]); //btTriangleShape tB(triangle[0],triangle[1],triangle[2]); btVector3 normalA; btVector3 normalB; tA.calcNormal(normalA); tB.calcNormal(normalB); edge.normalize(); btVector3 edgeCrossA = edge.cross(normalA).normalize(); { btVector3 tmp = m_triangleVerticesA[otherIndexA]-m_triangleVerticesA[sharedVertsA[0]]; if (edgeCrossA.dot(tmp) < 0) { edgeCrossA*=-1; } } btVector3 edgeCrossB = edge.cross(normalB).normalize(); { btVector3 tmp = triangle[otherIndexB]-triangle[sharedVertsB[0]]; if (edgeCrossB.dot(tmp) < 0) { edgeCrossB*=-1; } } btScalar angle2 = 0; btScalar ang4 = 0.f; btVector3 calculatedEdge = edgeCrossA.cross(edgeCrossB); btScalar len2 = calculatedEdge.length2(); btScalar correctedAngle(0); btVector3 calculatedNormalB = normalA; bool isConvex = false; if (len2m_planarEpsilon) { angle2 = 0.f; ang4 = 0.f; } else { calculatedEdge.normalize(); btVector3 calculatedNormalA = calculatedEdge.cross(edgeCrossA); calculatedNormalA.normalize(); angle2 = btGetAngle(calculatedNormalA,edgeCrossA,edgeCrossB); ang4 = SIMD_PI-angle2; btScalar dotA = normalA.dot(edgeCrossB); ///@todo: check if we need some epsilon, due to floating point imprecision isConvex = (dotA<0.); correctedAngle = isConvex ? ang4 : -ang4; btQuaternion orn2(calculatedEdge,-correctedAngle); calculatedNormalB = btMatrix3x3(orn2)*normalA; } //alternatively use //btVector3 calculatedNormalB2 = quatRotate(orn,normalA); switch (sumvertsA) { case 1: { btVector3 edge = m_triangleVerticesA[0]-m_triangleVerticesA[1]; btQuaternion orn(edge,-correctedAngle); btVector3 computedNormalB = quatRotate(orn,normalA); btScalar bla = computedNormalB.dot(normalB); if (bla<0) { computedNormalB*=-1; info->m_flags |= TRI_INFO_V0V1_SWAP_NORMALB; } #ifdef DEBUG_INTERNAL_EDGE if ((computedNormalB-normalB).length()>0.0001) { printf("warning: normals not identical\n"); } #endif//DEBUG_INTERNAL_EDGE info->m_edgeV0V1Angle = -correctedAngle; if (isConvex) info->m_flags |= TRI_INFO_V0V1_CONVEX; break; } case 2: { btVector3 edge = m_triangleVerticesA[2]-m_triangleVerticesA[0]; btQuaternion orn(edge,-correctedAngle); btVector3 computedNormalB = quatRotate(orn,normalA); if (computedNormalB.dot(normalB)<0) { computedNormalB*=-1; info->m_flags |= TRI_INFO_V2V0_SWAP_NORMALB; } #ifdef DEBUG_INTERNAL_EDGE if ((computedNormalB-normalB).length()>0.0001) { printf("warning: normals not identical\n"); } #endif //DEBUG_INTERNAL_EDGE info->m_edgeV2V0Angle = -correctedAngle; if (isConvex) info->m_flags |= TRI_INFO_V2V0_CONVEX; break; } case 3: { btVector3 edge = m_triangleVerticesA[1]-m_triangleVerticesA[2]; btQuaternion orn(edge,-correctedAngle); btVector3 computedNormalB = quatRotate(orn,normalA); if (computedNormalB.dot(normalB)<0) { info->m_flags |= TRI_INFO_V1V2_SWAP_NORMALB; computedNormalB*=-1; } #ifdef DEBUG_INTERNAL_EDGE if ((computedNormalB-normalB).length()>0.0001) { printf("warning: normals not identical\n"); } #endif //DEBUG_INTERNAL_EDGE info->m_edgeV1V2Angle = -correctedAngle; if (isConvex) info->m_flags |= TRI_INFO_V1V2_CONVEX; break; } } break; } default: { // printf("warning: duplicate triangle\n"); } } } }; ///////////////////////////////////////////////////////// ///////////////////////////////////////////////////////// void btGenerateInternalEdgeInfo (btBvhTriangleMeshShape*trimeshShape, btTriangleInfoMap* triangleInfoMap) { //the user pointer shouldn't already be used for other purposes, we intend to store connectivity info there! if (trimeshShape->getTriangleInfoMap()) return; trimeshShape->setTriangleInfoMap(triangleInfoMap); btStridingMeshInterface* meshInterface = trimeshShape->getMeshInterface(); const btVector3& meshScaling = meshInterface->getScaling(); for (int partId = 0; partId< meshInterface->getNumSubParts();partId++) { const unsigned char *vertexbase = 0; int numverts = 0; PHY_ScalarType type = PHY_INTEGER; int stride = 0; const unsigned char *indexbase = 0; int indexstride = 0; int numfaces = 0; PHY_ScalarType indicestype = PHY_INTEGER; //PHY_ScalarType indexType=0; btVector3 triangleVerts[3]; meshInterface->getLockedReadOnlyVertexIndexBase(&vertexbase,numverts, type,stride,&indexbase,indexstride,numfaces,indicestype,partId); btVector3 aabbMin,aabbMax; for (int triangleIndex = 0 ; triangleIndex < numfaces;triangleIndex++) { unsigned int* gfxbase = (unsigned int*)(indexbase+triangleIndex*indexstride); for (int j=2;j>=0;j--) { int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j]; if (type == PHY_FLOAT) { float* graphicsbase = (float*)(vertexbase+graphicsindex*stride); triangleVerts[j] = btVector3( graphicsbase[0]*meshScaling.getX(), graphicsbase[1]*meshScaling.getY(), graphicsbase[2]*meshScaling.getZ()); } else { double* graphicsbase = (double*)(vertexbase+graphicsindex*stride); triangleVerts[j] = btVector3( btScalar(graphicsbase[0]*meshScaling.getX()), btScalar(graphicsbase[1]*meshScaling.getY()), btScalar(graphicsbase[2]*meshScaling.getZ())); } } aabbMin.setValue(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); aabbMax.setValue(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); aabbMin.setMin(triangleVerts[0]); aabbMax.setMax(triangleVerts[0]); aabbMin.setMin(triangleVerts[1]); aabbMax.setMax(triangleVerts[1]); aabbMin.setMin(triangleVerts[2]); aabbMax.setMax(triangleVerts[2]); btConnectivityProcessor connectivityProcessor; connectivityProcessor.m_partIdA = partId; connectivityProcessor.m_triangleIndexA = triangleIndex; connectivityProcessor.m_triangleVerticesA = &triangleVerts[0]; connectivityProcessor.m_triangleInfoMap = triangleInfoMap; trimeshShape->processAllTriangles(&connectivityProcessor,aabbMin,aabbMax); } } } // Given a point and a line segment (defined by two points), compute the closest point // in the line. Cap the point at the endpoints of the line segment. void btNearestPointInLineSegment(const btVector3 &point, const btVector3& line0, const btVector3& line1, btVector3& nearestPoint) { btVector3 lineDelta = line1 - line0; // Handle degenerate lines if ( lineDelta.fuzzyZero()) { nearestPoint = line0; } else { btScalar delta = (point-line0).dot(lineDelta) / (lineDelta).dot(lineDelta); // Clamp the point to conform to the segment's endpoints if ( delta < 0 ) delta = 0; else if ( delta > 1 ) delta = 1; nearestPoint = line0 + lineDelta*delta; } } bool btClampNormal(const btVector3& edge,const btVector3& tri_normal_org,const btVector3& localContactNormalOnB, btScalar correctedEdgeAngle, btVector3 & clampedLocalNormal) { btVector3 tri_normal = tri_normal_org; //we only have a local triangle normal, not a local contact normal -> only normal in world space... //either compute the current angle all in local space, or all in world space btVector3 edgeCross = edge.cross(tri_normal).normalize(); btScalar curAngle = btGetAngle(edgeCross,tri_normal,localContactNormalOnB); if (correctedEdgeAngle<0) { if (curAngle < correctedEdgeAngle) { btScalar diffAngle = correctedEdgeAngle-curAngle; btQuaternion rotation(edge,diffAngle ); clampedLocalNormal = btMatrix3x3(rotation)*localContactNormalOnB; return true; } } if (correctedEdgeAngle>=0) { if (curAngle > correctedEdgeAngle) { btScalar diffAngle = correctedEdgeAngle-curAngle; btQuaternion rotation(edge,diffAngle ); clampedLocalNormal = btMatrix3x3(rotation)*localContactNormalOnB; return true; } } return false; } /// Changes a btManifoldPoint collision normal to the normal from the mesh. void btAdjustInternalEdgeContacts(btManifoldPoint& cp, const btCollisionObject* colObj0,const btCollisionObject* colObj1, int partId0, int index0, int normalAdjustFlags) { //btAssert(colObj0->getCollisionShape()->getShapeType() == TRIANGLE_SHAPE_PROXYTYPE); if (colObj0->getCollisionShape()->getShapeType() != TRIANGLE_SHAPE_PROXYTYPE) return; btBvhTriangleMeshShape* trimesh = (btBvhTriangleMeshShape*)colObj0->getRootCollisionShape(); btTriangleInfoMap* triangleInfoMapPtr = (btTriangleInfoMap*) trimesh->getTriangleInfoMap(); if (!triangleInfoMapPtr) return; int hash = btGetHash(partId0,index0); btTriangleInfo* info = triangleInfoMapPtr->find(hash); if (!info) return; btScalar frontFacing = (normalAdjustFlags & BT_TRIANGLE_CONVEX_BACKFACE_MODE)==0? 1.f : -1.f; const btTriangleShape* tri_shape = static_cast(colObj0->getCollisionShape()); btVector3 v0,v1,v2; tri_shape->getVertex(0,v0); tri_shape->getVertex(1,v1); tri_shape->getVertex(2,v2); btVector3 center = (v0+v1+v2)*btScalar(1./3.); btVector3 red(1,0,0), green(0,1,0),blue(0,0,1),white(1,1,1),black(0,0,0); btVector3 tri_normal; tri_shape->calcNormal(tri_normal); //btScalar dot = tri_normal.dot(cp.m_normalWorldOnB); btVector3 nearest; btNearestPointInLineSegment(cp.m_localPointB,v0,v1,nearest); btVector3 contact = cp.m_localPointB; #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW const btTransform& tr = colObj0->getWorldTransform(); btDebugDrawLine(tr*nearest,tr*cp.m_localPointB,red); #endif //BT_INTERNAL_EDGE_DEBUG_DRAW bool isNearEdge = false; int numConcaveEdgeHits = 0; int numConvexEdgeHits = 0; btVector3 localContactNormalOnB = colObj0->getWorldTransform().getBasis().transpose() * cp.m_normalWorldOnB; localContactNormalOnB.normalize();//is this necessary? if ((info->m_edgeV0V1Angle)< SIMD_2_PI) { #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW btDebugDrawLine(tr*contact,tr*(contact+cp.m_normalWorldOnB*10),black); #endif btScalar len = (contact-nearest).length(); if(lenm_edgeDistanceThreshold) { btVector3 edge(v0-v1); isNearEdge = true; if (info->m_edgeV0V1Angle==btScalar(0)) { numConcaveEdgeHits++; } else { bool isEdgeConvex = (info->m_flags & TRI_INFO_V0V1_CONVEX); btScalar swapFactor = isEdgeConvex ? btScalar(1) : btScalar(-1); #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW btDebugDrawLine(tr*nearest,tr*(nearest+swapFactor*tri_normal*10),white); #endif //BT_INTERNAL_EDGE_DEBUG_DRAW btVector3 nA = swapFactor * tri_normal; btQuaternion orn(edge,info->m_edgeV0V1Angle); btVector3 computedNormalB = quatRotate(orn,tri_normal); if (info->m_flags & TRI_INFO_V0V1_SWAP_NORMALB) computedNormalB*=-1; btVector3 nB = swapFactor*computedNormalB; btScalar NdotA = localContactNormalOnB.dot(nA); btScalar NdotB = localContactNormalOnB.dot(nB); bool backFacingNormal = (NdotA< triangleInfoMapPtr->m_convexEpsilon) && (NdotBm_convexEpsilon); #ifdef DEBUG_INTERNAL_EDGE { btDebugDrawLine(cp.getPositionWorldOnB(),cp.getPositionWorldOnB()+tr.getBasis()*(nB*20),red); } #endif //DEBUG_INTERNAL_EDGE if (backFacingNormal) { numConcaveEdgeHits++; } else { numConvexEdgeHits++; btVector3 clampedLocalNormal; bool isClamped = btClampNormal(edge,swapFactor*tri_normal,localContactNormalOnB, info->m_edgeV0V1Angle,clampedLocalNormal); if (isClamped) { if (((normalAdjustFlags & BT_TRIANGLE_CONVEX_DOUBLE_SIDED)!=0) || (clampedLocalNormal.dot(frontFacing*tri_normal)>0)) { btVector3 newNormal = colObj0->getWorldTransform().getBasis() * clampedLocalNormal; // cp.m_distance1 = cp.m_distance1 * newNormal.dot(cp.m_normalWorldOnB); cp.m_normalWorldOnB = newNormal; // Reproject collision point along normal. (what about cp.m_distance1?) cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1; cp.m_localPointB = colObj0->getWorldTransform().invXform(cp.m_positionWorldOnB); } } } } } } btNearestPointInLineSegment(contact,v1,v2,nearest); #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW btDebugDrawLine(tr*nearest,tr*cp.m_localPointB,green); #endif //BT_INTERNAL_EDGE_DEBUG_DRAW if ((info->m_edgeV1V2Angle)< SIMD_2_PI) { #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW btDebugDrawLine(tr*contact,tr*(contact+cp.m_normalWorldOnB*10),black); #endif //BT_INTERNAL_EDGE_DEBUG_DRAW btScalar len = (contact-nearest).length(); if(lenm_edgeDistanceThreshold) { isNearEdge = true; #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW btDebugDrawLine(tr*nearest,tr*(nearest+tri_normal*10),white); #endif //BT_INTERNAL_EDGE_DEBUG_DRAW btVector3 edge(v1-v2); isNearEdge = true; if (info->m_edgeV1V2Angle == btScalar(0)) { numConcaveEdgeHits++; } else { bool isEdgeConvex = (info->m_flags & TRI_INFO_V1V2_CONVEX)!=0; btScalar swapFactor = isEdgeConvex ? btScalar(1) : btScalar(-1); #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW btDebugDrawLine(tr*nearest,tr*(nearest+swapFactor*tri_normal*10),white); #endif //BT_INTERNAL_EDGE_DEBUG_DRAW btVector3 nA = swapFactor * tri_normal; btQuaternion orn(edge,info->m_edgeV1V2Angle); btVector3 computedNormalB = quatRotate(orn,tri_normal); if (info->m_flags & TRI_INFO_V1V2_SWAP_NORMALB) computedNormalB*=-1; btVector3 nB = swapFactor*computedNormalB; #ifdef DEBUG_INTERNAL_EDGE { btDebugDrawLine(cp.getPositionWorldOnB(),cp.getPositionWorldOnB()+tr.getBasis()*(nB*20),red); } #endif //DEBUG_INTERNAL_EDGE btScalar NdotA = localContactNormalOnB.dot(nA); btScalar NdotB = localContactNormalOnB.dot(nB); bool backFacingNormal = (NdotA< triangleInfoMapPtr->m_convexEpsilon) && (NdotBm_convexEpsilon); if (backFacingNormal) { numConcaveEdgeHits++; } else { numConvexEdgeHits++; btVector3 localContactNormalOnB = colObj0->getWorldTransform().getBasis().transpose() * cp.m_normalWorldOnB; btVector3 clampedLocalNormal; bool isClamped = btClampNormal(edge,swapFactor*tri_normal,localContactNormalOnB, info->m_edgeV1V2Angle,clampedLocalNormal); if (isClamped) { if (((normalAdjustFlags & BT_TRIANGLE_CONVEX_DOUBLE_SIDED)!=0) || (clampedLocalNormal.dot(frontFacing*tri_normal)>0)) { btVector3 newNormal = colObj0->getWorldTransform().getBasis() * clampedLocalNormal; // cp.m_distance1 = cp.m_distance1 * newNormal.dot(cp.m_normalWorldOnB); cp.m_normalWorldOnB = newNormal; // Reproject collision point along normal. cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1; cp.m_localPointB = colObj0->getWorldTransform().invXform(cp.m_positionWorldOnB); } } } } } } btNearestPointInLineSegment(contact,v2,v0,nearest); #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW btDebugDrawLine(tr*nearest,tr*cp.m_localPointB,blue); #endif //BT_INTERNAL_EDGE_DEBUG_DRAW if ((info->m_edgeV2V0Angle)< SIMD_2_PI) { #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW btDebugDrawLine(tr*contact,tr*(contact+cp.m_normalWorldOnB*10),black); #endif //BT_INTERNAL_EDGE_DEBUG_DRAW btScalar len = (contact-nearest).length(); if(lenm_edgeDistanceThreshold) { isNearEdge = true; #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW btDebugDrawLine(tr*nearest,tr*(nearest+tri_normal*10),white); #endif //BT_INTERNAL_EDGE_DEBUG_DRAW btVector3 edge(v2-v0); if (info->m_edgeV2V0Angle==btScalar(0)) { numConcaveEdgeHits++; } else { bool isEdgeConvex = (info->m_flags & TRI_INFO_V2V0_CONVEX)!=0; btScalar swapFactor = isEdgeConvex ? btScalar(1) : btScalar(-1); #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW btDebugDrawLine(tr*nearest,tr*(nearest+swapFactor*tri_normal*10),white); #endif //BT_INTERNAL_EDGE_DEBUG_DRAW btVector3 nA = swapFactor * tri_normal; btQuaternion orn(edge,info->m_edgeV2V0Angle); btVector3 computedNormalB = quatRotate(orn,tri_normal); if (info->m_flags & TRI_INFO_V2V0_SWAP_NORMALB) computedNormalB*=-1; btVector3 nB = swapFactor*computedNormalB; #ifdef DEBUG_INTERNAL_EDGE { btDebugDrawLine(cp.getPositionWorldOnB(),cp.getPositionWorldOnB()+tr.getBasis()*(nB*20),red); } #endif //DEBUG_INTERNAL_EDGE btScalar NdotA = localContactNormalOnB.dot(nA); btScalar NdotB = localContactNormalOnB.dot(nB); bool backFacingNormal = (NdotA< triangleInfoMapPtr->m_convexEpsilon) && (NdotBm_convexEpsilon); if (backFacingNormal) { numConcaveEdgeHits++; } else { numConvexEdgeHits++; // printf("hitting convex edge\n"); btVector3 localContactNormalOnB = colObj0->getWorldTransform().getBasis().transpose() * cp.m_normalWorldOnB; btVector3 clampedLocalNormal; bool isClamped = btClampNormal(edge,swapFactor*tri_normal,localContactNormalOnB,info->m_edgeV2V0Angle,clampedLocalNormal); if (isClamped) { if (((normalAdjustFlags & BT_TRIANGLE_CONVEX_DOUBLE_SIDED)!=0) || (clampedLocalNormal.dot(frontFacing*tri_normal)>0)) { btVector3 newNormal = colObj0->getWorldTransform().getBasis() * clampedLocalNormal; // cp.m_distance1 = cp.m_distance1 * newNormal.dot(cp.m_normalWorldOnB); cp.m_normalWorldOnB = newNormal; // Reproject collision point along normal. cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1; cp.m_localPointB = colObj0->getWorldTransform().invXform(cp.m_positionWorldOnB); } } } } } } #ifdef DEBUG_INTERNAL_EDGE { btVector3 color(0,1,1); btDebugDrawLine(cp.getPositionWorldOnB(),cp.getPositionWorldOnB()+cp.m_normalWorldOnB*10,color); } #endif //DEBUG_INTERNAL_EDGE if (isNearEdge) { if (numConcaveEdgeHits>0) { if ((normalAdjustFlags & BT_TRIANGLE_CONCAVE_DOUBLE_SIDED)!=0) { //fix tri_normal so it pointing the same direction as the current local contact normal if (tri_normal.dot(localContactNormalOnB) < 0) { tri_normal *= -1; } cp.m_normalWorldOnB = colObj0->getWorldTransform().getBasis()*tri_normal; } else { //modify the normal to be the triangle normal (or backfacing normal) cp.m_normalWorldOnB = colObj0->getWorldTransform().getBasis() *(tri_normal *frontFacing); } // Reproject collision point along normal. cp.m_positionWorldOnB = cp.m_positionWorldOnA - cp.m_normalWorldOnB * cp.m_distance1; cp.m_localPointB = colObj0->getWorldTransform().invXform(cp.m_positionWorldOnB); } } } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btBoxBoxDetector.cpp0000644000175000017500000005144011344267705031433 0ustar bobkebobke/* * Box-Box collision detection re-distributed under the ZLib license with permission from Russell L. Smith * Original version is from Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * All rights reserved. Email: russ@q12.org Web: www.q12.org Bullet Continuous Collision Detection and Physics Library Bullet is Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ ///ODE box-box collision detection is adapted to work with Bullet #include "btBoxBoxDetector.h" #include "BulletCollision/CollisionShapes/btBoxShape.h" #include #include btBoxBoxDetector::btBoxBoxDetector(btBoxShape* box1,btBoxShape* box2) : m_box1(box1), m_box2(box2) { } // given two boxes (p1,R1,side1) and (p2,R2,side2), collide them together and // generate contact points. this returns 0 if there is no contact otherwise // it returns the number of contacts generated. // `normal' returns the contact normal. // `depth' returns the maximum penetration depth along that normal. // `return_code' returns a number indicating the type of contact that was // detected: // 1,2,3 = box 2 intersects with a face of box 1 // 4,5,6 = box 1 intersects with a face of box 2 // 7..15 = edge-edge contact // `maxc' is the maximum number of contacts allowed to be generated, i.e. // the size of the `contact' array. // `contact' and `skip' are the contact array information provided to the // collision functions. this function only fills in the position and depth // fields. struct dContactGeom; #define dDOTpq(a,b,p,q) ((a)[0]*(b)[0] + (a)[p]*(b)[q] + (a)[2*(p)]*(b)[2*(q)]) #define dInfinity FLT_MAX /*PURE_INLINE btScalar dDOT (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,1); } PURE_INLINE btScalar dDOT13 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,3); } PURE_INLINE btScalar dDOT31 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,3,1); } PURE_INLINE btScalar dDOT33 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,3,3); } */ static btScalar dDOT (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,1); } static btScalar dDOT44 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,4,4); } static btScalar dDOT41 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,4,1); } static btScalar dDOT14 (const btScalar *a, const btScalar *b) { return dDOTpq(a,b,1,4); } #define dMULTIPLYOP1_331(A,op,B,C) \ {\ (A)[0] op dDOT41((B),(C)); \ (A)[1] op dDOT41((B+1),(C)); \ (A)[2] op dDOT41((B+2),(C)); \ } #define dMULTIPLYOP0_331(A,op,B,C) \ { \ (A)[0] op dDOT((B),(C)); \ (A)[1] op dDOT((B+4),(C)); \ (A)[2] op dDOT((B+8),(C)); \ } #define dMULTIPLY1_331(A,B,C) dMULTIPLYOP1_331(A,=,B,C) #define dMULTIPLY0_331(A,B,C) dMULTIPLYOP0_331(A,=,B,C) typedef btScalar dMatrix3[4*3]; void dLineClosestApproach (const btVector3& pa, const btVector3& ua, const btVector3& pb, const btVector3& ub, btScalar *alpha, btScalar *beta); void dLineClosestApproach (const btVector3& pa, const btVector3& ua, const btVector3& pb, const btVector3& ub, btScalar *alpha, btScalar *beta) { btVector3 p; p[0] = pb[0] - pa[0]; p[1] = pb[1] - pa[1]; p[2] = pb[2] - pa[2]; btScalar uaub = dDOT(ua,ub); btScalar q1 = dDOT(ua,p); btScalar q2 = -dDOT(ub,p); btScalar d = 1-uaub*uaub; if (d <= btScalar(0.0001f)) { // @@@ this needs to be made more robust *alpha = 0; *beta = 0; } else { d = 1.f/d; *alpha = (q1 + uaub*q2)*d; *beta = (uaub*q1 + q2)*d; } } // find all the intersection points between the 2D rectangle with vertices // at (+/-h[0],+/-h[1]) and the 2D quadrilateral with vertices (p[0],p[1]), // (p[2],p[3]),(p[4],p[5]),(p[6],p[7]). // // the intersection points are returned as x,y pairs in the 'ret' array. // the number of intersection points is returned by the function (this will // be in the range 0 to 8). static int intersectRectQuad2 (btScalar h[2], btScalar p[8], btScalar ret[16]) { // q (and r) contain nq (and nr) coordinate points for the current (and // chopped) polygons int nq=4,nr=0; btScalar buffer[16]; btScalar *q = p; btScalar *r = ret; for (int dir=0; dir <= 1; dir++) { // direction notation: xy[0] = x axis, xy[1] = y axis for (int sign=-1; sign <= 1; sign += 2) { // chop q along the line xy[dir] = sign*h[dir] btScalar *pq = q; btScalar *pr = r; nr = 0; for (int i=nq; i > 0; i--) { // go through all points in q and all lines between adjacent points if (sign*pq[dir] < h[dir]) { // this point is inside the chopping line pr[0] = pq[0]; pr[1] = pq[1]; pr += 2; nr++; if (nr & 8) { q = r; goto done; } } btScalar *nextq = (i > 1) ? pq+2 : q; if ((sign*pq[dir] < h[dir]) ^ (sign*nextq[dir] < h[dir])) { // this line crosses the chopping line pr[1-dir] = pq[1-dir] + (nextq[1-dir]-pq[1-dir]) / (nextq[dir]-pq[dir]) * (sign*h[dir]-pq[dir]); pr[dir] = sign*h[dir]; pr += 2; nr++; if (nr & 8) { q = r; goto done; } } pq += 2; } q = r; r = (q==ret) ? buffer : ret; nq = nr; } } done: if (q != ret) memcpy (ret,q,nr*2*sizeof(btScalar)); return nr; } #define M__PI 3.14159265f // given n points in the plane (array p, of size 2*n), generate m points that // best represent the whole set. the definition of 'best' here is not // predetermined - the idea is to select points that give good box-box // collision detection behavior. the chosen point indexes are returned in the // array iret (of size m). 'i0' is always the first entry in the array. // n must be in the range [1..8]. m must be in the range [1..n]. i0 must be // in the range [0..n-1]. void cullPoints2 (int n, btScalar p[], int m, int i0, int iret[]); void cullPoints2 (int n, btScalar p[], int m, int i0, int iret[]) { // compute the centroid of the polygon in cx,cy int i,j; btScalar a,cx,cy,q; if (n==1) { cx = p[0]; cy = p[1]; } else if (n==2) { cx = btScalar(0.5)*(p[0] + p[2]); cy = btScalar(0.5)*(p[1] + p[3]); } else { a = 0; cx = 0; cy = 0; for (i=0; i<(n-1); i++) { q = p[i*2]*p[i*2+3] - p[i*2+2]*p[i*2+1]; a += q; cx += q*(p[i*2]+p[i*2+2]); cy += q*(p[i*2+1]+p[i*2+3]); } q = p[n*2-2]*p[1] - p[0]*p[n*2-1]; if (btFabs(a+q) > SIMD_EPSILON) { a = 1.f/(btScalar(3.0)*(a+q)); } else { a=BT_LARGE_FLOAT; } cx = a*(cx + q*(p[n*2-2]+p[0])); cy = a*(cy + q*(p[n*2-1]+p[1])); } // compute the angle of each point w.r.t. the centroid btScalar A[8]; for (i=0; i M__PI) a -= 2*M__PI; btScalar maxdiff=1e9,diff; *iret = i0; // iret is not allowed to keep this value, but it sometimes does, when diff=#QNAN0 for (i=0; i M__PI) diff = 2*M__PI - diff; if (diff < maxdiff) { maxdiff = diff; *iret = i; } } } #if defined(DEBUG) || defined (_DEBUG) btAssert (*iret != i0); // ensure iret got set #endif avail[*iret] = 0; iret++; } } int dBoxBox2 (const btVector3& p1, const dMatrix3 R1, const btVector3& side1, const btVector3& p2, const dMatrix3 R2, const btVector3& side2, btVector3& normal, btScalar *depth, int *return_code, int maxc, dContactGeom * /*contact*/, int /*skip*/,btDiscreteCollisionDetectorInterface::Result& output); int dBoxBox2 (const btVector3& p1, const dMatrix3 R1, const btVector3& side1, const btVector3& p2, const dMatrix3 R2, const btVector3& side2, btVector3& normal, btScalar *depth, int *return_code, int maxc, dContactGeom * /*contact*/, int /*skip*/,btDiscreteCollisionDetectorInterface::Result& output) { const btScalar fudge_factor = btScalar(1.05); btVector3 p,pp,normalC(0.f,0.f,0.f); const btScalar *normalR = 0; btScalar A[3],B[3],R11,R12,R13,R21,R22,R23,R31,R32,R33, Q11,Q12,Q13,Q21,Q22,Q23,Q31,Q32,Q33,s,s2,l; int i,j,invert_normal,code; // get vector from centers of box 1 to box 2, relative to box 1 p = p2 - p1; dMULTIPLY1_331 (pp,R1,p); // get pp = p relative to body 1 // get side lengths / 2 A[0] = side1[0]*btScalar(0.5); A[1] = side1[1]*btScalar(0.5); A[2] = side1[2]*btScalar(0.5); B[0] = side2[0]*btScalar(0.5); B[1] = side2[1]*btScalar(0.5); B[2] = side2[2]*btScalar(0.5); // Rij is R1'*R2, i.e. the relative rotation between R1 and R2 R11 = dDOT44(R1+0,R2+0); R12 = dDOT44(R1+0,R2+1); R13 = dDOT44(R1+0,R2+2); R21 = dDOT44(R1+1,R2+0); R22 = dDOT44(R1+1,R2+1); R23 = dDOT44(R1+1,R2+2); R31 = dDOT44(R1+2,R2+0); R32 = dDOT44(R1+2,R2+1); R33 = dDOT44(R1+2,R2+2); Q11 = btFabs(R11); Q12 = btFabs(R12); Q13 = btFabs(R13); Q21 = btFabs(R21); Q22 = btFabs(R22); Q23 = btFabs(R23); Q31 = btFabs(R31); Q32 = btFabs(R32); Q33 = btFabs(R33); // for all 15 possible separating axes: // * see if the axis separates the boxes. if so, return 0. // * find the depth of the penetration along the separating axis (s2) // * if this is the largest depth so far, record it. // the normal vector will be set to the separating axis with the smallest // depth. note: normalR is set to point to a column of R1 or R2 if that is // the smallest depth normal so far. otherwise normalR is 0 and normalC is // set to a vector relative to body 1. invert_normal is 1 if the sign of // the normal should be flipped. #define TST(expr1,expr2,norm,cc) \ s2 = btFabs(expr1) - (expr2); \ if (s2 > 0) return 0; \ if (s2 > s) { \ s = s2; \ normalR = norm; \ invert_normal = ((expr1) < 0); \ code = (cc); \ } s = -dInfinity; invert_normal = 0; code = 0; // separating axis = u1,u2,u3 TST (pp[0],(A[0] + B[0]*Q11 + B[1]*Q12 + B[2]*Q13),R1+0,1); TST (pp[1],(A[1] + B[0]*Q21 + B[1]*Q22 + B[2]*Q23),R1+1,2); TST (pp[2],(A[2] + B[0]*Q31 + B[1]*Q32 + B[2]*Q33),R1+2,3); // separating axis = v1,v2,v3 TST (dDOT41(R2+0,p),(A[0]*Q11 + A[1]*Q21 + A[2]*Q31 + B[0]),R2+0,4); TST (dDOT41(R2+1,p),(A[0]*Q12 + A[1]*Q22 + A[2]*Q32 + B[1]),R2+1,5); TST (dDOT41(R2+2,p),(A[0]*Q13 + A[1]*Q23 + A[2]*Q33 + B[2]),R2+2,6); // note: cross product axes need to be scaled when s is computed. // normal (n1,n2,n3) is relative to box 1. #undef TST #define TST(expr1,expr2,n1,n2,n3,cc) \ s2 = btFabs(expr1) - (expr2); \ if (s2 > SIMD_EPSILON) return 0; \ l = btSqrt((n1)*(n1) + (n2)*(n2) + (n3)*(n3)); \ if (l > SIMD_EPSILON) { \ s2 /= l; \ if (s2*fudge_factor > s) { \ s = s2; \ normalR = 0; \ normalC[0] = (n1)/l; normalC[1] = (n2)/l; normalC[2] = (n3)/l; \ invert_normal = ((expr1) < 0); \ code = (cc); \ } \ } // separating axis = u1 x (v1,v2,v3) TST(pp[2]*R21-pp[1]*R31,(A[1]*Q31+A[2]*Q21+B[1]*Q13+B[2]*Q12),0,-R31,R21,7); TST(pp[2]*R22-pp[1]*R32,(A[1]*Q32+A[2]*Q22+B[0]*Q13+B[2]*Q11),0,-R32,R22,8); TST(pp[2]*R23-pp[1]*R33,(A[1]*Q33+A[2]*Q23+B[0]*Q12+B[1]*Q11),0,-R33,R23,9); // separating axis = u2 x (v1,v2,v3) TST(pp[0]*R31-pp[2]*R11,(A[0]*Q31+A[2]*Q11+B[1]*Q23+B[2]*Q22),R31,0,-R11,10); TST(pp[0]*R32-pp[2]*R12,(A[0]*Q32+A[2]*Q12+B[0]*Q23+B[2]*Q21),R32,0,-R12,11); TST(pp[0]*R33-pp[2]*R13,(A[0]*Q33+A[2]*Q13+B[0]*Q22+B[1]*Q21),R33,0,-R13,12); // separating axis = u3 x (v1,v2,v3) TST(pp[1]*R11-pp[0]*R21,(A[0]*Q21+A[1]*Q11+B[1]*Q33+B[2]*Q32),-R21,R11,0,13); TST(pp[1]*R12-pp[0]*R22,(A[0]*Q22+A[1]*Q12+B[0]*Q33+B[2]*Q31),-R22,R12,0,14); TST(pp[1]*R13-pp[0]*R23,(A[0]*Q23+A[1]*Q13+B[0]*Q32+B[1]*Q31),-R23,R13,0,15); #undef TST if (!code) return 0; // if we get to this point, the boxes interpenetrate. compute the normal // in global coordinates. if (normalR) { normal[0] = normalR[0]; normal[1] = normalR[4]; normal[2] = normalR[8]; } else { dMULTIPLY0_331 (normal,R1,normalC); } if (invert_normal) { normal[0] = -normal[0]; normal[1] = -normal[1]; normal[2] = -normal[2]; } *depth = -s; // compute contact point(s) if (code > 6) { // an edge from box 1 touches an edge from box 2. // find a point pa on the intersecting edge of box 1 btVector3 pa; btScalar sign; for (i=0; i<3; i++) pa[i] = p1[i]; for (j=0; j<3; j++) { sign = (dDOT14(normal,R1+j) > 0) ? btScalar(1.0) : btScalar(-1.0); for (i=0; i<3; i++) pa[i] += sign * A[j] * R1[i*4+j]; } // find a point pb on the intersecting edge of box 2 btVector3 pb; for (i=0; i<3; i++) pb[i] = p2[i]; for (j=0; j<3; j++) { sign = (dDOT14(normal,R2+j) > 0) ? btScalar(-1.0) : btScalar(1.0); for (i=0; i<3; i++) pb[i] += sign * B[j] * R2[i*4+j]; } btScalar alpha,beta; btVector3 ua,ub; for (i=0; i<3; i++) ua[i] = R1[((code)-7)/3 + i*4]; for (i=0; i<3; i++) ub[i] = R2[((code)-7)%3 + i*4]; dLineClosestApproach (pa,ua,pb,ub,&alpha,&beta); for (i=0; i<3; i++) pa[i] += ua[i]*alpha; for (i=0; i<3; i++) pb[i] += ub[i]*beta; { //contact[0].pos[i] = btScalar(0.5)*(pa[i]+pb[i]); //contact[0].depth = *depth; btVector3 pointInWorld; #ifdef USE_CENTER_POINT for (i=0; i<3; i++) pointInWorld[i] = (pa[i]+pb[i])*btScalar(0.5); output.addContactPoint(-normal,pointInWorld,-*depth); #else output.addContactPoint(-normal,pb,-*depth); #endif // *return_code = code; } return 1; } // okay, we have a face-something intersection (because the separating // axis is perpendicular to a face). define face 'a' to be the reference // face (i.e. the normal vector is perpendicular to this) and face 'b' to be // the incident face (the closest face of the other box). const btScalar *Ra,*Rb,*pa,*pb,*Sa,*Sb; if (code <= 3) { Ra = R1; Rb = R2; pa = p1; pb = p2; Sa = A; Sb = B; } else { Ra = R2; Rb = R1; pa = p2; pb = p1; Sa = B; Sb = A; } // nr = normal vector of reference face dotted with axes of incident box. // anr = absolute values of nr. btVector3 normal2,nr,anr; if (code <= 3) { normal2[0] = normal[0]; normal2[1] = normal[1]; normal2[2] = normal[2]; } else { normal2[0] = -normal[0]; normal2[1] = -normal[1]; normal2[2] = -normal[2]; } dMULTIPLY1_331 (nr,Rb,normal2); anr[0] = btFabs (nr[0]); anr[1] = btFabs (nr[1]); anr[2] = btFabs (nr[2]); // find the largest compontent of anr: this corresponds to the normal // for the indident face. the other axis numbers of the indicent face // are stored in a1,a2. int lanr,a1,a2; if (anr[1] > anr[0]) { if (anr[1] > anr[2]) { a1 = 0; lanr = 1; a2 = 2; } else { a1 = 0; a2 = 1; lanr = 2; } } else { if (anr[0] > anr[2]) { lanr = 0; a1 = 1; a2 = 2; } else { a1 = 0; a2 = 1; lanr = 2; } } // compute center point of incident face, in reference-face coordinates btVector3 center; if (nr[lanr] < 0) { for (i=0; i<3; i++) center[i] = pb[i] - pa[i] + Sb[lanr] * Rb[i*4+lanr]; } else { for (i=0; i<3; i++) center[i] = pb[i] - pa[i] - Sb[lanr] * Rb[i*4+lanr]; } // find the normal and non-normal axis numbers of the reference box int codeN,code1,code2; if (code <= 3) codeN = code-1; else codeN = code-4; if (codeN==0) { code1 = 1; code2 = 2; } else if (codeN==1) { code1 = 0; code2 = 2; } else { code1 = 0; code2 = 1; } // find the four corners of the incident face, in reference-face coordinates btScalar quad[8]; // 2D coordinate of incident face (x,y pairs) btScalar c1,c2,m11,m12,m21,m22; c1 = dDOT14 (center,Ra+code1); c2 = dDOT14 (center,Ra+code2); // optimize this? - we have already computed this data above, but it is not // stored in an easy-to-index format. for now it's quicker just to recompute // the four dot products. m11 = dDOT44 (Ra+code1,Rb+a1); m12 = dDOT44 (Ra+code1,Rb+a2); m21 = dDOT44 (Ra+code2,Rb+a1); m22 = dDOT44 (Ra+code2,Rb+a2); { btScalar k1 = m11*Sb[a1]; btScalar k2 = m21*Sb[a1]; btScalar k3 = m12*Sb[a2]; btScalar k4 = m22*Sb[a2]; quad[0] = c1 - k1 - k3; quad[1] = c2 - k2 - k4; quad[2] = c1 - k1 + k3; quad[3] = c2 - k2 + k4; quad[4] = c1 + k1 + k3; quad[5] = c2 + k2 + k4; quad[6] = c1 + k1 - k3; quad[7] = c2 + k2 - k4; } // find the size of the reference face btScalar rect[2]; rect[0] = Sa[code1]; rect[1] = Sa[code2]; // intersect the incident and reference faces btScalar ret[16]; int n = intersectRectQuad2 (rect,quad,ret); if (n < 1) return 0; // this should never happen // convert the intersection points into reference-face coordinates, // and compute the contact position and depth for each point. only keep // those points that have a positive (penetrating) depth. delete points in // the 'ret' array as necessary so that 'point' and 'ret' correspond. btScalar point[3*8]; // penetrating contact points btScalar dep[8]; // depths for those points btScalar det1 = 1.f/(m11*m22 - m12*m21); m11 *= det1; m12 *= det1; m21 *= det1; m22 *= det1; int cnum = 0; // number of penetrating contact points found for (j=0; j < n; j++) { btScalar k1 = m22*(ret[j*2]-c1) - m12*(ret[j*2+1]-c2); btScalar k2 = -m21*(ret[j*2]-c1) + m11*(ret[j*2+1]-c2); for (i=0; i<3; i++) point[cnum*3+i] = center[i] + k1*Rb[i*4+a1] + k2*Rb[i*4+a2]; dep[cnum] = Sa[codeN] - dDOT(normal2,point+cnum*3); if (dep[cnum] >= 0) { ret[cnum*2] = ret[j*2]; ret[cnum*2+1] = ret[j*2+1]; cnum++; } } if (cnum < 1) return 0; // this should never happen // we can't generate more contacts than we actually have if (maxc > cnum) maxc = cnum; if (maxc < 1) maxc = 1; if (cnum <= maxc) { if (code<4) { // we have less contacts than we need, so we use them all for (j=0; j < cnum; j++) { btVector3 pointInWorld; for (i=0; i<3; i++) pointInWorld[i] = point[j*3+i] + pa[i]; output.addContactPoint(-normal,pointInWorld,-dep[j]); } } else { // we have less contacts than we need, so we use them all for (j=0; j < cnum; j++) { btVector3 pointInWorld; for (i=0; i<3; i++) pointInWorld[i] = point[j*3+i] + pa[i]-normal[i]*dep[j]; //pointInWorld[i] = point[j*3+i] + pa[i]; output.addContactPoint(-normal,pointInWorld,-dep[j]); } } } else { // we have more contacts than are wanted, some of them must be culled. // find the deepest point, it is always the first contact. int i1 = 0; btScalar maxdepth = dep[0]; for (i=1; i maxdepth) { maxdepth = dep[i]; i1 = i; } } int iret[8]; cullPoints2 (cnum,ret,maxc,i1,iret); for (j=0; j < maxc; j++) { // dContactGeom *con = CONTACT(contact,skip*j); // for (i=0; i<3; i++) con->pos[i] = point[iret[j]*3+i] + pa[i]; // con->depth = dep[iret[j]]; btVector3 posInWorld; for (i=0; i<3; i++) posInWorld[i] = point[iret[j]*3+i] + pa[i]; if (code<4) { output.addContactPoint(-normal,posInWorld,-dep[iret[j]]); } else { output.addContactPoint(-normal,posInWorld-normal*dep[iret[j]],-dep[iret[j]]); } } cnum = maxc; } *return_code = code; return cnum; } void btBoxBoxDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* /*debugDraw*/,bool /*swapResults*/) { const btTransform& transformA = input.m_transformA; const btTransform& transformB = input.m_transformB; int skip = 0; dContactGeom *contact = 0; dMatrix3 R1; dMatrix3 R2; for (int j=0;j<3;j++) { R1[0+4*j] = transformA.getBasis()[j].x(); R2[0+4*j] = transformB.getBasis()[j].x(); R1[1+4*j] = transformA.getBasis()[j].y(); R2[1+4*j] = transformB.getBasis()[j].y(); R1[2+4*j] = transformA.getBasis()[j].z(); R2[2+4*j] = transformB.getBasis()[j].z(); } btVector3 normal; btScalar depth; int return_code; int maxc = 4; dBoxBox2 (transformA.getOrigin(), R1, 2.f*m_box1->getHalfExtentsWithMargin(), transformB.getOrigin(), R2, 2.f*m_box2->getHalfExtentsWithMargin(), normal, &depth, &return_code, maxc, contact, skip, output ); } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btEmptyCollisionAlgorithm.h0000644000175000017500000000434011337071441033013 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 EMPTY_ALGORITH #define EMPTY_ALGORITH #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" #include "btCollisionCreateFunc.h" #include "btCollisionDispatcher.h" #define ATTRIBUTE_ALIGNED(a) ///EmptyAlgorithm is a stub for unsupported collision pairs. ///The dispatcher can dispatch a persistent btEmptyAlgorithm to avoid a search every frame. class btEmptyAlgorithm : public btCollisionAlgorithm { public: btEmptyAlgorithm(const btCollisionAlgorithmConstructionInfo& ci); virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual void getAllContactManifolds(btManifoldArray& manifoldArray) { } struct CreateFunc :public btCollisionAlgorithmCreateFunc { virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { (void)body0; (void)body1; void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btEmptyAlgorithm)); return new(mem) btEmptyAlgorithm(ci); } }; } ATTRIBUTE_ALIGNED(16); #endif //EMPTY_ALGORITH ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.hcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorit0000644000175000017500000000316511337071441033237 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com 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 __BT_ACTIVATING_COLLISION_ALGORITHM_H #define __BT_ACTIVATING_COLLISION_ALGORITHM_H #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" ///This class is not enabled yet (work-in-progress) to more aggressively activate objects. class btActivatingCollisionAlgorithm : public btCollisionAlgorithm { // btCollisionObject* m_colObj0; // btCollisionObject* m_colObj1; public: btActivatingCollisionAlgorithm (const btCollisionAlgorithmConstructionInfo& ci); btActivatingCollisionAlgorithm (const btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* colObj0,btCollisionObject* colObj1); virtual ~btActivatingCollisionAlgorithm(); }; #endif //__BT_ACTIVATING_COLLISION_ALGORITHM_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.h0000644000175000017500000001121411344267705032474 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 CONVEX_CONVEX_ALGORITHM_H #define CONVEX_CONVEX_ALGORITHM_H #include "btActivatingCollisionAlgorithm.h" #include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" #include "btCollisionCreateFunc.h" #include "btCollisionDispatcher.h" #include "LinearMath/btTransformUtil.h" //for btConvexSeparatingDistanceUtil class btConvexPenetrationDepthSolver; ///Enabling USE_SEPDISTANCE_UTIL2 requires 100% reliable distance computation. However, when using large size ratios GJK can be imprecise ///so the distance is not conservative. In that case, enabling this USE_SEPDISTANCE_UTIL2 would result in failing/missing collisions. ///Either improve GJK for large size ratios (testing a 100 units versus a 0.1 unit object) or only enable the util ///for certain pairs that have a small size ratio //#define USE_SEPDISTANCE_UTIL2 1 ///The convexConvexAlgorithm collision algorithm implements time of impact, convex closest points and penetration depth calculations between two convex objects. ///Multiple contact points are calculated by perturbing the orientation of the smallest object orthogonal to the separating normal. ///This idea was described by Gino van den Bergen in this forum topic http://www.bulletphysics.com/Bullet/phpBB3/viewtopic.php?f=4&t=288&p=888#p888 class btConvexConvexAlgorithm : public btActivatingCollisionAlgorithm { #ifdef USE_SEPDISTANCE_UTIL2 btConvexSeparatingDistanceUtil m_sepDistance; #endif btSimplexSolverInterface* m_simplexSolver; btConvexPenetrationDepthSolver* m_pdSolver; bool m_ownManifold; btPersistentManifold* m_manifoldPtr; bool m_lowLevelOfDetail; int m_numPerturbationIterations; int m_minimumPointsPerturbationThreshold; ///cache separating vector to speedup collision detection public: btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1, btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold); virtual ~btConvexConvexAlgorithm(); virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual void getAllContactManifolds(btManifoldArray& manifoldArray) { ///should we use m_ownManifold to avoid adding duplicates? if (m_manifoldPtr && m_ownManifold) manifoldArray.push_back(m_manifoldPtr); } void setLowLevelOfDetail(bool useLowLevel); const btPersistentManifold* getManifold() { return m_manifoldPtr; } struct CreateFunc :public btCollisionAlgorithmCreateFunc { btConvexPenetrationDepthSolver* m_pdSolver; btSimplexSolverInterface* m_simplexSolver; int m_numPerturbationIterations; int m_minimumPointsPerturbationThreshold; CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver); virtual ~CreateFunc(); virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexConvexAlgorithm)); return new(mem) btConvexConvexAlgorithm(ci.m_manifold,ci,body0,body1,m_simplexSolver,m_pdSolver,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold); } }; }; #endif //CONVEX_CONVEX_ALGORITHM_H ././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgor0000644000175000017500000000703711337071441033210 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btSphereSphereCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" btSphereSphereCollisionAlgorithm::btSphereSphereCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1) : btActivatingCollisionAlgorithm(ci,col0,col1), m_ownManifold(false), m_manifoldPtr(mf) { if (!m_manifoldPtr) { m_manifoldPtr = m_dispatcher->getNewManifold(col0,col1); m_ownManifold = true; } } btSphereSphereCollisionAlgorithm::~btSphereSphereCollisionAlgorithm() { if (m_ownManifold) { if (m_manifoldPtr) m_dispatcher->releaseManifold(m_manifoldPtr); } } void btSphereSphereCollisionAlgorithm::processCollision (btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { (void)dispatchInfo; if (!m_manifoldPtr) return; resultOut->setPersistentManifold(m_manifoldPtr); btSphereShape* sphere0 = (btSphereShape*)col0->getCollisionShape(); btSphereShape* sphere1 = (btSphereShape*)col1->getCollisionShape(); btVector3 diff = col0->getWorldTransform().getOrigin()- col1->getWorldTransform().getOrigin(); btScalar len = diff.length(); btScalar radius0 = sphere0->getRadius(); btScalar radius1 = sphere1->getRadius(); #ifdef CLEAR_MANIFOLD m_manifoldPtr->clearManifold(); //don't do this, it disables warmstarting #endif ///iff distance positive, don't generate a new contact if ( len > (radius0+radius1)) { #ifndef CLEAR_MANIFOLD resultOut->refreshContactPoints(); #endif //CLEAR_MANIFOLD return; } ///distance (negative means penetration) btScalar dist = len - (radius0+radius1); btVector3 normalOnSurfaceB(1,0,0); if (len > SIMD_EPSILON) { normalOnSurfaceB = diff / len; } ///point on A (worldspace) ///btVector3 pos0 = col0->getWorldTransform().getOrigin() - radius0 * normalOnSurfaceB; ///point on B (worldspace) btVector3 pos1 = col1->getWorldTransform().getOrigin() + radius1* normalOnSurfaceB; /// report a contact. internally this will be kept persistent, and contact reduction is done resultOut->addContactPoint(normalOnSurfaceB,pos1,dist); #ifndef CLEAR_MANIFOLD resultOut->refreshContactPoints(); #endif //CLEAR_MANIFOLD } btScalar btSphereSphereCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { (void)col0; (void)col1; (void)dispatchInfo; (void)resultOut; //not yet return btScalar(1.); } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btManifoldResult.h0000644000175000017500000000635111344267705031136 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 MANIFOLD_RESULT_H #define MANIFOLD_RESULT_H class btCollisionObject; #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" class btManifoldPoint; #include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" #include "LinearMath/btTransform.h" typedef bool (*ContactAddedCallback)(btManifoldPoint& cp, const btCollisionObject* colObj0,int partId0,int index0,const btCollisionObject* colObj1,int partId1,int index1); extern ContactAddedCallback gContactAddedCallback; //#define DEBUG_PART_INDEX 1 ///btManifoldResult is a helper class to manage contact results. class btManifoldResult : public btDiscreteCollisionDetectorInterface::Result { protected: btPersistentManifold* m_manifoldPtr; //we need this for compounds btTransform m_rootTransA; btTransform m_rootTransB; btCollisionObject* m_body0; btCollisionObject* m_body1; int m_partId0; int m_partId1; int m_index0; int m_index1; public: btManifoldResult() #ifdef DEBUG_PART_INDEX : m_partId0(-1), m_partId1(-1), m_index0(-1), m_index1(-1) #endif //DEBUG_PART_INDEX { } btManifoldResult(btCollisionObject* body0,btCollisionObject* body1); virtual ~btManifoldResult() {}; void setPersistentManifold(btPersistentManifold* manifoldPtr) { m_manifoldPtr = manifoldPtr; } const btPersistentManifold* getPersistentManifold() const { return m_manifoldPtr; } btPersistentManifold* getPersistentManifold() { return m_manifoldPtr; } virtual void setShapeIdentifiersA(int partId0,int index0) { m_partId0=partId0; m_index0=index0; } virtual void setShapeIdentifiersB( int partId1,int index1) { m_partId1=partId1; m_index1=index1; } virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth); SIMD_FORCE_INLINE void refreshContactPoints() { btAssert(m_manifoldPtr); if (!m_manifoldPtr->getNumContacts()) return; bool isSwapped = m_manifoldPtr->getBody0() != m_body0; if (isSwapped) { m_manifoldPtr->refreshContactPoints(m_rootTransB,m_rootTransA); } else { m_manifoldPtr->refreshContactPoints(m_rootTransA,m_rootTransB); } } const btCollisionObject* getBody0Internal() const { return m_body0; } const btCollisionObject* getBody1Internal() const { return m_body1; } }; #endif //MANIFOLD_RESULT_H ././@LongLink0000000000000000000000000000015700000000000011570 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlg0000644000175000017500000000627311337071441033167 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btSphereTriangleCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "SphereTriangleDetector.h" btSphereTriangleCollisionAlgorithm::btSphereTriangleCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1,bool swapped) : btActivatingCollisionAlgorithm(ci,col0,col1), m_ownManifold(false), m_manifoldPtr(mf), m_swapped(swapped) { if (!m_manifoldPtr) { m_manifoldPtr = m_dispatcher->getNewManifold(col0,col1); m_ownManifold = true; } } btSphereTriangleCollisionAlgorithm::~btSphereTriangleCollisionAlgorithm() { if (m_ownManifold) { if (m_manifoldPtr) m_dispatcher->releaseManifold(m_manifoldPtr); } } void btSphereTriangleCollisionAlgorithm::processCollision (btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { if (!m_manifoldPtr) return; btCollisionObject* sphereObj = m_swapped? col1 : col0; btCollisionObject* triObj = m_swapped? col0 : col1; btSphereShape* sphere = (btSphereShape*)sphereObj->getCollisionShape(); btTriangleShape* triangle = (btTriangleShape*)triObj->getCollisionShape(); /// report a contact. internally this will be kept persistent, and contact reduction is done resultOut->setPersistentManifold(m_manifoldPtr); SphereTriangleDetector detector(sphere,triangle, m_manifoldPtr->getContactBreakingThreshold()); btDiscreteCollisionDetectorInterface::ClosestPointInput input; input.m_maximumDistanceSquared = btScalar(BT_LARGE_FLOAT);///@todo: tighter bounds input.m_transformA = sphereObj->getWorldTransform(); input.m_transformB = triObj->getWorldTransform(); bool swapResults = m_swapped; detector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw,swapResults); if (m_ownManifold) resultOut->refreshContactPoints(); } btScalar btSphereTriangleCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { (void)resultOut; (void)dispatchInfo; (void)col0; (void)col1; //not yet return btScalar(1.); } ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.0000644000175000017500000002131011337071441032766 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btConvex2dConvex2dAlgorithm.h" //#include #include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionShapes/btConvexShape.h" #include "BulletCollision/CollisionShapes/btCapsuleShape.h" #include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/CollisionShapes/btBoxShape.h" #include "BulletCollision/CollisionDispatch/btManifoldResult.h" #include "BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h" #include "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h" #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" #include "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h" #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" #include "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h" #include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h" #include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h" btConvex2dConvex2dAlgorithm::CreateFunc::CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver) { m_numPerturbationIterations = 0; m_minimumPointsPerturbationThreshold = 3; m_simplexSolver = simplexSolver; m_pdSolver = pdSolver; } btConvex2dConvex2dAlgorithm::CreateFunc::~CreateFunc() { } btConvex2dConvex2dAlgorithm::btConvex2dConvex2dAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold) : btActivatingCollisionAlgorithm(ci,body0,body1), m_simplexSolver(simplexSolver), m_pdSolver(pdSolver), m_ownManifold (false), m_manifoldPtr(mf), m_lowLevelOfDetail(false), m_numPerturbationIterations(numPerturbationIterations), m_minimumPointsPerturbationThreshold(minimumPointsPerturbationThreshold) { (void)body0; (void)body1; } btConvex2dConvex2dAlgorithm::~btConvex2dConvex2dAlgorithm() { if (m_ownManifold) { if (m_manifoldPtr) m_dispatcher->releaseManifold(m_manifoldPtr); } } void btConvex2dConvex2dAlgorithm ::setLowLevelOfDetail(bool useLowLevel) { m_lowLevelOfDetail = useLowLevel; } extern btScalar gContactBreakingThreshold; // // Convex-Convex collision algorithm // void btConvex2dConvex2dAlgorithm ::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { if (!m_manifoldPtr) { //swapped? m_manifoldPtr = m_dispatcher->getNewManifold(body0,body1); m_ownManifold = true; } resultOut->setPersistentManifold(m_manifoldPtr); //comment-out next line to test multi-contact generation //resultOut->getPersistentManifold()->clearManifold(); btConvexShape* min0 = static_cast(body0->getCollisionShape()); btConvexShape* min1 = static_cast(body1->getCollisionShape()); btVector3 normalOnB; btVector3 pointOnBWorld; { btGjkPairDetector::ClosestPointInput input; btGjkPairDetector gjkPairDetector(min0,min1,m_simplexSolver,m_pdSolver); //TODO: if (dispatchInfo.m_useContinuous) gjkPairDetector.setMinkowskiA(min0); gjkPairDetector.setMinkowskiB(min1); { input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactBreakingThreshold(); input.m_maximumDistanceSquared*= input.m_maximumDistanceSquared; } input.m_stackAlloc = dispatchInfo.m_stackAllocator; input.m_transformA = body0->getWorldTransform(); input.m_transformB = body1->getWorldTransform(); gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); btVector3 v0,v1; btVector3 sepNormalWorldSpace; } if (m_ownManifold) { resultOut->refreshContactPoints(); } } btScalar btConvex2dConvex2dAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { (void)resultOut; (void)dispatchInfo; ///Rather then checking ALL pairs, only calculate TOI when motion exceeds threshold ///Linear motion for one of objects needs to exceed m_ccdSquareMotionThreshold ///col0->m_worldTransform, btScalar resultFraction = btScalar(1.); btScalar squareMot0 = (col0->getInterpolationWorldTransform().getOrigin() - col0->getWorldTransform().getOrigin()).length2(); btScalar squareMot1 = (col1->getInterpolationWorldTransform().getOrigin() - col1->getWorldTransform().getOrigin()).length2(); if (squareMot0 < col0->getCcdSquareMotionThreshold() && squareMot1 < col1->getCcdSquareMotionThreshold()) return resultFraction; //An adhoc way of testing the Continuous Collision Detection algorithms //One object is approximated as a sphere, to simplify things //Starting in penetration should report no time of impact //For proper CCD, better accuracy and handling of 'allowed' penetration should be added //also the mainloop of the physics should have a kind of toi queue (something like Brian Mirtich's application of Timewarp for Rigidbodies) /// Convex0 against sphere for Convex1 { btConvexShape* convex0 = static_cast(col0->getCollisionShape()); btSphereShape sphere1(col1->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation btConvexCast::CastResult result; btVoronoiSimplexSolver voronoiSimplex; //SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex); ///Simplification, one object is simplified as a sphere btGjkConvexCast ccd1( convex0 ,&sphere1,&voronoiSimplex); //ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0); if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(), col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result)) { //store result.m_fraction in both bodies if (col0->getHitFraction()> result.m_fraction) col0->setHitFraction( result.m_fraction ); if (col1->getHitFraction() > result.m_fraction) col1->setHitFraction( result.m_fraction); if (resultFraction > result.m_fraction) resultFraction = result.m_fraction; } } /// Sphere (for convex0) against Convex1 { btConvexShape* convex1 = static_cast(col1->getCollisionShape()); btSphereShape sphere0(col0->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation btConvexCast::CastResult result; btVoronoiSimplexSolver voronoiSimplex; //SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex); ///Simplification, one object is simplified as a sphere btGjkConvexCast ccd1(&sphere0,convex1,&voronoiSimplex); //ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0); if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(), col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result)) { //store result.m_fraction in both bodies if (col0->getHitFraction() > result.m_fraction) col0->setHitFraction( result.m_fraction); if (col1->getHitFraction() > result.m_fraction) col1->setHitFraction( result.m_fraction); if (resultFraction > result.m_fraction) resultFraction = result.m_fraction; } } return resultFraction; } ././@LongLink0000000000000000000000000000015000000000000011561 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.hcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorith0000644000175000017500000000630311337071441033212 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 SPHERE_BOX_COLLISION_ALGORITHM_H #define SPHERE_BOX_COLLISION_ALGORITHM_H #include "btActivatingCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" class btPersistentManifold; #include "btCollisionDispatcher.h" #include "LinearMath/btVector3.h" /// btSphereBoxCollisionAlgorithm provides sphere-box collision detection. /// Other features are frame-coherency (persistent data) and collision response. class btSphereBoxCollisionAlgorithm : public btActivatingCollisionAlgorithm { bool m_ownManifold; btPersistentManifold* m_manifoldPtr; bool m_isSwapped; public: btSphereBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped); virtual ~btSphereBoxCollisionAlgorithm(); virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual void getAllContactManifolds(btManifoldArray& manifoldArray) { if (m_manifoldPtr && m_ownManifold) { manifoldArray.push_back(m_manifoldPtr); } } btScalar getSphereDistance( btCollisionObject* boxObj,btVector3& v3PointOnBox, btVector3& v3PointOnSphere, const btVector3& v3SphereCenter, btScalar fRadius ); btScalar getSpherePenetration( btCollisionObject* boxObj, btVector3& v3PointOnBox, btVector3& v3PointOnSphere, const btVector3& v3SphereCenter, btScalar fRadius, const btVector3& aabbMin, const btVector3& aabbMax); struct CreateFunc :public btCollisionAlgorithmCreateFunc { virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btSphereBoxCollisionAlgorithm)); if (!m_swapped) { return new(mem) btSphereBoxCollisionAlgorithm(0,ci,body0,body1,false); } else { return new(mem) btSphereBoxCollisionAlgorithm(0,ci,body0,body1,true); } } }; }; #endif //SPHERE_BOX_COLLISION_ALGORITHM_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btCollisionObject.h0000644000175000017500000003260711344267705031273 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 COLLISION_OBJECT_H #define COLLISION_OBJECT_H #include "LinearMath/btTransform.h" //island management, m_activationState1 #define ACTIVE_TAG 1 #define ISLAND_SLEEPING 2 #define WANTS_DEACTIVATION 3 #define DISABLE_DEACTIVATION 4 #define DISABLE_SIMULATION 5 struct btBroadphaseProxy; class btCollisionShape; struct btCollisionShapeData; #include "LinearMath/btMotionState.h" #include "LinearMath/btAlignedAllocator.h" #include "LinearMath/btAlignedObjectArray.h" typedef btAlignedObjectArray btCollisionObjectArray; #ifdef BT_USE_DOUBLE_PRECISION #define btCollisionObjectData btCollisionObjectDoubleData #define btCollisionObjectDataName "btCollisionObjectDoubleData" #else #define btCollisionObjectData btCollisionObjectFloatData #define btCollisionObjectDataName "btCollisionObjectFloatData" #endif /// btCollisionObject can be used to manage collision detection objects. /// btCollisionObject maintains all information that is needed for a collision detection: Shape, Transform and AABB proxy. /// They can be added to the btCollisionWorld. ATTRIBUTE_ALIGNED16(class) btCollisionObject { protected: btTransform m_worldTransform; ///m_interpolationWorldTransform is used for CCD and interpolation ///it can be either previous or future (predicted) transform btTransform m_interpolationWorldTransform; //those two are experimental: just added for bullet time effect, so you can still apply impulses (directly modifying velocities) //without destroying the continuous interpolated motion (which uses this interpolation velocities) btVector3 m_interpolationLinearVelocity; btVector3 m_interpolationAngularVelocity; btVector3 m_anisotropicFriction; int m_hasAnisotropicFriction; btScalar m_contactProcessingThreshold; btBroadphaseProxy* m_broadphaseHandle; btCollisionShape* m_collisionShape; ///m_rootCollisionShape is temporarily used to store the original collision shape ///The m_collisionShape might be temporarily replaced by a child collision shape during collision detection purposes ///If it is NULL, the m_collisionShape is not temporarily replaced. btCollisionShape* m_rootCollisionShape; int m_collisionFlags; int m_islandTag1; int m_companionId; int m_activationState1; btScalar m_deactivationTime; btScalar m_friction; btScalar m_restitution; ///m_internalType is reserved to distinguish Bullet's btCollisionObject, btRigidBody, btSoftBody, btGhostObject etc. ///do not assign your own m_internalType unless you write a new dynamics object class. int m_internalType; ///users can point to their objects, m_userPointer is not used by Bullet, see setUserPointer/getUserPointer void* m_userObjectPointer; ///time of impact calculation btScalar m_hitFraction; ///Swept sphere radius (0.0 by default), see btConvexConvexAlgorithm:: btScalar m_ccdSweptSphereRadius; /// Don't do continuous collision detection if the motion (in one step) is less then m_ccdMotionThreshold btScalar m_ccdMotionThreshold; /// If some object should have elaborate collision filtering by sub-classes int m_checkCollideWith; virtual bool checkCollideWithOverride(btCollisionObject* /* co */) { return true; } public: BT_DECLARE_ALIGNED_ALLOCATOR(); enum CollisionFlags { CF_STATIC_OBJECT= 1, CF_KINEMATIC_OBJECT= 2, CF_NO_CONTACT_RESPONSE = 4, CF_CUSTOM_MATERIAL_CALLBACK = 8,//this allows per-triangle material (friction/restitution) CF_CHARACTER_OBJECT = 16, CF_DISABLE_VISUALIZE_OBJECT = 32, //disable debug drawing CF_DISABLE_SPU_COLLISION_PROCESSING = 64//disable parallel/SPU processing }; enum CollisionObjectTypes { CO_COLLISION_OBJECT =1, CO_RIGID_BODY, ///CO_GHOST_OBJECT keeps track of all objects overlapping its AABB and that pass its collision filter ///It is useful for collision sensors, explosion objects, character controller etc. CO_GHOST_OBJECT, CO_SOFT_BODY, CO_HF_FLUID }; SIMD_FORCE_INLINE bool mergesSimulationIslands() const { ///static objects, kinematic and object without contact response don't merge islands return ((m_collisionFlags & (CF_STATIC_OBJECT | CF_KINEMATIC_OBJECT | CF_NO_CONTACT_RESPONSE) )==0); } const btVector3& getAnisotropicFriction() const { return m_anisotropicFriction; } void setAnisotropicFriction(const btVector3& anisotropicFriction) { m_anisotropicFriction = anisotropicFriction; m_hasAnisotropicFriction = (anisotropicFriction[0]!=1.f) || (anisotropicFriction[1]!=1.f) || (anisotropicFriction[2]!=1.f); } bool hasAnisotropicFriction() const { return m_hasAnisotropicFriction!=0; } ///the constraint solver can discard solving contacts, if the distance is above this threshold. 0 by default. ///Note that using contacts with positive distance can improve stability. It increases, however, the chance of colliding with degerate contacts, such as 'interior' triangle edges void setContactProcessingThreshold( btScalar contactProcessingThreshold) { m_contactProcessingThreshold = contactProcessingThreshold; } btScalar getContactProcessingThreshold() const { return m_contactProcessingThreshold; } SIMD_FORCE_INLINE bool isStaticObject() const { return (m_collisionFlags & CF_STATIC_OBJECT) != 0; } SIMD_FORCE_INLINE bool isKinematicObject() const { return (m_collisionFlags & CF_KINEMATIC_OBJECT) != 0; } SIMD_FORCE_INLINE bool isStaticOrKinematicObject() const { return (m_collisionFlags & (CF_KINEMATIC_OBJECT | CF_STATIC_OBJECT)) != 0 ; } SIMD_FORCE_INLINE bool hasContactResponse() const { return (m_collisionFlags & CF_NO_CONTACT_RESPONSE)==0; } btCollisionObject(); virtual ~btCollisionObject(); virtual void setCollisionShape(btCollisionShape* collisionShape) { m_collisionShape = collisionShape; m_rootCollisionShape = collisionShape; } SIMD_FORCE_INLINE const btCollisionShape* getCollisionShape() const { return m_collisionShape; } SIMD_FORCE_INLINE btCollisionShape* getCollisionShape() { return m_collisionShape; } SIMD_FORCE_INLINE const btCollisionShape* getRootCollisionShape() const { return m_rootCollisionShape; } SIMD_FORCE_INLINE btCollisionShape* getRootCollisionShape() { return m_rootCollisionShape; } ///Avoid using this internal API call ///internalSetTemporaryCollisionShape is used to temporary replace the actual collision shape by a child collision shape. void internalSetTemporaryCollisionShape(btCollisionShape* collisionShape) { m_collisionShape = collisionShape; } SIMD_FORCE_INLINE int getActivationState() const { return m_activationState1;} void setActivationState(int newState); void setDeactivationTime(btScalar time) { m_deactivationTime = time; } btScalar getDeactivationTime() const { return m_deactivationTime; } void forceActivationState(int newState); void activate(bool forceActivation = false); SIMD_FORCE_INLINE bool isActive() const { return ((getActivationState() != ISLAND_SLEEPING) && (getActivationState() != DISABLE_SIMULATION)); } void setRestitution(btScalar rest) { m_restitution = rest; } btScalar getRestitution() const { return m_restitution; } void setFriction(btScalar frict) { m_friction = frict; } btScalar getFriction() const { return m_friction; } ///reserved for Bullet internal usage int getInternalType() const { return m_internalType; } btTransform& getWorldTransform() { return m_worldTransform; } const btTransform& getWorldTransform() const { return m_worldTransform; } void setWorldTransform(const btTransform& worldTrans) { m_worldTransform = worldTrans; } SIMD_FORCE_INLINE btBroadphaseProxy* getBroadphaseHandle() { return m_broadphaseHandle; } SIMD_FORCE_INLINE const btBroadphaseProxy* getBroadphaseHandle() const { return m_broadphaseHandle; } void setBroadphaseHandle(btBroadphaseProxy* handle) { m_broadphaseHandle = handle; } const btTransform& getInterpolationWorldTransform() const { return m_interpolationWorldTransform; } btTransform& getInterpolationWorldTransform() { return m_interpolationWorldTransform; } void setInterpolationWorldTransform(const btTransform& trans) { m_interpolationWorldTransform = trans; } void setInterpolationLinearVelocity(const btVector3& linvel) { m_interpolationLinearVelocity = linvel; } void setInterpolationAngularVelocity(const btVector3& angvel) { m_interpolationAngularVelocity = angvel; } const btVector3& getInterpolationLinearVelocity() const { return m_interpolationLinearVelocity; } const btVector3& getInterpolationAngularVelocity() const { return m_interpolationAngularVelocity; } SIMD_FORCE_INLINE int getIslandTag() const { return m_islandTag1; } void setIslandTag(int tag) { m_islandTag1 = tag; } SIMD_FORCE_INLINE int getCompanionId() const { return m_companionId; } void setCompanionId(int id) { m_companionId = id; } SIMD_FORCE_INLINE btScalar getHitFraction() const { return m_hitFraction; } void setHitFraction(btScalar hitFraction) { m_hitFraction = hitFraction; } SIMD_FORCE_INLINE int getCollisionFlags() const { return m_collisionFlags; } void setCollisionFlags(int flags) { m_collisionFlags = flags; } ///Swept sphere radius (0.0 by default), see btConvexConvexAlgorithm:: btScalar getCcdSweptSphereRadius() const { return m_ccdSweptSphereRadius; } ///Swept sphere radius (0.0 by default), see btConvexConvexAlgorithm:: void setCcdSweptSphereRadius(btScalar radius) { m_ccdSweptSphereRadius = radius; } btScalar getCcdMotionThreshold() const { return m_ccdMotionThreshold; } btScalar getCcdSquareMotionThreshold() const { return m_ccdMotionThreshold*m_ccdMotionThreshold; } /// Don't do continuous collision detection if the motion (in one step) is less then m_ccdMotionThreshold void setCcdMotionThreshold(btScalar ccdMotionThreshold) { m_ccdMotionThreshold = ccdMotionThreshold; } ///users can point to their objects, userPointer is not used by Bullet void* getUserPointer() const { return m_userObjectPointer; } ///users can point to their objects, userPointer is not used by Bullet void setUserPointer(void* userPointer) { m_userObjectPointer = userPointer; } inline bool checkCollideWith(btCollisionObject* co) { if (m_checkCollideWith) return checkCollideWithOverride(co); return true; } virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, class btSerializer* serializer) const; virtual void serializeSingleObject(class btSerializer* serializer) const; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btCollisionObjectDoubleData { void *m_broadphaseHandle; void *m_collisionShape; btCollisionShapeData *m_rootCollisionShape; char *m_name; btTransformDoubleData m_worldTransform; btTransformDoubleData m_interpolationWorldTransform; btVector3DoubleData m_interpolationLinearVelocity; btVector3DoubleData m_interpolationAngularVelocity; btVector3DoubleData m_anisotropicFriction; double m_contactProcessingThreshold; double m_deactivationTime; double m_friction; double m_restitution; double m_hitFraction; double m_ccdSweptSphereRadius; double m_ccdMotionThreshold; int m_hasAnisotropicFriction; int m_collisionFlags; int m_islandTag1; int m_companionId; int m_activationState1; int m_internalType; int m_checkCollideWith; char m_padding[4]; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btCollisionObjectFloatData { void *m_broadphaseHandle; void *m_collisionShape; btCollisionShapeData *m_rootCollisionShape; char *m_name; btTransformFloatData m_worldTransform; btTransformFloatData m_interpolationWorldTransform; btVector3FloatData m_interpolationLinearVelocity; btVector3FloatData m_interpolationAngularVelocity; btVector3FloatData m_anisotropicFriction; float m_contactProcessingThreshold; float m_deactivationTime; float m_friction; float m_restitution; float m_hitFraction; float m_ccdSweptSphereRadius; float m_ccdMotionThreshold; int m_hasAnisotropicFriction; int m_collisionFlags; int m_islandTag1; int m_companionId; int m_activationState1; int m_internalType; int m_checkCollideWith; }; SIMD_FORCE_INLINE int btCollisionObject::calculateSerializeBufferSize() const { return sizeof(btCollisionObjectData); } #endif //COLLISION_OBJECT_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btGhostObject.h0000644000175000017500000001277411344267705030427 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com 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 BT_GHOST_OBJECT_H #define BT_GHOST_OBJECT_H #include "btCollisionObject.h" #include "BulletCollision/BroadphaseCollision/btOverlappingPairCallback.h" #include "LinearMath/btAlignedAllocator.h" #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" #include "btCollisionWorld.h" class btConvexShape; class btDispatcher; ///The btGhostObject can keep track of all objects that are overlapping ///By default, this overlap is based on the AABB ///This is useful for creating a character controller, collision sensors/triggers, explosions etc. ///We plan on adding rayTest and other queries for the btGhostObject ATTRIBUTE_ALIGNED16(class) btGhostObject : public btCollisionObject { protected: btAlignedObjectArray m_overlappingObjects; public: btGhostObject(); virtual ~btGhostObject(); void convexSweepTest(const class btConvexShape* castShape, const btTransform& convexFromWorld, const btTransform& convexToWorld, btCollisionWorld::ConvexResultCallback& resultCallback, btScalar allowedCcdPenetration = 0.f) const; void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const; ///this method is mainly for expert/internal use only. virtual void addOverlappingObjectInternal(btBroadphaseProxy* otherProxy, btBroadphaseProxy* thisProxy=0); ///this method is mainly for expert/internal use only. virtual void removeOverlappingObjectInternal(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher,btBroadphaseProxy* thisProxy=0); int getNumOverlappingObjects() const { return m_overlappingObjects.size(); } btCollisionObject* getOverlappingObject(int index) { return m_overlappingObjects[index]; } const btCollisionObject* getOverlappingObject(int index) const { return m_overlappingObjects[index]; } btAlignedObjectArray& getOverlappingPairs() { return m_overlappingObjects; } const btAlignedObjectArray getOverlappingPairs() const { return m_overlappingObjects; } // // internal cast // static const btGhostObject* upcast(const btCollisionObject* colObj) { if (colObj->getInternalType()==CO_GHOST_OBJECT) return (const btGhostObject*)colObj; return 0; } static btGhostObject* upcast(btCollisionObject* colObj) { if (colObj->getInternalType()==CO_GHOST_OBJECT) return (btGhostObject*)colObj; return 0; } }; class btPairCachingGhostObject : public btGhostObject { btHashedOverlappingPairCache* m_hashPairCache; public: btPairCachingGhostObject(); virtual ~btPairCachingGhostObject(); ///this method is mainly for expert/internal use only. virtual void addOverlappingObjectInternal(btBroadphaseProxy* otherProxy, btBroadphaseProxy* thisProxy=0); virtual void removeOverlappingObjectInternal(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher,btBroadphaseProxy* thisProxy=0); btHashedOverlappingPairCache* getOverlappingPairCache() { return m_hashPairCache; } }; ///The btGhostPairCallback interfaces and forwards adding and removal of overlapping pairs from the btBroadphaseInterface to btGhostObject. class btGhostPairCallback : public btOverlappingPairCallback { public: btGhostPairCallback() { } virtual ~btGhostPairCallback() { } virtual btBroadphasePair* addOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1) { btCollisionObject* colObj0 = (btCollisionObject*) proxy0->m_clientObject; btCollisionObject* colObj1 = (btCollisionObject*) proxy1->m_clientObject; btGhostObject* ghost0 = btGhostObject::upcast(colObj0); btGhostObject* ghost1 = btGhostObject::upcast(colObj1); if (ghost0) ghost0->addOverlappingObjectInternal(proxy1, proxy0); if (ghost1) ghost1->addOverlappingObjectInternal(proxy0, proxy1); return 0; } virtual void* removeOverlappingPair(btBroadphaseProxy* proxy0,btBroadphaseProxy* proxy1,btDispatcher* dispatcher) { btCollisionObject* colObj0 = (btCollisionObject*) proxy0->m_clientObject; btCollisionObject* colObj1 = (btCollisionObject*) proxy1->m_clientObject; btGhostObject* ghost0 = btGhostObject::upcast(colObj0); btGhostObject* ghost1 = btGhostObject::upcast(colObj1); if (ghost0) ghost0->removeOverlappingObjectInternal(proxy1,dispatcher,proxy0); if (ghost1) ghost1->removeOverlappingObjectInternal(proxy0,dispatcher,proxy1); return 0; } virtual void removeOverlappingPairsContainingProxy(btBroadphaseProxy* proxy0,btDispatcher* dispatcher) { btAssert(0); //need to keep track of all ghost objects and call them here //m_hashPairCache->removeOverlappingPairsContainingProxy(proxy0,dispatcher); } }; #endif critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btCollisionDispatcher.cpp0000644000175000017500000002157311344267705032506 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btCollisionDispatcher.h" #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" #include "BulletCollision/CollisionShapes/btCollisionShape.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" #include "LinearMath/btPoolAllocator.h" #include "BulletCollision/CollisionDispatch/btCollisionConfiguration.h" int gNumManifold = 0; #ifdef BT_DEBUG #include #endif btCollisionDispatcher::btCollisionDispatcher (btCollisionConfiguration* collisionConfiguration): m_dispatcherFlags(btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESHOLD), m_collisionConfiguration(collisionConfiguration) { int i; setNearCallback(defaultNearCallback); m_collisionAlgorithmPoolAllocator = collisionConfiguration->getCollisionAlgorithmPool(); m_persistentManifoldPoolAllocator = collisionConfiguration->getPersistentManifoldPool(); for (i=0;igetCollisionAlgorithmCreateFunc(i,j); btAssert(m_doubleDispatch[i][j]); } } } void btCollisionDispatcher::registerCollisionCreateFunc(int proxyType0, int proxyType1, btCollisionAlgorithmCreateFunc *createFunc) { m_doubleDispatch[proxyType0][proxyType1] = createFunc; } btCollisionDispatcher::~btCollisionDispatcher() { } btPersistentManifold* btCollisionDispatcher::getNewManifold(void* b0,void* b1) { gNumManifold++; //btAssert(gNumManifold < 65535); btCollisionObject* body0 = (btCollisionObject*)b0; btCollisionObject* body1 = (btCollisionObject*)b1; //optional relative contact breaking threshold, turned on by default (use setDispatcherFlags to switch off feature for improved performance) btScalar contactBreakingThreshold = (m_dispatcherFlags & btCollisionDispatcher::CD_USE_RELATIVE_CONTACT_BREAKING_THRESHOLD) ? btMin(body0->getCollisionShape()->getContactBreakingThreshold(gContactBreakingThreshold) , body1->getCollisionShape()->getContactBreakingThreshold(gContactBreakingThreshold)) : gContactBreakingThreshold ; btScalar contactProcessingThreshold = btMin(body0->getContactProcessingThreshold(),body1->getContactProcessingThreshold()); void* mem = 0; if (m_persistentManifoldPoolAllocator->getFreeCount()) { mem = m_persistentManifoldPoolAllocator->allocate(sizeof(btPersistentManifold)); } else { mem = btAlignedAlloc(sizeof(btPersistentManifold),16); } btPersistentManifold* manifold = new(mem) btPersistentManifold (body0,body1,0,contactBreakingThreshold,contactProcessingThreshold); manifold->m_index1a = m_manifoldsPtr.size(); m_manifoldsPtr.push_back(manifold); return manifold; } void btCollisionDispatcher::clearManifold(btPersistentManifold* manifold) { manifold->clearManifold(); } void btCollisionDispatcher::releaseManifold(btPersistentManifold* manifold) { gNumManifold--; //printf("releaseManifold: gNumManifold %d\n",gNumManifold); clearManifold(manifold); int findIndex = manifold->m_index1a; btAssert(findIndex < m_manifoldsPtr.size()); m_manifoldsPtr.swap(findIndex,m_manifoldsPtr.size()-1); m_manifoldsPtr[findIndex]->m_index1a = findIndex; m_manifoldsPtr.pop_back(); manifold->~btPersistentManifold(); if (m_persistentManifoldPoolAllocator->validPtr(manifold)) { m_persistentManifoldPoolAllocator->freeMemory(manifold); } else { btAlignedFree(manifold); } } btCollisionAlgorithm* btCollisionDispatcher::findAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold) { btCollisionAlgorithmConstructionInfo ci; ci.m_dispatcher1 = this; ci.m_manifold = sharedManifold; btCollisionAlgorithm* algo = m_doubleDispatch[body0->getCollisionShape()->getShapeType()][body1->getCollisionShape()->getShapeType()]->CreateCollisionAlgorithm(ci,body0,body1); return algo; } bool btCollisionDispatcher::needsResponse(btCollisionObject* body0,btCollisionObject* body1) { //here you can do filtering bool hasResponse = (body0->hasContactResponse() && body1->hasContactResponse()); //no response between two static/kinematic bodies: hasResponse = hasResponse && ((!body0->isStaticOrKinematicObject()) ||(! body1->isStaticOrKinematicObject())); return hasResponse; } bool btCollisionDispatcher::needsCollision(btCollisionObject* body0,btCollisionObject* body1) { btAssert(body0); btAssert(body1); bool needsCollision = true; #ifdef BT_DEBUG if (!(m_dispatcherFlags & btCollisionDispatcher::CD_STATIC_STATIC_REPORTED)) { //broadphase filtering already deals with this if ((body0->isStaticObject() || body0->isKinematicObject()) && (body1->isStaticObject() || body1->isKinematicObject())) { m_dispatcherFlags |= btCollisionDispatcher::CD_STATIC_STATIC_REPORTED; printf("warning btCollisionDispatcher::needsCollision: static-static collision!\n"); } } #endif //BT_DEBUG if ((!body0->isActive()) && (!body1->isActive())) needsCollision = false; else if (!body0->checkCollideWith(body1)) needsCollision = false; return needsCollision ; } ///interface for iterating all overlapping collision pairs, no matter how those pairs are stored (array, set, map etc) ///this is useful for the collision dispatcher. class btCollisionPairCallback : public btOverlapCallback { const btDispatcherInfo& m_dispatchInfo; btCollisionDispatcher* m_dispatcher; public: btCollisionPairCallback(const btDispatcherInfo& dispatchInfo,btCollisionDispatcher* dispatcher) :m_dispatchInfo(dispatchInfo), m_dispatcher(dispatcher) { } /*btCollisionPairCallback& operator=(btCollisionPairCallback& other) { m_dispatchInfo = other.m_dispatchInfo; m_dispatcher = other.m_dispatcher; return *this; } */ virtual ~btCollisionPairCallback() {} virtual bool processOverlap(btBroadphasePair& pair) { (*m_dispatcher->getNearCallback())(pair,*m_dispatcher,m_dispatchInfo); return false; } }; void btCollisionDispatcher::dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher) { //m_blockedForChanges = true; btCollisionPairCallback collisionCallback(dispatchInfo,this); pairCache->processAllOverlappingPairs(&collisionCallback,dispatcher); //m_blockedForChanges = false; } //by default, Bullet will use this near callback void btCollisionDispatcher::defaultNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo) { btCollisionObject* colObj0 = (btCollisionObject*)collisionPair.m_pProxy0->m_clientObject; btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject; if (dispatcher.needsCollision(colObj0,colObj1)) { //dispatcher will keep algorithms persistent in the collision pair if (!collisionPair.m_algorithm) { collisionPair.m_algorithm = dispatcher.findAlgorithm(colObj0,colObj1); } if (collisionPair.m_algorithm) { btManifoldResult contactPointResult(colObj0,colObj1); if (dispatchInfo.m_dispatchFunc == btDispatcherInfo::DISPATCH_DISCRETE) { //discrete collision detection query collisionPair.m_algorithm->processCollision(colObj0,colObj1,dispatchInfo,&contactPointResult); } else { //continuous collision detection query, time of impact (toi) btScalar toi = collisionPair.m_algorithm->calculateTimeOfImpact(colObj0,colObj1,dispatchInfo,&contactPointResult); if (dispatchInfo.m_timeOfImpact > toi) dispatchInfo.m_timeOfImpact = toi; } } } } void* btCollisionDispatcher::allocateCollisionAlgorithm(int size) { if (m_collisionAlgorithmPoolAllocator->getFreeCount()) { return m_collisionAlgorithmPoolAllocator->allocate(size); } //warn user for overflow? return btAlignedAlloc(static_cast(size), 16); } void btCollisionDispatcher::freeCollisionAlgorithm(void* ptr) { if (m_collisionAlgorithmPoolAllocator->validPtr(ptr)) { m_collisionAlgorithmPoolAllocator->freeMemory(ptr); } else { btAlignedFree(ptr); } } ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btActivatingCollisionAlgorit0000644000175000017500000000333711337071441033240 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com 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 "btActivatingCollisionAlgorithm.h" #include "btCollisionDispatcher.h" #include "btCollisionObject.h" btActivatingCollisionAlgorithm::btActivatingCollisionAlgorithm (const btCollisionAlgorithmConstructionInfo& ci) :btCollisionAlgorithm(ci) //, //m_colObj0(0), //m_colObj1(0) { } btActivatingCollisionAlgorithm::btActivatingCollisionAlgorithm (const btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* colObj0,btCollisionObject* colObj1) :btCollisionAlgorithm(ci) //, //m_colObj0(0), //m_colObj1(0) { // if (ci.m_dispatcher1->needsCollision(colObj0,colObj1)) // { // m_colObj0 = colObj0; // m_colObj1 = colObj1; // // m_colObj0->activate(); // m_colObj1->activate(); // } } btActivatingCollisionAlgorithm::~btActivatingCollisionAlgorithm() { // m_colObj0->activate(); // m_colObj1->activate(); } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.h0000644000175000017500000000523611337071441033123 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BOX_BOX__COLLISION_ALGORITHM_H #define BOX_BOX__COLLISION_ALGORITHM_H #include "btActivatingCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/BroadphaseCollision/btDispatcher.h" #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" class btPersistentManifold; ///box-box collision detection class btBoxBoxCollisionAlgorithm : public btActivatingCollisionAlgorithm { bool m_ownManifold; btPersistentManifold* m_manifoldPtr; public: btBoxBoxCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) : btActivatingCollisionAlgorithm(ci) {} virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); btBoxBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1); virtual ~btBoxBoxCollisionAlgorithm(); virtual void getAllContactManifolds(btManifoldArray& manifoldArray) { if (m_manifoldPtr && m_ownManifold) { manifoldArray.push_back(m_manifoldPtr); } } struct CreateFunc :public btCollisionAlgorithmCreateFunc { virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { int bbsize = sizeof(btBoxBoxCollisionAlgorithm); void* ptr = ci.m_dispatcher1->allocateCollisionAlgorithm(bbsize); return new(ptr) btBoxBoxCollisionAlgorithm(0,ci,body0,body1); } }; }; #endif //BOX_BOX__COLLISION_ALGORITHM_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.cpp0000644000175000017500000014350211344267705031504 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btCollisionWorld.h" #include "btCollisionDispatcher.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionShapes/btCollisionShape.h" #include "BulletCollision/CollisionShapes/btConvexShape.h" #include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" //for raycasting #include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" //for raycasting #include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h" #include "BulletCollision/CollisionShapes/btCompoundShape.h" #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" #include "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h" #include "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h" #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" #include "LinearMath/btAabbUtil2.h" #include "LinearMath/btQuickprof.h" #include "LinearMath/btStackAlloc.h" #include "LinearMath/btSerializer.h" //#define USE_BRUTEFORCE_RAYBROADPHASE 1 //RECALCULATE_AABB is slower, but benefit is that you don't need to call 'stepSimulation' or 'updateAabbs' before using a rayTest //#define RECALCULATE_AABB_RAYCAST 1 //When the user doesn't provide dispatcher or broadphase, create basic versions (and delete them in destructor) #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/BroadphaseCollision/btSimpleBroadphase.h" #include "BulletCollision/CollisionDispatch/btCollisionConfiguration.h" ///for debug drawing //for debug rendering #include "BulletCollision/CollisionShapes/btBoxShape.h" #include "BulletCollision/CollisionShapes/btCapsuleShape.h" #include "BulletCollision/CollisionShapes/btCompoundShape.h" #include "BulletCollision/CollisionShapes/btConeShape.h" #include "BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h" #include "BulletCollision/CollisionShapes/btCylinderShape.h" #include "BulletCollision/CollisionShapes/btMultiSphereShape.h" #include "BulletCollision/CollisionShapes/btPolyhedralConvexShape.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" #include "BulletCollision/CollisionShapes/btTriangleCallback.h" #include "BulletCollision/CollisionShapes/btTriangleMeshShape.h" #include "BulletCollision/CollisionShapes/btStaticPlaneShape.h" btCollisionWorld::btCollisionWorld(btDispatcher* dispatcher,btBroadphaseInterface* pairCache, btCollisionConfiguration* collisionConfiguration) :m_dispatcher1(dispatcher), m_broadphasePairCache(pairCache), m_debugDrawer(0), m_forceUpdateAllAabbs(true) { m_stackAlloc = collisionConfiguration->getStackAllocator(); m_dispatchInfo.m_stackAllocator = m_stackAlloc; } btCollisionWorld::~btCollisionWorld() { //clean up remaining objects int i; for (i=0;igetBroadphaseHandle(); if (bp) { // // only clear the cached algorithms // getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(bp,m_dispatcher1); getBroadphase()->destroyProxy(bp,m_dispatcher1); collisionObject->setBroadphaseHandle(0); } } } void btCollisionWorld::addCollisionObject(btCollisionObject* collisionObject,short int collisionFilterGroup,short int collisionFilterMask) { btAssert(collisionObject); //check that the object isn't already added btAssert( m_collisionObjects.findLinearSearch(collisionObject) == m_collisionObjects.size()); m_collisionObjects.push_back(collisionObject); //calculate new AABB btTransform trans = collisionObject->getWorldTransform(); btVector3 minAabb; btVector3 maxAabb; collisionObject->getCollisionShape()->getAabb(trans,minAabb,maxAabb); int type = collisionObject->getCollisionShape()->getShapeType(); collisionObject->setBroadphaseHandle( getBroadphase()->createProxy( minAabb, maxAabb, type, collisionObject, collisionFilterGroup, collisionFilterMask, m_dispatcher1,0 )) ; } void btCollisionWorld::updateSingleAabb(btCollisionObject* colObj) { btVector3 minAabb,maxAabb; colObj->getCollisionShape()->getAabb(colObj->getWorldTransform(), minAabb,maxAabb); //need to increase the aabb for contact thresholds btVector3 contactThreshold(gContactBreakingThreshold,gContactBreakingThreshold,gContactBreakingThreshold); minAabb -= contactThreshold; maxAabb += contactThreshold; btBroadphaseInterface* bp = (btBroadphaseInterface*)m_broadphasePairCache; //moving objects should be moderately sized, probably something wrong if not if ( colObj->isStaticObject() || ((maxAabb-minAabb).length2() < btScalar(1e12))) { bp->setAabb(colObj->getBroadphaseHandle(),minAabb,maxAabb, m_dispatcher1); } else { //something went wrong, investigate //this assert is unwanted in 3D modelers (danger of loosing work) colObj->setActivationState(DISABLE_SIMULATION); static bool reportMe = true; if (reportMe && m_debugDrawer) { reportMe = false; m_debugDrawer->reportErrorWarning("Overflow in AABB, object removed from simulation"); m_debugDrawer->reportErrorWarning("If you can reproduce this, please email bugs@continuousphysics.com\n"); m_debugDrawer->reportErrorWarning("Please include above information, your Platform, version of OS.\n"); m_debugDrawer->reportErrorWarning("Thanks.\n"); } } } void btCollisionWorld::updateAabbs() { BT_PROFILE("updateAabbs"); btTransform predictedTrans; for ( int i=0;iisActive()) { updateSingleAabb(colObj); } } } void btCollisionWorld::performDiscreteCollisionDetection() { BT_PROFILE("performDiscreteCollisionDetection"); btDispatcherInfo& dispatchInfo = getDispatchInfo(); updateAabbs(); { BT_PROFILE("calculateOverlappingPairs"); m_broadphasePairCache->calculateOverlappingPairs(m_dispatcher1); } btDispatcher* dispatcher = getDispatcher(); { BT_PROFILE("dispatchAllCollisionPairs"); if (dispatcher) dispatcher->dispatchAllCollisionPairs(m_broadphasePairCache->getOverlappingPairCache(),dispatchInfo,m_dispatcher1); } } void btCollisionWorld::removeCollisionObject(btCollisionObject* collisionObject) { //bool removeFromBroadphase = false; { btBroadphaseProxy* bp = collisionObject->getBroadphaseHandle(); if (bp) { // // only clear the cached algorithms // getBroadphase()->getOverlappingPairCache()->cleanProxyFromPairs(bp,m_dispatcher1); getBroadphase()->destroyProxy(bp,m_dispatcher1); collisionObject->setBroadphaseHandle(0); } } //swapremove m_collisionObjects.remove(collisionObject); } void btCollisionWorld::rayTestSingle(const btTransform& rayFromTrans,const btTransform& rayToTrans, btCollisionObject* collisionObject, const btCollisionShape* collisionShape, const btTransform& colObjWorldTransform, RayResultCallback& resultCallback) { btSphereShape pointShape(btScalar(0.0)); pointShape.setMargin(0.f); const btConvexShape* castShape = &pointShape; if (collisionShape->isConvex()) { // BT_PROFILE("rayTestConvex"); btConvexCast::CastResult castResult; castResult.m_fraction = resultCallback.m_closestHitFraction; btConvexShape* convexShape = (btConvexShape*) collisionShape; btVoronoiSimplexSolver simplexSolver; #define USE_SUBSIMPLEX_CONVEX_CAST 1 #ifdef USE_SUBSIMPLEX_CONVEX_CAST btSubsimplexConvexCast convexCaster(castShape,convexShape,&simplexSolver); #else //btGjkConvexCast convexCaster(castShape,convexShape,&simplexSolver); //btContinuousConvexCollision convexCaster(castShape,convexShape,&simplexSolver,0); #endif //#USE_SUBSIMPLEX_CONVEX_CAST if (convexCaster.calcTimeOfImpact(rayFromTrans,rayToTrans,colObjWorldTransform,colObjWorldTransform,castResult)) { //add hit if (castResult.m_normal.length2() > btScalar(0.0001)) { if (castResult.m_fraction < resultCallback.m_closestHitFraction) { #ifdef USE_SUBSIMPLEX_CONVEX_CAST //rotate normal into worldspace castResult.m_normal = rayFromTrans.getBasis() * castResult.m_normal; #endif //USE_SUBSIMPLEX_CONVEX_CAST castResult.m_normal.normalize(); btCollisionWorld::LocalRayResult localRayResult ( collisionObject, 0, castResult.m_normal, castResult.m_fraction ); bool normalInWorldSpace = true; resultCallback.addSingleResult(localRayResult, normalInWorldSpace); } } } } else { if (collisionShape->isConcave()) { // BT_PROFILE("rayTestConcave"); if (collisionShape->getShapeType()==TRIANGLE_MESH_SHAPE_PROXYTYPE) { ///optimized version for btBvhTriangleMeshShape btBvhTriangleMeshShape* triangleMesh = (btBvhTriangleMeshShape*)collisionShape; btTransform worldTocollisionObject = colObjWorldTransform.inverse(); btVector3 rayFromLocal = worldTocollisionObject * rayFromTrans.getOrigin(); btVector3 rayToLocal = worldTocollisionObject * rayToTrans.getOrigin(); //ConvexCast::CastResult struct BridgeTriangleRaycastCallback : public btTriangleRaycastCallback { btCollisionWorld::RayResultCallback* m_resultCallback; btCollisionObject* m_collisionObject; btTriangleMeshShape* m_triangleMesh; btTransform m_colObjWorldTransform; BridgeTriangleRaycastCallback( const btVector3& from,const btVector3& to, btCollisionWorld::RayResultCallback* resultCallback, btCollisionObject* collisionObject,btTriangleMeshShape* triangleMesh,const btTransform& colObjWorldTransform): //@BP Mod btTriangleRaycastCallback(from,to, resultCallback->m_flags), m_resultCallback(resultCallback), m_collisionObject(collisionObject), m_triangleMesh(triangleMesh), m_colObjWorldTransform(colObjWorldTransform) { } virtual btScalar reportHit(const btVector3& hitNormalLocal, btScalar hitFraction, int partId, int triangleIndex ) { btCollisionWorld::LocalShapeInfo shapeInfo; shapeInfo.m_shapePart = partId; shapeInfo.m_triangleIndex = triangleIndex; btVector3 hitNormalWorld = m_colObjWorldTransform.getBasis() * hitNormalLocal; btCollisionWorld::LocalRayResult rayResult (m_collisionObject, &shapeInfo, hitNormalWorld, hitFraction); bool normalInWorldSpace = true; return m_resultCallback->addSingleResult(rayResult,normalInWorldSpace); } }; BridgeTriangleRaycastCallback rcb(rayFromLocal,rayToLocal,&resultCallback,collisionObject,triangleMesh,colObjWorldTransform); rcb.m_hitFraction = resultCallback.m_closestHitFraction; triangleMesh->performRaycast(&rcb,rayFromLocal,rayToLocal); } else { //generic (slower) case btConcaveShape* concaveShape = (btConcaveShape*)collisionShape; btTransform worldTocollisionObject = colObjWorldTransform.inverse(); btVector3 rayFromLocal = worldTocollisionObject * rayFromTrans.getOrigin(); btVector3 rayToLocal = worldTocollisionObject * rayToTrans.getOrigin(); //ConvexCast::CastResult struct BridgeTriangleRaycastCallback : public btTriangleRaycastCallback { btCollisionWorld::RayResultCallback* m_resultCallback; btCollisionObject* m_collisionObject; btConcaveShape* m_triangleMesh; btTransform m_colObjWorldTransform; BridgeTriangleRaycastCallback( const btVector3& from,const btVector3& to, btCollisionWorld::RayResultCallback* resultCallback, btCollisionObject* collisionObject,btConcaveShape* triangleMesh, const btTransform& colObjWorldTransform): //@BP Mod btTriangleRaycastCallback(from,to, resultCallback->m_flags), m_resultCallback(resultCallback), m_collisionObject(collisionObject), m_triangleMesh(triangleMesh), m_colObjWorldTransform(colObjWorldTransform) { } virtual btScalar reportHit(const btVector3& hitNormalLocal, btScalar hitFraction, int partId, int triangleIndex ) { btCollisionWorld::LocalShapeInfo shapeInfo; shapeInfo.m_shapePart = partId; shapeInfo.m_triangleIndex = triangleIndex; btVector3 hitNormalWorld = m_colObjWorldTransform.getBasis() * hitNormalLocal; btCollisionWorld::LocalRayResult rayResult (m_collisionObject, &shapeInfo, hitNormalWorld, hitFraction); bool normalInWorldSpace = true; return m_resultCallback->addSingleResult(rayResult,normalInWorldSpace); } }; BridgeTriangleRaycastCallback rcb(rayFromLocal,rayToLocal,&resultCallback,collisionObject,concaveShape, colObjWorldTransform); rcb.m_hitFraction = resultCallback.m_closestHitFraction; btVector3 rayAabbMinLocal = rayFromLocal; rayAabbMinLocal.setMin(rayToLocal); btVector3 rayAabbMaxLocal = rayFromLocal; rayAabbMaxLocal.setMax(rayToLocal); concaveShape->processAllTriangles(&rcb,rayAabbMinLocal,rayAabbMaxLocal); } } else { // BT_PROFILE("rayTestCompound"); ///@todo: use AABB tree or other BVH acceleration structure, see btDbvt if (collisionShape->isCompound()) { const btCompoundShape* compoundShape = static_cast(collisionShape); int i=0; for (i=0;igetNumChildShapes();i++) { btTransform childTrans = compoundShape->getChildTransform(i); const btCollisionShape* childCollisionShape = compoundShape->getChildShape(i); btTransform childWorldTrans = colObjWorldTransform * childTrans; // replace collision shape so that callback can determine the triangle btCollisionShape* saveCollisionShape = collisionObject->getCollisionShape(); collisionObject->internalSetTemporaryCollisionShape((btCollisionShape*)childCollisionShape); struct LocalInfoAdder2 : public RayResultCallback { int m_i; RayResultCallback* m_userCallback; LocalInfoAdder2 (int i, RayResultCallback *user) : m_i(i), m_userCallback(user) { } virtual btScalar addSingleResult (btCollisionWorld::LocalRayResult &r, bool b) { btCollisionWorld::LocalShapeInfo shapeInfo; shapeInfo.m_shapePart = -1; shapeInfo.m_triangleIndex = m_i; if (r.m_localShapeInfo == NULL) r.m_localShapeInfo = &shapeInfo; return m_userCallback->addSingleResult(r, b); } }; LocalInfoAdder2 my_cb(i, &resultCallback); my_cb.m_closestHitFraction = resultCallback.m_closestHitFraction; rayTestSingle(rayFromTrans,rayToTrans, collisionObject, childCollisionShape, childWorldTrans, my_cb); // restore collisionObject->internalSetTemporaryCollisionShape(saveCollisionShape); } } } } } void btCollisionWorld::objectQuerySingle(const btConvexShape* castShape,const btTransform& convexFromTrans,const btTransform& convexToTrans, btCollisionObject* collisionObject, const btCollisionShape* collisionShape, const btTransform& colObjWorldTransform, ConvexResultCallback& resultCallback, btScalar allowedPenetration) { if (collisionShape->isConvex()) { //BT_PROFILE("convexSweepConvex"); btConvexCast::CastResult castResult; castResult.m_allowedPenetration = allowedPenetration; castResult.m_fraction = resultCallback.m_closestHitFraction;//btScalar(1.);//?? btConvexShape* convexShape = (btConvexShape*) collisionShape; btVoronoiSimplexSolver simplexSolver; btGjkEpaPenetrationDepthSolver gjkEpaPenetrationSolver; btContinuousConvexCollision convexCaster1(castShape,convexShape,&simplexSolver,&gjkEpaPenetrationSolver); //btGjkConvexCast convexCaster2(castShape,convexShape,&simplexSolver); //btSubsimplexConvexCast convexCaster3(castShape,convexShape,&simplexSolver); btConvexCast* castPtr = &convexCaster1; if (castPtr->calcTimeOfImpact(convexFromTrans,convexToTrans,colObjWorldTransform,colObjWorldTransform,castResult)) { //add hit if (castResult.m_normal.length2() > btScalar(0.0001)) { if (castResult.m_fraction < resultCallback.m_closestHitFraction) { castResult.m_normal.normalize(); btCollisionWorld::LocalConvexResult localConvexResult ( collisionObject, 0, castResult.m_normal, castResult.m_hitPoint, castResult.m_fraction ); bool normalInWorldSpace = true; resultCallback.addSingleResult(localConvexResult, normalInWorldSpace); } } } } else { if (collisionShape->isConcave()) { if (collisionShape->getShapeType()==TRIANGLE_MESH_SHAPE_PROXYTYPE) { //BT_PROFILE("convexSweepbtBvhTriangleMesh"); btBvhTriangleMeshShape* triangleMesh = (btBvhTriangleMeshShape*)collisionShape; btTransform worldTocollisionObject = colObjWorldTransform.inverse(); btVector3 convexFromLocal = worldTocollisionObject * convexFromTrans.getOrigin(); btVector3 convexToLocal = worldTocollisionObject * convexToTrans.getOrigin(); // rotation of box in local mesh space = MeshRotation^-1 * ConvexToRotation btTransform rotationXform = btTransform(worldTocollisionObject.getBasis() * convexToTrans.getBasis()); //ConvexCast::CastResult struct BridgeTriangleConvexcastCallback : public btTriangleConvexcastCallback { btCollisionWorld::ConvexResultCallback* m_resultCallback; btCollisionObject* m_collisionObject; btTriangleMeshShape* m_triangleMesh; BridgeTriangleConvexcastCallback(const btConvexShape* castShape, const btTransform& from,const btTransform& to, btCollisionWorld::ConvexResultCallback* resultCallback, btCollisionObject* collisionObject,btTriangleMeshShape* triangleMesh, const btTransform& triangleToWorld): btTriangleConvexcastCallback(castShape, from,to, triangleToWorld, triangleMesh->getMargin()), m_resultCallback(resultCallback), m_collisionObject(collisionObject), m_triangleMesh(triangleMesh) { } virtual btScalar reportHit(const btVector3& hitNormalLocal, const btVector3& hitPointLocal, btScalar hitFraction, int partId, int triangleIndex ) { btCollisionWorld::LocalShapeInfo shapeInfo; shapeInfo.m_shapePart = partId; shapeInfo.m_triangleIndex = triangleIndex; if (hitFraction <= m_resultCallback->m_closestHitFraction) { btCollisionWorld::LocalConvexResult convexResult (m_collisionObject, &shapeInfo, hitNormalLocal, hitPointLocal, hitFraction); bool normalInWorldSpace = true; return m_resultCallback->addSingleResult(convexResult,normalInWorldSpace); } return hitFraction; } }; BridgeTriangleConvexcastCallback tccb(castShape, convexFromTrans,convexToTrans,&resultCallback,collisionObject,triangleMesh, colObjWorldTransform); tccb.m_hitFraction = resultCallback.m_closestHitFraction; btVector3 boxMinLocal, boxMaxLocal; castShape->getAabb(rotationXform, boxMinLocal, boxMaxLocal); triangleMesh->performConvexcast(&tccb,convexFromLocal,convexToLocal,boxMinLocal, boxMaxLocal); } else { //BT_PROFILE("convexSweepConcave"); btConcaveShape* concaveShape = (btConcaveShape*)collisionShape; btTransform worldTocollisionObject = colObjWorldTransform.inverse(); btVector3 convexFromLocal = worldTocollisionObject * convexFromTrans.getOrigin(); btVector3 convexToLocal = worldTocollisionObject * convexToTrans.getOrigin(); // rotation of box in local mesh space = MeshRotation^-1 * ConvexToRotation btTransform rotationXform = btTransform(worldTocollisionObject.getBasis() * convexToTrans.getBasis()); //ConvexCast::CastResult struct BridgeTriangleConvexcastCallback : public btTriangleConvexcastCallback { btCollisionWorld::ConvexResultCallback* m_resultCallback; btCollisionObject* m_collisionObject; btConcaveShape* m_triangleMesh; BridgeTriangleConvexcastCallback(const btConvexShape* castShape, const btTransform& from,const btTransform& to, btCollisionWorld::ConvexResultCallback* resultCallback, btCollisionObject* collisionObject,btConcaveShape* triangleMesh, const btTransform& triangleToWorld): btTriangleConvexcastCallback(castShape, from,to, triangleToWorld, triangleMesh->getMargin()), m_resultCallback(resultCallback), m_collisionObject(collisionObject), m_triangleMesh(triangleMesh) { } virtual btScalar reportHit(const btVector3& hitNormalLocal, const btVector3& hitPointLocal, btScalar hitFraction, int partId, int triangleIndex ) { btCollisionWorld::LocalShapeInfo shapeInfo; shapeInfo.m_shapePart = partId; shapeInfo.m_triangleIndex = triangleIndex; if (hitFraction <= m_resultCallback->m_closestHitFraction) { btCollisionWorld::LocalConvexResult convexResult (m_collisionObject, &shapeInfo, hitNormalLocal, hitPointLocal, hitFraction); bool normalInWorldSpace = false; return m_resultCallback->addSingleResult(convexResult,normalInWorldSpace); } return hitFraction; } }; BridgeTriangleConvexcastCallback tccb(castShape, convexFromTrans,convexToTrans,&resultCallback,collisionObject,concaveShape, colObjWorldTransform); tccb.m_hitFraction = resultCallback.m_closestHitFraction; btVector3 boxMinLocal, boxMaxLocal; castShape->getAabb(rotationXform, boxMinLocal, boxMaxLocal); btVector3 rayAabbMinLocal = convexFromLocal; rayAabbMinLocal.setMin(convexToLocal); btVector3 rayAabbMaxLocal = convexFromLocal; rayAabbMaxLocal.setMax(convexToLocal); rayAabbMinLocal += boxMinLocal; rayAabbMaxLocal += boxMaxLocal; concaveShape->processAllTriangles(&tccb,rayAabbMinLocal,rayAabbMaxLocal); } } else { ///@todo : use AABB tree or other BVH acceleration structure! if (collisionShape->isCompound()) { BT_PROFILE("convexSweepCompound"); const btCompoundShape* compoundShape = static_cast(collisionShape); int i=0; for (i=0;igetNumChildShapes();i++) { btTransform childTrans = compoundShape->getChildTransform(i); const btCollisionShape* childCollisionShape = compoundShape->getChildShape(i); btTransform childWorldTrans = colObjWorldTransform * childTrans; // replace collision shape so that callback can determine the triangle btCollisionShape* saveCollisionShape = collisionObject->getCollisionShape(); collisionObject->internalSetTemporaryCollisionShape((btCollisionShape*)childCollisionShape); struct LocalInfoAdder : public ConvexResultCallback { ConvexResultCallback* m_userCallback; int m_i; LocalInfoAdder (int i, ConvexResultCallback *user) : m_userCallback(user),m_i(i) { } virtual btScalar addSingleResult (btCollisionWorld::LocalConvexResult& r, bool b) { btCollisionWorld::LocalShapeInfo shapeInfo; shapeInfo.m_shapePart = -1; shapeInfo.m_triangleIndex = m_i; if (r.m_localShapeInfo == NULL) r.m_localShapeInfo = &shapeInfo; return m_userCallback->addSingleResult(r, b); } }; LocalInfoAdder my_cb(i, &resultCallback); my_cb.m_closestHitFraction = resultCallback.m_closestHitFraction; objectQuerySingle(castShape, convexFromTrans,convexToTrans, collisionObject, childCollisionShape, childWorldTrans, my_cb, allowedPenetration); // restore collisionObject->internalSetTemporaryCollisionShape(saveCollisionShape); } } } } } struct btSingleRayCallback : public btBroadphaseRayCallback { btVector3 m_rayFromWorld; btVector3 m_rayToWorld; btTransform m_rayFromTrans; btTransform m_rayToTrans; btVector3 m_hitNormal; const btCollisionWorld* m_world; btCollisionWorld::RayResultCallback& m_resultCallback; btSingleRayCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld,const btCollisionWorld* world,btCollisionWorld::RayResultCallback& resultCallback) :m_rayFromWorld(rayFromWorld), m_rayToWorld(rayToWorld), m_world(world), m_resultCallback(resultCallback) { m_rayFromTrans.setIdentity(); m_rayFromTrans.setOrigin(m_rayFromWorld); m_rayToTrans.setIdentity(); m_rayToTrans.setOrigin(m_rayToWorld); btVector3 rayDir = (rayToWorld-rayFromWorld); rayDir.normalize (); ///what about division by zero? --> just set rayDirection[i] to INF/BT_LARGE_FLOAT m_rayDirectionInverse[0] = rayDir[0] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[0]; m_rayDirectionInverse[1] = rayDir[1] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[1]; m_rayDirectionInverse[2] = rayDir[2] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[2]; m_signs[0] = m_rayDirectionInverse[0] < 0.0; m_signs[1] = m_rayDirectionInverse[1] < 0.0; m_signs[2] = m_rayDirectionInverse[2] < 0.0; m_lambda_max = rayDir.dot(m_rayToWorld-m_rayFromWorld); } virtual bool process(const btBroadphaseProxy* proxy) { ///terminate further ray tests, once the closestHitFraction reached zero if (m_resultCallback.m_closestHitFraction == btScalar(0.f)) return false; btCollisionObject* collisionObject = (btCollisionObject*)proxy->m_clientObject; //only perform raycast if filterMask matches if(m_resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) { //RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject(); //btVector3 collisionObjectAabbMin,collisionObjectAabbMax; #if 0 #ifdef RECALCULATE_AABB btVector3 collisionObjectAabbMin,collisionObjectAabbMax; collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax); #else //getBroadphase()->getAabb(collisionObject->getBroadphaseHandle(),collisionObjectAabbMin,collisionObjectAabbMax); const btVector3& collisionObjectAabbMin = collisionObject->getBroadphaseHandle()->m_aabbMin; const btVector3& collisionObjectAabbMax = collisionObject->getBroadphaseHandle()->m_aabbMax; #endif #endif //btScalar hitLambda = m_resultCallback.m_closestHitFraction; //culling already done by broadphase //if (btRayAabb(m_rayFromWorld,m_rayToWorld,collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,m_hitNormal)) { m_world->rayTestSingle(m_rayFromTrans,m_rayToTrans, collisionObject, collisionObject->getCollisionShape(), collisionObject->getWorldTransform(), m_resultCallback); } } return true; } }; void btCollisionWorld::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const { //BT_PROFILE("rayTest"); /// use the broadphase to accelerate the search for objects, based on their aabb /// and for each object with ray-aabb overlap, perform an exact ray test btSingleRayCallback rayCB(rayFromWorld,rayToWorld,this,resultCallback); #ifndef USE_BRUTEFORCE_RAYBROADPHASE m_broadphasePairCache->rayTest(rayFromWorld,rayToWorld,rayCB); #else for (int i=0;igetNumCollisionObjects();i++) { rayCB.process(m_collisionObjects[i]->getBroadphaseHandle()); } #endif //USE_BRUTEFORCE_RAYBROADPHASE } struct btSingleSweepCallback : public btBroadphaseRayCallback { btTransform m_convexFromTrans; btTransform m_convexToTrans; btVector3 m_hitNormal; const btCollisionWorld* m_world; btCollisionWorld::ConvexResultCallback& m_resultCallback; btScalar m_allowedCcdPenetration; const btConvexShape* m_castShape; btSingleSweepCallback(const btConvexShape* castShape, const btTransform& convexFromTrans,const btTransform& convexToTrans,const btCollisionWorld* world,btCollisionWorld::ConvexResultCallback& resultCallback,btScalar allowedPenetration) :m_convexFromTrans(convexFromTrans), m_convexToTrans(convexToTrans), m_world(world), m_resultCallback(resultCallback), m_allowedCcdPenetration(allowedPenetration), m_castShape(castShape) { btVector3 unnormalizedRayDir = (m_convexToTrans.getOrigin()-m_convexFromTrans.getOrigin()); btVector3 rayDir = unnormalizedRayDir.normalized(); ///what about division by zero? --> just set rayDirection[i] to INF/BT_LARGE_FLOAT m_rayDirectionInverse[0] = rayDir[0] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[0]; m_rayDirectionInverse[1] = rayDir[1] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[1]; m_rayDirectionInverse[2] = rayDir[2] == btScalar(0.0) ? btScalar(BT_LARGE_FLOAT) : btScalar(1.0) / rayDir[2]; m_signs[0] = m_rayDirectionInverse[0] < 0.0; m_signs[1] = m_rayDirectionInverse[1] < 0.0; m_signs[2] = m_rayDirectionInverse[2] < 0.0; m_lambda_max = rayDir.dot(unnormalizedRayDir); } virtual bool process(const btBroadphaseProxy* proxy) { ///terminate further convex sweep tests, once the closestHitFraction reached zero if (m_resultCallback.m_closestHitFraction == btScalar(0.f)) return false; btCollisionObject* collisionObject = (btCollisionObject*)proxy->m_clientObject; //only perform raycast if filterMask matches if(m_resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) { //RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject(); m_world->objectQuerySingle(m_castShape, m_convexFromTrans,m_convexToTrans, collisionObject, collisionObject->getCollisionShape(), collisionObject->getWorldTransform(), m_resultCallback, m_allowedCcdPenetration); } return true; } }; void btCollisionWorld::convexSweepTest(const btConvexShape* castShape, const btTransform& convexFromWorld, const btTransform& convexToWorld, ConvexResultCallback& resultCallback, btScalar allowedCcdPenetration) const { BT_PROFILE("convexSweepTest"); /// use the broadphase to accelerate the search for objects, based on their aabb /// and for each object with ray-aabb overlap, perform an exact ray test /// unfortunately the implementation for rayTest and convexSweepTest duplicated, albeit practically identical btTransform convexFromTrans,convexToTrans; convexFromTrans = convexFromWorld; convexToTrans = convexToWorld; btVector3 castShapeAabbMin, castShapeAabbMax; /* Compute AABB that encompasses angular movement */ { btVector3 linVel, angVel; btTransformUtil::calculateVelocity (convexFromTrans, convexToTrans, 1.0, linVel, angVel); btVector3 zeroLinVel; zeroLinVel.setValue(0,0,0); btTransform R; R.setIdentity (); R.setRotation (convexFromTrans.getRotation()); castShape->calculateTemporalAabb (R, zeroLinVel, angVel, 1.0, castShapeAabbMin, castShapeAabbMax); } #ifndef USE_BRUTEFORCE_RAYBROADPHASE btSingleSweepCallback convexCB(castShape,convexFromWorld,convexToWorld,this,resultCallback,allowedCcdPenetration); m_broadphasePairCache->rayTest(convexFromTrans.getOrigin(),convexToTrans.getOrigin(),convexCB,castShapeAabbMin,castShapeAabbMax); #else /// go over all objects, and if the ray intersects their aabb + cast shape aabb, // do a ray-shape query using convexCaster (CCD) int i; for (i=0;igetBroadphaseHandle())) { //RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject(); btVector3 collisionObjectAabbMin,collisionObjectAabbMax; collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax); AabbExpand (collisionObjectAabbMin, collisionObjectAabbMax, castShapeAabbMin, castShapeAabbMax); btScalar hitLambda = btScalar(1.); //could use resultCallback.m_closestHitFraction, but needs testing btVector3 hitNormal; if (btRayAabb(convexFromWorld.getOrigin(),convexToWorld.getOrigin(),collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,hitNormal)) { objectQuerySingle(castShape, convexFromTrans,convexToTrans, collisionObject, collisionObject->getCollisionShape(), collisionObject->getWorldTransform(), resultCallback, allowedCcdPenetration); } } } #endif //USE_BRUTEFORCE_RAYBROADPHASE } struct btBridgedManifoldResult : public btManifoldResult { btCollisionWorld::ContactResultCallback& m_resultCallback; btBridgedManifoldResult( btCollisionObject* obj0,btCollisionObject* obj1,btCollisionWorld::ContactResultCallback& resultCallback ) :btManifoldResult(obj0,obj1), m_resultCallback(resultCallback) { } virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth) { bool isSwapped = m_manifoldPtr->getBody0() != m_body0; btVector3 pointA = pointInWorld + normalOnBInWorld * depth; btVector3 localA; btVector3 localB; if (isSwapped) { localA = m_rootTransB.invXform(pointA ); localB = m_rootTransA.invXform(pointInWorld); } else { localA = m_rootTransA.invXform(pointA ); localB = m_rootTransB.invXform(pointInWorld); } btManifoldPoint newPt(localA,localB,normalOnBInWorld,depth); newPt.m_positionWorldOnA = pointA; newPt.m_positionWorldOnB = pointInWorld; //BP mod, store contact triangles. if (isSwapped) { newPt.m_partId0 = m_partId1; newPt.m_partId1 = m_partId0; newPt.m_index0 = m_index1; newPt.m_index1 = m_index0; } else { newPt.m_partId0 = m_partId0; newPt.m_partId1 = m_partId1; newPt.m_index0 = m_index0; newPt.m_index1 = m_index1; } //experimental feature info, for per-triangle material etc. btCollisionObject* obj0 = isSwapped? m_body1 : m_body0; btCollisionObject* obj1 = isSwapped? m_body0 : m_body1; m_resultCallback.addSingleResult(newPt,obj0,newPt.m_partId0,newPt.m_index0,obj1,newPt.m_partId1,newPt.m_index1); } }; struct btSingleContactCallback : public btBroadphaseAabbCallback { btCollisionObject* m_collisionObject; btCollisionWorld* m_world; btCollisionWorld::ContactResultCallback& m_resultCallback; btSingleContactCallback(btCollisionObject* collisionObject, btCollisionWorld* world,btCollisionWorld::ContactResultCallback& resultCallback) :m_collisionObject(collisionObject), m_world(world), m_resultCallback(resultCallback) { } virtual bool process(const btBroadphaseProxy* proxy) { btCollisionObject* collisionObject = (btCollisionObject*)proxy->m_clientObject; if (collisionObject == m_collisionObject) return true; //only perform raycast if filterMask matches if(m_resultCallback.needsCollision(collisionObject->getBroadphaseHandle())) { btCollisionAlgorithm* algorithm = m_world->getDispatcher()->findAlgorithm(m_collisionObject,collisionObject); if (algorithm) { btBridgedManifoldResult contactPointResult(m_collisionObject,collisionObject, m_resultCallback); //discrete collision detection query algorithm->processCollision(m_collisionObject,collisionObject, m_world->getDispatchInfo(),&contactPointResult); algorithm->~btCollisionAlgorithm(); m_world->getDispatcher()->freeCollisionAlgorithm(algorithm); } } return true; } }; ///contactTest performs a discrete collision test against all objects in the btCollisionWorld, and calls the resultCallback. ///it reports one or more contact points for every overlapping object (including the one with deepest penetration) void btCollisionWorld::contactTest( btCollisionObject* colObj, ContactResultCallback& resultCallback) { btVector3 aabbMin,aabbMax; colObj->getCollisionShape()->getAabb(colObj->getWorldTransform(),aabbMin,aabbMax); btSingleContactCallback contactCB(colObj,this,resultCallback); m_broadphasePairCache->aabbTest(aabbMin,aabbMax,contactCB); } ///contactTest performs a discrete collision test between two collision objects and calls the resultCallback if overlap if detected. ///it reports one or more contact points (including the one with deepest penetration) void btCollisionWorld::contactPairTest(btCollisionObject* colObjA, btCollisionObject* colObjB, ContactResultCallback& resultCallback) { btCollisionAlgorithm* algorithm = getDispatcher()->findAlgorithm(colObjA,colObjB); if (algorithm) { btBridgedManifoldResult contactPointResult(colObjA,colObjB, resultCallback); //discrete collision detection query algorithm->processCollision(colObjA,colObjB, getDispatchInfo(),&contactPointResult); algorithm->~btCollisionAlgorithm(); getDispatcher()->freeCollisionAlgorithm(algorithm); } } class DebugDrawcallback : public btTriangleCallback, public btInternalTriangleIndexCallback { btIDebugDraw* m_debugDrawer; btVector3 m_color; btTransform m_worldTrans; public: DebugDrawcallback(btIDebugDraw* debugDrawer,const btTransform& worldTrans,const btVector3& color) : m_debugDrawer(debugDrawer), m_color(color), m_worldTrans(worldTrans) { } virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex) { processTriangle(triangle,partId,triangleIndex); } virtual void processTriangle(btVector3* triangle,int partId, int triangleIndex) { (void)partId; (void)triangleIndex; btVector3 wv0,wv1,wv2; wv0 = m_worldTrans*triangle[0]; wv1 = m_worldTrans*triangle[1]; wv2 = m_worldTrans*triangle[2]; btVector3 center = (wv0+wv1+wv2)*btScalar(1./3.); btVector3 normal = (wv1-wv0).cross(wv2-wv0); normal.normalize(); btVector3 normalColor(1,1,0); m_debugDrawer->drawLine(center,center+normal,normalColor); m_debugDrawer->drawLine(wv0,wv1,m_color); m_debugDrawer->drawLine(wv1,wv2,m_color); m_debugDrawer->drawLine(wv2,wv0,m_color); } }; void btCollisionWorld::debugDrawObject(const btTransform& worldTransform, const btCollisionShape* shape, const btVector3& color) { // Draw a small simplex at the center of the object { btVector3 start = worldTransform.getOrigin(); getDebugDrawer()->drawLine(start, start+worldTransform.getBasis() * btVector3(1,0,0), btVector3(1,0,0)); getDebugDrawer()->drawLine(start, start+worldTransform.getBasis() * btVector3(0,1,0), btVector3(0,1,0)); getDebugDrawer()->drawLine(start, start+worldTransform.getBasis() * btVector3(0,0,1), btVector3(0,0,1)); } if (shape->getShapeType() == COMPOUND_SHAPE_PROXYTYPE) { const btCompoundShape* compoundShape = static_cast(shape); for (int i=compoundShape->getNumChildShapes()-1;i>=0;i--) { btTransform childTrans = compoundShape->getChildTransform(i); const btCollisionShape* colShape = compoundShape->getChildShape(i); debugDrawObject(worldTransform*childTrans,colShape,color); } } else { switch (shape->getShapeType()) { case BOX_SHAPE_PROXYTYPE: { const btBoxShape* boxShape = static_cast(shape); btVector3 halfExtents = boxShape->getHalfExtentsWithMargin(); getDebugDrawer()->drawBox(-halfExtents,halfExtents,worldTransform,color); break; } case SPHERE_SHAPE_PROXYTYPE: { const btSphereShape* sphereShape = static_cast(shape); btScalar radius = sphereShape->getMargin();//radius doesn't include the margin, so draw with margin getDebugDrawer()->drawSphere(radius, worldTransform, color); break; } case MULTI_SPHERE_SHAPE_PROXYTYPE: { const btMultiSphereShape* multiSphereShape = static_cast(shape); btTransform childTransform; childTransform.setIdentity(); for (int i = multiSphereShape->getSphereCount()-1; i>=0;i--) { childTransform.setOrigin(multiSphereShape->getSpherePosition(i)); getDebugDrawer()->drawSphere(multiSphereShape->getSphereRadius(i), worldTransform*childTransform, color); } break; } case CAPSULE_SHAPE_PROXYTYPE: { const btCapsuleShape* capsuleShape = static_cast(shape); btScalar radius = capsuleShape->getRadius(); btScalar halfHeight = capsuleShape->getHalfHeight(); int upAxis = capsuleShape->getUpAxis(); btVector3 capStart(0.f,0.f,0.f); capStart[upAxis] = -halfHeight; btVector3 capEnd(0.f,0.f,0.f); capEnd[upAxis] = halfHeight; // Draw the ends { btTransform childTransform = worldTransform; childTransform.getOrigin() = worldTransform * capStart; getDebugDrawer()->drawSphere(radius, childTransform, color); } { btTransform childTransform = worldTransform; childTransform.getOrigin() = worldTransform * capEnd; getDebugDrawer()->drawSphere(radius, childTransform, color); } // Draw some additional lines btVector3 start = worldTransform.getOrigin(); capStart[(upAxis+1)%3] = radius; capEnd[(upAxis+1)%3] = radius; getDebugDrawer()->drawLine(start+worldTransform.getBasis() * capStart,start+worldTransform.getBasis() * capEnd, color); capStart[(upAxis+1)%3] = -radius; capEnd[(upAxis+1)%3] = -radius; getDebugDrawer()->drawLine(start+worldTransform.getBasis() * capStart,start+worldTransform.getBasis() * capEnd, color); capStart[(upAxis+1)%3] = 0.f; capEnd[(upAxis+1)%3] = 0.f; capStart[(upAxis+2)%3] = radius; capEnd[(upAxis+2)%3] = radius; getDebugDrawer()->drawLine(start+worldTransform.getBasis() * capStart,start+worldTransform.getBasis() * capEnd, color); capStart[(upAxis+2)%3] = -radius; capEnd[(upAxis+2)%3] = -radius; getDebugDrawer()->drawLine(start+worldTransform.getBasis() * capStart,start+worldTransform.getBasis() * capEnd, color); break; } case CONE_SHAPE_PROXYTYPE: { const btConeShape* coneShape = static_cast(shape); btScalar radius = coneShape->getRadius();//+coneShape->getMargin(); btScalar height = coneShape->getHeight();//+coneShape->getMargin(); btVector3 start = worldTransform.getOrigin(); int upAxis= coneShape->getConeUpIndex(); btVector3 offsetHeight(0,0,0); offsetHeight[upAxis] = height * btScalar(0.5); btVector3 offsetRadius(0,0,0); offsetRadius[(upAxis+1)%3] = radius; btVector3 offset2Radius(0,0,0); offset2Radius[(upAxis+2)%3] = radius; getDebugDrawer()->drawLine(start+worldTransform.getBasis() * (offsetHeight),start+worldTransform.getBasis() * (-offsetHeight+offsetRadius),color); getDebugDrawer()->drawLine(start+worldTransform.getBasis() * (offsetHeight),start+worldTransform.getBasis() * (-offsetHeight-offsetRadius),color); getDebugDrawer()->drawLine(start+worldTransform.getBasis() * (offsetHeight),start+worldTransform.getBasis() * (-offsetHeight+offset2Radius),color); getDebugDrawer()->drawLine(start+worldTransform.getBasis() * (offsetHeight),start+worldTransform.getBasis() * (-offsetHeight-offset2Radius),color); break; } case CYLINDER_SHAPE_PROXYTYPE: { const btCylinderShape* cylinder = static_cast(shape); int upAxis = cylinder->getUpAxis(); btScalar radius = cylinder->getRadius(); btScalar halfHeight = cylinder->getHalfExtentsWithMargin()[upAxis]; btVector3 start = worldTransform.getOrigin(); btVector3 offsetHeight(0,0,0); offsetHeight[upAxis] = halfHeight; btVector3 offsetRadius(0,0,0); offsetRadius[(upAxis+1)%3] = radius; getDebugDrawer()->drawLine(start+worldTransform.getBasis() * (offsetHeight+offsetRadius),start+worldTransform.getBasis() * (-offsetHeight+offsetRadius),color); getDebugDrawer()->drawLine(start+worldTransform.getBasis() * (offsetHeight-offsetRadius),start+worldTransform.getBasis() * (-offsetHeight-offsetRadius),color); break; } case STATIC_PLANE_PROXYTYPE: { const btStaticPlaneShape* staticPlaneShape = static_cast(shape); btScalar planeConst = staticPlaneShape->getPlaneConstant(); const btVector3& planeNormal = staticPlaneShape->getPlaneNormal(); btVector3 planeOrigin = planeNormal * planeConst; btVector3 vec0,vec1; btPlaneSpace1(planeNormal,vec0,vec1); btScalar vecLen = 100.f; btVector3 pt0 = planeOrigin + vec0*vecLen; btVector3 pt1 = planeOrigin - vec0*vecLen; btVector3 pt2 = planeOrigin + vec1*vecLen; btVector3 pt3 = planeOrigin - vec1*vecLen; getDebugDrawer()->drawLine(worldTransform*pt0,worldTransform*pt1,color); getDebugDrawer()->drawLine(worldTransform*pt2,worldTransform*pt3,color); break; } default: { if (shape->isConcave()) { btConcaveShape* concaveMesh = (btConcaveShape*) shape; ///@todo pass camera, for some culling? no -> we are not a graphics lib btVector3 aabbMax(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); btVector3 aabbMin(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); DebugDrawcallback drawCallback(getDebugDrawer(),worldTransform,color); concaveMesh->processAllTriangles(&drawCallback,aabbMin,aabbMax); } if (shape->getShapeType() == CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE) { btConvexTriangleMeshShape* convexMesh = (btConvexTriangleMeshShape*) shape; //todo: pass camera for some culling btVector3 aabbMax(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); btVector3 aabbMin(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); //DebugDrawcallback drawCallback; DebugDrawcallback drawCallback(getDebugDrawer(),worldTransform,color); convexMesh->getMeshInterface()->InternalProcessAllTriangles(&drawCallback,aabbMin,aabbMax); } /// for polyhedral shapes if (shape->isPolyhedral()) { btPolyhedralConvexShape* polyshape = (btPolyhedralConvexShape*) shape; int i; for (i=0;igetNumEdges();i++) { btVector3 a,b; polyshape->getEdge(i,a,b); btVector3 wa = worldTransform * a; btVector3 wb = worldTransform * b; getDebugDrawer()->drawLine(wa,wb,color); } } } } } } void btCollisionWorld::debugDrawWorld() { if (getDebugDrawer() && getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawContactPoints) { int numManifolds = getDispatcher()->getNumManifolds(); btVector3 color(0,0,0); for (int i=0;igetManifoldByIndexInternal(i); //btCollisionObject* obA = static_cast(contactManifold->getBody0()); //btCollisionObject* obB = static_cast(contactManifold->getBody1()); int numContacts = contactManifold->getNumContacts(); for (int j=0;jgetContactPoint(j); getDebugDrawer()->drawContactPoint(cp.m_positionWorldOnB,cp.m_normalWorldOnB,cp.getDistance(),cp.getLifeTime(),color); } } } if (getDebugDrawer() && getDebugDrawer()->getDebugMode() & (btIDebugDraw::DBG_DrawWireframe | btIDebugDraw::DBG_DrawAabb)) { int i; for ( i=0;igetCollisionFlags() & btCollisionObject::CF_DISABLE_VISUALIZE_OBJECT)==0) { if (getDebugDrawer() && getDebugDrawer()->getDebugMode() & btIDebugDraw::DBG_DrawWireframe) { btVector3 color(btScalar(1.),btScalar(1.),btScalar(1.)); switch(colObj->getActivationState()) { case ACTIVE_TAG: color = btVector3(btScalar(1.),btScalar(1.),btScalar(1.)); break; case ISLAND_SLEEPING: color = btVector3(btScalar(0.),btScalar(1.),btScalar(0.));break; case WANTS_DEACTIVATION: color = btVector3(btScalar(0.),btScalar(1.),btScalar(1.));break; case DISABLE_DEACTIVATION: color = btVector3(btScalar(1.),btScalar(0.),btScalar(0.));break; case DISABLE_SIMULATION: color = btVector3(btScalar(1.),btScalar(1.),btScalar(0.));break; default: { color = btVector3(btScalar(1),btScalar(0.),btScalar(0.)); } }; debugDrawObject(colObj->getWorldTransform(),colObj->getCollisionShape(),color); } if (m_debugDrawer && (m_debugDrawer->getDebugMode() & btIDebugDraw::DBG_DrawAabb)) { btVector3 minAabb,maxAabb; btVector3 colorvec(1,0,0); colObj->getCollisionShape()->getAabb(colObj->getWorldTransform(), minAabb,maxAabb); m_debugDrawer->drawAabb(minAabb,maxAabb,colorvec); } } } } } void btCollisionWorld::serializeCollisionObjects(btSerializer* serializer) { int i; //serialize all collision objects for (i=0;igetInternalType() == btCollisionObject::CO_COLLISION_OBJECT) { colObj->serializeSingleObject(serializer); } } ///keep track of shapes already serialized btHashMap serializedShapes; for (i=0;igetCollisionShape(); if (!serializedShapes.find(shape)) { serializedShapes.insert(shape,shape); shape->serializeSingleShape(serializer); } } } void btCollisionWorld::serialize(btSerializer* serializer) { serializer->startSerialization(); serializeCollisionObjects(serializer); serializer->finishSerialization(); } ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btDefaultCollisionConfiguration.hcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btDefaultCollisionConfigurat0000644000175000017500000001200311344267705033231 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BT_DEFAULT_COLLISION_CONFIGURATION #define BT_DEFAULT_COLLISION_CONFIGURATION #include "btCollisionConfiguration.h" class btVoronoiSimplexSolver; class btConvexPenetrationDepthSolver; struct btDefaultCollisionConstructionInfo { btStackAlloc* m_stackAlloc; btPoolAllocator* m_persistentManifoldPool; btPoolAllocator* m_collisionAlgorithmPool; int m_defaultMaxPersistentManifoldPoolSize; int m_defaultMaxCollisionAlgorithmPoolSize; int m_customCollisionAlgorithmMaxElementSize; int m_defaultStackAllocatorSize; int m_useEpaPenetrationAlgorithm; btDefaultCollisionConstructionInfo() :m_stackAlloc(0), m_persistentManifoldPool(0), m_collisionAlgorithmPool(0), m_defaultMaxPersistentManifoldPoolSize(4096), m_defaultMaxCollisionAlgorithmPoolSize(4096), m_customCollisionAlgorithmMaxElementSize(0), m_defaultStackAllocatorSize(0), m_useEpaPenetrationAlgorithm(true) { } }; ///btCollisionConfiguration allows to configure Bullet collision detection ///stack allocator, pool memory allocators ///@todo: describe the meaning class btDefaultCollisionConfiguration : public btCollisionConfiguration { protected: int m_persistentManifoldPoolSize; btStackAlloc* m_stackAlloc; bool m_ownsStackAllocator; btPoolAllocator* m_persistentManifoldPool; bool m_ownsPersistentManifoldPool; btPoolAllocator* m_collisionAlgorithmPool; bool m_ownsCollisionAlgorithmPool; //default simplex/penetration depth solvers btVoronoiSimplexSolver* m_simplexSolver; btConvexPenetrationDepthSolver* m_pdSolver; //default CreationFunctions, filling the m_doubleDispatch table btCollisionAlgorithmCreateFunc* m_convexConvexCreateFunc; btCollisionAlgorithmCreateFunc* m_convexConcaveCreateFunc; btCollisionAlgorithmCreateFunc* m_swappedConvexConcaveCreateFunc; btCollisionAlgorithmCreateFunc* m_compoundCreateFunc; btCollisionAlgorithmCreateFunc* m_swappedCompoundCreateFunc; btCollisionAlgorithmCreateFunc* m_emptyCreateFunc; btCollisionAlgorithmCreateFunc* m_sphereSphereCF; #ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM btCollisionAlgorithmCreateFunc* m_sphereBoxCF; btCollisionAlgorithmCreateFunc* m_boxSphereCF; #endif //USE_BUGGY_SPHERE_BOX_ALGORITHM btCollisionAlgorithmCreateFunc* m_boxBoxCF; btCollisionAlgorithmCreateFunc* m_sphereTriangleCF; btCollisionAlgorithmCreateFunc* m_triangleSphereCF; btCollisionAlgorithmCreateFunc* m_planeConvexCF; btCollisionAlgorithmCreateFunc* m_convexPlaneCF; public: btDefaultCollisionConfiguration(const btDefaultCollisionConstructionInfo& constructionInfo = btDefaultCollisionConstructionInfo()); virtual ~btDefaultCollisionConfiguration(); ///memory pools virtual btPoolAllocator* getPersistentManifoldPool() { return m_persistentManifoldPool; } virtual btPoolAllocator* getCollisionAlgorithmPool() { return m_collisionAlgorithmPool; } virtual btStackAlloc* getStackAllocator() { return m_stackAlloc; } virtual btVoronoiSimplexSolver* getSimplexSolver() { return m_simplexSolver; } virtual btCollisionAlgorithmCreateFunc* getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1); ///Use this method to allow to generate multiple contact points between at once, between two objects using the generic convex-convex algorithm. ///By default, this feature is disabled for best performance. ///@param numPerturbationIterations controls the number of collision queries. Set it to zero to disable the feature. ///@param minimumPointsPerturbationThreshold is the minimum number of points in the contact cache, above which the feature is disabled ///3 is a good value for both params, if you want to enable the feature. This is because the default contact cache contains a maximum of 4 points, and one collision query at the unperturbed orientation is performed first. ///See Bullet/Demos/CollisionDemo for an example how this feature gathers multiple points. ///@todo we could add a per-object setting of those parameters, for level-of-detail collision detection. void setConvexConvexMultipointIterations(int numPerturbationIterations=3, int minimumPointsPerturbationThreshold = 3); }; #endif //BT_DEFAULT_COLLISION_CONFIGURATION ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorithm.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btSphereBoxCollisionAlgorith0000644000175000017500000001714411337071441033217 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btSphereBoxCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" #include "BulletCollision/CollisionShapes/btBoxShape.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" //#include btSphereBoxCollisionAlgorithm::btSphereBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped) : btActivatingCollisionAlgorithm(ci,col0,col1), m_ownManifold(false), m_manifoldPtr(mf), m_isSwapped(isSwapped) { btCollisionObject* sphereObj = m_isSwapped? col1 : col0; btCollisionObject* boxObj = m_isSwapped? col0 : col1; if (!m_manifoldPtr && m_dispatcher->needsCollision(sphereObj,boxObj)) { m_manifoldPtr = m_dispatcher->getNewManifold(sphereObj,boxObj); m_ownManifold = true; } } btSphereBoxCollisionAlgorithm::~btSphereBoxCollisionAlgorithm() { if (m_ownManifold) { if (m_manifoldPtr) m_dispatcher->releaseManifold(m_manifoldPtr); } } void btSphereBoxCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { (void)dispatchInfo; (void)resultOut; if (!m_manifoldPtr) return; btCollisionObject* sphereObj = m_isSwapped? body1 : body0; btCollisionObject* boxObj = m_isSwapped? body0 : body1; btSphereShape* sphere0 = (btSphereShape*)sphereObj->getCollisionShape(); btVector3 normalOnSurfaceB; btVector3 pOnBox,pOnSphere; btVector3 sphereCenter = sphereObj->getWorldTransform().getOrigin(); btScalar radius = sphere0->getRadius(); btScalar dist = getSphereDistance(boxObj,pOnBox,pOnSphere,sphereCenter,radius); resultOut->setPersistentManifold(m_manifoldPtr); if (dist < SIMD_EPSILON) { btVector3 normalOnSurfaceB = (pOnBox- pOnSphere).normalize(); /// report a contact. internally this will be kept persistent, and contact reduction is done resultOut->addContactPoint(normalOnSurfaceB,pOnBox,dist); } if (m_ownManifold) { if (m_manifoldPtr->getNumContacts()) { resultOut->refreshContactPoints(); } } } btScalar btSphereBoxCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { (void)resultOut; (void)dispatchInfo; (void)col0; (void)col1; //not yet return btScalar(1.); } btScalar btSphereBoxCollisionAlgorithm::getSphereDistance(btCollisionObject* boxObj, btVector3& pointOnBox, btVector3& v3PointOnSphere, const btVector3& sphereCenter, btScalar fRadius ) { btScalar margins; btVector3 bounds[2]; btBoxShape* boxShape= (btBoxShape*)boxObj->getCollisionShape(); bounds[0] = -boxShape->getHalfExtentsWithoutMargin(); bounds[1] = boxShape->getHalfExtentsWithoutMargin(); margins = boxShape->getMargin();//also add sphereShape margin? const btTransform& m44T = boxObj->getWorldTransform(); btVector3 boundsVec[2]; btScalar fPenetration; boundsVec[0] = bounds[0]; boundsVec[1] = bounds[1]; btVector3 marginsVec( margins, margins, margins ); // add margins bounds[0] += marginsVec; bounds[1] -= marginsVec; ///////////////////////////////////////////////// btVector3 tmp, prel, n[6], normal, v3P; btScalar fSep = btScalar(10000000.0), fSepThis; n[0].setValue( btScalar(-1.0), btScalar(0.0), btScalar(0.0) ); n[1].setValue( btScalar(0.0), btScalar(-1.0), btScalar(0.0) ); n[2].setValue( btScalar(0.0), btScalar(0.0), btScalar(-1.0) ); n[3].setValue( btScalar(1.0), btScalar(0.0), btScalar(0.0) ); n[4].setValue( btScalar(0.0), btScalar(1.0), btScalar(0.0) ); n[5].setValue( btScalar(0.0), btScalar(0.0), btScalar(1.0) ); // convert point in local space prel = m44T.invXform( sphereCenter); bool bFound = false; v3P = prel; for (int i=0;i<6;i++) { int j = i<3? 0:1; if ( (fSepThis = ((v3P-bounds[j]) .dot(n[i]))) > btScalar(0.0) ) { v3P = v3P - n[i]*fSepThis; bFound = true; } } // if ( bFound ) { bounds[0] = boundsVec[0]; bounds[1] = boundsVec[1]; normal = (prel - v3P).normalize(); pointOnBox = v3P + normal*margins; v3PointOnSphere = prel - normal*fRadius; if ( ((v3PointOnSphere - pointOnBox) .dot (normal)) > btScalar(0.0) ) { return btScalar(1.0); } // transform back in world space tmp = m44T( pointOnBox); pointOnBox = tmp; tmp = m44T( v3PointOnSphere); v3PointOnSphere = tmp; btScalar fSeps2 = (pointOnBox-v3PointOnSphere).length2(); //if this fails, fallback into deeper penetration case, below if (fSeps2 > SIMD_EPSILON) { fSep = - btSqrt(fSeps2); normal = (pointOnBox-v3PointOnSphere); normal *= btScalar(1.)/fSep; } return fSep; } ////////////////////////////////////////////////// // Deep penetration case fPenetration = getSpherePenetration( boxObj,pointOnBox, v3PointOnSphere, sphereCenter, fRadius,bounds[0],bounds[1] ); bounds[0] = boundsVec[0]; bounds[1] = boundsVec[1]; if ( fPenetration <= btScalar(0.0) ) return (fPenetration-margins); else return btScalar(1.0); } btScalar btSphereBoxCollisionAlgorithm::getSpherePenetration( btCollisionObject* boxObj,btVector3& pointOnBox, btVector3& v3PointOnSphere, const btVector3& sphereCenter, btScalar fRadius, const btVector3& aabbMin, const btVector3& aabbMax) { btVector3 bounds[2]; bounds[0] = aabbMin; bounds[1] = aabbMax; btVector3 p0, tmp, prel, n[6], normal; btScalar fSep = btScalar(-10000000.0), fSepThis; // set p0 and normal to a default value to shup up GCC p0.setValue(btScalar(0.), btScalar(0.), btScalar(0.)); normal.setValue(btScalar(0.), btScalar(0.), btScalar(0.)); n[0].setValue( btScalar(-1.0), btScalar(0.0), btScalar(0.0) ); n[1].setValue( btScalar(0.0), btScalar(-1.0), btScalar(0.0) ); n[2].setValue( btScalar(0.0), btScalar(0.0), btScalar(-1.0) ); n[3].setValue( btScalar(1.0), btScalar(0.0), btScalar(0.0) ); n[4].setValue( btScalar(0.0), btScalar(1.0), btScalar(0.0) ); n[5].setValue( btScalar(0.0), btScalar(0.0), btScalar(1.0) ); const btTransform& m44T = boxObj->getWorldTransform(); // convert point in local space prel = m44T.invXform( sphereCenter); /////////// for (int i=0;i<6;i++) { int j = i<3 ? 0:1; if ( (fSepThis = ((prel-bounds[j]) .dot( n[i]))-fRadius) > btScalar(0.0) ) return btScalar(1.0); if ( fSepThis > fSep ) { p0 = bounds[j]; normal = (btVector3&)n[i]; fSep = fSepThis; } } pointOnBox = prel - normal*(normal.dot((prel-p0))); v3PointOnSphere = pointOnBox + normal*fSep; // transform back in world space tmp = m44T( pointOnBox); pointOnBox = tmp; tmp = m44T( v3PointOnSphere); v3PointOnSphere = tmp; normal = (pointOnBox-v3PointOnSphere).normalize(); return fSep; } ././@LongLink0000000000000000000000000000015600000000000011567 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgorithm.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btConvexConcaveCollisionAlgo0000644000175000017500000002561411344267705033203 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btConvexConcaveCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionShapes/btMultiSphereShape.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/CollisionShapes/btConcaveShape.h" #include "BulletCollision/CollisionDispatch/btManifoldResult.h" #include "BulletCollision/NarrowPhaseCollision/btRaycastCallback.h" #include "BulletCollision/CollisionShapes/btTriangleShape.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" #include "LinearMath/btIDebugDraw.h" #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" btConvexConcaveCollisionAlgorithm::btConvexConcaveCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1,bool isSwapped) : btActivatingCollisionAlgorithm(ci,body0,body1), m_isSwapped(isSwapped), m_btConvexTriangleCallback(ci.m_dispatcher1,body0,body1,isSwapped) { } btConvexConcaveCollisionAlgorithm::~btConvexConcaveCollisionAlgorithm() { } void btConvexConcaveCollisionAlgorithm::getAllContactManifolds(btManifoldArray& manifoldArray) { if (m_btConvexTriangleCallback.m_manifoldPtr) { manifoldArray.push_back(m_btConvexTriangleCallback.m_manifoldPtr); } } btConvexTriangleCallback::btConvexTriangleCallback(btDispatcher* dispatcher,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped): m_dispatcher(dispatcher), m_dispatchInfoPtr(0) { m_convexBody = isSwapped? body1:body0; m_triBody = isSwapped? body0:body1; // // create the manifold from the dispatcher 'manifold pool' // m_manifoldPtr = m_dispatcher->getNewManifold(m_convexBody,m_triBody); clearCache(); } btConvexTriangleCallback::~btConvexTriangleCallback() { clearCache(); m_dispatcher->releaseManifold( m_manifoldPtr ); } void btConvexTriangleCallback::clearCache() { m_dispatcher->clearManifold(m_manifoldPtr); } void btConvexTriangleCallback::processTriangle(btVector3* triangle,int partId, int triangleIndex) { //just for debugging purposes //printf("triangle %d",m_triangleCount++); //aabb filter is already applied! btCollisionAlgorithmConstructionInfo ci; ci.m_dispatcher1 = m_dispatcher; btCollisionObject* ob = static_cast(m_triBody); ///debug drawing of the overlapping triangles if (m_dispatchInfoPtr && m_dispatchInfoPtr->m_debugDraw && (m_dispatchInfoPtr->m_debugDraw->getDebugMode() &btIDebugDraw::DBG_DrawWireframe )) { btVector3 color(1,1,0); btTransform& tr = ob->getWorldTransform(); m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[0]),tr(triangle[1]),color); m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[1]),tr(triangle[2]),color); m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[2]),tr(triangle[0]),color); //btVector3 center = triangle[0] + triangle[1]+triangle[2]; //center *= btScalar(0.333333); //m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[0]),tr(center),color); //m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[1]),tr(center),color); //m_dispatchInfoPtr->m_debugDraw->drawLine(tr(triangle[2]),tr(center),color); } //btCollisionObject* colObj = static_cast(m_convexProxy->m_clientObject); if (m_convexBody->getCollisionShape()->isConvex()) { btTriangleShape tm(triangle[0],triangle[1],triangle[2]); tm.setMargin(m_collisionMarginTriangle); btCollisionShape* tmpShape = ob->getCollisionShape(); ob->internalSetTemporaryCollisionShape( &tm ); btCollisionAlgorithm* colAlgo = ci.m_dispatcher1->findAlgorithm(m_convexBody,m_triBody,m_manifoldPtr); if (m_resultOut->getBody0Internal() == m_triBody) { m_resultOut->setShapeIdentifiersA(partId,triangleIndex); } else { m_resultOut->setShapeIdentifiersB(partId,triangleIndex); } colAlgo->processCollision(m_convexBody,m_triBody,*m_dispatchInfoPtr,m_resultOut); colAlgo->~btCollisionAlgorithm(); ci.m_dispatcher1->freeCollisionAlgorithm(colAlgo); ob->internalSetTemporaryCollisionShape( tmpShape); } } void btConvexTriangleCallback::setTimeStepAndCounters(btScalar collisionMarginTriangle,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { m_dispatchInfoPtr = &dispatchInfo; m_collisionMarginTriangle = collisionMarginTriangle; m_resultOut = resultOut; //recalc aabbs btTransform convexInTriangleSpace; convexInTriangleSpace = m_triBody->getWorldTransform().inverse() * m_convexBody->getWorldTransform(); btCollisionShape* convexShape = static_cast(m_convexBody->getCollisionShape()); //CollisionShape* triangleShape = static_cast(triBody->m_collisionShape); convexShape->getAabb(convexInTriangleSpace,m_aabbMin,m_aabbMax); btScalar extraMargin = collisionMarginTriangle; btVector3 extra(extraMargin,extraMargin,extraMargin); m_aabbMax += extra; m_aabbMin -= extra; } void btConvexConcaveCollisionAlgorithm::clearCache() { m_btConvexTriangleCallback.clearCache(); } void btConvexConcaveCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { btCollisionObject* convexBody = m_isSwapped ? body1 : body0; btCollisionObject* triBody = m_isSwapped ? body0 : body1; if (triBody->getCollisionShape()->isConcave()) { btCollisionObject* triOb = triBody; btConcaveShape* concaveShape = static_cast( triOb->getCollisionShape()); if (convexBody->getCollisionShape()->isConvex()) { btScalar collisionMarginTriangle = concaveShape->getMargin(); resultOut->setPersistentManifold(m_btConvexTriangleCallback.m_manifoldPtr); m_btConvexTriangleCallback.setTimeStepAndCounters(collisionMarginTriangle,dispatchInfo,resultOut); //Disable persistency. previously, some older algorithm calculated all contacts in one go, so you can clear it here. //m_dispatcher->clearManifold(m_btConvexTriangleCallback.m_manifoldPtr); m_btConvexTriangleCallback.m_manifoldPtr->setBodies(convexBody,triBody); concaveShape->processAllTriangles( &m_btConvexTriangleCallback,m_btConvexTriangleCallback.getAabbMin(),m_btConvexTriangleCallback.getAabbMax()); resultOut->refreshContactPoints(); } } } btScalar btConvexConcaveCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { (void)resultOut; (void)dispatchInfo; btCollisionObject* convexbody = m_isSwapped ? body1 : body0; btCollisionObject* triBody = m_isSwapped ? body0 : body1; //quick approximation using raycast, todo: hook up to the continuous collision detection (one of the btConvexCast) //only perform CCD above a certain threshold, this prevents blocking on the long run //because object in a blocked ccd state (hitfraction<1) get their linear velocity halved each frame... btScalar squareMot0 = (convexbody->getInterpolationWorldTransform().getOrigin() - convexbody->getWorldTransform().getOrigin()).length2(); if (squareMot0 < convexbody->getCcdSquareMotionThreshold()) { return btScalar(1.); } //const btVector3& from = convexbody->m_worldTransform.getOrigin(); //btVector3 to = convexbody->m_interpolationWorldTransform.getOrigin(); //todo: only do if the motion exceeds the 'radius' btTransform triInv = triBody->getWorldTransform().inverse(); btTransform convexFromLocal = triInv * convexbody->getWorldTransform(); btTransform convexToLocal = triInv * convexbody->getInterpolationWorldTransform(); struct LocalTriangleSphereCastCallback : public btTriangleCallback { btTransform m_ccdSphereFromTrans; btTransform m_ccdSphereToTrans; btTransform m_meshTransform; btScalar m_ccdSphereRadius; btScalar m_hitFraction; LocalTriangleSphereCastCallback(const btTransform& from,const btTransform& to,btScalar ccdSphereRadius,btScalar hitFraction) :m_ccdSphereFromTrans(from), m_ccdSphereToTrans(to), m_ccdSphereRadius(ccdSphereRadius), m_hitFraction(hitFraction) { } virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex) { (void)partId; (void)triangleIndex; //do a swept sphere for now btTransform ident; ident.setIdentity(); btConvexCast::CastResult castResult; castResult.m_fraction = m_hitFraction; btSphereShape pointShape(m_ccdSphereRadius); btTriangleShape triShape(triangle[0],triangle[1],triangle[2]); btVoronoiSimplexSolver simplexSolver; btSubsimplexConvexCast convexCaster(&pointShape,&triShape,&simplexSolver); //GjkConvexCast convexCaster(&pointShape,convexShape,&simplexSolver); //ContinuousConvexCollision convexCaster(&pointShape,convexShape,&simplexSolver,0); //local space? if (convexCaster.calcTimeOfImpact(m_ccdSphereFromTrans,m_ccdSphereToTrans, ident,ident,castResult)) { if (m_hitFraction > castResult.m_fraction) m_hitFraction = castResult.m_fraction; } } }; if (triBody->getCollisionShape()->isConcave()) { btVector3 rayAabbMin = convexFromLocal.getOrigin(); rayAabbMin.setMin(convexToLocal.getOrigin()); btVector3 rayAabbMax = convexFromLocal.getOrigin(); rayAabbMax.setMax(convexToLocal.getOrigin()); btScalar ccdRadius0 = convexbody->getCcdSweptSphereRadius(); rayAabbMin -= btVector3(ccdRadius0,ccdRadius0,ccdRadius0); rayAabbMax += btVector3(ccdRadius0,ccdRadius0,ccdRadius0); btScalar curHitFraction = btScalar(1.); //is this available? LocalTriangleSphereCastCallback raycastCallback(convexFromLocal,convexToLocal, convexbody->getCcdSweptSphereRadius(),curHitFraction); raycastCallback.m_hitFraction = convexbody->getHitFraction(); btCollisionObject* concavebody = triBody; btConcaveShape* triangleMesh = (btConcaveShape*) concavebody->getCollisionShape(); if (triangleMesh) { triangleMesh->processAllTriangles(&raycastCallback,rayAabbMin,rayAabbMax); } if (raycastCallback.m_hitFraction < convexbody->getHitFraction()) { convexbody->setHitFraction( raycastCallback.m_hitFraction); return raycastCallback.m_hitFraction; } } return btScalar(1.); } ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.hcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm0000644000175000017500000000712011337071441033252 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 COMPOUND_COLLISION_ALGORITHM_H #define COMPOUND_COLLISION_ALGORITHM_H #include "btActivatingCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btDispatcher.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" class btDispatcher; #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "btCollisionCreateFunc.h" #include "LinearMath/btAlignedObjectArray.h" class btDispatcher; class btCollisionObject; /// btCompoundCollisionAlgorithm supports collision between CompoundCollisionShapes and other collision shapes class btCompoundCollisionAlgorithm : public btActivatingCollisionAlgorithm { btAlignedObjectArray m_childCollisionAlgorithms; bool m_isSwapped; class btPersistentManifold* m_sharedManifold; bool m_ownsManifold; int m_compoundShapeRevision;//to keep track of changes, so that childAlgorithm array can be updated void removeChildAlgorithms(); void preallocateChildAlgorithms(btCollisionObject* body0,btCollisionObject* body1); public: btCompoundCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped); virtual ~btCompoundCollisionAlgorithm(); virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual void getAllContactManifolds(btManifoldArray& manifoldArray) { int i; for (i=0;igetAllContactManifolds(manifoldArray); } } struct CreateFunc :public btCollisionAlgorithmCreateFunc { virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btCompoundCollisionAlgorithm)); return new(mem) btCompoundCollisionAlgorithm(ci,body0,body1,false); } }; struct SwappedCreateFunc :public btCollisionAlgorithmCreateFunc { virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btCompoundCollisionAlgorithm)); return new(mem) btCompoundCollisionAlgorithm(ci,body0,body1,true); } }; }; #endif //COMPOUND_COLLISION_ALGORITHM_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btCollisionDispatcher.h0000644000175000017500000001142411344267705032145 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 COLLISION__DISPATCHER_H #define COLLISION__DISPATCHER_H #include "BulletCollision/BroadphaseCollision/btDispatcher.h" #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" #include "BulletCollision/CollisionDispatch/btManifoldResult.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "LinearMath/btAlignedObjectArray.h" class btIDebugDraw; class btOverlappingPairCache; class btPoolAllocator; class btCollisionConfiguration; #include "btCollisionCreateFunc.h" #define USE_DISPATCH_REGISTRY_ARRAY 1 class btCollisionDispatcher; ///user can override this nearcallback for collision filtering and more finegrained control over collision detection typedef void (*btNearCallback)(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo); ///btCollisionDispatcher supports algorithms that handle ConvexConvex and ConvexConcave collision pairs. ///Time of Impact, Closest Points and Penetration Depth. class btCollisionDispatcher : public btDispatcher { int m_dispatcherFlags; btAlignedObjectArray m_manifoldsPtr; btManifoldResult m_defaultManifoldResult; btNearCallback m_nearCallback; btPoolAllocator* m_collisionAlgorithmPoolAllocator; btPoolAllocator* m_persistentManifoldPoolAllocator; btCollisionAlgorithmCreateFunc* m_doubleDispatch[MAX_BROADPHASE_COLLISION_TYPES][MAX_BROADPHASE_COLLISION_TYPES]; btCollisionConfiguration* m_collisionConfiguration; public: enum DispatcherFlags { CD_STATIC_STATIC_REPORTED = 1, CD_USE_RELATIVE_CONTACT_BREAKING_THRESHOLD = 2 }; int getDispatherFlags() const { return m_dispatcherFlags; } void setDispatcherFlags(int flags) { (void) flags; m_dispatcherFlags = 0; } ///registerCollisionCreateFunc allows registration of custom/alternative collision create functions void registerCollisionCreateFunc(int proxyType0,int proxyType1, btCollisionAlgorithmCreateFunc* createFunc); int getNumManifolds() const { return int( m_manifoldsPtr.size()); } btPersistentManifold** getInternalManifoldPointer() { return &m_manifoldsPtr[0]; } btPersistentManifold* getManifoldByIndexInternal(int index) { return m_manifoldsPtr[index]; } const btPersistentManifold* getManifoldByIndexInternal(int index) const { return m_manifoldsPtr[index]; } btCollisionDispatcher (btCollisionConfiguration* collisionConfiguration); virtual ~btCollisionDispatcher(); virtual btPersistentManifold* getNewManifold(void* b0,void* b1); virtual void releaseManifold(btPersistentManifold* manifold); virtual void clearManifold(btPersistentManifold* manifold); btCollisionAlgorithm* findAlgorithm(btCollisionObject* body0,btCollisionObject* body1,btPersistentManifold* sharedManifold = 0); virtual bool needsCollision(btCollisionObject* body0,btCollisionObject* body1); virtual bool needsResponse(btCollisionObject* body0,btCollisionObject* body1); virtual void dispatchAllCollisionPairs(btOverlappingPairCache* pairCache,const btDispatcherInfo& dispatchInfo,btDispatcher* dispatcher) ; void setNearCallback(btNearCallback nearCallback) { m_nearCallback = nearCallback; } btNearCallback getNearCallback() const { return m_nearCallback; } //by default, Bullet will use this near callback static void defaultNearCallback(btBroadphasePair& collisionPair, btCollisionDispatcher& dispatcher, const btDispatcherInfo& dispatchInfo); virtual void* allocateCollisionAlgorithm(int size); virtual void freeCollisionAlgorithm(void* ptr); btCollisionConfiguration* getCollisionConfiguration() { return m_collisionConfiguration; } const btCollisionConfiguration* getCollisionConfiguration() const { return m_collisionConfiguration; } void setCollisionConfiguration(btCollisionConfiguration* config) { m_collisionConfiguration = config; } }; #endif //COLLISION__DISPATCHER_H ././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlgorithm.hcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btSphereTriangleCollisionAlg0000644000175000017500000000567411337071441033173 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 SPHERE_TRIANGLE_COLLISION_ALGORITHM_H #define SPHERE_TRIANGLE_COLLISION_ALGORITHM_H #include "btActivatingCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" class btPersistentManifold; #include "btCollisionDispatcher.h" /// btSphereSphereCollisionAlgorithm provides sphere-sphere collision detection. /// Other features are frame-coherency (persistent data) and collision response. /// Also provides the most basic sample for custom/user btCollisionAlgorithm class btSphereTriangleCollisionAlgorithm : public btActivatingCollisionAlgorithm { bool m_ownManifold; btPersistentManifold* m_manifoldPtr; bool m_swapped; public: btSphereTriangleCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool swapped); btSphereTriangleCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) : btActivatingCollisionAlgorithm(ci) {} virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual void getAllContactManifolds(btManifoldArray& manifoldArray) { if (m_manifoldPtr && m_ownManifold) { manifoldArray.push_back(m_manifoldPtr); } } virtual ~btSphereTriangleCollisionAlgorithm(); struct CreateFunc :public btCollisionAlgorithmCreateFunc { virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btSphereTriangleCollisionAlgorithm)); return new(mem) btSphereTriangleCollisionAlgorithm(ci.m_manifold,ci,body0,body1,m_swapped); } }; }; #endif //SPHERE_TRIANGLE_COLLISION_ALGORITHM_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btInternalEdgeUtility.h0000644000175000017500000000344611344271164032127 0ustar bobkebobke #ifndef BT_INTERNAL_EDGE_UTILITY_H #define BT_INTERNAL_EDGE_UTILITY_H #include "LinearMath/btHashMap.h" #include "LinearMath/btVector3.h" #include "BulletCollision/CollisionShapes/btTriangleInfoMap.h" ///The btInternalEdgeUtility helps to avoid or reduce artifacts due to wrong collision normals caused by internal edges. ///See also http://code.google.com/p/bullet/issues/detail?id=27 class btBvhTriangleMeshShape; class btCollisionObject; class btManifoldPoint; class btIDebugDraw; enum btInternalEdgeAdjustFlags { BT_TRIANGLE_CONVEX_BACKFACE_MODE = 1, BT_TRIANGLE_CONCAVE_DOUBLE_SIDED = 2, //double sided options are experimental, single sided is recommended BT_TRIANGLE_CONVEX_DOUBLE_SIDED = 4 }; ///Call btGenerateInternalEdgeInfo to create triangle info, store in the shape 'userInfo' void btGenerateInternalEdgeInfo (btBvhTriangleMeshShape*trimeshShape, btTriangleInfoMap* triangleInfoMap); ///Call the btFixMeshNormal to adjust the collision normal, using the triangle info map (generated using btGenerateInternalEdgeInfo) ///If this info map is missing, or the triangle is not store in this map, nothing will be done void btAdjustInternalEdgeContacts(btManifoldPoint& cp, const btCollisionObject* trimeshColObj0,const btCollisionObject* otherColObj1, int partId0, int index0, int normalAdjustFlags = 0); ///Enable the BT_INTERNAL_EDGE_DEBUG_DRAW define and call btSetDebugDrawer, to get visual info to see if the internal edge utility works properly. ///If the utility doesn't work properly, you might have to adjust the threshold values in btTriangleInfoMap //#define BT_INTERNAL_EDGE_DEBUG_DRAW #ifdef BT_INTERNAL_EDGE_DEBUG_DRAW void btSetDebugDrawer(btIDebugDraw* debugDrawer); #endif //BT_INTERNAL_EDGE_DEBUG_DRAW #endif //BT_INTERNAL_EDGE_UTILITY_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/SphereTriangleDetector.cpp0000644000175000017500000001443411337071441032612 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "LinearMath/btScalar.h" #include "SphereTriangleDetector.h" #include "BulletCollision/CollisionShapes/btTriangleShape.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" SphereTriangleDetector::SphereTriangleDetector(btSphereShape* sphere,btTriangleShape* triangle,btScalar contactBreakingThreshold) :m_sphere(sphere), m_triangle(triangle), m_contactBreakingThreshold(contactBreakingThreshold) { } void SphereTriangleDetector::getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults) { (void)debugDraw; const btTransform& transformA = input.m_transformA; const btTransform& transformB = input.m_transformB; btVector3 point,normal; btScalar timeOfImpact = btScalar(1.); btScalar depth = btScalar(0.); // output.m_distance = btScalar(BT_LARGE_FLOAT); //move sphere into triangle space btTransform sphereInTr = transformB.inverseTimes(transformA); if (collide(sphereInTr.getOrigin(),point,normal,depth,timeOfImpact,m_contactBreakingThreshold)) { if (swapResults) { btVector3 normalOnB = transformB.getBasis()*normal; btVector3 normalOnA = -normalOnB; btVector3 pointOnA = transformB*point+normalOnB*depth; output.addContactPoint(normalOnA,pointOnA,depth); } else { output.addContactPoint(transformB.getBasis()*normal,transformB*point,depth); } } } #define MAX_OVERLAP btScalar(0.) // See also geometrictools.com // Basic idea: D = |p - (lo + t0*lv)| where t0 = lv . (p - lo) / lv . lv btScalar SegmentSqrDistance(const btVector3& from, const btVector3& to,const btVector3 &p, btVector3 &nearest); btScalar SegmentSqrDistance(const btVector3& from, const btVector3& to,const btVector3 &p, btVector3 &nearest) { btVector3 diff = p - from; btVector3 v = to - from; btScalar t = v.dot(diff); if (t > 0) { btScalar dotVV = v.dot(v); if (t < dotVV) { t /= dotVV; diff -= t*v; } else { t = 1; diff -= v; } } else t = 0; nearest = from + t*v; return diff.dot(diff); } bool SphereTriangleDetector::facecontains(const btVector3 &p,const btVector3* vertices,btVector3& normal) { btVector3 lp(p); btVector3 lnormal(normal); return pointInTriangle(vertices, lnormal, &lp); } ///combined discrete/continuous sphere-triangle bool SphereTriangleDetector::collide(const btVector3& sphereCenter,btVector3 &point, btVector3& resultNormal, btScalar& depth, btScalar &timeOfImpact, btScalar contactBreakingThreshold) { const btVector3* vertices = &m_triangle->getVertexPtr(0); const btVector3& c = sphereCenter; btScalar r = m_sphere->getRadius(); btVector3 delta (0,0,0); btVector3 normal = (vertices[1]-vertices[0]).cross(vertices[2]-vertices[0]); normal.normalize(); btVector3 p1ToCentre = c - vertices[0]; btScalar distanceFromPlane = p1ToCentre.dot(normal); if (distanceFromPlane < btScalar(0.)) { //triangle facing the other way distanceFromPlane *= btScalar(-1.); normal *= btScalar(-1.); } btScalar contactMargin = contactBreakingThreshold; bool isInsideContactPlane = distanceFromPlane < r + contactMargin; bool isInsideShellPlane = distanceFromPlane < r; btScalar deltaDotNormal = delta.dot(normal); if (!isInsideShellPlane && deltaDotNormal >= btScalar(0.0)) return false; // Check for contact / intersection bool hasContact = false; btVector3 contactPoint; if (isInsideContactPlane) { if (facecontains(c,vertices,normal)) { // Inside the contact wedge - touches a point on the shell plane hasContact = true; contactPoint = c - normal*distanceFromPlane; } else { // Could be inside one of the contact capsules btScalar contactCapsuleRadiusSqr = (r + contactMargin) * (r + contactMargin); btVector3 nearestOnEdge; for (int i = 0; i < m_triangle->getNumEdges(); i++) { btVector3 pa; btVector3 pb; m_triangle->getEdge(i,pa,pb); btScalar distanceSqr = SegmentSqrDistance(pa,pb,c, nearestOnEdge); if (distanceSqr < contactCapsuleRadiusSqr) { // Yep, we're inside a capsule hasContact = true; contactPoint = nearestOnEdge; } } } } if (hasContact) { btVector3 contactToCentre = c - contactPoint; btScalar distanceSqr = contactToCentre.length2(); if (distanceSqr < (r - MAX_OVERLAP)*(r - MAX_OVERLAP)) { btScalar distance = btSqrt(distanceSqr); resultNormal = contactToCentre; resultNormal.normalize(); point = contactPoint; depth = -(r-distance); return true; } if (delta.dot(contactToCentre) >= btScalar(0.0)) return false; // Moving towards the contact point -> collision point = contactPoint; timeOfImpact = btScalar(0.0); return true; } return false; } bool SphereTriangleDetector::pointInTriangle(const btVector3 vertices[], const btVector3 &normal, btVector3 *p ) { const btVector3* p1 = &vertices[0]; const btVector3* p2 = &vertices[1]; const btVector3* p3 = &vertices[2]; btVector3 edge1( *p2 - *p1 ); btVector3 edge2( *p3 - *p2 ); btVector3 edge3( *p1 - *p3 ); btVector3 p1_to_p( *p - *p1 ); btVector3 p2_to_p( *p - *p2 ); btVector3 p3_to_p( *p - *p3 ); btVector3 edge1_normal( edge1.cross(normal)); btVector3 edge2_normal( edge2.cross(normal)); btVector3 edge3_normal( edge3.cross(normal)); btScalar r1, r2, r3; r1 = edge1_normal.dot( p1_to_p ); r2 = edge2_normal.dot( p2_to_p ); r3 = edge3_normal.dot( p3_to_p ); if ( ( r1 > 0 && r2 > 0 && r3 > 0 ) || ( r1 <= 0 && r2 <= 0 && r3 <= 0 ) ) return true; return false; } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btManifoldResult.cpp0000644000175000017500000001067211337071441031462 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btManifoldResult.h" #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" ///This is to allow MaterialCombiner/Custom Friction/Restitution values ContactAddedCallback gContactAddedCallback=0; ///User can override this material combiner by implementing gContactAddedCallback and setting body0->m_collisionFlags |= btCollisionObject::customMaterialCallback; inline btScalar calculateCombinedFriction(const btCollisionObject* body0,const btCollisionObject* body1) { btScalar friction = body0->getFriction() * body1->getFriction(); const btScalar MAX_FRICTION = btScalar(10.); if (friction < -MAX_FRICTION) friction = -MAX_FRICTION; if (friction > MAX_FRICTION) friction = MAX_FRICTION; return friction; } inline btScalar calculateCombinedRestitution(const btCollisionObject* body0,const btCollisionObject* body1) { return body0->getRestitution() * body1->getRestitution(); } btManifoldResult::btManifoldResult(btCollisionObject* body0,btCollisionObject* body1) :m_manifoldPtr(0), m_body0(body0), m_body1(body1) #ifdef DEBUG_PART_INDEX ,m_partId0(-1), m_partId1(-1), m_index0(-1), m_index1(-1) #endif //DEBUG_PART_INDEX { m_rootTransA = body0->getWorldTransform(); m_rootTransB = body1->getWorldTransform(); } void btManifoldResult::addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar depth) { btAssert(m_manifoldPtr); //order in manifold needs to match if (depth > m_manifoldPtr->getContactBreakingThreshold()) return; bool isSwapped = m_manifoldPtr->getBody0() != m_body0; btVector3 pointA = pointInWorld + normalOnBInWorld * depth; btVector3 localA; btVector3 localB; if (isSwapped) { localA = m_rootTransB.invXform(pointA ); localB = m_rootTransA.invXform(pointInWorld); } else { localA = m_rootTransA.invXform(pointA ); localB = m_rootTransB.invXform(pointInWorld); } btManifoldPoint newPt(localA,localB,normalOnBInWorld,depth); newPt.m_positionWorldOnA = pointA; newPt.m_positionWorldOnB = pointInWorld; int insertIndex = m_manifoldPtr->getCacheEntry(newPt); newPt.m_combinedFriction = calculateCombinedFriction(m_body0,m_body1); newPt.m_combinedRestitution = calculateCombinedRestitution(m_body0,m_body1); //BP mod, store contact triangles. if (isSwapped) { newPt.m_partId0 = m_partId1; newPt.m_partId1 = m_partId0; newPt.m_index0 = m_index1; newPt.m_index1 = m_index0; } else { newPt.m_partId0 = m_partId0; newPt.m_partId1 = m_partId1; newPt.m_index0 = m_index0; newPt.m_index1 = m_index1; } //printf("depth=%f\n",depth); ///@todo, check this for any side effects if (insertIndex >= 0) { //const btManifoldPoint& oldPoint = m_manifoldPtr->getContactPoint(insertIndex); m_manifoldPtr->replaceContactPoint(newPt,insertIndex); } else { insertIndex = m_manifoldPtr->addManifoldPoint(newPt); } //User can override friction and/or restitution if (gContactAddedCallback && //and if either of the two bodies requires custom material ((m_body0->getCollisionFlags() & btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK) || (m_body1->getCollisionFlags() & btCollisionObject::CF_CUSTOM_MATERIAL_CALLBACK))) { //experimental feature info, for per-triangle material etc. btCollisionObject* obj0 = isSwapped? m_body1 : m_body0; btCollisionObject* obj1 = isSwapped? m_body0 : m_body1; (*gContactAddedCallback)(m_manifoldPtr->getContactPoint(insertIndex),obj0,newPt.m_partId0,newPt.m_index0,obj1,newPt.m_partId1,newPt.m_index1); } } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btCollisionObject.cpp0000644000175000017500000001032311344267705031615 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btCollisionObject.h" #include "LinearMath/btSerializer.h" btCollisionObject::btCollisionObject() : m_anisotropicFriction(1.f,1.f,1.f), m_hasAnisotropicFriction(false), m_contactProcessingThreshold(BT_LARGE_FLOAT), m_broadphaseHandle(0), m_collisionShape(0), m_rootCollisionShape(0), m_collisionFlags(btCollisionObject::CF_STATIC_OBJECT), m_islandTag1(-1), m_companionId(-1), m_activationState1(1), m_deactivationTime(btScalar(0.)), m_friction(btScalar(0.5)), m_restitution(btScalar(0.)), m_internalType(CO_COLLISION_OBJECT), m_userObjectPointer(0), m_hitFraction(btScalar(1.)), m_ccdSweptSphereRadius(btScalar(0.)), m_ccdMotionThreshold(btScalar(0.)), m_checkCollideWith(false) { m_worldTransform.setIdentity(); } btCollisionObject::~btCollisionObject() { } void btCollisionObject::setActivationState(int newState) { if ( (m_activationState1 != DISABLE_DEACTIVATION) && (m_activationState1 != DISABLE_SIMULATION)) m_activationState1 = newState; } void btCollisionObject::forceActivationState(int newState) { m_activationState1 = newState; } void btCollisionObject::activate(bool forceActivation) { if (forceActivation || !(m_collisionFlags & (CF_STATIC_OBJECT|CF_KINEMATIC_OBJECT))) { setActivationState(ACTIVE_TAG); m_deactivationTime = btScalar(0.); } } const char* btCollisionObject::serialize(void* dataBuffer, btSerializer* serializer) const { btCollisionObjectData* dataOut = (btCollisionObjectData*)dataBuffer; m_worldTransform.serialize(dataOut->m_worldTransform); m_interpolationWorldTransform.serialize(dataOut->m_interpolationWorldTransform); m_interpolationLinearVelocity.serialize(dataOut->m_interpolationLinearVelocity); m_interpolationAngularVelocity.serialize(dataOut->m_interpolationAngularVelocity); m_anisotropicFriction.serialize(dataOut->m_anisotropicFriction); dataOut->m_hasAnisotropicFriction = m_hasAnisotropicFriction; dataOut->m_contactProcessingThreshold = m_contactProcessingThreshold; dataOut->m_broadphaseHandle = 0; dataOut->m_collisionShape = serializer->getUniquePointer(m_collisionShape); dataOut->m_rootCollisionShape = 0;//@todo dataOut->m_collisionFlags = m_collisionFlags; dataOut->m_islandTag1 = m_islandTag1; dataOut->m_companionId = m_companionId; dataOut->m_activationState1 = m_activationState1; dataOut->m_activationState1 = m_activationState1; dataOut->m_deactivationTime = m_deactivationTime; dataOut->m_friction = m_friction; dataOut->m_restitution = m_restitution; dataOut->m_internalType = m_internalType; char* name = (char*) serializer->findNameForPointer(this); dataOut->m_name = (char*)serializer->getUniquePointer(name); if (dataOut->m_name) { serializer->serializeName(name); } dataOut->m_hitFraction = m_hitFraction; dataOut->m_ccdSweptSphereRadius = m_ccdSweptSphereRadius; dataOut->m_ccdMotionThreshold = m_ccdMotionThreshold; dataOut->m_ccdMotionThreshold = m_ccdMotionThreshold; dataOut->m_checkCollideWith = m_checkCollideWith; return btCollisionObjectDataName; } void btCollisionObject::serializeSingleObject(class btSerializer* serializer) const { int len = calculateSerializeBufferSize(); btChunk* chunk = serializer->allocate(len,1); const char* structType = serialize(chunk->m_oldPtr, serializer); serializer->finalizeChunk(chunk,structType,BT_COLLISIONOBJECT_CODE,(void*)this); } ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btSimulationIslandManager.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btSimulationIslandManager.cp0000644000175000017500000002615711344267705033141 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "LinearMath/btScalar.h" #include "btSimulationIslandManager.h" #include "BulletCollision/BroadphaseCollision/btDispatcher.h" #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionDispatch/btCollisionWorld.h" //#include #include "LinearMath/btQuickprof.h" btSimulationIslandManager::btSimulationIslandManager(): m_splitIslands(true) { } btSimulationIslandManager::~btSimulationIslandManager() { } void btSimulationIslandManager::initUnionFind(int n) { m_unionFind.reset(n); } void btSimulationIslandManager::findUnions(btDispatcher* /* dispatcher */,btCollisionWorld* colWorld) { { btOverlappingPairCache* pairCachePtr = colWorld->getPairCache(); const int numOverlappingPairs = pairCachePtr->getNumOverlappingPairs(); btBroadphasePair* pairPtr = pairCachePtr->getOverlappingPairArrayPtr(); for (int i=0;im_clientObject; btCollisionObject* colObj1 = (btCollisionObject*)collisionPair.m_pProxy1->m_clientObject; if (((colObj0) && ((colObj0)->mergesSimulationIslands())) && ((colObj1) && ((colObj1)->mergesSimulationIslands()))) { m_unionFind.unite((colObj0)->getIslandTag(), (colObj1)->getIslandTag()); } } } } void btSimulationIslandManager::updateActivationState(btCollisionWorld* colWorld,btDispatcher* dispatcher) { initUnionFind( int (colWorld->getCollisionObjectArray().size())); // put the index into m_controllers into m_tag { int index = 0; int i; for (i=0;igetCollisionObjectArray().size(); i++) { btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i]; collisionObject->setIslandTag(index); collisionObject->setCompanionId(-1); collisionObject->setHitFraction(btScalar(1.)); index++; } } // do the union find findUnions(dispatcher,colWorld); } void btSimulationIslandManager::storeIslandActivationState(btCollisionWorld* colWorld) { // put the islandId ('find' value) into m_tag { int index = 0; int i; for (i=0;igetCollisionObjectArray().size();i++) { btCollisionObject* collisionObject= colWorld->getCollisionObjectArray()[i]; if (!collisionObject->isStaticOrKinematicObject()) { collisionObject->setIslandTag( m_unionFind.find(index) ); collisionObject->setCompanionId(-1); } else { collisionObject->setIslandTag(-1); collisionObject->setCompanionId(-2); } index++; } } } inline int getIslandId(const btPersistentManifold* lhs) { int islandId; const btCollisionObject* rcolObj0 = static_cast(lhs->getBody0()); const btCollisionObject* rcolObj1 = static_cast(lhs->getBody1()); islandId= rcolObj0->getIslandTag()>=0?rcolObj0->getIslandTag():rcolObj1->getIslandTag(); return islandId; } /// function object that routes calls to operator< class btPersistentManifoldSortPredicate { public: SIMD_FORCE_INLINE bool operator() ( const btPersistentManifold* lhs, const btPersistentManifold* rhs ) { return getIslandId(lhs) < getIslandId(rhs); } }; void btSimulationIslandManager::buildIslands(btDispatcher* dispatcher,btCollisionWorld* collisionWorld) { BT_PROFILE("islandUnionFindAndQuickSort"); btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray(); m_islandmanifold.resize(0); //we are going to sort the unionfind array, and store the element id in the size //afterwards, we clean unionfind, to make sure no-one uses it anymore getUnionFind().sortIslands(); int numElem = getUnionFind().getNumElements(); int endIslandIndex=1; int startIslandIndex; //update the sleeping state for bodies, if all are sleeping for ( startIslandIndex=0;startIslandIndexgetIslandTag() != islandId) && (colObj0->getIslandTag() != -1)) { // printf("error in island management\n"); } btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); if (colObj0->getIslandTag() == islandId) { if (colObj0->getActivationState()== ACTIVE_TAG) { allSleeping = false; } if (colObj0->getActivationState()== DISABLE_DEACTIVATION) { allSleeping = false; } } } if (allSleeping) { int idx; for (idx=startIslandIndex;idxgetIslandTag() != islandId) && (colObj0->getIslandTag() != -1)) { // printf("error in island management\n"); } btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); if (colObj0->getIslandTag() == islandId) { colObj0->setActivationState( ISLAND_SLEEPING ); } } } else { int idx; for (idx=startIslandIndex;idxgetIslandTag() != islandId) && (colObj0->getIslandTag() != -1)) { // printf("error in island management\n"); } btAssert((colObj0->getIslandTag() == islandId) || (colObj0->getIslandTag() == -1)); if (colObj0->getIslandTag() == islandId) { if ( colObj0->getActivationState() == ISLAND_SLEEPING) { colObj0->setActivationState( WANTS_DEACTIVATION); colObj0->setDeactivationTime(0.f); } } } } } int i; int maxNumManifolds = dispatcher->getNumManifolds(); //#define SPLIT_ISLANDS 1 //#ifdef SPLIT_ISLANDS //#endif //SPLIT_ISLANDS for (i=0;igetManifoldByIndexInternal(i); btCollisionObject* colObj0 = static_cast(manifold->getBody0()); btCollisionObject* colObj1 = static_cast(manifold->getBody1()); ///@todo: check sleeping conditions! if (((colObj0) && colObj0->getActivationState() != ISLAND_SLEEPING) || ((colObj1) && colObj1->getActivationState() != ISLAND_SLEEPING)) { //kinematic objects don't merge islands, but wake up all connected objects if (colObj0->isKinematicObject() && colObj0->getActivationState() != ISLAND_SLEEPING) { colObj1->activate(); } if (colObj1->isKinematicObject() && colObj1->getActivationState() != ISLAND_SLEEPING) { colObj0->activate(); } if(m_splitIslands) { //filtering for response if (dispatcher->needsResponse(colObj0,colObj1)) m_islandmanifold.push_back(manifold); } } } } ///@todo: this is random access, it can be walked 'cache friendly'! void btSimulationIslandManager::buildAndProcessIslands(btDispatcher* dispatcher,btCollisionWorld* collisionWorld, IslandCallback* callback) { btCollisionObjectArray& collisionObjects = collisionWorld->getCollisionObjectArray(); buildIslands(dispatcher,collisionWorld); int endIslandIndex=1; int startIslandIndex; int numElem = getUnionFind().getNumElements(); BT_PROFILE("processIslands"); if(!m_splitIslands) { btPersistentManifold** manifold = dispatcher->getInternalManifoldPointer(); int maxNumManifolds = dispatcher->getNumManifolds(); callback->ProcessIsland(&collisionObjects[0],collisionObjects.size(),manifold,maxNumManifolds, -1); } else { // Sort manifolds, based on islands // Sort the vector using predicate and std::sort //std::sort(islandmanifold.begin(), islandmanifold.end(), btPersistentManifoldSortPredicate); int numManifolds = int (m_islandmanifold.size()); //we should do radix sort, it it much faster (O(n) instead of O (n log2(n)) m_islandmanifold.quickSort(btPersistentManifoldSortPredicate()); //now process all active islands (sets of manifolds for now) int startManifoldIndex = 0; int endManifoldIndex = 1; //int islandId; // printf("Start Islands\n"); //traverse the simulation islands, and call the solver, unless all objects are sleeping/deactivated for ( startIslandIndex=0;startIslandIndexisActive()) islandSleeping = true; } //find the accompanying contact manifold for this islandId int numIslandManifolds = 0; btPersistentManifold** startManifold = 0; if (startManifoldIndexProcessIsland(&m_islandBodies[0],m_islandBodies.size(),startManifold,numIslandManifolds, islandId); // printf("Island callback of size:%d bodies, %d manifolds\n",islandBodies.size(),numIslandManifolds); } if (numIslandManifolds) { startManifoldIndex = endManifoldIndex; } m_islandBodies.resize(0); } } // else if(!splitIslands) } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btUnionFind.h0000644000175000017500000000632411344267705030077 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 UNION_FIND_H #define UNION_FIND_H #include "LinearMath/btAlignedObjectArray.h" #define USE_PATH_COMPRESSION 1 struct btElement { int m_id; int m_sz; }; ///UnionFind calculates connected subsets // Implements weighted Quick Union with path compression // optimization: could use short ints instead of ints (halving memory, would limit the number of rigid bodies to 64k, sounds reasonable) class btUnionFind { private: btAlignedObjectArray m_elements; public: btUnionFind(); ~btUnionFind(); //this is a special operation, destroying the content of btUnionFind. //it sorts the elements, based on island id, in order to make it easy to iterate over islands void sortIslands(); void reset(int N); SIMD_FORCE_INLINE int getNumElements() const { return int(m_elements.size()); } SIMD_FORCE_INLINE bool isRoot(int x) const { return (x == m_elements[x].m_id); } btElement& getElement(int index) { return m_elements[index]; } const btElement& getElement(int index) const { return m_elements[index]; } void allocate(int N); void Free(); int find(int p, int q) { return (find(p) == find(q)); } void unite(int p, int q) { int i = find(p), j = find(q); if (i == j) return; #ifndef USE_PATH_COMPRESSION //weighted quick union, this keeps the 'trees' balanced, and keeps performance of unite O( log(n) ) if (m_elements[i].m_sz < m_elements[j].m_sz) { m_elements[i].m_id = j; m_elements[j].m_sz += m_elements[i].m_sz; } else { m_elements[j].m_id = i; m_elements[i].m_sz += m_elements[j].m_sz; } #else m_elements[i].m_id = j; m_elements[j].m_sz += m_elements[i].m_sz; #endif //USE_PATH_COMPRESSION } int find(int x) { //btAssert(x < m_N); //btAssert(x >= 0); while (x != m_elements[x].m_id) { //not really a reason not to use path compression, and it flattens the trees/improves find performance dramatically #ifdef USE_PATH_COMPRESSION const btElement* elementPtr = &m_elements[m_elements[x].m_id]; m_elements[x].m_id = elementPtr->m_id; x = elementPtr->m_id; #else// x = m_elements[x].m_id; #endif //btAssert(x < m_N); //btAssert(x >= 0); } return x; } }; #endif //UNION_FIND_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btBoxBoxDetector.h0000644000175000017500000000355211337071441031071 0ustar bobkebobke/* * Box-Box collision detection re-distributed under the ZLib license with permission from Russell L. Smith * Original version is from Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * All rights reserved. Email: russ@q12.org Web: www.q12.org Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BOX_BOX_DETECTOR_H #define BOX_BOX_DETECTOR_H class btBoxShape; #include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" /// btBoxBoxDetector wraps the ODE box-box collision detector /// re-distributed under the Zlib license with permission from Russell L. Smith struct btBoxBoxDetector : public btDiscreteCollisionDetectorInterface { btBoxShape* m_box1; btBoxShape* m_box2; public: btBoxBoxDetector(btBoxShape* box1,btBoxShape* box2); virtual ~btBoxBoxDetector() {}; virtual void getClosestPoints(const ClosestPointInput& input,Result& output,class btIDebugDraw* debugDraw,bool swapResults=false); }; #endif //BT_BOX_BOX_DETECTOR_H ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm0000644000175000017500000003041611337071441033256 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "BulletCollision/CollisionDispatch/btCompoundCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionShapes/btCompoundShape.h" #include "BulletCollision/BroadphaseCollision/btDbvt.h" #include "LinearMath/btIDebugDraw.h" #include "LinearMath/btAabbUtil2.h" #include "btManifoldResult.h" btCompoundCollisionAlgorithm::btCompoundCollisionAlgorithm( const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,bool isSwapped) :btActivatingCollisionAlgorithm(ci,body0,body1), m_isSwapped(isSwapped), m_sharedManifold(ci.m_manifold) { m_ownsManifold = false; btCollisionObject* colObj = m_isSwapped? body1 : body0; btAssert (colObj->getCollisionShape()->isCompound()); btCompoundShape* compoundShape = static_cast(colObj->getCollisionShape()); m_compoundShapeRevision = compoundShape->getUpdateRevision(); preallocateChildAlgorithms(body0,body1); } void btCompoundCollisionAlgorithm::preallocateChildAlgorithms(btCollisionObject* body0,btCollisionObject* body1) { btCollisionObject* colObj = m_isSwapped? body1 : body0; btCollisionObject* otherObj = m_isSwapped? body0 : body1; btAssert (colObj->getCollisionShape()->isCompound()); btCompoundShape* compoundShape = static_cast(colObj->getCollisionShape()); int numChildren = compoundShape->getNumChildShapes(); int i; m_childCollisionAlgorithms.resize(numChildren); for (i=0;igetDynamicAabbTree()) { m_childCollisionAlgorithms[i] = 0; } else { btCollisionShape* tmpShape = colObj->getCollisionShape(); btCollisionShape* childShape = compoundShape->getChildShape(i); colObj->internalSetTemporaryCollisionShape( childShape ); m_childCollisionAlgorithms[i] = m_dispatcher->findAlgorithm(colObj,otherObj,m_sharedManifold); colObj->internalSetTemporaryCollisionShape( tmpShape ); } } } void btCompoundCollisionAlgorithm::removeChildAlgorithms() { int numChildren = m_childCollisionAlgorithms.size(); int i; for (i=0;i~btCollisionAlgorithm(); m_dispatcher->freeCollisionAlgorithm(m_childCollisionAlgorithms[i]); } } } btCompoundCollisionAlgorithm::~btCompoundCollisionAlgorithm() { removeChildAlgorithms(); } struct btCompoundLeafCallback : btDbvt::ICollide { public: btCollisionObject* m_compoundColObj; btCollisionObject* m_otherObj; btDispatcher* m_dispatcher; const btDispatcherInfo& m_dispatchInfo; btManifoldResult* m_resultOut; btCollisionAlgorithm** m_childCollisionAlgorithms; btPersistentManifold* m_sharedManifold; btCompoundLeafCallback (btCollisionObject* compoundObj,btCollisionObject* otherObj,btDispatcher* dispatcher,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut,btCollisionAlgorithm** childCollisionAlgorithms,btPersistentManifold* sharedManifold) :m_compoundColObj(compoundObj),m_otherObj(otherObj),m_dispatcher(dispatcher),m_dispatchInfo(dispatchInfo),m_resultOut(resultOut), m_childCollisionAlgorithms(childCollisionAlgorithms), m_sharedManifold(sharedManifold) { } void ProcessChildShape(btCollisionShape* childShape,int index) { btCompoundShape* compoundShape = static_cast(m_compoundColObj->getCollisionShape()); //backup btTransform orgTrans = m_compoundColObj->getWorldTransform(); btTransform orgInterpolationTrans = m_compoundColObj->getInterpolationWorldTransform(); const btTransform& childTrans = compoundShape->getChildTransform(index); btTransform newChildWorldTrans = orgTrans*childTrans ; //perform an AABB check first btVector3 aabbMin0,aabbMax0,aabbMin1,aabbMax1; childShape->getAabb(newChildWorldTrans,aabbMin0,aabbMax0); m_otherObj->getCollisionShape()->getAabb(m_otherObj->getWorldTransform(),aabbMin1,aabbMax1); if (TestAabbAgainstAabb2(aabbMin0,aabbMax0,aabbMin1,aabbMax1)) { m_compoundColObj->setWorldTransform( newChildWorldTrans); m_compoundColObj->setInterpolationWorldTransform(newChildWorldTrans); //the contactpoint is still projected back using the original inverted worldtrans btCollisionShape* tmpShape = m_compoundColObj->getCollisionShape(); m_compoundColObj->internalSetTemporaryCollisionShape( childShape ); if (!m_childCollisionAlgorithms[index]) m_childCollisionAlgorithms[index] = m_dispatcher->findAlgorithm(m_compoundColObj,m_otherObj,m_sharedManifold); ///detect swapping case if (m_resultOut->getBody0Internal() == m_compoundColObj) { m_resultOut->setShapeIdentifiersA(-1,index); } else { m_resultOut->setShapeIdentifiersB(-1,index); } m_childCollisionAlgorithms[index]->processCollision(m_compoundColObj,m_otherObj,m_dispatchInfo,m_resultOut); if (m_dispatchInfo.m_debugDraw && (m_dispatchInfo.m_debugDraw->getDebugMode() & btIDebugDraw::DBG_DrawAabb)) { btVector3 worldAabbMin,worldAabbMax; m_dispatchInfo.m_debugDraw->drawAabb(aabbMin0,aabbMax0,btVector3(1,1,1)); m_dispatchInfo.m_debugDraw->drawAabb(aabbMin1,aabbMax1,btVector3(1,1,1)); } //revert back transform m_compoundColObj->internalSetTemporaryCollisionShape( tmpShape); m_compoundColObj->setWorldTransform( orgTrans ); m_compoundColObj->setInterpolationWorldTransform(orgInterpolationTrans); } } void Process(const btDbvtNode* leaf) { int index = leaf->dataAsInt; btCompoundShape* compoundShape = static_cast(m_compoundColObj->getCollisionShape()); btCollisionShape* childShape = compoundShape->getChildShape(index); if (m_dispatchInfo.m_debugDraw && (m_dispatchInfo.m_debugDraw->getDebugMode() & btIDebugDraw::DBG_DrawAabb)) { btVector3 worldAabbMin,worldAabbMax; btTransform orgTrans = m_compoundColObj->getWorldTransform(); btTransformAabb(leaf->volume.Mins(),leaf->volume.Maxs(),0.,orgTrans,worldAabbMin,worldAabbMax); m_dispatchInfo.m_debugDraw->drawAabb(worldAabbMin,worldAabbMax,btVector3(1,0,0)); } ProcessChildShape(childShape,index); } }; void btCompoundCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { btCollisionObject* colObj = m_isSwapped? body1 : body0; btCollisionObject* otherObj = m_isSwapped? body0 : body1; btAssert (colObj->getCollisionShape()->isCompound()); btCompoundShape* compoundShape = static_cast(colObj->getCollisionShape()); ///btCompoundShape might have changed: ////make sure the internal child collision algorithm caches are still valid if (compoundShape->getUpdateRevision() != m_compoundShapeRevision) { ///clear and update all removeChildAlgorithms(); preallocateChildAlgorithms(body0,body1); } btDbvt* tree = compoundShape->getDynamicAabbTree(); //use a dynamic aabb tree to cull potential child-overlaps btCompoundLeafCallback callback(colObj,otherObj,m_dispatcher,dispatchInfo,resultOut,&m_childCollisionAlgorithms[0],m_sharedManifold); ///we need to refresh all contact manifolds ///note that we should actually recursively traverse all children, btCompoundShape can nested more then 1 level deep ///so we should add a 'refreshManifolds' in the btCollisionAlgorithm { int i; btManifoldArray manifoldArray; for (i=0;igetAllContactManifolds(manifoldArray); for (int m=0;mgetNumContacts()) { resultOut->setPersistentManifold(manifoldArray[m]); resultOut->refreshContactPoints(); resultOut->setPersistentManifold(0);//??necessary? } } manifoldArray.clear(); } } } if (tree) { btVector3 localAabbMin,localAabbMax; btTransform otherInCompoundSpace; otherInCompoundSpace = colObj->getWorldTransform().inverse() * otherObj->getWorldTransform(); otherObj->getCollisionShape()->getAabb(otherInCompoundSpace,localAabbMin,localAabbMax); const ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds=btDbvtVolume::FromMM(localAabbMin,localAabbMax); //process all children, that overlap with the given AABB bounds tree->collideTV(tree->m_root,bounds,callback); } else { //iterate over all children, perform an AABB check inside ProcessChildShape int numChildren = m_childCollisionAlgorithms.size(); int i; for (i=0;igetChildShape(i),i); } } { //iterate over all children, perform an AABB check inside ProcessChildShape int numChildren = m_childCollisionAlgorithms.size(); int i; btManifoldArray manifoldArray; for (i=0;igetChildShape(i); //if not longer overlapping, remove the algorithm btTransform orgTrans = colObj->getWorldTransform(); btTransform orgInterpolationTrans = colObj->getInterpolationWorldTransform(); const btTransform& childTrans = compoundShape->getChildTransform(i); btTransform newChildWorldTrans = orgTrans*childTrans ; //perform an AABB check first btVector3 aabbMin0,aabbMax0,aabbMin1,aabbMax1; childShape->getAabb(newChildWorldTrans,aabbMin0,aabbMax0); otherObj->getCollisionShape()->getAabb(otherObj->getWorldTransform(),aabbMin1,aabbMax1); if (!TestAabbAgainstAabb2(aabbMin0,aabbMax0,aabbMin1,aabbMax1)) { m_childCollisionAlgorithms[i]->~btCollisionAlgorithm(); m_dispatcher->freeCollisionAlgorithm(m_childCollisionAlgorithms[i]); m_childCollisionAlgorithms[i] = 0; } } } } } btScalar btCompoundCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { btCollisionObject* colObj = m_isSwapped? body1 : body0; btCollisionObject* otherObj = m_isSwapped? body0 : body1; btAssert (colObj->getCollisionShape()->isCompound()); btCompoundShape* compoundShape = static_cast(colObj->getCollisionShape()); //We will use the OptimizedBVH, AABB tree to cull potential child-overlaps //If both proxies are Compound, we will deal with that directly, by performing sequential/parallel tree traversals //given Proxy0 and Proxy1, if both have a tree, Tree0 and Tree1, this means: //determine overlapping nodes of Proxy1 using Proxy0 AABB against Tree1 //then use each overlapping node AABB against Tree0 //and vise versa. btScalar hitFraction = btScalar(1.); int numChildren = m_childCollisionAlgorithms.size(); int i; for (i=0;igetChildShape(i); //backup btTransform orgTrans = colObj->getWorldTransform(); const btTransform& childTrans = compoundShape->getChildTransform(i); //btTransform newChildWorldTrans = orgTrans*childTrans ; colObj->setWorldTransform( orgTrans*childTrans ); btCollisionShape* tmpShape = colObj->getCollisionShape(); colObj->internalSetTemporaryCollisionShape( childShape ); btScalar frac = m_childCollisionAlgorithms[i]->calculateTimeOfImpact(colObj,otherObj,dispatchInfo,resultOut); if (fracinternalSetTemporaryCollisionShape( tmpShape); colObj->setWorldTransform( orgTrans); } return hitFraction; } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btCollisionCreateFunc.h0000644000175000017500000000316111337071441032065 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 COLLISION_CREATE_FUNC #define COLLISION_CREATE_FUNC #include "LinearMath/btAlignedObjectArray.h" class btCollisionAlgorithm; class btCollisionObject; struct btCollisionAlgorithmConstructionInfo; ///Used by the btCollisionDispatcher to register and create instances for btCollisionAlgorithm struct btCollisionAlgorithmCreateFunc { bool m_swapped; btCollisionAlgorithmCreateFunc() :m_swapped(false) { } virtual ~btCollisionAlgorithmCreateFunc(){}; virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& , btCollisionObject* body0,btCollisionObject* body1) { (void)body0; (void)body1; return 0; } }; #endif //COLLISION_CREATE_FUNC ././@LongLink0000000000000000000000000000015400000000000011565 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgori0000644000175000017500000001401511337071441033200 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btConvexPlaneCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionShapes/btConvexShape.h" #include "BulletCollision/CollisionShapes/btStaticPlaneShape.h" //#include btConvexPlaneCollisionAlgorithm::btConvexPlaneCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped, int numPerturbationIterations,int minimumPointsPerturbationThreshold) : btCollisionAlgorithm(ci), m_ownManifold(false), m_manifoldPtr(mf), m_isSwapped(isSwapped), m_numPerturbationIterations(numPerturbationIterations), m_minimumPointsPerturbationThreshold(minimumPointsPerturbationThreshold) { btCollisionObject* convexObj = m_isSwapped? col1 : col0; btCollisionObject* planeObj = m_isSwapped? col0 : col1; if (!m_manifoldPtr && m_dispatcher->needsCollision(convexObj,planeObj)) { m_manifoldPtr = m_dispatcher->getNewManifold(convexObj,planeObj); m_ownManifold = true; } } btConvexPlaneCollisionAlgorithm::~btConvexPlaneCollisionAlgorithm() { if (m_ownManifold) { if (m_manifoldPtr) m_dispatcher->releaseManifold(m_manifoldPtr); } } void btConvexPlaneCollisionAlgorithm::collideSingleContact (const btQuaternion& perturbeRot, btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { btCollisionObject* convexObj = m_isSwapped? body1 : body0; btCollisionObject* planeObj = m_isSwapped? body0: body1; btConvexShape* convexShape = (btConvexShape*) convexObj->getCollisionShape(); btStaticPlaneShape* planeShape = (btStaticPlaneShape*) planeObj->getCollisionShape(); bool hasCollision = false; const btVector3& planeNormal = planeShape->getPlaneNormal(); const btScalar& planeConstant = planeShape->getPlaneConstant(); btTransform convexWorldTransform = convexObj->getWorldTransform(); btTransform convexInPlaneTrans; convexInPlaneTrans= planeObj->getWorldTransform().inverse() * convexWorldTransform; //now perturbe the convex-world transform convexWorldTransform.getBasis()*=btMatrix3x3(perturbeRot); btTransform planeInConvex; planeInConvex= convexWorldTransform.inverse() * planeObj->getWorldTransform(); btVector3 vtx = convexShape->localGetSupportingVertex(planeInConvex.getBasis()*-planeNormal); btVector3 vtxInPlane = convexInPlaneTrans(vtx); btScalar distance = (planeNormal.dot(vtxInPlane) - planeConstant); btVector3 vtxInPlaneProjected = vtxInPlane - distance*planeNormal; btVector3 vtxInPlaneWorld = planeObj->getWorldTransform() * vtxInPlaneProjected; hasCollision = distance < m_manifoldPtr->getContactBreakingThreshold(); resultOut->setPersistentManifold(m_manifoldPtr); if (hasCollision) { /// report a contact. internally this will be kept persistent, and contact reduction is done btVector3 normalOnSurfaceB = planeObj->getWorldTransform().getBasis() * planeNormal; btVector3 pOnB = vtxInPlaneWorld; resultOut->addContactPoint(normalOnSurfaceB,pOnB,distance); } } void btConvexPlaneCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { (void)dispatchInfo; if (!m_manifoldPtr) return; btCollisionObject* convexObj = m_isSwapped? body1 : body0; btCollisionObject* planeObj = m_isSwapped? body0: body1; btConvexShape* convexShape = (btConvexShape*) convexObj->getCollisionShape(); btStaticPlaneShape* planeShape = (btStaticPlaneShape*) planeObj->getCollisionShape(); const btVector3& planeNormal = planeShape->getPlaneNormal(); //const btScalar& planeConstant = planeShape->getPlaneConstant(); //first perform a collision query with the non-perturbated collision objects { btQuaternion rotq(0,0,0,1); collideSingleContact(rotq,body0,body1,dispatchInfo,resultOut); } if (resultOut->getPersistentManifold()->getNumContacts()getAngularMotionDisc(); perturbeAngle = gContactBreakingThreshold / radius; if ( perturbeAngle > angleLimit ) perturbeAngle = angleLimit; btQuaternion perturbeRot(v0,perturbeAngle); for (int i=0;igetNumContacts()) { resultOut->refreshContactPoints(); } } } btScalar btConvexPlaneCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { (void)resultOut; (void)dispatchInfo; (void)col0; (void)col1; //not yet return btScalar(1.); } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btGhostObject.cpp0000644000175000017500000001510411337071441030740 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2008 Erwin Coumans http://bulletphysics.com 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 "btGhostObject.h" #include "btCollisionWorld.h" #include "BulletCollision/CollisionShapes/btConvexShape.h" #include "LinearMath/btAabbUtil2.h" btGhostObject::btGhostObject() { m_internalType = CO_GHOST_OBJECT; } btGhostObject::~btGhostObject() { ///btGhostObject should have been removed from the world, so no overlapping objects btAssert(!m_overlappingObjects.size()); } void btGhostObject::addOverlappingObjectInternal(btBroadphaseProxy* otherProxy,btBroadphaseProxy* thisProxy) { btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject; btAssert(otherObject); ///if this linearSearch becomes too slow (too many overlapping objects) we should add a more appropriate data structure int index = m_overlappingObjects.findLinearSearch(otherObject); if (index==m_overlappingObjects.size()) { //not found m_overlappingObjects.push_back(otherObject); } } void btGhostObject::removeOverlappingObjectInternal(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher,btBroadphaseProxy* thisProxy) { btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject; btAssert(otherObject); int index = m_overlappingObjects.findLinearSearch(otherObject); if (index~btHashedOverlappingPairCache(); btAlignedFree( m_hashPairCache ); } void btPairCachingGhostObject::addOverlappingObjectInternal(btBroadphaseProxy* otherProxy,btBroadphaseProxy* thisProxy) { btBroadphaseProxy*actualThisProxy = thisProxy ? thisProxy : getBroadphaseHandle(); btAssert(actualThisProxy); btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject; btAssert(otherObject); int index = m_overlappingObjects.findLinearSearch(otherObject); if (index==m_overlappingObjects.size()) { m_overlappingObjects.push_back(otherObject); m_hashPairCache->addOverlappingPair(actualThisProxy,otherProxy); } } void btPairCachingGhostObject::removeOverlappingObjectInternal(btBroadphaseProxy* otherProxy,btDispatcher* dispatcher,btBroadphaseProxy* thisProxy1) { btCollisionObject* otherObject = (btCollisionObject*)otherProxy->m_clientObject; btBroadphaseProxy* actualThisProxy = thisProxy1 ? thisProxy1 : getBroadphaseHandle(); btAssert(actualThisProxy); btAssert(otherObject); int index = m_overlappingObjects.findLinearSearch(otherObject); if (indexremoveOverlappingPair(actualThisProxy,otherProxy,dispatcher); } } void btGhostObject::convexSweepTest(const btConvexShape* castShape, const btTransform& convexFromWorld, const btTransform& convexToWorld, btCollisionWorld::ConvexResultCallback& resultCallback, btScalar allowedCcdPenetration) const { btTransform convexFromTrans,convexToTrans; convexFromTrans = convexFromWorld; convexToTrans = convexToWorld; btVector3 castShapeAabbMin, castShapeAabbMax; /* Compute AABB that encompasses angular movement */ { btVector3 linVel, angVel; btTransformUtil::calculateVelocity (convexFromTrans, convexToTrans, 1.0, linVel, angVel); btTransform R; R.setIdentity (); R.setRotation (convexFromTrans.getRotation()); castShape->calculateTemporalAabb (R, linVel, angVel, 1.0, castShapeAabbMin, castShapeAabbMax); } /// go over all objects, and if the ray intersects their aabb + cast shape aabb, // do a ray-shape query using convexCaster (CCD) int i; for (i=0;igetBroadphaseHandle())) { //RigidcollisionObject* collisionObject = ctrl->GetRigidcollisionObject(); btVector3 collisionObjectAabbMin,collisionObjectAabbMax; collisionObject->getCollisionShape()->getAabb(collisionObject->getWorldTransform(),collisionObjectAabbMin,collisionObjectAabbMax); AabbExpand (collisionObjectAabbMin, collisionObjectAabbMax, castShapeAabbMin, castShapeAabbMax); btScalar hitLambda = btScalar(1.); //could use resultCallback.m_closestHitFraction, but needs testing btVector3 hitNormal; if (btRayAabb(convexFromWorld.getOrigin(),convexToWorld.getOrigin(),collisionObjectAabbMin,collisionObjectAabbMax,hitLambda,hitNormal)) { btCollisionWorld::objectQuerySingle(castShape, convexFromTrans,convexToTrans, collisionObject, collisionObject->getCollisionShape(), collisionObject->getWorldTransform(), resultCallback, allowedCcdPenetration); } } } } void btGhostObject::rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, btCollisionWorld::RayResultCallback& resultCallback) const { btTransform rayFromTrans; rayFromTrans.setIdentity(); rayFromTrans.setOrigin(rayFromWorld); btTransform rayToTrans; rayToTrans.setIdentity(); rayToTrans.setOrigin(rayToWorld); int i; for (i=0;igetBroadphaseHandle())) { btCollisionWorld::rayTestSingle(rayFromTrans,rayToTrans, collisionObject, collisionObject->getCollisionShape(), collisionObject->getWorldTransform(), resultCallback); } } } ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.hcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgor0000644000175000017500000000555711337071441033215 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 SPHERE_SPHERE_COLLISION_ALGORITHM_H #define SPHERE_SPHERE_COLLISION_ALGORITHM_H #include "btActivatingCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" #include "btCollisionDispatcher.h" class btPersistentManifold; /// btSphereSphereCollisionAlgorithm provides sphere-sphere collision detection. /// Other features are frame-coherency (persistent data) and collision response. /// Also provides the most basic sample for custom/user btCollisionAlgorithm class btSphereSphereCollisionAlgorithm : public btActivatingCollisionAlgorithm { bool m_ownManifold; btPersistentManifold* m_manifoldPtr; public: btSphereSphereCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1); btSphereSphereCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) : btActivatingCollisionAlgorithm(ci) {} virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual void getAllContactManifolds(btManifoldArray& manifoldArray) { if (m_manifoldPtr && m_ownManifold) { manifoldArray.push_back(m_manifoldPtr); } } virtual ~btSphereSphereCollisionAlgorithm(); struct CreateFunc :public btCollisionAlgorithmCreateFunc { virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btSphereSphereCollisionAlgorithm)); return new(mem) btSphereSphereCollisionAlgorithm(0,ci,body0,body1); } }; }; #endif //SPHERE_SPHERE_COLLISION_ALGORITHM_H ././@LongLink0000000000000000000000000000014600000000000011566 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.hcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btConvex2dConvex2dAlgorithm.0000644000175000017500000001006011337071441032766 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 CONVEX_2D_CONVEX_2D_ALGORITHM_H #define CONVEX_2D_CONVEX_2D_ALGORITHM_H #include "BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h" #include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" #include "BulletCollision/NarrowPhaseCollision/btPersistentManifold.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "LinearMath/btTransformUtil.h" //for btConvexSeparatingDistanceUtil class btConvexPenetrationDepthSolver; ///The convex2dConvex2dAlgorithm collision algorithm support 2d collision detection for btConvex2dShape ///Currently it requires the btMinkowskiPenetrationDepthSolver, it has support for 2d penetration depth computation class btConvex2dConvex2dAlgorithm : public btActivatingCollisionAlgorithm { btSimplexSolverInterface* m_simplexSolver; btConvexPenetrationDepthSolver* m_pdSolver; bool m_ownManifold; btPersistentManifold* m_manifoldPtr; bool m_lowLevelOfDetail; int m_numPerturbationIterations; int m_minimumPointsPerturbationThreshold; public: btConvex2dConvex2dAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1, btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver, int numPerturbationIterations, int minimumPointsPerturbationThreshold); virtual ~btConvex2dConvex2dAlgorithm(); virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual void getAllContactManifolds(btManifoldArray& manifoldArray) { ///should we use m_ownManifold to avoid adding duplicates? if (m_manifoldPtr && m_ownManifold) manifoldArray.push_back(m_manifoldPtr); } void setLowLevelOfDetail(bool useLowLevel); const btPersistentManifold* getManifold() { return m_manifoldPtr; } struct CreateFunc :public btCollisionAlgorithmCreateFunc { btConvexPenetrationDepthSolver* m_pdSolver; btSimplexSolverInterface* m_simplexSolver; int m_numPerturbationIterations; int m_minimumPointsPerturbationThreshold; CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver); virtual ~CreateFunc(); virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvex2dConvex2dAlgorithm)); return new(mem) btConvex2dConvex2dAlgorithm(ci.m_manifold,ci,body0,body1,m_simplexSolver,m_pdSolver,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold); } }; }; #endif //CONVEX_2D_CONVEX_2D_ALGORITHM_H ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorit0000644000175000017500000003056011344267705033032 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library * The b2CollidePolygons routines are Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com 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. */ ///btBox2dBox2dCollisionAlgorithm, with modified b2CollidePolygons routines from the Box2D library. ///The modifications include: switching from b2Vec to btVector3, redefinition of b2Dot, b2Cross #include "btBox2dBox2dCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/CollisionShapes/btBoxShape.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionDispatch/btBoxBoxDetector.h" #include "BulletCollision/CollisionShapes/btBox2dShape.h" #define USE_PERSISTENT_CONTACTS 1 btBox2dBox2dCollisionAlgorithm::btBox2dBox2dCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* obj0,btCollisionObject* obj1) : btActivatingCollisionAlgorithm(ci,obj0,obj1), m_ownManifold(false), m_manifoldPtr(mf) { if (!m_manifoldPtr && m_dispatcher->needsCollision(obj0,obj1)) { m_manifoldPtr = m_dispatcher->getNewManifold(obj0,obj1); m_ownManifold = true; } } btBox2dBox2dCollisionAlgorithm::~btBox2dBox2dCollisionAlgorithm() { if (m_ownManifold) { if (m_manifoldPtr) m_dispatcher->releaseManifold(m_manifoldPtr); } } void b2CollidePolygons(btManifoldResult* manifold, const btBox2dShape* polyA, const btTransform& xfA, const btBox2dShape* polyB, const btTransform& xfB); //#include void btBox2dBox2dCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { if (!m_manifoldPtr) return; btCollisionObject* col0 = body0; btCollisionObject* col1 = body1; btBox2dShape* box0 = (btBox2dShape*)col0->getCollisionShape(); btBox2dShape* box1 = (btBox2dShape*)col1->getCollisionShape(); resultOut->setPersistentManifold(m_manifoldPtr); b2CollidePolygons(resultOut,box0,col0->getWorldTransform(),box1,col1->getWorldTransform()); // refreshContactPoints is only necessary when using persistent contact points. otherwise all points are newly added if (m_ownManifold) { resultOut->refreshContactPoints(); } } btScalar btBox2dBox2dCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* /*body0*/,btCollisionObject* /*body1*/,const btDispatcherInfo& /*dispatchInfo*/,btManifoldResult* /*resultOut*/) { //not yet return 1.f; } struct ClipVertex { btVector3 v; int id; //b2ContactID id; //b2ContactID id; }; #define b2Dot(a,b) (a).dot(b) #define b2Mul(a,b) (a)*(b) #define b2MulT(a,b) (a).transpose()*(b) #define b2Cross(a,b) (a).cross(b) #define btCrossS(a,s) btVector3(s * a.getY(), -s * a.getX(),0.f) int b2_maxManifoldPoints =2; static int ClipSegmentToLine(ClipVertex vOut[2], ClipVertex vIn[2], const btVector3& normal, btScalar offset) { // Start with no output points int numOut = 0; // Calculate the distance of end points to the line btScalar distance0 = b2Dot(normal, vIn[0].v) - offset; btScalar distance1 = b2Dot(normal, vIn[1].v) - offset; // If the points are behind the plane if (distance0 <= 0.0f) vOut[numOut++] = vIn[0]; if (distance1 <= 0.0f) vOut[numOut++] = vIn[1]; // If the points are on different sides of the plane if (distance0 * distance1 < 0.0f) { // Find intersection point of edge and plane btScalar interp = distance0 / (distance0 - distance1); vOut[numOut].v = vIn[0].v + interp * (vIn[1].v - vIn[0].v); if (distance0 > 0.0f) { vOut[numOut].id = vIn[0].id; } else { vOut[numOut].id = vIn[1].id; } ++numOut; } return numOut; } // Find the separation between poly1 and poly2 for a give edge normal on poly1. static btScalar EdgeSeparation(const btBox2dShape* poly1, const btTransform& xf1, int edge1, const btBox2dShape* poly2, const btTransform& xf2) { const btVector3* vertices1 = poly1->getVertices(); const btVector3* normals1 = poly1->getNormals(); int count2 = poly2->getVertexCount(); const btVector3* vertices2 = poly2->getVertices(); btAssert(0 <= edge1 && edge1 < poly1->getVertexCount()); // Convert normal from poly1's frame into poly2's frame. btVector3 normal1World = b2Mul(xf1.getBasis(), normals1[edge1]); btVector3 normal1 = b2MulT(xf2.getBasis(), normal1World); // Find support vertex on poly2 for -normal. int index = 0; btScalar minDot = BT_LARGE_FLOAT; for (int i = 0; i < count2; ++i) { btScalar dot = b2Dot(vertices2[i], normal1); if (dot < minDot) { minDot = dot; index = i; } } btVector3 v1 = b2Mul(xf1, vertices1[edge1]); btVector3 v2 = b2Mul(xf2, vertices2[index]); btScalar separation = b2Dot(v2 - v1, normal1World); return separation; } // Find the max separation between poly1 and poly2 using edge normals from poly1. static btScalar FindMaxSeparation(int* edgeIndex, const btBox2dShape* poly1, const btTransform& xf1, const btBox2dShape* poly2, const btTransform& xf2) { int count1 = poly1->getVertexCount(); const btVector3* normals1 = poly1->getNormals(); // Vector pointing from the centroid of poly1 to the centroid of poly2. btVector3 d = b2Mul(xf2, poly2->getCentroid()) - b2Mul(xf1, poly1->getCentroid()); btVector3 dLocal1 = b2MulT(xf1.getBasis(), d); // Find edge normal on poly1 that has the largest projection onto d. int edge = 0; btScalar maxDot = -BT_LARGE_FLOAT; for (int i = 0; i < count1; ++i) { btScalar dot = b2Dot(normals1[i], dLocal1); if (dot > maxDot) { maxDot = dot; edge = i; } } // Get the separation for the edge normal. btScalar s = EdgeSeparation(poly1, xf1, edge, poly2, xf2); if (s > 0.0f) { return s; } // Check the separation for the previous edge normal. int prevEdge = edge - 1 >= 0 ? edge - 1 : count1 - 1; btScalar sPrev = EdgeSeparation(poly1, xf1, prevEdge, poly2, xf2); if (sPrev > 0.0f) { return sPrev; } // Check the separation for the next edge normal. int nextEdge = edge + 1 < count1 ? edge + 1 : 0; btScalar sNext = EdgeSeparation(poly1, xf1, nextEdge, poly2, xf2); if (sNext > 0.0f) { return sNext; } // Find the best edge and the search direction. int bestEdge; btScalar bestSeparation; int increment; if (sPrev > s && sPrev > sNext) { increment = -1; bestEdge = prevEdge; bestSeparation = sPrev; } else if (sNext > s) { increment = 1; bestEdge = nextEdge; bestSeparation = sNext; } else { *edgeIndex = edge; return s; } // Perform a local search for the best edge normal. for ( ; ; ) { if (increment == -1) edge = bestEdge - 1 >= 0 ? bestEdge - 1 : count1 - 1; else edge = bestEdge + 1 < count1 ? bestEdge + 1 : 0; s = EdgeSeparation(poly1, xf1, edge, poly2, xf2); if (s > 0.0f) { return s; } if (s > bestSeparation) { bestEdge = edge; bestSeparation = s; } else { break; } } *edgeIndex = bestEdge; return bestSeparation; } static void FindIncidentEdge(ClipVertex c[2], const btBox2dShape* poly1, const btTransform& xf1, int edge1, const btBox2dShape* poly2, const btTransform& xf2) { const btVector3* normals1 = poly1->getNormals(); int count2 = poly2->getVertexCount(); const btVector3* vertices2 = poly2->getVertices(); const btVector3* normals2 = poly2->getNormals(); btAssert(0 <= edge1 && edge1 < poly1->getVertexCount()); // Get the normal of the reference edge in poly2's frame. btVector3 normal1 = b2MulT(xf2.getBasis(), b2Mul(xf1.getBasis(), normals1[edge1])); // Find the incident edge on poly2. int index = 0; btScalar minDot = BT_LARGE_FLOAT; for (int i = 0; i < count2; ++i) { btScalar dot = b2Dot(normal1, normals2[i]); if (dot < minDot) { minDot = dot; index = i; } } // Build the clip vertices for the incident edge. int i1 = index; int i2 = i1 + 1 < count2 ? i1 + 1 : 0; c[0].v = b2Mul(xf2, vertices2[i1]); // c[0].id.features.referenceEdge = (unsigned char)edge1; // c[0].id.features.incidentEdge = (unsigned char)i1; // c[0].id.features.incidentVertex = 0; c[1].v = b2Mul(xf2, vertices2[i2]); // c[1].id.features.referenceEdge = (unsigned char)edge1; // c[1].id.features.incidentEdge = (unsigned char)i2; // c[1].id.features.incidentVertex = 1; } // Find edge normal of max separation on A - return if separating axis is found // Find edge normal of max separation on B - return if separation axis is found // Choose reference edge as min(minA, minB) // Find incident edge // Clip // The normal points from 1 to 2 void b2CollidePolygons(btManifoldResult* manifold, const btBox2dShape* polyA, const btTransform& xfA, const btBox2dShape* polyB, const btTransform& xfB) { int edgeA = 0; btScalar separationA = FindMaxSeparation(&edgeA, polyA, xfA, polyB, xfB); if (separationA > 0.0f) return; int edgeB = 0; btScalar separationB = FindMaxSeparation(&edgeB, polyB, xfB, polyA, xfA); if (separationB > 0.0f) return; const btBox2dShape* poly1; // reference poly const btBox2dShape* poly2; // incident poly btTransform xf1, xf2; int edge1; // reference edge unsigned char flip; const btScalar k_relativeTol = 0.98f; const btScalar k_absoluteTol = 0.001f; // TODO_ERIN use "radius" of poly for absolute tolerance. if (separationB > k_relativeTol * separationA + k_absoluteTol) { poly1 = polyB; poly2 = polyA; xf1 = xfB; xf2 = xfA; edge1 = edgeB; flip = 1; } else { poly1 = polyA; poly2 = polyB; xf1 = xfA; xf2 = xfB; edge1 = edgeA; flip = 0; } ClipVertex incidentEdge[2]; FindIncidentEdge(incidentEdge, poly1, xf1, edge1, poly2, xf2); int count1 = poly1->getVertexCount(); const btVector3* vertices1 = poly1->getVertices(); btVector3 v11 = vertices1[edge1]; btVector3 v12 = edge1 + 1 < count1 ? vertices1[edge1+1] : vertices1[0]; btVector3 dv = v12 - v11; btVector3 sideNormal = b2Mul(xf1.getBasis(), v12 - v11); sideNormal.normalize(); btVector3 frontNormal = btCrossS(sideNormal, 1.0f); v11 = b2Mul(xf1, v11); v12 = b2Mul(xf1, v12); btScalar frontOffset = b2Dot(frontNormal, v11); btScalar sideOffset1 = -b2Dot(sideNormal, v11); btScalar sideOffset2 = b2Dot(sideNormal, v12); // Clip incident edge against extruded edge1 side edges. ClipVertex clipPoints1[2]; clipPoints1[0].v.setValue(0,0,0); clipPoints1[1].v.setValue(0,0,0); ClipVertex clipPoints2[2]; clipPoints2[0].v.setValue(0,0,0); clipPoints2[1].v.setValue(0,0,0); int np; // Clip to box side 1 np = ClipSegmentToLine(clipPoints1, incidentEdge, -sideNormal, sideOffset1); if (np < 2) return; // Clip to negative box side 1 np = ClipSegmentToLine(clipPoints2, clipPoints1, sideNormal, sideOffset2); if (np < 2) { return; } // Now clipPoints2 contains the clipped points. btVector3 manifoldNormal = flip ? -frontNormal : frontNormal; int pointCount = 0; for (int i = 0; i < b2_maxManifoldPoints; ++i) { btScalar separation = b2Dot(frontNormal, clipPoints2[i].v) - frontOffset; if (separation <= 0.0f) { //b2ManifoldPoint* cp = manifold->points + pointCount; //btScalar separation = separation; //cp->localPoint1 = b2MulT(xfA, clipPoints2[i].v); //cp->localPoint2 = b2MulT(xfB, clipPoints2[i].v); manifold->addContactPoint(-manifoldNormal,clipPoints2[i].v,separation); // cp->id = clipPoints2[i].id; // cp->id.features.flip = flip; ++pointCount; } } // manifold->pointCount = pointCount;} } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btConvexConvexAlgorithm.cpp0000644000175000017500000004364711344267705033046 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ ///Specialized capsule-capsule collision algorithm has been added for Bullet 2.75 release to increase ragdoll performance ///If you experience problems with capsule-capsule collision, try to define BT_DISABLE_CAPSULE_CAPSULE_COLLIDER and report it in the Bullet forums ///with reproduction case //define BT_DISABLE_CAPSULE_CAPSULE_COLLIDER 1 #include "btConvexConvexAlgorithm.h" //#include #include "BulletCollision/NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseInterface.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "BulletCollision/CollisionShapes/btConvexShape.h" #include "BulletCollision/CollisionShapes/btCapsuleShape.h" #include "BulletCollision/NarrowPhaseCollision/btGjkPairDetector.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/CollisionShapes/btBoxShape.h" #include "BulletCollision/CollisionDispatch/btManifoldResult.h" #include "BulletCollision/NarrowPhaseCollision/btConvexPenetrationDepthSolver.h" #include "BulletCollision/NarrowPhaseCollision/btContinuousConvexCollision.h" #include "BulletCollision/NarrowPhaseCollision/btSubSimplexConvexCast.h" #include "BulletCollision/NarrowPhaseCollision/btGjkConvexCast.h" #include "BulletCollision/NarrowPhaseCollision/btVoronoiSimplexSolver.h" #include "BulletCollision/CollisionShapes/btSphereShape.h" #include "BulletCollision/NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h" #include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h" #include "BulletCollision/NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h" /////////// static SIMD_FORCE_INLINE void segmentsClosestPoints( btVector3& ptsVector, btVector3& offsetA, btVector3& offsetB, btScalar& tA, btScalar& tB, const btVector3& translation, const btVector3& dirA, btScalar hlenA, const btVector3& dirB, btScalar hlenB ) { // compute the parameters of the closest points on each line segment btScalar dirA_dot_dirB = btDot(dirA,dirB); btScalar dirA_dot_trans = btDot(dirA,translation); btScalar dirB_dot_trans = btDot(dirB,translation); btScalar denom = 1.0f - dirA_dot_dirB * dirA_dot_dirB; if ( denom == 0.0f ) { tA = 0.0f; } else { tA = ( dirA_dot_trans - dirB_dot_trans * dirA_dot_dirB ) / denom; if ( tA < -hlenA ) tA = -hlenA; else if ( tA > hlenA ) tA = hlenA; } tB = tA * dirA_dot_dirB - dirB_dot_trans; if ( tB < -hlenB ) { tB = -hlenB; tA = tB * dirA_dot_dirB + dirA_dot_trans; if ( tA < -hlenA ) tA = -hlenA; else if ( tA > hlenA ) tA = hlenA; } else if ( tB > hlenB ) { tB = hlenB; tA = tB * dirA_dot_dirB + dirA_dot_trans; if ( tA < -hlenA ) tA = -hlenA; else if ( tA > hlenA ) tA = hlenA; } // compute the closest points relative to segment centers. offsetA = dirA * tA; offsetB = dirB * tB; ptsVector = translation - offsetA + offsetB; } static SIMD_FORCE_INLINE btScalar capsuleCapsuleDistance( btVector3& normalOnB, btVector3& pointOnB, btScalar capsuleLengthA, btScalar capsuleRadiusA, btScalar capsuleLengthB, btScalar capsuleRadiusB, int capsuleAxisA, int capsuleAxisB, const btTransform& transformA, const btTransform& transformB, btScalar distanceThreshold ) { btVector3 directionA = transformA.getBasis().getColumn(capsuleAxisA); btVector3 translationA = transformA.getOrigin(); btVector3 directionB = transformB.getBasis().getColumn(capsuleAxisB); btVector3 translationB = transformB.getOrigin(); // translation between centers btVector3 translation = translationB - translationA; // compute the closest points of the capsule line segments btVector3 ptsVector; // the vector between the closest points btVector3 offsetA, offsetB; // offsets from segment centers to their closest points btScalar tA, tB; // parameters on line segment segmentsClosestPoints( ptsVector, offsetA, offsetB, tA, tB, translation, directionA, capsuleLengthA, directionB, capsuleLengthB ); btScalar distance = ptsVector.length() - capsuleRadiusA - capsuleRadiusB; if ( distance > distanceThreshold ) return distance; btScalar lenSqr = ptsVector.length2(); if (lenSqr<= (SIMD_EPSILON*SIMD_EPSILON)) { //degenerate case where 2 capsules are likely at the same location: take a vector tangential to 'directionA' btVector3 q; btPlaneSpace1(directionA,normalOnB,q); } else { // compute the contact normal normalOnB = ptsVector*-btRecipSqrt(lenSqr); } pointOnB = transformB.getOrigin()+offsetB + normalOnB * capsuleRadiusB; return distance; } ////////// btConvexConvexAlgorithm::CreateFunc::CreateFunc(btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver) { m_numPerturbationIterations = 0; m_minimumPointsPerturbationThreshold = 3; m_simplexSolver = simplexSolver; m_pdSolver = pdSolver; } btConvexConvexAlgorithm::CreateFunc::~CreateFunc() { } btConvexConvexAlgorithm::btConvexConvexAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1,btSimplexSolverInterface* simplexSolver, btConvexPenetrationDepthSolver* pdSolver,int numPerturbationIterations, int minimumPointsPerturbationThreshold) : btActivatingCollisionAlgorithm(ci,body0,body1), m_simplexSolver(simplexSolver), m_pdSolver(pdSolver), m_ownManifold (false), m_manifoldPtr(mf), m_lowLevelOfDetail(false), #ifdef USE_SEPDISTANCE_UTIL2 m_sepDistance((static_cast(body0->getCollisionShape()))->getAngularMotionDisc(), (static_cast(body1->getCollisionShape()))->getAngularMotionDisc()), #endif m_numPerturbationIterations(numPerturbationIterations), m_minimumPointsPerturbationThreshold(minimumPointsPerturbationThreshold) { (void)body0; (void)body1; } btConvexConvexAlgorithm::~btConvexConvexAlgorithm() { if (m_ownManifold) { if (m_manifoldPtr) m_dispatcher->releaseManifold(m_manifoldPtr); } } void btConvexConvexAlgorithm ::setLowLevelOfDetail(bool useLowLevel) { m_lowLevelOfDetail = useLowLevel; } struct btPerturbedContactResult : public btManifoldResult { btManifoldResult* m_originalManifoldResult; btTransform m_transformA; btTransform m_transformB; btTransform m_unPerturbedTransform; bool m_perturbA; btIDebugDraw* m_debugDrawer; btPerturbedContactResult(btManifoldResult* originalResult,const btTransform& transformA,const btTransform& transformB,const btTransform& unPerturbedTransform,bool perturbA,btIDebugDraw* debugDrawer) :m_originalManifoldResult(originalResult), m_transformA(transformA), m_transformB(transformB), m_unPerturbedTransform(unPerturbedTransform), m_perturbA(perturbA), m_debugDrawer(debugDrawer) { } virtual ~ btPerturbedContactResult() { } virtual void addContactPoint(const btVector3& normalOnBInWorld,const btVector3& pointInWorld,btScalar orgDepth) { btVector3 endPt,startPt; btScalar newDepth; btVector3 newNormal; if (m_perturbA) { btVector3 endPtOrg = pointInWorld + normalOnBInWorld*orgDepth; endPt = (m_unPerturbedTransform*m_transformA.inverse())(endPtOrg); newDepth = (endPt - pointInWorld).dot(normalOnBInWorld); startPt = endPt+normalOnBInWorld*newDepth; } else { endPt = pointInWorld + normalOnBInWorld*orgDepth; startPt = (m_unPerturbedTransform*m_transformB.inverse())(pointInWorld); newDepth = (endPt - startPt).dot(normalOnBInWorld); } //#define DEBUG_CONTACTS 1 #ifdef DEBUG_CONTACTS m_debugDrawer->drawLine(startPt,endPt,btVector3(1,0,0)); m_debugDrawer->drawSphere(startPt,0.05,btVector3(0,1,0)); m_debugDrawer->drawSphere(endPt,0.05,btVector3(0,0,1)); #endif //DEBUG_CONTACTS m_originalManifoldResult->addContactPoint(normalOnBInWorld,startPt,newDepth); } }; extern btScalar gContactBreakingThreshold; // // Convex-Convex collision algorithm // void btConvexConvexAlgorithm ::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { if (!m_manifoldPtr) { //swapped? m_manifoldPtr = m_dispatcher->getNewManifold(body0,body1); m_ownManifold = true; } resultOut->setPersistentManifold(m_manifoldPtr); //comment-out next line to test multi-contact generation //resultOut->getPersistentManifold()->clearManifold(); btConvexShape* min0 = static_cast(body0->getCollisionShape()); btConvexShape* min1 = static_cast(body1->getCollisionShape()); btVector3 normalOnB; btVector3 pointOnBWorld; #ifndef BT_DISABLE_CAPSULE_CAPSULE_COLLIDER if ((min0->getShapeType() == CAPSULE_SHAPE_PROXYTYPE) && (min1->getShapeType() == CAPSULE_SHAPE_PROXYTYPE)) { btCapsuleShape* capsuleA = (btCapsuleShape*) min0; btCapsuleShape* capsuleB = (btCapsuleShape*) min1; btVector3 localScalingA = capsuleA->getLocalScaling(); btVector3 localScalingB = capsuleB->getLocalScaling(); btScalar threshold = m_manifoldPtr->getContactBreakingThreshold(); btScalar dist = capsuleCapsuleDistance(normalOnB, pointOnBWorld,capsuleA->getHalfHeight(),capsuleA->getRadius(), capsuleB->getHalfHeight(),capsuleB->getRadius(),capsuleA->getUpAxis(),capsuleB->getUpAxis(), body0->getWorldTransform(),body1->getWorldTransform(),threshold); if (dist=(SIMD_EPSILON*SIMD_EPSILON)); resultOut->addContactPoint(normalOnB,pointOnBWorld,dist); } resultOut->refreshContactPoints(); return; } #endif //BT_DISABLE_CAPSULE_CAPSULE_COLLIDER #ifdef USE_SEPDISTANCE_UTIL2 if (dispatchInfo.m_useConvexConservativeDistanceUtil) { m_sepDistance.updateSeparatingDistance(body0->getWorldTransform(),body1->getWorldTransform()); } if (!dispatchInfo.m_useConvexConservativeDistanceUtil || m_sepDistance.getConservativeSeparatingDistance()<=0.f) #endif //USE_SEPDISTANCE_UTIL2 { btGjkPairDetector::ClosestPointInput input; btGjkPairDetector gjkPairDetector(min0,min1,m_simplexSolver,m_pdSolver); //TODO: if (dispatchInfo.m_useContinuous) gjkPairDetector.setMinkowskiA(min0); gjkPairDetector.setMinkowskiB(min1); #ifdef USE_SEPDISTANCE_UTIL2 if (dispatchInfo.m_useConvexConservativeDistanceUtil) { input.m_maximumDistanceSquared = BT_LARGE_FLOAT; } else #endif //USE_SEPDISTANCE_UTIL2 { input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactBreakingThreshold(); input.m_maximumDistanceSquared*= input.m_maximumDistanceSquared; } input.m_stackAlloc = dispatchInfo.m_stackAllocator; input.m_transformA = body0->getWorldTransform(); input.m_transformB = body1->getWorldTransform(); gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); #ifdef USE_SEPDISTANCE_UTIL2 btScalar sepDist = 0.f; if (dispatchInfo.m_useConvexConservativeDistanceUtil) { sepDist = gjkPairDetector.getCachedSeparatingDistance(); if (sepDist>SIMD_EPSILON) { sepDist += dispatchInfo.m_convexConservativeDistanceThreshold; //now perturbe directions to get multiple contact points } } #endif //USE_SEPDISTANCE_UTIL2 //now perform 'm_numPerturbationIterations' collision queries with the perturbated collision objects //perform perturbation when more then 'm_minimumPointsPerturbationThreshold' points if (m_numPerturbationIterations && resultOut->getPersistentManifold()->getNumContacts() < m_minimumPointsPerturbationThreshold) { int i; btVector3 v0,v1; btVector3 sepNormalWorldSpace; sepNormalWorldSpace = gjkPairDetector.getCachedSeparatingAxis().normalized(); btPlaneSpace1(sepNormalWorldSpace,v0,v1); bool perturbeA = true; const btScalar angleLimit = 0.125f * SIMD_PI; btScalar perturbeAngle; btScalar radiusA = min0->getAngularMotionDisc(); btScalar radiusB = min1->getAngularMotionDisc(); if (radiusA < radiusB) { perturbeAngle = gContactBreakingThreshold /radiusA; perturbeA = true; } else { perturbeAngle = gContactBreakingThreshold / radiusB; perturbeA = false; } if ( perturbeAngle > angleLimit ) perturbeAngle = angleLimit; btTransform unPerturbedTransform; if (perturbeA) { unPerturbedTransform = input.m_transformA; } else { unPerturbedTransform = input.m_transformB; } for ( i=0;iSIMD_EPSILON) { btQuaternion perturbeRot(v0,perturbeAngle); btScalar iterationAngle = i*(SIMD_2_PI/btScalar(m_numPerturbationIterations)); btQuaternion rotq(sepNormalWorldSpace,iterationAngle); if (perturbeA) { input.m_transformA.setBasis( btMatrix3x3(rotq.inverse()*perturbeRot*rotq)*body0->getWorldTransform().getBasis()); input.m_transformB = body1->getWorldTransform(); #ifdef DEBUG_CONTACTS dispatchInfo.m_debugDraw->drawTransform(input.m_transformA,10.0); #endif //DEBUG_CONTACTS } else { input.m_transformA = body0->getWorldTransform(); input.m_transformB.setBasis( btMatrix3x3(rotq.inverse()*perturbeRot*rotq)*body1->getWorldTransform().getBasis()); #ifdef DEBUG_CONTACTS dispatchInfo.m_debugDraw->drawTransform(input.m_transformB,10.0); #endif } btPerturbedContactResult perturbedResultOut(resultOut,input.m_transformA,input.m_transformB,unPerturbedTransform,perturbeA,dispatchInfo.m_debugDraw); gjkPairDetector.getClosestPoints(input,perturbedResultOut,dispatchInfo.m_debugDraw); } } } #ifdef USE_SEPDISTANCE_UTIL2 if (dispatchInfo.m_useConvexConservativeDistanceUtil && (sepDist>SIMD_EPSILON)) { m_sepDistance.initSeparatingDistance(gjkPairDetector.getCachedSeparatingAxis(),sepDist,body0->getWorldTransform(),body1->getWorldTransform()); } #endif //USE_SEPDISTANCE_UTIL2 } if (m_ownManifold) { resultOut->refreshContactPoints(); } } bool disableCcd = false; btScalar btConvexConvexAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { (void)resultOut; (void)dispatchInfo; ///Rather then checking ALL pairs, only calculate TOI when motion exceeds threshold ///Linear motion for one of objects needs to exceed m_ccdSquareMotionThreshold ///col0->m_worldTransform, btScalar resultFraction = btScalar(1.); btScalar squareMot0 = (col0->getInterpolationWorldTransform().getOrigin() - col0->getWorldTransform().getOrigin()).length2(); btScalar squareMot1 = (col1->getInterpolationWorldTransform().getOrigin() - col1->getWorldTransform().getOrigin()).length2(); if (squareMot0 < col0->getCcdSquareMotionThreshold() && squareMot1 < col1->getCcdSquareMotionThreshold()) return resultFraction; if (disableCcd) return btScalar(1.); //An adhoc way of testing the Continuous Collision Detection algorithms //One object is approximated as a sphere, to simplify things //Starting in penetration should report no time of impact //For proper CCD, better accuracy and handling of 'allowed' penetration should be added //also the mainloop of the physics should have a kind of toi queue (something like Brian Mirtich's application of Timewarp for Rigidbodies) /// Convex0 against sphere for Convex1 { btConvexShape* convex0 = static_cast(col0->getCollisionShape()); btSphereShape sphere1(col1->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation btConvexCast::CastResult result; btVoronoiSimplexSolver voronoiSimplex; //SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex); ///Simplification, one object is simplified as a sphere btGjkConvexCast ccd1( convex0 ,&sphere1,&voronoiSimplex); //ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0); if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(), col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result)) { //store result.m_fraction in both bodies if (col0->getHitFraction()> result.m_fraction) col0->setHitFraction( result.m_fraction ); if (col1->getHitFraction() > result.m_fraction) col1->setHitFraction( result.m_fraction); if (resultFraction > result.m_fraction) resultFraction = result.m_fraction; } } /// Sphere (for convex0) against Convex1 { btConvexShape* convex1 = static_cast(col1->getCollisionShape()); btSphereShape sphere0(col0->getCcdSweptSphereRadius()); //todo: allow non-zero sphere sizes, for better approximation btConvexCast::CastResult result; btVoronoiSimplexSolver voronoiSimplex; //SubsimplexConvexCast ccd0(&sphere,min0,&voronoiSimplex); ///Simplification, one object is simplified as a sphere btGjkConvexCast ccd1(&sphere0,convex1,&voronoiSimplex); //ContinuousConvexCollision ccd(min0,min1,&voronoiSimplex,0); if (ccd1.calcTimeOfImpact(col0->getWorldTransform(),col0->getInterpolationWorldTransform(), col1->getWorldTransform(),col1->getInterpolationWorldTransform(),result)) { //store result.m_fraction in both bodies if (col0->getHitFraction() > result.m_fraction) col0->setHitFraction( result.m_fraction); if (col1->getHitFraction() > result.m_fraction) col1->setHitFraction( result.m_fraction); if (resultFraction > result.m_fraction) resultFraction = result.m_fraction; } } return resultFraction; } ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btBoxBoxCollisionAlgorithm.c0000644000175000017500000000627111337071441033116 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btBoxBoxCollisionAlgorithm.h" #include "BulletCollision/CollisionDispatch/btCollisionDispatcher.h" #include "BulletCollision/CollisionShapes/btBoxShape.h" #include "BulletCollision/CollisionDispatch/btCollisionObject.h" #include "btBoxBoxDetector.h" #define USE_PERSISTENT_CONTACTS 1 btBoxBoxCollisionAlgorithm::btBoxBoxCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* obj0,btCollisionObject* obj1) : btActivatingCollisionAlgorithm(ci,obj0,obj1), m_ownManifold(false), m_manifoldPtr(mf) { if (!m_manifoldPtr && m_dispatcher->needsCollision(obj0,obj1)) { m_manifoldPtr = m_dispatcher->getNewManifold(obj0,obj1); m_ownManifold = true; } } btBoxBoxCollisionAlgorithm::~btBoxBoxCollisionAlgorithm() { if (m_ownManifold) { if (m_manifoldPtr) m_dispatcher->releaseManifold(m_manifoldPtr); } } void btBoxBoxCollisionAlgorithm::processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) { if (!m_manifoldPtr) return; btCollisionObject* col0 = body0; btCollisionObject* col1 = body1; btBoxShape* box0 = (btBoxShape*)col0->getCollisionShape(); btBoxShape* box1 = (btBoxShape*)col1->getCollisionShape(); /// report a contact. internally this will be kept persistent, and contact reduction is done resultOut->setPersistentManifold(m_manifoldPtr); #ifndef USE_PERSISTENT_CONTACTS m_manifoldPtr->clearManifold(); #endif //USE_PERSISTENT_CONTACTS btDiscreteCollisionDetectorInterface::ClosestPointInput input; input.m_maximumDistanceSquared = BT_LARGE_FLOAT; input.m_transformA = body0->getWorldTransform(); input.m_transformB = body1->getWorldTransform(); btBoxBoxDetector detector(box0,box1); detector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); #ifdef USE_PERSISTENT_CONTACTS // refreshContactPoints is only necessary when using persistent contact points. otherwise all points are newly added if (m_ownManifold) { resultOut->refreshContactPoints(); } #endif //USE_PERSISTENT_CONTACTS } btScalar btBoxBoxCollisionAlgorithm::calculateTimeOfImpact(btCollisionObject* /*body0*/,btCollisionObject* /*body1*/,const btDispatcherInfo& /*dispatchInfo*/,btManifoldResult* /*resultOut*/) { //not yet return 1.f; } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btSimulationIslandManager.h0000644000175000017500000000501211337071441032741 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 SIMULATION_ISLAND_MANAGER_H #define SIMULATION_ISLAND_MANAGER_H #include "BulletCollision/CollisionDispatch/btUnionFind.h" #include "btCollisionCreateFunc.h" #include "LinearMath/btAlignedObjectArray.h" #include "btCollisionObject.h" class btCollisionObject; class btCollisionWorld; class btDispatcher; class btPersistentManifold; ///SimulationIslandManager creates and handles simulation islands, using btUnionFind class btSimulationIslandManager { btUnionFind m_unionFind; btAlignedObjectArray m_islandmanifold; btAlignedObjectArray m_islandBodies; bool m_splitIslands; public: btSimulationIslandManager(); virtual ~btSimulationIslandManager(); void initUnionFind(int n); btUnionFind& getUnionFind() { return m_unionFind;} virtual void updateActivationState(btCollisionWorld* colWorld,btDispatcher* dispatcher); virtual void storeIslandActivationState(btCollisionWorld* world); void findUnions(btDispatcher* dispatcher,btCollisionWorld* colWorld); struct IslandCallback { virtual ~IslandCallback() {}; virtual void ProcessIsland(btCollisionObject** bodies,int numBodies,class btPersistentManifold** manifolds,int numManifolds, int islandId) = 0; }; void buildAndProcessIslands(btDispatcher* dispatcher,btCollisionWorld* collisionWorld, IslandCallback* callback); void buildIslands(btDispatcher* dispatcher,btCollisionWorld* colWorld); bool getSplitIslands() { return m_splitIslands; } void setSplitIslands(bool doSplitIslands) { m_splitIslands = doSplitIslands; } }; #endif //SIMULATION_ISLAND_MANAGER_H ././@LongLink0000000000000000000000000000015200000000000011563 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgorithm.hcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btConvexPlaneCollisionAlgori0000644000175000017500000000676211337071441033212 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 CONVEX_PLANE_COLLISION_ALGORITHM_H #define CONVEX_PLANE_COLLISION_ALGORITHM_H #include "BulletCollision/BroadphaseCollision/btCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" class btPersistentManifold; #include "btCollisionDispatcher.h" #include "LinearMath/btVector3.h" /// btSphereBoxCollisionAlgorithm provides sphere-box collision detection. /// Other features are frame-coherency (persistent data) and collision response. class btConvexPlaneCollisionAlgorithm : public btCollisionAlgorithm { bool m_ownManifold; btPersistentManifold* m_manifoldPtr; bool m_isSwapped; int m_numPerturbationIterations; int m_minimumPointsPerturbationThreshold; public: btConvexPlaneCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* col0,btCollisionObject* col1, bool isSwapped, int numPerturbationIterations,int minimumPointsPerturbationThreshold); virtual ~btConvexPlaneCollisionAlgorithm(); virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); void collideSingleContact (const btQuaternion& perturbeRot, btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual void getAllContactManifolds(btManifoldArray& manifoldArray) { if (m_manifoldPtr && m_ownManifold) { manifoldArray.push_back(m_manifoldPtr); } } struct CreateFunc :public btCollisionAlgorithmCreateFunc { int m_numPerturbationIterations; int m_minimumPointsPerturbationThreshold; CreateFunc() : m_numPerturbationIterations(1), m_minimumPointsPerturbationThreshold(1) { } virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexPlaneCollisionAlgorithm)); if (!m_swapped) { return new(mem) btConvexPlaneCollisionAlgorithm(0,ci,body0,body1,false,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold); } else { return new(mem) btConvexPlaneCollisionAlgorithm(0,ci,body0,body1,true,m_numPerturbationIterations,m_minimumPointsPerturbationThreshold); } } }; }; #endif //CONVEX_PLANE_COLLISION_ALGORITHM_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btCollisionWorld.h0000644000175000017500000003727011344267705031155 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://bulletphysics.com/Bullet/ 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. */ /** * @mainpage Bullet Documentation * * @section intro_sec Introduction * Bullet Collision Detection & Physics SDK * * Bullet is a Collision Detection and Rigid Body Dynamics Library. The Library is Open Source and free for commercial use, under the ZLib license ( http://opensource.org/licenses/zlib-license.php ). * * The main documentation is Bullet_User_Manual.pdf, included in the source code distribution. * There is the Physics Forum for feedback and general Collision Detection and Physics discussions. * Please visit http://www.bulletphysics.com * * @section install_sec Installation * * @subsection step1 Step 1: Download * You can download the Bullet Physics Library from the Google Code repository: http://code.google.com/p/bullet/downloads/list * * @subsection step2 Step 2: Building * Bullet main build system for all platforms is cmake, you can download http://www.cmake.org * cmake can autogenerate projectfiles for Microsoft Visual Studio, Apple Xcode, KDevelop and Unix Makefiles. * The easiest is to run the CMake cmake-gui graphical user interface and choose the options and generate projectfiles. * You can also use cmake in the command-line. Here are some examples for various platforms: * cmake . -G "Visual Studio 9 2008" * cmake . -G Xcode * cmake . -G "Unix Makefiles" * Although cmake is recommended, you can also use autotools for UNIX: ./autogen.sh ./configure to create a Makefile and then run make. * * @subsection step3 Step 3: Testing demos * Try to run and experiment with BasicDemo executable as a starting point. * Bullet can be used in several ways, as Full Rigid Body simulation, as Collision Detector Library or Low Level / Snippets like the GJK Closest Point calculation. * The Dependencies can be seen in this documentation under Directories * * @subsection step4 Step 4: Integrating in your application, full Rigid Body and Soft Body simulation * Check out BasicDemo how to create a btDynamicsWorld, btRigidBody and btCollisionShape, Stepping the simulation and synchronizing your graphics object transform. * Check out SoftDemo how to use soft body dynamics, using btSoftRigidDynamicsWorld. * @subsection step5 Step 5 : Integrate the Collision Detection Library (without Dynamics and other Extras) * Bullet Collision Detection can also be used without the Dynamics/Extras. * Check out btCollisionWorld and btCollisionObject, and the CollisionInterfaceDemo. * @subsection step6 Step 6 : Use Snippets like the GJK Closest Point calculation. * Bullet has been designed in a modular way keeping dependencies to a minimum. The ConvexHullDistance demo demonstrates direct use of btGjkPairDetector. * * @section copyright Copyright * For up-to-data information and copyright and contributors list check out the Bullet_User_Manual.pdf * */ #ifndef COLLISION_WORLD_H #define COLLISION_WORLD_H class btStackAlloc; class btCollisionShape; class btConvexShape; class btBroadphaseInterface; class btSerializer; #include "LinearMath/btVector3.h" #include "LinearMath/btTransform.h" #include "btCollisionObject.h" #include "btCollisionDispatcher.h" #include "BulletCollision/BroadphaseCollision/btOverlappingPairCache.h" #include "LinearMath/btAlignedObjectArray.h" ///CollisionWorld is interface and container for the collision detection class btCollisionWorld { protected: btAlignedObjectArray m_collisionObjects; btDispatcher* m_dispatcher1; btDispatcherInfo m_dispatchInfo; btStackAlloc* m_stackAlloc; btBroadphaseInterface* m_broadphasePairCache; btIDebugDraw* m_debugDrawer; ///m_forceUpdateAllAabbs can be set to false as an optimization to only update active object AABBs ///it is true by default, because it is error-prone (setting the position of static objects wouldn't update their AABB) bool m_forceUpdateAllAabbs; void serializeCollisionObjects(btSerializer* serializer); public: //this constructor doesn't own the dispatcher and paircache/broadphase btCollisionWorld(btDispatcher* dispatcher,btBroadphaseInterface* broadphasePairCache, btCollisionConfiguration* collisionConfiguration); virtual ~btCollisionWorld(); void setBroadphase(btBroadphaseInterface* pairCache) { m_broadphasePairCache = pairCache; } const btBroadphaseInterface* getBroadphase() const { return m_broadphasePairCache; } btBroadphaseInterface* getBroadphase() { return m_broadphasePairCache; } btOverlappingPairCache* getPairCache() { return m_broadphasePairCache->getOverlappingPairCache(); } btDispatcher* getDispatcher() { return m_dispatcher1; } const btDispatcher* getDispatcher() const { return m_dispatcher1; } void updateSingleAabb(btCollisionObject* colObj); virtual void updateAabbs(); virtual void setDebugDrawer(btIDebugDraw* debugDrawer) { m_debugDrawer = debugDrawer; } virtual btIDebugDraw* getDebugDrawer() { return m_debugDrawer; } virtual void debugDrawWorld(); virtual void debugDrawObject(const btTransform& worldTransform, const btCollisionShape* shape, const btVector3& color); ///LocalShapeInfo gives extra information for complex shapes ///Currently, only btTriangleMeshShape is available, so it just contains triangleIndex and subpart struct LocalShapeInfo { int m_shapePart; int m_triangleIndex; //const btCollisionShape* m_shapeTemp; //const btTransform* m_shapeLocalTransform; }; struct LocalRayResult { LocalRayResult(btCollisionObject* collisionObject, LocalShapeInfo* localShapeInfo, const btVector3& hitNormalLocal, btScalar hitFraction) :m_collisionObject(collisionObject), m_localShapeInfo(localShapeInfo), m_hitNormalLocal(hitNormalLocal), m_hitFraction(hitFraction) { } btCollisionObject* m_collisionObject; LocalShapeInfo* m_localShapeInfo; btVector3 m_hitNormalLocal; btScalar m_hitFraction; }; ///RayResultCallback is used to report new raycast results struct RayResultCallback { btScalar m_closestHitFraction; btCollisionObject* m_collisionObject; short int m_collisionFilterGroup; short int m_collisionFilterMask; //@BP Mod - Custom flags, currently used to enable backface culling on tri-meshes, see btRaycastCallback unsigned int m_flags; virtual ~RayResultCallback() { } bool hasHit() const { return (m_collisionObject != 0); } RayResultCallback() :m_closestHitFraction(btScalar(1.)), m_collisionObject(0), m_collisionFilterGroup(btBroadphaseProxy::DefaultFilter), m_collisionFilterMask(btBroadphaseProxy::AllFilter), //@BP Mod m_flags(0) { } virtual bool needsCollision(btBroadphaseProxy* proxy0) const { bool collides = (proxy0->m_collisionFilterGroup & m_collisionFilterMask) != 0; collides = collides && (m_collisionFilterGroup & proxy0->m_collisionFilterMask); return collides; } virtual btScalar addSingleResult(LocalRayResult& rayResult,bool normalInWorldSpace) = 0; }; struct ClosestRayResultCallback : public RayResultCallback { ClosestRayResultCallback(const btVector3& rayFromWorld,const btVector3& rayToWorld) :m_rayFromWorld(rayFromWorld), m_rayToWorld(rayToWorld) { } btVector3 m_rayFromWorld;//used to calculate hitPointWorld from hitFraction btVector3 m_rayToWorld; btVector3 m_hitNormalWorld; btVector3 m_hitPointWorld; virtual btScalar addSingleResult(LocalRayResult& rayResult,bool normalInWorldSpace) { //caller already does the filter on the m_closestHitFraction btAssert(rayResult.m_hitFraction <= m_closestHitFraction); m_closestHitFraction = rayResult.m_hitFraction; m_collisionObject = rayResult.m_collisionObject; if (normalInWorldSpace) { m_hitNormalWorld = rayResult.m_hitNormalLocal; } else { ///need to transform normal into worldspace m_hitNormalWorld = m_collisionObject->getWorldTransform().getBasis()*rayResult.m_hitNormalLocal; } m_hitPointWorld.setInterpolate3(m_rayFromWorld,m_rayToWorld,rayResult.m_hitFraction); return rayResult.m_hitFraction; } }; struct LocalConvexResult { LocalConvexResult(btCollisionObject* hitCollisionObject, LocalShapeInfo* localShapeInfo, const btVector3& hitNormalLocal, const btVector3& hitPointLocal, btScalar hitFraction ) :m_hitCollisionObject(hitCollisionObject), m_localShapeInfo(localShapeInfo), m_hitNormalLocal(hitNormalLocal), m_hitPointLocal(hitPointLocal), m_hitFraction(hitFraction) { } btCollisionObject* m_hitCollisionObject; LocalShapeInfo* m_localShapeInfo; btVector3 m_hitNormalLocal; btVector3 m_hitPointLocal; btScalar m_hitFraction; }; ///RayResultCallback is used to report new raycast results struct ConvexResultCallback { btScalar m_closestHitFraction; short int m_collisionFilterGroup; short int m_collisionFilterMask; ConvexResultCallback() :m_closestHitFraction(btScalar(1.)), m_collisionFilterGroup(btBroadphaseProxy::DefaultFilter), m_collisionFilterMask(btBroadphaseProxy::AllFilter) { } virtual ~ConvexResultCallback() { } bool hasHit() const { return (m_closestHitFraction < btScalar(1.)); } virtual bool needsCollision(btBroadphaseProxy* proxy0) const { bool collides = (proxy0->m_collisionFilterGroup & m_collisionFilterMask) != 0; collides = collides && (m_collisionFilterGroup & proxy0->m_collisionFilterMask); return collides; } virtual btScalar addSingleResult(LocalConvexResult& convexResult,bool normalInWorldSpace) = 0; }; struct ClosestConvexResultCallback : public ConvexResultCallback { ClosestConvexResultCallback(const btVector3& convexFromWorld,const btVector3& convexToWorld) :m_convexFromWorld(convexFromWorld), m_convexToWorld(convexToWorld), m_hitCollisionObject(0) { } btVector3 m_convexFromWorld;//used to calculate hitPointWorld from hitFraction btVector3 m_convexToWorld; btVector3 m_hitNormalWorld; btVector3 m_hitPointWorld; btCollisionObject* m_hitCollisionObject; virtual btScalar addSingleResult(LocalConvexResult& convexResult,bool normalInWorldSpace) { //caller already does the filter on the m_closestHitFraction btAssert(convexResult.m_hitFraction <= m_closestHitFraction); m_closestHitFraction = convexResult.m_hitFraction; m_hitCollisionObject = convexResult.m_hitCollisionObject; if (normalInWorldSpace) { m_hitNormalWorld = convexResult.m_hitNormalLocal; } else { ///need to transform normal into worldspace m_hitNormalWorld = m_hitCollisionObject->getWorldTransform().getBasis()*convexResult.m_hitNormalLocal; } m_hitPointWorld = convexResult.m_hitPointLocal; return convexResult.m_hitFraction; } }; ///ContactResultCallback is used to report contact points struct ContactResultCallback { short int m_collisionFilterGroup; short int m_collisionFilterMask; ContactResultCallback() :m_collisionFilterGroup(btBroadphaseProxy::DefaultFilter), m_collisionFilterMask(btBroadphaseProxy::AllFilter) { } virtual ~ContactResultCallback() { } virtual bool needsCollision(btBroadphaseProxy* proxy0) const { bool collides = (proxy0->m_collisionFilterGroup & m_collisionFilterMask) != 0; collides = collides && (m_collisionFilterGroup & proxy0->m_collisionFilterMask); return collides; } virtual btScalar addSingleResult(btManifoldPoint& cp, const btCollisionObject* colObj0,int partId0,int index0,const btCollisionObject* colObj1,int partId1,int index1) = 0; }; int getNumCollisionObjects() const { return int(m_collisionObjects.size()); } /// rayTest performs a raycast on all objects in the btCollisionWorld, and calls the resultCallback /// This allows for several queries: first hit, all hits, any hit, dependent on the value returned by the callback. virtual void rayTest(const btVector3& rayFromWorld, const btVector3& rayToWorld, RayResultCallback& resultCallback) const; /// convexTest performs a swept convex cast on all objects in the btCollisionWorld, and calls the resultCallback /// This allows for several queries: first hit, all hits, any hit, dependent on the value return by the callback. void convexSweepTest (const btConvexShape* castShape, const btTransform& from, const btTransform& to, ConvexResultCallback& resultCallback, btScalar allowedCcdPenetration = btScalar(0.)) const; ///contactTest performs a discrete collision test between colObj against all objects in the btCollisionWorld, and calls the resultCallback. ///it reports one or more contact points for every overlapping object (including the one with deepest penetration) void contactTest(btCollisionObject* colObj, ContactResultCallback& resultCallback); ///contactTest performs a discrete collision test between two collision objects and calls the resultCallback if overlap if detected. ///it reports one or more contact points (including the one with deepest penetration) void contactPairTest(btCollisionObject* colObjA, btCollisionObject* colObjB, ContactResultCallback& resultCallback); /// rayTestSingle performs a raycast call and calls the resultCallback. It is used internally by rayTest. /// In a future implementation, we consider moving the ray test as a virtual method in btCollisionShape. /// This allows more customization. static void rayTestSingle(const btTransform& rayFromTrans,const btTransform& rayToTrans, btCollisionObject* collisionObject, const btCollisionShape* collisionShape, const btTransform& colObjWorldTransform, RayResultCallback& resultCallback); /// objectQuerySingle performs a collision detection query and calls the resultCallback. It is used internally by rayTest. static void objectQuerySingle(const btConvexShape* castShape, const btTransform& rayFromTrans,const btTransform& rayToTrans, btCollisionObject* collisionObject, const btCollisionShape* collisionShape, const btTransform& colObjWorldTransform, ConvexResultCallback& resultCallback, btScalar allowedPenetration); virtual void addCollisionObject(btCollisionObject* collisionObject,short int collisionFilterGroup=btBroadphaseProxy::DefaultFilter,short int collisionFilterMask=btBroadphaseProxy::AllFilter); btCollisionObjectArray& getCollisionObjectArray() { return m_collisionObjects; } const btCollisionObjectArray& getCollisionObjectArray() const { return m_collisionObjects; } virtual void removeCollisionObject(btCollisionObject* collisionObject); virtual void performDiscreteCollisionDetection(); btDispatcherInfo& getDispatchInfo() { return m_dispatchInfo; } const btDispatcherInfo& getDispatchInfo() const { return m_dispatchInfo; } bool getForceUpdateAllAabbs() const { return m_forceUpdateAllAabbs; } void setForceUpdateAllAabbs( bool forceUpdateAllAabbs) { m_forceUpdateAllAabbs = forceUpdateAllAabbs; } ///Preliminary serialization test for Bullet 2.76. Loading those files requires a separate parser (Bullet/Demos/SerializeDemo) virtual void serialize(btSerializer* serializer); }; #endif //COLLISION_WORLD_H ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorithm.hcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btBox2dBox2dCollisionAlgorit0000644000175000017500000000545411337071441033026 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BOX_2D_BOX_2D__COLLISION_ALGORITHM_H #define BOX_2D_BOX_2D__COLLISION_ALGORITHM_H #include "BulletCollision/CollisionDispatch/btActivatingCollisionAlgorithm.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "BulletCollision/BroadphaseCollision/btDispatcher.h" #include "BulletCollision/CollisionDispatch/btCollisionCreateFunc.h" class btPersistentManifold; ///box-box collision detection class btBox2dBox2dCollisionAlgorithm : public btActivatingCollisionAlgorithm { bool m_ownManifold; btPersistentManifold* m_manifoldPtr; public: btBox2dBox2dCollisionAlgorithm(const btCollisionAlgorithmConstructionInfo& ci) : btActivatingCollisionAlgorithm(ci) {} virtual void processCollision (btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); virtual btScalar calculateTimeOfImpact(btCollisionObject* body0,btCollisionObject* body1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut); btBox2dBox2dCollisionAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,btCollisionObject* body0,btCollisionObject* body1); virtual ~btBox2dBox2dCollisionAlgorithm(); virtual void getAllContactManifolds(btManifoldArray& manifoldArray) { if (m_manifoldPtr && m_ownManifold) { manifoldArray.push_back(m_manifoldPtr); } } struct CreateFunc :public btCollisionAlgorithmCreateFunc { virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, btCollisionObject* body0,btCollisionObject* body1) { int bbsize = sizeof(btBox2dBox2dCollisionAlgorithm); void* ptr = ci.m_dispatcher1->allocateCollisionAlgorithm(bbsize); return new(ptr) btBox2dBox2dCollisionAlgorithm(0,ci,body0,body1); } }; }; #endif //BOX_2D_BOX_2D__COLLISION_ALGORITHM_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btCollisionConfiguration.h0000644000175000017500000000327011337071441032656 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BT_COLLISION_CONFIGURATION #define BT_COLLISION_CONFIGURATION struct btCollisionAlgorithmCreateFunc; class btStackAlloc; class btPoolAllocator; ///btCollisionConfiguration allows to configure Bullet collision detection ///stack allocator size, default collision algorithms and persistent manifold pool size ///@todo: describe the meaning class btCollisionConfiguration { public: virtual ~btCollisionConfiguration() { } ///memory pools virtual btPoolAllocator* getPersistentManifoldPool() = 0; virtual btPoolAllocator* getCollisionAlgorithmPool() = 0; virtual btStackAlloc* getStackAllocator() = 0; virtual btCollisionAlgorithmCreateFunc* getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1) =0; }; #endif //BT_COLLISION_CONFIGURATION critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionDispatch/btUnionFind.cpp0000644000175000017500000000401511337071441030415 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btUnionFind.h" btUnionFind::~btUnionFind() { Free(); } btUnionFind::btUnionFind() { } void btUnionFind::allocate(int N) { m_elements.resize(N); } void btUnionFind::Free() { m_elements.clear(); } void btUnionFind::reset(int N) { allocate(N); for (int i = 0; i < N; i++) { m_elements[i].m_id = i; m_elements[i].m_sz = 1; } } class btUnionFindElementSortPredicate { public: bool operator() ( const btElement& lhs, const btElement& rhs ) { return lhs.m_id < rhs.m_id; } }; ///this is a special operation, destroying the content of btUnionFind. ///it sorts the elements, based on island id, in order to make it easy to iterate over islands void btUnionFind::sortIslands() { //first store the original body index, and islandId int numElements = m_elements.size(); for (int i=0;im_swapped = true; #endif //USE_BUGGY_SPHERE_BOX_ALGORITHM mem = btAlignedAlloc(sizeof(btSphereTriangleCollisionAlgorithm::CreateFunc),16); m_sphereTriangleCF = new (mem)btSphereTriangleCollisionAlgorithm::CreateFunc; mem = btAlignedAlloc(sizeof(btSphereTriangleCollisionAlgorithm::CreateFunc),16); m_triangleSphereCF = new (mem)btSphereTriangleCollisionAlgorithm::CreateFunc; m_triangleSphereCF->m_swapped = true; mem = btAlignedAlloc(sizeof(btBoxBoxCollisionAlgorithm::CreateFunc),16); m_boxBoxCF = new(mem)btBoxBoxCollisionAlgorithm::CreateFunc; //convex versus plane mem = btAlignedAlloc (sizeof(btConvexPlaneCollisionAlgorithm::CreateFunc),16); m_convexPlaneCF = new (mem) btConvexPlaneCollisionAlgorithm::CreateFunc; mem = btAlignedAlloc (sizeof(btConvexPlaneCollisionAlgorithm::CreateFunc),16); m_planeConvexCF = new (mem) btConvexPlaneCollisionAlgorithm::CreateFunc; m_planeConvexCF->m_swapped = true; ///calculate maximum element size, big enough to fit any collision algorithm in the memory pool int maxSize = sizeof(btConvexConvexAlgorithm); int maxSize2 = sizeof(btConvexConcaveCollisionAlgorithm); int maxSize3 = sizeof(btCompoundCollisionAlgorithm); int sl = sizeof(btConvexSeparatingDistanceUtil); sl = sizeof(btGjkPairDetector); int collisionAlgorithmMaxElementSize = btMax(maxSize,constructionInfo.m_customCollisionAlgorithmMaxElementSize); collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize2); collisionAlgorithmMaxElementSize = btMax(collisionAlgorithmMaxElementSize,maxSize3); if (constructionInfo.m_stackAlloc) { m_ownsStackAllocator = false; this->m_stackAlloc = constructionInfo.m_stackAlloc; } else { m_ownsStackAllocator = true; void* mem = btAlignedAlloc(sizeof(btStackAlloc),16); m_stackAlloc = new(mem)btStackAlloc(constructionInfo.m_defaultStackAllocatorSize); } if (constructionInfo.m_persistentManifoldPool) { m_ownsPersistentManifoldPool = false; m_persistentManifoldPool = constructionInfo.m_persistentManifoldPool; } else { m_ownsPersistentManifoldPool = true; void* mem = btAlignedAlloc(sizeof(btPoolAllocator),16); m_persistentManifoldPool = new (mem) btPoolAllocator(sizeof(btPersistentManifold),constructionInfo.m_defaultMaxPersistentManifoldPoolSize); } if (constructionInfo.m_collisionAlgorithmPool) { m_ownsCollisionAlgorithmPool = false; m_collisionAlgorithmPool = constructionInfo.m_collisionAlgorithmPool; } else { m_ownsCollisionAlgorithmPool = true; void* mem = btAlignedAlloc(sizeof(btPoolAllocator),16); m_collisionAlgorithmPool = new(mem) btPoolAllocator(collisionAlgorithmMaxElementSize,constructionInfo.m_defaultMaxCollisionAlgorithmPoolSize); } } btDefaultCollisionConfiguration::~btDefaultCollisionConfiguration() { if (m_ownsStackAllocator) { m_stackAlloc->destroy(); m_stackAlloc->~btStackAlloc(); btAlignedFree(m_stackAlloc); } if (m_ownsCollisionAlgorithmPool) { m_collisionAlgorithmPool->~btPoolAllocator(); btAlignedFree(m_collisionAlgorithmPool); } if (m_ownsPersistentManifoldPool) { m_persistentManifoldPool->~btPoolAllocator(); btAlignedFree(m_persistentManifoldPool); } m_convexConvexCreateFunc->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_convexConvexCreateFunc); m_convexConcaveCreateFunc->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_convexConcaveCreateFunc); m_swappedConvexConcaveCreateFunc->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_swappedConvexConcaveCreateFunc); m_compoundCreateFunc->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_compoundCreateFunc); m_swappedCompoundCreateFunc->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_swappedCompoundCreateFunc); m_emptyCreateFunc->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_emptyCreateFunc); m_sphereSphereCF->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_sphereSphereCF); #ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM m_sphereBoxCF->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_sphereBoxCF); m_boxSphereCF->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_boxSphereCF); #endif //USE_BUGGY_SPHERE_BOX_ALGORITHM m_sphereTriangleCF->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_sphereTriangleCF); m_triangleSphereCF->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_triangleSphereCF); m_boxBoxCF->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_boxBoxCF); m_convexPlaneCF->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_convexPlaneCF); m_planeConvexCF->~btCollisionAlgorithmCreateFunc(); btAlignedFree( m_planeConvexCF); m_simplexSolver->~btVoronoiSimplexSolver(); btAlignedFree(m_simplexSolver); m_pdSolver->~btConvexPenetrationDepthSolver(); btAlignedFree(m_pdSolver); } btCollisionAlgorithmCreateFunc* btDefaultCollisionConfiguration::getCollisionAlgorithmCreateFunc(int proxyType0,int proxyType1) { if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1==SPHERE_SHAPE_PROXYTYPE)) { return m_sphereSphereCF; } #ifdef USE_BUGGY_SPHERE_BOX_ALGORITHM if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE) && (proxyType1==BOX_SHAPE_PROXYTYPE)) { return m_sphereBoxCF; } if ((proxyType0 == BOX_SHAPE_PROXYTYPE ) && (proxyType1==SPHERE_SHAPE_PROXYTYPE)) { return m_boxSphereCF; } #endif //USE_BUGGY_SPHERE_BOX_ALGORITHM if ((proxyType0 == SPHERE_SHAPE_PROXYTYPE ) && (proxyType1==TRIANGLE_SHAPE_PROXYTYPE)) { return m_sphereTriangleCF; } if ((proxyType0 == TRIANGLE_SHAPE_PROXYTYPE ) && (proxyType1==SPHERE_SHAPE_PROXYTYPE)) { return m_triangleSphereCF; } if ((proxyType0 == BOX_SHAPE_PROXYTYPE) && (proxyType1 == BOX_SHAPE_PROXYTYPE)) { return m_boxBoxCF; } if (btBroadphaseProxy::isConvex(proxyType0) && (proxyType1 == STATIC_PLANE_PROXYTYPE)) { return m_convexPlaneCF; } if (btBroadphaseProxy::isConvex(proxyType1) && (proxyType0 == STATIC_PLANE_PROXYTYPE)) { return m_planeConvexCF; } if (btBroadphaseProxy::isConvex(proxyType0) && btBroadphaseProxy::isConvex(proxyType1)) { return m_convexConvexCreateFunc; } if (btBroadphaseProxy::isConvex(proxyType0) && btBroadphaseProxy::isConcave(proxyType1)) { return m_convexConcaveCreateFunc; } if (btBroadphaseProxy::isConvex(proxyType1) && btBroadphaseProxy::isConcave(proxyType0)) { return m_swappedConvexConcaveCreateFunc; } if (btBroadphaseProxy::isCompound(proxyType0)) { return m_compoundCreateFunc; } else { if (btBroadphaseProxy::isCompound(proxyType1)) { return m_swappedCompoundCreateFunc; } } //failed to find an algorithm return m_emptyCreateFunc; } void btDefaultCollisionConfiguration::setConvexConvexMultipointIterations(int numPerturbationIterations, int minimumPointsPerturbationThreshold) { btConvexConvexAlgorithm::CreateFunc* convexConvex = (btConvexConvexAlgorithm::CreateFunc*) m_convexConvexCreateFunc; convexConvex->m_numPerturbationIterations = numPerturbationIterations; convexConvex->m_minimumPointsPerturbationThreshold = minimumPointsPerturbationThreshold; } critterding-beta12.1/src/utils/bullet/BulletCollision/ibmsdk/0000755000175000017500000000000011347266042023334 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletCollision/ibmsdk/Makefile0000644000175000017500000000534011337071441024772 0ustar bobkebobke#### Source code Dirs VPATH = \ ../BroadphaseCollision \ ../CollisionDispatch \ ../NarrowPhaseCollision \ ../CollisionShapes ROOT = ../../.. #### Library LIBRARY_ppu = bulletcollision.a #### Compiler flags CPPFLAGS = \ -DUSE_LIBSPE2 \ -I../BroadphaseCollision \ -I../CollisionDispath \ -I../NarrowPhaseCollision \ -I../CollisionShapes \ -I$(ROOT)/src/ \ -I$(SDKINC) #### Optimization level flags #CC_OPT_LEVEL = $(CC_OPT_LEVEL_DEBUG) CC_OPT_LEVEL = -O3 ##### Objects to be archived in lib OBJS = \ btAxisSweep3.o \ btQuantizedBvh.o \ btBroadphaseProxy.o \ btCollisionAlgorithm.o \ btDispatcher.o \ btDbvtBroadphase.o \ btDbvt.o \ btOverlappingPairCache.o \ btSimpleBroadphase.o \ btContinuousConvexCollision.o \ btConvexCast.o \ btGjkConvexCast.o \ btGjkEpa2.o \ btGjkEpaPenetrationDepthSolver.o \ btGjkPairDetector.o \ btDefaultCollisionConfiguration.o \ btMinkowskiPenetrationDepthSolver.o \ btPersistentManifold.o \ btRaycastCallback.o \ btSubSimplexConvexCast.o \ btVoronoiSimplexSolver.o \ btCollisionDispatcher.o \ btCollisionObject.o \ btCollisionWorld.o \ btCompoundCollisionAlgorithm.o \ btBoxBoxCollisionAlgorithm.o \ btBoxBoxDetector.o \ btConvexPlaneCollisionAlgorithm.o \ btConvexConcaveCollisionAlgorithm.o \ btConvexConvexAlgorithm.o \ btDefaultCollisionConfiguration.o \ btEmptyCollisionAlgorithm.o \ btManifoldResult.o \ btSimulationIslandManager.o \ btSphereBoxCollisionAlgorithm.o \ btSphereSphereCollisionAlgorithm.o \ btSphereTriangleCollisionAlgorithm.o \ btActivatingCollisionAlgorithm.o \ btUnionFind.o \ SphereTriangleDetector.o \ btBoxShape.o \ btBvhTriangleMeshShape.o \ btCapsuleShape.o \ btCollisionShape.o \ btCompoundShape.o \ btConcaveShape.o \ btConeShape.o \ btConvexHullShape.o \ btConvexShape.o \ btConvexInternalShape.o \ btConvexTriangleMeshShape.o \ btCylinderShape.o \ btEmptyShape.o \ btHeightfieldTerrainShape.o \ btMinkowskiSumShape.o \ btMultiSphereShape.o \ btOptimizedBvh.o \ btPolyhedralConvexShape.o \ btSphereShape.o \ btStaticPlaneShape.o \ btStridingMeshInterface.o \ btTetrahedronShape.o \ btTriangleBuffer.o \ btTriangleCallback.o \ btTriangleIndexVertexArray.o \ btTriangleMesh.o \ btTriangleMeshShape.o \ btUniformScalingShape.o #### Install directories INSTALL_DIR = $(ROOT)/lib/ibmsdk INSTALL_FILES = $(LIBRARY_ppu) IBM_CELLSDK_VERSION := $(shell if [ -d /opt/cell ]; then echo "3.0"; fi) ifeq ("$(IBM_CELLSDK_VERSION)","3.0") CELL_TOP ?= /opt/cell/sdk include $(CELL_TOP)/buildutils/make.footer else CELL_TOP ?= /opt/ibm/cell-sdk/prototype include $(CELL_TOP)/make.footer endif critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/0000755000175000017500000000000011347266042025162 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btTriangleCallback.h0000644000175000017500000000324211337071441031040 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 TRIANGLE_CALLBACK_H #define TRIANGLE_CALLBACK_H #include "LinearMath/btVector3.h" ///The btTriangleCallback provides a callback for each overlapping triangle when calling processAllTriangles. ///This callback is called by processAllTriangles for all btConcaveShape derived class, such as btBvhTriangleMeshShape, btStaticPlaneShape and btHeightfieldTerrainShape. class btTriangleCallback { public: virtual ~btTriangleCallback(); virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex) = 0; }; class btInternalTriangleIndexCallback { public: virtual ~btInternalTriangleIndexCallback(); virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex) = 0; }; #endif //TRIANGLE_CALLBACK_H ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshSha0000644000175000017500000000443711337071441033207 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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. */ /// This file was created by Alex Silverman #include "BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.h" #include "BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.h" //#include "BulletCollision/CollisionShapes/btOptimizedBvh.h" ///Obtains the material for a specific triangle const btMaterial * btMultimaterialTriangleMeshShape::getMaterialProperties(int partID, int triIndex) { const unsigned char * materialBase = 0; int numMaterials; PHY_ScalarType materialType; int materialStride; const unsigned char * triangleMaterialBase = 0; int numTriangles; int triangleMaterialStride; PHY_ScalarType triangleType; ((btTriangleIndexVertexMaterialArray*)m_meshInterface)->getLockedReadOnlyMaterialBase(&materialBase, numMaterials, materialType, materialStride, &triangleMaterialBase, numTriangles, triangleMaterialStride, triangleType, partID); // return the pointer to the place with the friction for the triangle // TODO: This depends on whether it's a moving mesh or not // BUG IN GIMPACT //return (btScalar*)(&materialBase[triangleMaterialBase[(triIndex-1) * triangleMaterialStride] * materialStride]); int * matInd = (int *)(&(triangleMaterialBase[(triIndex * triangleMaterialStride)])); btMaterial *matVal = (btMaterial *)(&(materialBase[*matInd * materialStride])); return (matVal); } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btConvexShape.cpp0000644000175000017500000003060111337071441030433 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btConvexShape.h" #include "btTriangleShape.h" #include "btSphereShape.h" #include "btCylinderShape.h" #include "btCapsuleShape.h" #include "btConvexHullShape.h" #include "btConvexPointCloudShape.h" ///not supported on IBM SDK, until we fix the alignment of btVector3 #if defined (__CELLOS_LV2__) && defined (__SPU__) #include static inline vec_float4 vec_dot3( vec_float4 vec0, vec_float4 vec1 ) { vec_float4 result; result = spu_mul( vec0, vec1 ); result = spu_madd( spu_rlqwbyte( vec0, 4 ), spu_rlqwbyte( vec1, 4 ), result ); return spu_madd( spu_rlqwbyte( vec0, 8 ), spu_rlqwbyte( vec1, 8 ), result ); } #endif //__SPU__ btConvexShape::btConvexShape () { } btConvexShape::~btConvexShape() { } static btVector3 convexHullSupport (const btVector3& localDirOrg, const btVector3* points, int numPoints, const btVector3& localScaling) { btVector3 vec = localDirOrg * localScaling; #if defined (__CELLOS_LV2__) && defined (__SPU__) btVector3 localDir = vec; vec_float4 v_distMax = {-FLT_MAX,0,0,0}; vec_int4 v_idxMax = {-999,0,0,0}; int v=0; int numverts = numPoints; for(;v<(int)numverts-4;v+=4) { vec_float4 p0 = vec_dot3(points[v ].get128(),localDir.get128()); vec_float4 p1 = vec_dot3(points[v+1].get128(),localDir.get128()); vec_float4 p2 = vec_dot3(points[v+2].get128(),localDir.get128()); vec_float4 p3 = vec_dot3(points[v+3].get128(),localDir.get128()); const vec_int4 i0 = {v ,0,0,0}; const vec_int4 i1 = {v+1,0,0,0}; const vec_int4 i2 = {v+2,0,0,0}; const vec_int4 i3 = {v+3,0,0,0}; vec_uint4 retGt01 = spu_cmpgt(p0,p1); vec_float4 pmax01 = spu_sel(p1,p0,retGt01); vec_int4 imax01 = spu_sel(i1,i0,retGt01); vec_uint4 retGt23 = spu_cmpgt(p2,p3); vec_float4 pmax23 = spu_sel(p3,p2,retGt23); vec_int4 imax23 = spu_sel(i3,i2,retGt23); vec_uint4 retGt0123 = spu_cmpgt(pmax01,pmax23); vec_float4 pmax0123 = spu_sel(pmax23,pmax01,retGt0123); vec_int4 imax0123 = spu_sel(imax23,imax01,retGt0123); vec_uint4 retGtMax = spu_cmpgt(v_distMax,pmax0123); v_distMax = spu_sel(pmax0123,v_distMax,retGtMax); v_idxMax = spu_sel(imax0123,v_idxMax,retGtMax); } for(;v<(int)numverts;v++) { vec_float4 p = vec_dot3(points[v].get128(),localDir.get128()); const vec_int4 i = {v,0,0,0}; vec_uint4 retGtMax = spu_cmpgt(v_distMax,p); v_distMax = spu_sel(p,v_distMax,retGtMax); v_idxMax = spu_sel(i,v_idxMax,retGtMax); } int ptIndex = spu_extract(v_idxMax,0); const btVector3& supVec= points[ptIndex] * localScaling; return supVec; #else btScalar newDot,maxDot = btScalar(-BT_LARGE_FLOAT); int ptIndex = -1; for (int i=0;i maxDot) { maxDot = newDot; ptIndex = i; } } btAssert(ptIndex >= 0); btVector3 supVec = points[ptIndex] * localScaling; return supVec; #endif //__SPU__ } btVector3 btConvexShape::localGetSupportVertexWithoutMarginNonVirtual (const btVector3& localDir) const { switch (m_shapeType) { case SPHERE_SHAPE_PROXYTYPE: { return btVector3(0,0,0); } case BOX_SHAPE_PROXYTYPE: { btBoxShape* convexShape = (btBoxShape*)this; const btVector3& halfExtents = convexShape->getImplicitShapeDimensions(); return btVector3(btFsels(localDir.x(), halfExtents.x(), -halfExtents.x()), btFsels(localDir.y(), halfExtents.y(), -halfExtents.y()), btFsels(localDir.z(), halfExtents.z(), -halfExtents.z())); } case TRIANGLE_SHAPE_PROXYTYPE: { btTriangleShape* triangleShape = (btTriangleShape*)this; btVector3 dir(localDir.getX(),localDir.getY(),localDir.getZ()); btVector3* vertices = &triangleShape->m_vertices1[0]; btVector3 dots(dir.dot(vertices[0]), dir.dot(vertices[1]), dir.dot(vertices[2])); btVector3 sup = vertices[dots.maxAxis()]; return btVector3(sup.getX(),sup.getY(),sup.getZ()); } case CYLINDER_SHAPE_PROXYTYPE: { btCylinderShape* cylShape = (btCylinderShape*)this; //mapping of halfextents/dimension onto radius/height depends on how cylinder local orientation is (upAxis) btVector3 halfExtents = cylShape->getImplicitShapeDimensions(); btVector3 v(localDir.getX(),localDir.getY(),localDir.getZ()); int cylinderUpAxis = cylShape->getUpAxis(); int XX(1),YY(0),ZZ(2); switch (cylinderUpAxis) { case 0: { XX = 1; YY = 0; ZZ = 2; } break; case 1: { XX = 0; YY = 1; ZZ = 2; } break; case 2: { XX = 0; YY = 2; ZZ = 1; } break; default: btAssert(0); break; }; btScalar radius = halfExtents[XX]; btScalar halfHeight = halfExtents[cylinderUpAxis]; btVector3 tmp; btScalar d ; btScalar s = btSqrt(v[XX] * v[XX] + v[ZZ] * v[ZZ]); if (s != btScalar(0.0)) { d = radius / s; tmp[XX] = v[XX] * d; tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; tmp[ZZ] = v[ZZ] * d; return btVector3(tmp.getX(),tmp.getY(),tmp.getZ()); } else { tmp[XX] = radius; tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; tmp[ZZ] = btScalar(0.0); return btVector3(tmp.getX(),tmp.getY(),tmp.getZ()); } } case CAPSULE_SHAPE_PROXYTYPE: { btVector3 vec0(localDir.getX(),localDir.getY(),localDir.getZ()); btCapsuleShape* capsuleShape = (btCapsuleShape*)this; btScalar halfHeight = capsuleShape->getHalfHeight(); int capsuleUpAxis = capsuleShape->getUpAxis(); btScalar radius = capsuleShape->getRadius(); btVector3 supVec(0,0,0); btScalar maxDot(btScalar(-BT_LARGE_FLOAT)); btVector3 vec = vec0; btScalar lenSqr = vec.length2(); if (lenSqr < btScalar(0.0001)) { vec.setValue(1,0,0); } else { btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); vec *= rlen; } btVector3 vtx; btScalar newDot; { btVector3 pos(0,0,0); pos[capsuleUpAxis] = halfHeight; //vtx = pos +vec*(radius); vtx = pos +vec*capsuleShape->getLocalScalingNV()*(radius) - vec * capsuleShape->getMarginNV(); newDot = vec.dot(vtx); if (newDot > maxDot) { maxDot = newDot; supVec = vtx; } } { btVector3 pos(0,0,0); pos[capsuleUpAxis] = -halfHeight; //vtx = pos +vec*(radius); vtx = pos +vec*capsuleShape->getLocalScalingNV()*(radius) - vec * capsuleShape->getMarginNV(); newDot = vec.dot(vtx); if (newDot > maxDot) { maxDot = newDot; supVec = vtx; } } return btVector3(supVec.getX(),supVec.getY(),supVec.getZ()); } case CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE: { btConvexPointCloudShape* convexPointCloudShape = (btConvexPointCloudShape*)this; btVector3* points = convexPointCloudShape->getUnscaledPoints (); int numPoints = convexPointCloudShape->getNumPoints (); return convexHullSupport (localDir, points, numPoints,convexPointCloudShape->getLocalScalingNV()); } case CONVEX_HULL_SHAPE_PROXYTYPE: { btConvexHullShape* convexHullShape = (btConvexHullShape*)this; btVector3* points = convexHullShape->getUnscaledPoints(); int numPoints = convexHullShape->getNumPoints (); return convexHullSupport (localDir, points, numPoints,convexHullShape->getLocalScalingNV()); } default: #ifndef __SPU__ return this->localGetSupportingVertexWithoutMargin (localDir); #else btAssert (0); #endif } // should never reach here btAssert (0); return btVector3 (btScalar(0.0f), btScalar(0.0f), btScalar(0.0f)); } btVector3 btConvexShape::localGetSupportVertexNonVirtual (const btVector3& localDir) const { btVector3 localDirNorm = localDir; if (localDirNorm .length2() < (SIMD_EPSILON*SIMD_EPSILON)) { localDirNorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.)); } localDirNorm.normalize (); return localGetSupportVertexWithoutMarginNonVirtual(localDirNorm)+ getMarginNonVirtual() * localDirNorm; } /* TODO: This should be bumped up to btCollisionShape () */ btScalar btConvexShape::getMarginNonVirtual () const { switch (m_shapeType) { case SPHERE_SHAPE_PROXYTYPE: { btSphereShape* sphereShape = (btSphereShape*)this; return sphereShape->getRadius (); } case BOX_SHAPE_PROXYTYPE: { btBoxShape* convexShape = (btBoxShape*)this; return convexShape->getMarginNV (); } case TRIANGLE_SHAPE_PROXYTYPE: { btTriangleShape* triangleShape = (btTriangleShape*)this; return triangleShape->getMarginNV (); } case CYLINDER_SHAPE_PROXYTYPE: { btCylinderShape* cylShape = (btCylinderShape*)this; return cylShape->getMarginNV(); } case CAPSULE_SHAPE_PROXYTYPE: { btCapsuleShape* capsuleShape = (btCapsuleShape*)this; return capsuleShape->getMarginNV(); } case CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE: /* fall through */ case CONVEX_HULL_SHAPE_PROXYTYPE: { btPolyhedralConvexShape* convexHullShape = (btPolyhedralConvexShape*)this; return convexHullShape->getMarginNV(); } default: #ifndef __SPU__ return this->getMargin (); #else btAssert (0); #endif } // should never reach here btAssert (0); return btScalar(0.0f); } #ifndef __SPU__ void btConvexShape::getAabbNonVirtual (const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const { switch (m_shapeType) { case SPHERE_SHAPE_PROXYTYPE: { btSphereShape* sphereShape = (btSphereShape*)this; btScalar radius = sphereShape->getImplicitShapeDimensions().getX();// * convexShape->getLocalScaling().getX(); btScalar margin = radius + sphereShape->getMarginNonVirtual(); const btVector3& center = t.getOrigin(); btVector3 extent(margin,margin,margin); aabbMin = center - extent; aabbMax = center + extent; } break; case CYLINDER_SHAPE_PROXYTYPE: /* fall through */ case BOX_SHAPE_PROXYTYPE: { btBoxShape* convexShape = (btBoxShape*)this; btScalar margin=convexShape->getMarginNonVirtual(); btVector3 halfExtents = convexShape->getImplicitShapeDimensions(); halfExtents += btVector3(margin,margin,margin); btMatrix3x3 abs_b = t.getBasis().absolute(); btVector3 center = t.getOrigin(); btVector3 extent = btVector3(abs_b[0].dot(halfExtents),abs_b[1].dot(halfExtents),abs_b[2].dot(halfExtents)); aabbMin = center - extent; aabbMax = center + extent; break; } case TRIANGLE_SHAPE_PROXYTYPE: { btTriangleShape* triangleShape = (btTriangleShape*)this; btScalar margin = triangleShape->getMarginNonVirtual(); for (int i=0;i<3;i++) { btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.)); vec[i] = btScalar(1.); btVector3 sv = localGetSupportVertexWithoutMarginNonVirtual(vec*t.getBasis()); btVector3 tmp = t(sv); aabbMax[i] = tmp[i]+margin; vec[i] = btScalar(-1.); tmp = t(localGetSupportVertexWithoutMarginNonVirtual(vec*t.getBasis())); aabbMin[i] = tmp[i]-margin; } } break; case CAPSULE_SHAPE_PROXYTYPE: { btCapsuleShape* capsuleShape = (btCapsuleShape*)this; btVector3 halfExtents(capsuleShape->getRadius(),capsuleShape->getRadius(),capsuleShape->getRadius()); int m_upAxis = capsuleShape->getUpAxis(); halfExtents[m_upAxis] = capsuleShape->getRadius() + capsuleShape->getHalfHeight(); halfExtents += btVector3(capsuleShape->getMarginNonVirtual(),capsuleShape->getMarginNonVirtual(),capsuleShape->getMarginNonVirtual()); btMatrix3x3 abs_b = t.getBasis().absolute(); btVector3 center = t.getOrigin(); btVector3 extent = btVector3(abs_b[0].dot(halfExtents),abs_b[1].dot(halfExtents),abs_b[2].dot(halfExtents)); aabbMin = center - extent; aabbMax = center + extent; } break; case CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE: case CONVEX_HULL_SHAPE_PROXYTYPE: { btPolyhedralConvexAabbCachingShape* convexHullShape = (btPolyhedralConvexAabbCachingShape*)this; btScalar margin = convexHullShape->getMarginNonVirtual(); convexHullShape->getNonvirtualAabb (t, aabbMin, aabbMax, margin); } break; default: #ifndef __SPU__ this->getAabb (t, aabbMin, aabbMax); #else btAssert (0); #endif break; } // should never reach here btAssert (0); } #endif //__SPU__ critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btMaterial.h0000644000175000017500000000261211344267705027424 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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. */ /// This file was created by Alex Silverman #ifndef MATERIAL_H #define MATERIAL_H // Material class to be used by btMultimaterialTriangleMeshShape to store triangle properties class btMaterial { // public members so that materials can change due to world events public: btScalar m_friction; btScalar m_restitution; int pad[2]; btMaterial(){} btMaterial(btScalar fric, btScalar rest) { m_friction = fric; m_restitution = rest; } }; #endif // MATERIAL_H ././@LongLink0000000000000000000000000000015300000000000011564 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.hcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialA0000644000175000017500000000763611337071441033156 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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. */ ///This file was created by Alex Silverman #ifndef BT_MULTIMATERIAL_TRIANGLE_INDEX_VERTEX_ARRAY_H #define BT_MULTIMATERIAL_TRIANGLE_INDEX_VERTEX_ARRAY_H #include "btTriangleIndexVertexArray.h" ATTRIBUTE_ALIGNED16( struct) btMaterialProperties { ///m_materialBase ==========> 2 btScalar values make up one material, friction then restitution int m_numMaterials; const unsigned char * m_materialBase; int m_materialStride; PHY_ScalarType m_materialType; ///m_numTriangles <=========== This exists in the btIndexedMesh object for the same subpart, but since we're /// padding the structure, it can be reproduced at no real cost ///m_triangleMaterials =====> 1 integer value makes up one entry /// eg: m_triangleMaterials[1] = 5; // This will set triangle 2 to use material 5 int m_numTriangles; const unsigned char * m_triangleMaterialsBase; int m_triangleMaterialStride; ///m_triangleType <========== Automatically set in addMaterialProperties PHY_ScalarType m_triangleType; }; typedef btAlignedObjectArray MaterialArray; ///Teh btTriangleIndexVertexMaterialArray is built on TriangleIndexVertexArray ///The addition of a material array allows for the utilization of the partID and ///triangleIndex that are returned in the ContactAddedCallback. As with ///TriangleIndexVertexArray, no duplicate is made of the material data, so it ///is the users responsibility to maintain the array during the lifetime of the ///TriangleIndexVertexMaterialArray. ATTRIBUTE_ALIGNED16(class) btTriangleIndexVertexMaterialArray : public btTriangleIndexVertexArray { protected: MaterialArray m_materials; public: BT_DECLARE_ALIGNED_ALLOCATOR(); btTriangleIndexVertexMaterialArray() { } btTriangleIndexVertexMaterialArray(int numTriangles,int* triangleIndexBase,int triangleIndexStride, int numVertices,btScalar* vertexBase,int vertexStride, int numMaterials, unsigned char* materialBase, int materialStride, int* triangleMaterialsBase, int materialIndexStride); virtual ~btTriangleIndexVertexMaterialArray() {} void addMaterialProperties(const btMaterialProperties& mat, PHY_ScalarType triangleType = PHY_INTEGER) { m_materials.push_back(mat); m_materials[m_materials.size()-1].m_triangleType = triangleType; } virtual void getLockedMaterialBase(unsigned char **materialBase, int& numMaterials, PHY_ScalarType& materialType, int& materialStride, unsigned char ** triangleMaterialBase, int& numTriangles, int& triangleMaterialStride, PHY_ScalarType& triangleType ,int subpart = 0); virtual void getLockedReadOnlyMaterialBase(const unsigned char **materialBase, int& numMaterials, PHY_ScalarType& materialType, int& materialStride, const unsigned char ** triangleMaterialBase, int& numTriangles, int& triangleMaterialStride, PHY_ScalarType& triangleType, int subpart = 0); } ; #endif //BT_MULTIMATERIAL_TRIANGLE_INDEX_VERTEX_ARRAY_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btTriangleMeshShape.h0000644000175000017500000000526611344267705031241 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 TRIANGLE_MESH_SHAPE_H #define TRIANGLE_MESH_SHAPE_H #include "btConcaveShape.h" #include "btStridingMeshInterface.h" ///The btTriangleMeshShape is an internal concave triangle mesh interface. Don't use this class directly, use btBvhTriangleMeshShape instead. class btTriangleMeshShape : public btConcaveShape { protected: btVector3 m_localAabbMin; btVector3 m_localAabbMax; btStridingMeshInterface* m_meshInterface; ///btTriangleMeshShape constructor has been disabled/protected, so that users will not mistakenly use this class. ///Don't use btTriangleMeshShape but use btBvhTriangleMeshShape instead! btTriangleMeshShape(btStridingMeshInterface* meshInterface); public: virtual ~btTriangleMeshShape(); virtual btVector3 localGetSupportingVertex(const btVector3& vec) const; virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const { btAssert(0); return localGetSupportingVertex(vec); } void recalcLocalAabb(); virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const; virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; virtual void setLocalScaling(const btVector3& scaling); virtual const btVector3& getLocalScaling() const; btStridingMeshInterface* getMeshInterface() { return m_meshInterface; } const btStridingMeshInterface* getMeshInterface() const { return m_meshInterface; } const btVector3& getLocalAabbMin() const { return m_localAabbMin; } const btVector3& getLocalAabbMax() const { return m_localAabbMax; } //debugging virtual const char* getName()const {return "TRIANGLEMESH";} }; #endif //TRIANGLE_MESH_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btUniformScalingShape.cpp0000644000175000017500000001012611337071441032111 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btUniformScalingShape.h" btUniformScalingShape::btUniformScalingShape( btConvexShape* convexChildShape,btScalar uniformScalingFactor): btConvexShape (), m_childConvexShape(convexChildShape), m_uniformScalingFactor(uniformScalingFactor) { m_shapeType = UNIFORM_SCALING_SHAPE_PROXYTYPE; } btUniformScalingShape::~btUniformScalingShape() { } btVector3 btUniformScalingShape::localGetSupportingVertexWithoutMargin(const btVector3& vec)const { btVector3 tmpVertex; tmpVertex = m_childConvexShape->localGetSupportingVertexWithoutMargin(vec); return tmpVertex*m_uniformScalingFactor; } void btUniformScalingShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const { m_childConvexShape->batchedUnitVectorGetSupportingVertexWithoutMargin(vectors,supportVerticesOut,numVectors); int i; for (i=0;ilocalGetSupportingVertex(vec); return tmpVertex*m_uniformScalingFactor; } void btUniformScalingShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const { ///this linear upscaling is not realistic, but we don't deal with large mass ratios... btVector3 tmpInertia; m_childConvexShape->calculateLocalInertia(mass,tmpInertia); inertia = tmpInertia * m_uniformScalingFactor; } ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version void btUniformScalingShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const { m_childConvexShape->getAabb(t,aabbMin,aabbMax); btVector3 aabbCenter = (aabbMax+aabbMin)*btScalar(0.5); btVector3 scaledAabbHalfExtends = (aabbMax-aabbMin)*btScalar(0.5)*m_uniformScalingFactor; aabbMin = aabbCenter - scaledAabbHalfExtends; aabbMax = aabbCenter + scaledAabbHalfExtends; } void btUniformScalingShape::getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const { m_childConvexShape->getAabbSlow(t,aabbMin,aabbMax); btVector3 aabbCenter = (aabbMax+aabbMin)*btScalar(0.5); btVector3 scaledAabbHalfExtends = (aabbMax-aabbMin)*btScalar(0.5)*m_uniformScalingFactor; aabbMin = aabbCenter - scaledAabbHalfExtends; aabbMax = aabbCenter + scaledAabbHalfExtends; } void btUniformScalingShape::setLocalScaling(const btVector3& scaling) { m_childConvexShape->setLocalScaling(scaling); } const btVector3& btUniformScalingShape::getLocalScaling() const { return m_childConvexShape->getLocalScaling(); } void btUniformScalingShape::setMargin(btScalar margin) { m_childConvexShape->setMargin(margin); } btScalar btUniformScalingShape::getMargin() const { return m_childConvexShape->getMargin() * m_uniformScalingFactor; } int btUniformScalingShape::getNumPreferredPenetrationDirections() const { return m_childConvexShape->getNumPreferredPenetrationDirections(); } void btUniformScalingShape::getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const { m_childConvexShape->getPreferredPenetrationDirection(index,penetrationVector); } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btEmptyShape.cpp0000644000175000017500000000303211337071441030265 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btEmptyShape.h" #include "btCollisionShape.h" btEmptyShape::btEmptyShape() : btConcaveShape () { m_shapeType = EMPTY_SHAPE_PROXYTYPE; } btEmptyShape::~btEmptyShape() { } ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version void btEmptyShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const { btVector3 margin(getMargin(),getMargin(),getMargin()); aabbMin = t.getOrigin() - margin; aabbMax = t.getOrigin() + margin; } void btEmptyShape::calculateLocalInertia(btScalar ,btVector3& ) const { btAssert(0); } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btConeShape.cpp0000644000175000017500000000673411337071441030067 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btConeShape.h" btConeShape::btConeShape (btScalar radius,btScalar height): btConvexInternalShape (), m_radius (radius), m_height(height) { m_shapeType = CONE_SHAPE_PROXYTYPE; setConeUpIndex(1); btVector3 halfExtents; m_sinAngle = (m_radius / btSqrt(m_radius * m_radius + m_height * m_height)); } btConeShapeZ::btConeShapeZ (btScalar radius,btScalar height): btConeShape(radius,height) { setConeUpIndex(2); } btConeShapeX::btConeShapeX (btScalar radius,btScalar height): btConeShape(radius,height) { setConeUpIndex(0); } ///choose upAxis index void btConeShape::setConeUpIndex(int upIndex) { switch (upIndex) { case 0: m_coneIndices[0] = 1; m_coneIndices[1] = 0; m_coneIndices[2] = 2; break; case 1: m_coneIndices[0] = 0; m_coneIndices[1] = 1; m_coneIndices[2] = 2; break; case 2: m_coneIndices[0] = 0; m_coneIndices[1] = 2; m_coneIndices[2] = 1; break; default: btAssert(0); }; } btVector3 btConeShape::coneLocalSupport(const btVector3& v) const { btScalar halfHeight = m_height * btScalar(0.5); if (v[m_coneIndices[1]] > v.length() * m_sinAngle) { btVector3 tmp; tmp[m_coneIndices[0]] = btScalar(0.); tmp[m_coneIndices[1]] = halfHeight; tmp[m_coneIndices[2]] = btScalar(0.); return tmp; } else { btScalar s = btSqrt(v[m_coneIndices[0]] * v[m_coneIndices[0]] + v[m_coneIndices[2]] * v[m_coneIndices[2]]); if (s > SIMD_EPSILON) { btScalar d = m_radius / s; btVector3 tmp; tmp[m_coneIndices[0]] = v[m_coneIndices[0]] * d; tmp[m_coneIndices[1]] = -halfHeight; tmp[m_coneIndices[2]] = v[m_coneIndices[2]] * d; return tmp; } else { btVector3 tmp; tmp[m_coneIndices[0]] = btScalar(0.); tmp[m_coneIndices[1]] = -halfHeight; tmp[m_coneIndices[2]] = btScalar(0.); return tmp; } } } btVector3 btConeShape::localGetSupportingVertexWithoutMargin(const btVector3& vec) const { return coneLocalSupport(vec); } void btConeShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const { for (int i=0;im_convexInternalShapeData,serializer); shapeData->m_upAxis = m_upAxis; return "btCylinderShapeData"; } #endif //CYLINDER_MINKOWSKI_H ././@LongLink0000000000000000000000000000015100000000000011562 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshShape.hcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btMultimaterialTriangleMeshSha0000644000175000017500000001136311344267705033213 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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. */ /// This file was created by Alex Silverman #ifndef BVH_TRIANGLE_MATERIAL_MESH_SHAPE_H #define BVH_TRIANGLE_MATERIAL_MESH_SHAPE_H #include "btBvhTriangleMeshShape.h" #include "btMaterial.h" ///The BvhTriangleMaterialMeshShape extends the btBvhTriangleMeshShape. Its main contribution is the interface into a material array, which allows per-triangle friction and restitution. ATTRIBUTE_ALIGNED16(class) btMultimaterialTriangleMeshShape : public btBvhTriangleMeshShape { btAlignedObjectArray m_materialList; int ** m_triangleMaterials; public: BT_DECLARE_ALIGNED_ALLOCATOR(); btMultimaterialTriangleMeshShape(): btBvhTriangleMeshShape() {m_shapeType = MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE;} btMultimaterialTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression, bool buildBvh = true): btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression, buildBvh) { m_shapeType = MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE; const unsigned char *vertexbase; int numverts; PHY_ScalarType type; int stride; const unsigned char *indexbase; int indexstride; int numfaces; PHY_ScalarType indicestype; //m_materialLookup = (int**)(btAlignedAlloc(sizeof(int*) * meshInterface->getNumSubParts(), 16)); for(int i = 0; i < meshInterface->getNumSubParts(); i++) { m_meshInterface->getLockedReadOnlyVertexIndexBase( &vertexbase, numverts, type, stride, &indexbase, indexstride, numfaces, indicestype, i); //m_materialLookup[i] = (int*)(btAlignedAlloc(sizeof(int) * numfaces, 16)); } } ///optionally pass in a larger bvh aabb, used for quantization. This allows for deformations within this aabb btMultimaterialTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression,const btVector3& bvhAabbMin,const btVector3& bvhAabbMax, bool buildBvh = true): btBvhTriangleMeshShape(meshInterface, useQuantizedAabbCompression, bvhAabbMin, bvhAabbMax, buildBvh) { m_shapeType = MULTIMATERIAL_TRIANGLE_MESH_PROXYTYPE; const unsigned char *vertexbase; int numverts; PHY_ScalarType type; int stride; const unsigned char *indexbase; int indexstride; int numfaces; PHY_ScalarType indicestype; //m_materialLookup = (int**)(btAlignedAlloc(sizeof(int*) * meshInterface->getNumSubParts(), 16)); for(int i = 0; i < meshInterface->getNumSubParts(); i++) { m_meshInterface->getLockedReadOnlyVertexIndexBase( &vertexbase, numverts, type, stride, &indexbase, indexstride, numfaces, indicestype, i); //m_materialLookup[i] = (int*)(btAlignedAlloc(sizeof(int) * numfaces * 2, 16)); } } virtual ~btMultimaterialTriangleMeshShape() { /* for(int i = 0; i < m_meshInterface->getNumSubParts(); i++) { btAlignedFree(m_materialValues[i]); m_materialLookup[i] = NULL; } btAlignedFree(m_materialValues); m_materialLookup = NULL; */ } //debugging virtual const char* getName()const {return "MULTIMATERIALTRIANGLEMESH";} ///Obtains the material for a specific triangle const btMaterial * getMaterialProperties(int partID, int triIndex); } ; #endif //BVH_TRIANGLE_MATERIAL_MESH_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btTriangleBuffer.cpp0000644000175000017500000000240311337071441031106 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btTriangleBuffer.h" void btTriangleBuffer::processTriangle(btVector3* triangle,int partId,int triangleIndex) { btTriangle tri; tri.m_vertex0 = triangle[0]; tri.m_vertex1 = triangle[1]; tri.m_vertex2 = triangle[2]; tri.m_partId = partId; tri.m_triangleIndex = triangleIndex; m_triangleBuffer.push_back(tri); } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btConvexInternalShape.h0000644000175000017500000001260611344267705031612 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 BT_CONVEX_INTERNAL_SHAPE_H #define BT_CONVEX_INTERNAL_SHAPE_H #include "btConvexShape.h" #include "LinearMath/btAabbUtil2.h" ///The btConvexInternalShape is an internal base class, shared by most convex shape implementations. class btConvexInternalShape : public btConvexShape { protected: //local scaling. collisionMargin is not scaled ! btVector3 m_localScaling; btVector3 m_implicitShapeDimensions; btScalar m_collisionMargin; btScalar m_padding; btConvexInternalShape(); public: virtual ~btConvexInternalShape() { } virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; const btVector3& getImplicitShapeDimensions() const { return m_implicitShapeDimensions; } ///warning: use setImplicitShapeDimensions with care ///changing a collision shape while the body is in the world is not recommended, ///it is best to remove the body from the world, then make the change, and re-add it ///alternatively flush the contact points, see documentation for 'cleanProxyFromPairs' void setImplicitShapeDimensions(const btVector3& dimensions) { m_implicitShapeDimensions = dimensions; } ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const { getAabbSlow(t,aabbMin,aabbMax); } virtual void getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; virtual void setLocalScaling(const btVector3& scaling); virtual const btVector3& getLocalScaling() const { return m_localScaling; } const btVector3& getLocalScalingNV() const { return m_localScaling; } virtual void setMargin(btScalar margin) { m_collisionMargin = margin; } virtual btScalar getMargin() const { return m_collisionMargin; } btScalar getMarginNV() const { return m_collisionMargin; } virtual int getNumPreferredPenetrationDirections() const { return 0; } virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const { (void)penetrationVector; (void)index; btAssert(0); } virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btConvexInternalShapeData { btCollisionShapeData m_collisionShapeData; btVector3FloatData m_localScaling; btVector3FloatData m_implicitShapeDimensions; float m_collisionMargin; int m_padding; }; SIMD_FORCE_INLINE int btConvexInternalShape::calculateSerializeBufferSize() const { return sizeof(btConvexInternalShapeData); } ///fills the dataBuffer and returns the struct name (and 0 on failure) SIMD_FORCE_INLINE const char* btConvexInternalShape::serialize(void* dataBuffer, btSerializer* serializer) const { btConvexInternalShapeData* shapeData = (btConvexInternalShapeData*) dataBuffer; btCollisionShape::serialize(&shapeData->m_collisionShapeData, serializer); m_implicitShapeDimensions.serializeFloat(shapeData->m_implicitShapeDimensions); m_localScaling.serializeFloat(shapeData->m_localScaling); shapeData->m_collisionMargin = float(m_collisionMargin); return "btConvexInternalShapeData"; } ///btConvexInternalAabbCachingShape adds local aabb caching for convex shapes, to avoid expensive bounding box calculations class btConvexInternalAabbCachingShape : public btConvexInternalShape { btVector3 m_localAabbMin; btVector3 m_localAabbMax; bool m_isLocalAabbValid; protected: btConvexInternalAabbCachingShape(); void setCachedLocalAabb (const btVector3& aabbMin, const btVector3& aabbMax) { m_isLocalAabbValid = true; m_localAabbMin = aabbMin; m_localAabbMax = aabbMax; } inline void getCachedLocalAabb (btVector3& aabbMin, btVector3& aabbMax) const { btAssert(m_isLocalAabbValid); aabbMin = m_localAabbMin; aabbMax = m_localAabbMax; } inline void getNonvirtualAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax, btScalar margin) const { //lazy evaluation of local aabb btAssert(m_isLocalAabbValid); btTransformAabb(m_localAabbMin,m_localAabbMax,margin,trans,aabbMin,aabbMax); } public: virtual void setLocalScaling(const btVector3& scaling); virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; void recalcLocalAabb(); }; #endif //BT_CONVEX_INTERNAL_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btStridingMeshInterface.h0000644000175000017500000001223211344267705032106 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 STRIDING_MESHINTERFACE_H #define STRIDING_MESHINTERFACE_H #include "LinearMath/btVector3.h" #include "btTriangleCallback.h" #include "btConcaveShape.h" /// The btStridingMeshInterface is the interface class for high performance generic access to triangle meshes, used in combination with btBvhTriangleMeshShape and some other collision shapes. /// Using index striding of 3*sizeof(integer) it can use triangle arrays, using index striding of 1*sizeof(integer) it can handle triangle strips. /// It allows for sharing graphics and collision meshes. Also it provides locking/unlocking of graphics meshes that are in gpu memory. class btStridingMeshInterface { protected: btVector3 m_scaling; public: btStridingMeshInterface() :m_scaling(btScalar(1.),btScalar(1.),btScalar(1.)) { } virtual ~btStridingMeshInterface(); virtual void InternalProcessAllTriangles(btInternalTriangleIndexCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const; ///brute force method to calculate aabb void calculateAabbBruteForce(btVector3& aabbMin,btVector3& aabbMax); /// get read and write access to a subpart of a triangle mesh /// this subpart has a continuous array of vertices and indices /// in this way the mesh can be handled as chunks of memory with striding /// very similar to OpenGL vertexarray support /// make a call to unLockVertexBase when the read and write access is finished virtual void getLockedVertexIndexBase(unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& stride,unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart=0)=0; virtual void getLockedReadOnlyVertexIndexBase(const unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& stride,const unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart=0) const=0; /// unLockVertexBase finishes the access to a subpart of the triangle mesh /// make a call to unLockVertexBase when the read and write access (using getLockedVertexIndexBase) is finished virtual void unLockVertexBase(int subpart)=0; virtual void unLockReadOnlyVertexBase(int subpart) const=0; /// getNumSubParts returns the number of seperate subparts /// each subpart has a continuous array of vertices and indices virtual int getNumSubParts() const=0; virtual void preallocateVertices(int numverts)=0; virtual void preallocateIndices(int numindices)=0; virtual bool hasPremadeAabb() const { return false; } virtual void setPremadeAabb(const btVector3& aabbMin, const btVector3& aabbMax ) const { (void) aabbMin; (void) aabbMax; } virtual void getPremadeAabb(btVector3* aabbMin, btVector3* aabbMax ) const { (void) aabbMin; (void) aabbMax; } const btVector3& getScaling() const { return m_scaling; } void setScaling(const btVector3& scaling) { m_scaling = scaling; } virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; }; struct btIntIndexData { int m_value; }; struct btShortIntIndexData { short m_value; char m_pad[2]; }; struct btShortIntIndexTripletData { short m_values[3]; char m_pad[2]; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btMeshPartData { btVector3FloatData *m_vertices3f; btVector3DoubleData *m_vertices3d; btIntIndexData *m_indices32; btShortIntIndexTripletData *m_3indices16; btShortIntIndexData *m_indices16;//backwards compatibility int m_numTriangles;//length of m_indices = m_numTriangles int m_numVertices; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btStridingMeshInterfaceData { btMeshPartData *m_meshPartsPtr; btVector3FloatData m_scaling; int m_numMeshParts; char m_padding[4]; }; SIMD_FORCE_INLINE int btStridingMeshInterface::calculateSerializeBufferSize() const { return sizeof(btStridingMeshInterfaceData); } #endif //STRIDING_MESHINTERFACE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btCollisionMargin.h0000644000175000017500000000217211337071441030750 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 COLLISION_MARGIN_H #define COLLISION_MARGIN_H //used by Gjk and some other algorithms #define CONVEX_DISTANCE_MARGIN btScalar(0.04)// btScalar(0.1)//;//btScalar(0.01) #endif //COLLISION_MARGIN_H ././@LongLink0000000000000000000000000000015500000000000011566 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialArray.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexMaterialA0000644000175000017500000000745011337071441033150 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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. */ ///This file was created by Alex Silverman #include "btTriangleIndexVertexMaterialArray.h" btTriangleIndexVertexMaterialArray::btTriangleIndexVertexMaterialArray(int numTriangles,int* triangleIndexBase,int triangleIndexStride, int numVertices,btScalar* vertexBase,int vertexStride, int numMaterials, unsigned char* materialBase, int materialStride, int* triangleMaterialsBase, int materialIndexStride) : btTriangleIndexVertexArray(numTriangles, triangleIndexBase, triangleIndexStride, numVertices, vertexBase, vertexStride) { btMaterialProperties mat; mat.m_numMaterials = numMaterials; mat.m_materialBase = materialBase; mat.m_materialStride = materialStride; #ifdef BT_USE_DOUBLE_PRECISION mat.m_materialType = PHY_DOUBLE; #else mat.m_materialType = PHY_FLOAT; #endif mat.m_numTriangles = numTriangles; mat.m_triangleMaterialsBase = (unsigned char *)triangleMaterialsBase; mat.m_triangleMaterialStride = materialIndexStride; mat.m_triangleType = PHY_INTEGER; addMaterialProperties(mat); } void btTriangleIndexVertexMaterialArray::getLockedMaterialBase(unsigned char **materialBase, int& numMaterials, PHY_ScalarType& materialType, int& materialStride, unsigned char ** triangleMaterialBase, int& numTriangles, int& triangleMaterialStride, PHY_ScalarType& triangleType, int subpart) { btAssert(subpart< getNumSubParts() ); btMaterialProperties& mats = m_materials[subpart]; numMaterials = mats.m_numMaterials; (*materialBase) = (unsigned char *) mats.m_materialBase; #ifdef BT_USE_DOUBLE_PRECISION materialType = PHY_DOUBLE; #else materialType = PHY_FLOAT; #endif materialStride = mats.m_materialStride; numTriangles = mats.m_numTriangles; (*triangleMaterialBase) = (unsigned char *)mats.m_triangleMaterialsBase; triangleMaterialStride = mats.m_triangleMaterialStride; triangleType = mats.m_triangleType; } void btTriangleIndexVertexMaterialArray::getLockedReadOnlyMaterialBase(const unsigned char **materialBase, int& numMaterials, PHY_ScalarType& materialType, int& materialStride, const unsigned char ** triangleMaterialBase, int& numTriangles, int& triangleMaterialStride, PHY_ScalarType& triangleType, int subpart) { btMaterialProperties& mats = m_materials[subpart]; numMaterials = mats.m_numMaterials; (*materialBase) = (const unsigned char *) mats.m_materialBase; #ifdef BT_USE_DOUBLE_PRECISION materialType = PHY_DOUBLE; #else materialType = PHY_FLOAT; #endif materialStride = mats.m_materialStride; numTriangles = mats.m_numTriangles; (*triangleMaterialBase) = (const unsigned char *)mats.m_triangleMaterialsBase; triangleMaterialStride = mats.m_triangleMaterialStride; triangleType = mats.m_triangleType; } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.h0000644000175000017500000000444511337071441033003 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 SCALED_BVH_TRIANGLE_MESH_SHAPE_H #define SCALED_BVH_TRIANGLE_MESH_SHAPE_H #include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" ///The btScaledBvhTriangleMeshShape allows to instance a scaled version of an existing btBvhTriangleMeshShape. ///Note that each btBvhTriangleMeshShape still can have its own local scaling, independent from this btScaledBvhTriangleMeshShape 'localScaling' ATTRIBUTE_ALIGNED16(class) btScaledBvhTriangleMeshShape : public btConcaveShape { btVector3 m_localScaling; btBvhTriangleMeshShape* m_bvhTriMeshShape; public: btScaledBvhTriangleMeshShape(btBvhTriangleMeshShape* childShape,const btVector3& localScaling); virtual ~btScaledBvhTriangleMeshShape(); virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; virtual void setLocalScaling(const btVector3& scaling); virtual const btVector3& getLocalScaling() const; virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const; btBvhTriangleMeshShape* getChildShape() { return m_bvhTriMeshShape; } const btBvhTriangleMeshShape* getChildShape() const { return m_bvhTriMeshShape; } //debugging virtual const char* getName()const {return "SCALEDBVHTRIANGLEMESH";} }; #endif //BVH_TRIANGLE_MESH_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btTetrahedronShape.h0000644000175000017500000000464711337071441031130 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 BU_SIMPLEX_1TO4_SHAPE #define BU_SIMPLEX_1TO4_SHAPE #include "btPolyhedralConvexShape.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" ///The btBU_Simplex1to4 implements tetrahedron, triangle, line, vertex collision shapes. In most cases it is better to use btConvexHullShape instead. class btBU_Simplex1to4 : public btPolyhedralConvexAabbCachingShape { protected: int m_numVertices; btVector3 m_vertices[4]; public: btBU_Simplex1to4(); btBU_Simplex1to4(const btVector3& pt0); btBU_Simplex1to4(const btVector3& pt0,const btVector3& pt1); btBU_Simplex1to4(const btVector3& pt0,const btVector3& pt1,const btVector3& pt2); btBU_Simplex1to4(const btVector3& pt0,const btVector3& pt1,const btVector3& pt2,const btVector3& pt3); void reset() { m_numVertices = 0; } virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; void addVertex(const btVector3& pt); //PolyhedralConvexShape interface virtual int getNumVertices() const; virtual int getNumEdges() const; virtual void getEdge(int i,btVector3& pa,btVector3& pb) const; virtual void getVertex(int i,btVector3& vtx) const; virtual int getNumPlanes() const; virtual void getPlane(btVector3& planeNormal,btVector3& planeSupport,int i) const; virtual int getIndex(int i) const; virtual bool isInside(const btVector3& pt,btScalar tolerance) const; ///getName is for debugging virtual const char* getName()const { return "btBU_Simplex1to4";} }; #endif //BU_SIMPLEX_1TO4_SHAPE critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btStaticPlaneShape.cpp0000644000175000017500000000711711337071441031406 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btStaticPlaneShape.h" #include "LinearMath/btTransformUtil.h" btStaticPlaneShape::btStaticPlaneShape(const btVector3& planeNormal,btScalar planeConstant) : btConcaveShape (), m_planeNormal(planeNormal.normalized()), m_planeConstant(planeConstant), m_localScaling(btScalar(0.),btScalar(0.),btScalar(0.)) { m_shapeType = STATIC_PLANE_PROXYTYPE; // btAssert( btFuzzyZero(m_planeNormal.length() - btScalar(1.)) ); } btStaticPlaneShape::~btStaticPlaneShape() { } void btStaticPlaneShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const { (void)t; /* btVector3 infvec (btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); btVector3 center = m_planeNormal*m_planeConstant; aabbMin = center + infvec*m_planeNormal; aabbMax = aabbMin; aabbMin.setMin(center - infvec*m_planeNormal); aabbMax.setMax(center - infvec*m_planeNormal); */ aabbMin.setValue(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); aabbMax.setValue(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); } void btStaticPlaneShape::processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const { btVector3 halfExtents = (aabbMax - aabbMin) * btScalar(0.5); btScalar radius = halfExtents.length(); btVector3 center = (aabbMax + aabbMin) * btScalar(0.5); //this is where the triangles are generated, given AABB and plane equation (normal/constant) btVector3 tangentDir0,tangentDir1; //tangentDir0/tangentDir1 can be precalculated btPlaneSpace1(m_planeNormal,tangentDir0,tangentDir1); btVector3 supVertex0,supVertex1; btVector3 projectedCenter = center - (m_planeNormal.dot(center) - m_planeConstant)*m_planeNormal; btVector3 triangle[3]; triangle[0] = projectedCenter + tangentDir0*radius + tangentDir1*radius; triangle[1] = projectedCenter + tangentDir0*radius - tangentDir1*radius; triangle[2] = projectedCenter - tangentDir0*radius - tangentDir1*radius; callback->processTriangle(triangle,0,0); triangle[0] = projectedCenter - tangentDir0*radius - tangentDir1*radius; triangle[1] = projectedCenter - tangentDir0*radius + tangentDir1*radius; triangle[2] = projectedCenter + tangentDir0*radius + tangentDir1*radius; callback->processTriangle(triangle,0,1); } void btStaticPlaneShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const { (void)mass; //moving concave objects not supported inertia.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); } void btStaticPlaneShape::setLocalScaling(const btVector3& scaling) { m_localScaling = scaling; } const btVector3& btStaticPlaneShape::getLocalScaling() const { return m_localScaling; } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btConvexShape.h0000644000175000017500000000604511337071441030105 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 CONVEX_SHAPE_INTERFACE1 #define CONVEX_SHAPE_INTERFACE1 #include "btCollisionShape.h" #include "LinearMath/btVector3.h" #include "LinearMath/btTransform.h" #include "LinearMath/btMatrix3x3.h" #include "btCollisionMargin.h" #include "LinearMath/btAlignedAllocator.h" #define MAX_PREFERRED_PENETRATION_DIRECTIONS 10 /// The btConvexShape is an abstract shape interface, implemented by all convex shapes such as btBoxShape, btConvexHullShape etc. /// It describes general convex shapes using the localGetSupportingVertex interface, used by collision detectors such as btGjkPairDetector. ATTRIBUTE_ALIGNED16(class) btConvexShape : public btCollisionShape { public: BT_DECLARE_ALIGNED_ALLOCATOR(); btConvexShape (); virtual ~btConvexShape(); virtual btVector3 localGetSupportingVertex(const btVector3& vec)const = 0; //////// #ifndef __SPU__ virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec) const=0; #endif //#ifndef __SPU__ btVector3 localGetSupportVertexWithoutMarginNonVirtual (const btVector3& vec) const; btVector3 localGetSupportVertexNonVirtual (const btVector3& vec) const; btScalar getMarginNonVirtual () const; void getAabbNonVirtual (const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const; //notice that the vectors should be unit length virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const= 0; ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const =0; virtual void getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const =0; virtual void setLocalScaling(const btVector3& scaling) =0; virtual const btVector3& getLocalScaling() const =0; virtual void setMargin(btScalar margin)=0; virtual btScalar getMargin() const=0; virtual int getNumPreferredPenetrationDirections() const=0; virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const=0; }; #endif //CONVEX_SHAPE_INTERFACE1 critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btMultiSphereShape.cpp0000644000175000017500000001112411344267705031441 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btMultiSphereShape.h" #include "BulletCollision/CollisionShapes/btCollisionMargin.h" #include "LinearMath/btQuaternion.h" #include "LinearMath/btSerializer.h" btMultiSphereShape::btMultiSphereShape (const btVector3* positions,const btScalar* radi,int numSpheres) :btConvexInternalAabbCachingShape () { m_shapeType = MULTI_SPHERE_SHAPE_PROXYTYPE; //btScalar startMargin = btScalar(BT_LARGE_FLOAT); m_localPositionArray.resize(numSpheres); m_radiArray.resize(numSpheres); for (int i=0;i maxDot) { maxDot = newDot; supVec = vtx; } } return supVec; } void btMultiSphereShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const { for (int j=0;j maxDot) { maxDot = newDot; supportVerticesOut[j] = vtx; } } } } void btMultiSphereShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const { //as an approximation, take the inertia of the box that bounds the spheres btVector3 localAabbMin,localAabbMax; getCachedLocalAabb(localAabbMin,localAabbMax); btVector3 halfExtents = (localAabbMax-localAabbMin)*btScalar(0.5); btScalar lx=btScalar(2.)*(halfExtents.x()); btScalar ly=btScalar(2.)*(halfExtents.y()); btScalar lz=btScalar(2.)*(halfExtents.z()); inertia.setValue(mass/(btScalar(12.0)) * (ly*ly + lz*lz), mass/(btScalar(12.0)) * (lx*lx + lz*lz), mass/(btScalar(12.0)) * (lx*lx + ly*ly)); } ///fills the dataBuffer and returns the struct name (and 0 on failure) const char* btMultiSphereShape::serialize(void* dataBuffer, btSerializer* serializer) const { btMultiSphereShapeData* shapeData = (btMultiSphereShapeData*) dataBuffer; btConvexInternalShape::serialize(&shapeData->m_convexInternalShapeData, serializer); int numElem = m_localPositionArray.size(); shapeData->m_localPositionArrayPtr = numElem ? (btPositionAndRadius*)serializer->getUniquePointer((void*)&m_localPositionArray[0]): 0; shapeData->m_localPositionArraySize = numElem; if (numElem) { btChunk* chunk = serializer->allocate(sizeof(btPositionAndRadius),numElem); btPositionAndRadius* memPtr = (btPositionAndRadius*)chunk->m_oldPtr; for (int i=0;im_pos); memPtr->m_radius = float(m_radiArray[i]); } serializer->finalizeChunk(chunk,"btPositionAndRadius",BT_ARRAY_CODE,(void*)&m_localPositionArray[0]); } return "btMultiSphereShapeData"; } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btBoxShape.cpp0000644000175000017500000000310711337071441027722 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btBoxShape.h" //{ void btBoxShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const { btTransformAabb(getHalfExtentsWithoutMargin(),getMargin(),t,aabbMin,aabbMax); } void btBoxShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const { //btScalar margin = btScalar(0.); btVector3 halfExtents = getHalfExtentsWithMargin(); btScalar lx=btScalar(2.)*(halfExtents.x()); btScalar ly=btScalar(2.)*(halfExtents.y()); btScalar lz=btScalar(2.)*(halfExtents.z()); inertia.setValue(mass/(btScalar(12.0)) * (ly*ly + lz*lz), mass/(btScalar(12.0)) * (lx*lx + lz*lz), mass/(btScalar(12.0)) * (lx*lx + ly*ly)); } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btTriangleBuffer.h0000644000175000017500000000411211337071441030552 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 BT_TRIANGLE_BUFFER_H #define BT_TRIANGLE_BUFFER_H #include "btTriangleCallback.h" #include "LinearMath/btAlignedObjectArray.h" struct btTriangle { btVector3 m_vertex0; btVector3 m_vertex1; btVector3 m_vertex2; int m_partId; int m_triangleIndex; }; ///The btTriangleBuffer callback can be useful to collect and store overlapping triangles between AABB and concave objects that support 'processAllTriangles' ///Example usage of this class: /// btTriangleBuffer triBuf; /// concaveShape->processAllTriangles(&triBuf,aabbMin, aabbMax); /// for (int i=0;i m_triangleBuffer; public: virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex); int getNumTriangles() const { return int(m_triangleBuffer.size()); } const btTriangle& getTriangle(int index) const { return m_triangleBuffer[index]; } void clearBuffer() { m_triangleBuffer.clear(); } }; #endif //BT_TRIANGLE_BUFFER_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btMinkowskiSumShape.h0000644000175000017500000000445711337071441031310 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 MINKOWSKI_SUM_SHAPE_H #define MINKOWSKI_SUM_SHAPE_H #include "btConvexInternalShape.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types /// The btMinkowskiSumShape is only for advanced users. This shape represents implicit based minkowski sum of two convex implicit shapes. class btMinkowskiSumShape : public btConvexInternalShape { btTransform m_transA; btTransform m_transB; const btConvexShape* m_shapeA; const btConvexShape* m_shapeB; public: btMinkowskiSumShape(const btConvexShape* shapeA,const btConvexShape* shapeB); virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; void setTransformA(const btTransform& transA) { m_transA = transA;} void setTransformB(const btTransform& transB) { m_transB = transB;} const btTransform& getTransformA()const { return m_transA;} const btTransform& GetTransformB()const { return m_transB;} virtual btScalar getMargin() const; const btConvexShape* getShapeA() const { return m_shapeA;} const btConvexShape* getShapeB() const { return m_shapeB;} virtual const char* getName()const { return "MinkowskiSum"; } }; #endif //MINKOWSKI_SUM_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.h0000644000175000017500000000701611337071441032407 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 CONVEX_TRIANGLEMESH_SHAPE_H #define CONVEX_TRIANGLEMESH_SHAPE_H #include "btPolyhedralConvexShape.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types /// The btConvexTriangleMeshShape is a convex hull of a triangle mesh, but the performance is not as good as btConvexHullShape. /// A small benefit of this class is that it uses the btStridingMeshInterface, so you can avoid the duplication of the triangle mesh data. Nevertheless, most users should use the much better performing btConvexHullShape instead. class btConvexTriangleMeshShape : public btPolyhedralConvexAabbCachingShape { class btStridingMeshInterface* m_stridingMesh; public: btConvexTriangleMeshShape(btStridingMeshInterface* meshInterface, bool calcAabb = true); class btStridingMeshInterface* getMeshInterface() { return m_stridingMesh; } const class btStridingMeshInterface* getMeshInterface() const { return m_stridingMesh; } virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; //debugging virtual const char* getName()const {return "ConvexTrimesh";} virtual int getNumVertices() const; virtual int getNumEdges() const; virtual void getEdge(int i,btVector3& pa,btVector3& pb) const; virtual void getVertex(int i,btVector3& vtx) const; virtual int getNumPlanes() const; virtual void getPlane(btVector3& planeNormal,btVector3& planeSupport,int i ) const; virtual bool isInside(const btVector3& pt,btScalar tolerance) const; virtual void setLocalScaling(const btVector3& scaling); virtual const btVector3& getLocalScaling() const; ///computes the exact moment of inertia and the transform from the coordinate system defined by the principal axes of the moment of inertia ///and the center of mass to the current coordinate system. A mass of 1 is assumed, for other masses just multiply the computed "inertia" ///by the mass. The resulting transform "principal" has to be applied inversely to the mesh in order for the local coordinate system of the ///shape to be centered at the center of mass and to coincide with the principal axes. This also necessitates a correction of the world transform ///of the collision object by the principal transform. This method also computes the volume of the convex mesh. void calculatePrincipalAxisTransform(btTransform& principal, btVector3& inertia, btScalar& volume) const; }; #endif //CONVEX_TRIANGLEMESH_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btUniformScalingShape.h0000644000175000017500000000574011337071441031564 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 BT_UNIFORM_SCALING_SHAPE_H #define BT_UNIFORM_SCALING_SHAPE_H #include "btConvexShape.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types ///The btUniformScalingShape allows to re-use uniform scaled instances of btConvexShape in a memory efficient way. ///Istead of using btUniformScalingShape, it is better to use the non-uniform setLocalScaling method on convex shapes that implement it. class btUniformScalingShape : public btConvexShape { btConvexShape* m_childConvexShape; btScalar m_uniformScalingFactor; public: btUniformScalingShape( btConvexShape* convexChildShape, btScalar uniformScalingFactor); virtual ~btUniformScalingShape(); virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; btScalar getUniformScalingFactor() const { return m_uniformScalingFactor; } btConvexShape* getChildShape() { return m_childConvexShape; } const btConvexShape* getChildShape() const { return m_childConvexShape; } virtual const char* getName()const { return "UniformScalingShape"; } /////////////////////////// ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; virtual void getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; virtual void setLocalScaling(const btVector3& scaling) ; virtual const btVector3& getLocalScaling() const ; virtual void setMargin(btScalar margin); virtual btScalar getMargin() const; virtual int getNumPreferredPenetrationDirections() const; virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const; }; #endif //BT_UNIFORM_SCALING_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btBox2dShape.h0000644000175000017500000002274111337071441027622 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 OBB_BOX_2D_SHAPE_H #define OBB_BOX_2D_SHAPE_H #include "BulletCollision/CollisionShapes/btPolyhedralConvexShape.h" #include "BulletCollision/CollisionShapes/btCollisionMargin.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "LinearMath/btVector3.h" #include "LinearMath/btMinMax.h" ///The btBox2dShape is a box primitive around the origin, its sides axis aligned with length specified by half extents, in local shape coordinates. When used as part of a btCollisionObject or btRigidBody it will be an oriented box in world space. class btBox2dShape: public btPolyhedralConvexShape { //btVector3 m_boxHalfExtents1; //use m_implicitShapeDimensions instead btVector3 m_centroid; btVector3 m_vertices[4]; btVector3 m_normals[4]; public: btVector3 getHalfExtentsWithMargin() const { btVector3 halfExtents = getHalfExtentsWithoutMargin(); btVector3 margin(getMargin(),getMargin(),getMargin()); halfExtents += margin; return halfExtents; } const btVector3& getHalfExtentsWithoutMargin() const { return m_implicitShapeDimensions;//changed in Bullet 2.63: assume the scaling and margin are included } virtual btVector3 localGetSupportingVertex(const btVector3& vec) const { btVector3 halfExtents = getHalfExtentsWithoutMargin(); btVector3 margin(getMargin(),getMargin(),getMargin()); halfExtents += margin; return btVector3(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()), btFsels(vec.y(), halfExtents.y(), -halfExtents.y()), btFsels(vec.z(), halfExtents.z(), -halfExtents.z())); } SIMD_FORCE_INLINE btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const { const btVector3& halfExtents = getHalfExtentsWithoutMargin(); return btVector3(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()), btFsels(vec.y(), halfExtents.y(), -halfExtents.y()), btFsels(vec.z(), halfExtents.z(), -halfExtents.z())); } virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const { const btVector3& halfExtents = getHalfExtentsWithoutMargin(); for (int i=0;i>1)) - halfExtents.y() * ((i&2)>>1), halfExtents.z() * (1-((i&4)>>2)) - halfExtents.z() * ((i&4)>>2)); } virtual void getPlaneEquation(btVector4& plane,int i) const { btVector3 halfExtents = getHalfExtentsWithoutMargin(); switch (i) { case 0: plane.setValue(btScalar(1.),btScalar(0.),btScalar(0.),-halfExtents.x()); break; case 1: plane.setValue(btScalar(-1.),btScalar(0.),btScalar(0.),-halfExtents.x()); break; case 2: plane.setValue(btScalar(0.),btScalar(1.),btScalar(0.),-halfExtents.y()); break; case 3: plane.setValue(btScalar(0.),btScalar(-1.),btScalar(0.),-halfExtents.y()); break; case 4: plane.setValue(btScalar(0.),btScalar(0.),btScalar(1.),-halfExtents.z()); break; case 5: plane.setValue(btScalar(0.),btScalar(0.),btScalar(-1.),-halfExtents.z()); break; default: btAssert(0); } } virtual void getEdge(int i,btVector3& pa,btVector3& pb) const //virtual void getEdge(int i,Edge& edge) const { int edgeVert0 = 0; int edgeVert1 = 0; switch (i) { case 0: edgeVert0 = 0; edgeVert1 = 1; break; case 1: edgeVert0 = 0; edgeVert1 = 2; break; case 2: edgeVert0 = 1; edgeVert1 = 3; break; case 3: edgeVert0 = 2; edgeVert1 = 3; break; case 4: edgeVert0 = 0; edgeVert1 = 4; break; case 5: edgeVert0 = 1; edgeVert1 = 5; break; case 6: edgeVert0 = 2; edgeVert1 = 6; break; case 7: edgeVert0 = 3; edgeVert1 = 7; break; case 8: edgeVert0 = 4; edgeVert1 = 5; break; case 9: edgeVert0 = 4; edgeVert1 = 6; break; case 10: edgeVert0 = 5; edgeVert1 = 7; break; case 11: edgeVert0 = 6; edgeVert1 = 7; break; default: btAssert(0); } getVertex(edgeVert0,pa ); getVertex(edgeVert1,pb ); } virtual bool isInside(const btVector3& pt,btScalar tolerance) const { btVector3 halfExtents = getHalfExtentsWithoutMargin(); //btScalar minDist = 2*tolerance; bool result = (pt.x() <= (halfExtents.x()+tolerance)) && (pt.x() >= (-halfExtents.x()-tolerance)) && (pt.y() <= (halfExtents.y()+tolerance)) && (pt.y() >= (-halfExtents.y()-tolerance)) && (pt.z() <= (halfExtents.z()+tolerance)) && (pt.z() >= (-halfExtents.z()-tolerance)); return result; } //debugging virtual const char* getName()const { return "Box2d"; } virtual int getNumPreferredPenetrationDirections() const { return 6; } virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const { switch (index) { case 0: penetrationVector.setValue(btScalar(1.),btScalar(0.),btScalar(0.)); break; case 1: penetrationVector.setValue(btScalar(-1.),btScalar(0.),btScalar(0.)); break; case 2: penetrationVector.setValue(btScalar(0.),btScalar(1.),btScalar(0.)); break; case 3: penetrationVector.setValue(btScalar(0.),btScalar(-1.),btScalar(0.)); break; case 4: penetrationVector.setValue(btScalar(0.),btScalar(0.),btScalar(1.)); break; case 5: penetrationVector.setValue(btScalar(0.),btScalar(0.),btScalar(-1.)); break; default: btAssert(0); } } }; #endif //OBB_BOX_2D_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btPolyhedralConvexShape.cpp0000644000175000017500000001120511337071441032456 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "BulletCollision/CollisionShapes/btPolyhedralConvexShape.h" btPolyhedralConvexShape::btPolyhedralConvexShape() :btConvexInternalShape() { } btVector3 btPolyhedralConvexShape::localGetSupportingVertexWithoutMargin(const btVector3& vec0)const { btVector3 supVec(0,0,0); #ifndef __SPU__ int i; btScalar maxDot(btScalar(-BT_LARGE_FLOAT)); btVector3 vec = vec0; btScalar lenSqr = vec.length2(); if (lenSqr < btScalar(0.0001)) { vec.setValue(1,0,0); } else { btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); vec *= rlen; } btVector3 vtx; btScalar newDot; for (i=0;i maxDot) { maxDot = newDot; supVec = vtx; } } #endif //__SPU__ return supVec; } void btPolyhedralConvexShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const { #ifndef __SPU__ int i; btVector3 vtx; btScalar newDot; for (i=0;i supportVerticesOut[j][3]) { //WARNING: don't swap next lines, the w component would get overwritten! supportVerticesOut[j] = vtx; supportVerticesOut[j][3] = newDot; } } } #endif //__SPU__ } void btPolyhedralConvexShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const { #ifndef __SPU__ //not yet, return box inertia btScalar margin = getMargin(); btTransform ident; ident.setIdentity(); btVector3 aabbMin,aabbMax; getAabb(ident,aabbMin,aabbMax); btVector3 halfExtents = (aabbMax-aabbMin)*btScalar(0.5); btScalar lx=btScalar(2.)*(halfExtents.x()+margin); btScalar ly=btScalar(2.)*(halfExtents.y()+margin); btScalar lz=btScalar(2.)*(halfExtents.z()+margin); const btScalar x2 = lx*lx; const btScalar y2 = ly*ly; const btScalar z2 = lz*lz; const btScalar scaledmass = mass * btScalar(0.08333333); inertia = scaledmass * (btVector3(y2+z2,x2+z2,x2+y2)); #endif //__SPU__ } void btPolyhedralConvexAabbCachingShape::setLocalScaling(const btVector3& scaling) { btConvexInternalShape::setLocalScaling(scaling); recalcLocalAabb(); } btPolyhedralConvexAabbCachingShape::btPolyhedralConvexAabbCachingShape() :btPolyhedralConvexShape(), m_localAabbMin(1,1,1), m_localAabbMax(-1,-1,-1), m_isLocalAabbValid(false) { } void btPolyhedralConvexAabbCachingShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax) const { getNonvirtualAabb(trans,aabbMin,aabbMax,getMargin()); } void btPolyhedralConvexAabbCachingShape::recalcLocalAabb() { m_isLocalAabbValid = true; #if 1 static const btVector3 _directions[] = { btVector3( 1., 0., 0.), btVector3( 0., 1., 0.), btVector3( 0., 0., 1.), btVector3( -1., 0., 0.), btVector3( 0., -1., 0.), btVector3( 0., 0., -1.) }; btVector3 _supporting[] = { btVector3( 0., 0., 0.), btVector3( 0., 0., 0.), btVector3( 0., 0., 0.), btVector3( 0., 0., 0.), btVector3( 0., 0., 0.), btVector3( 0., 0., 0.) }; batchedUnitVectorGetSupportingVertexWithoutMargin(_directions, _supporting, 6); for ( int i = 0; i < 3; ++i ) { m_localAabbMax[i] = _supporting[i][i] + m_collisionMargin; m_localAabbMin[i] = _supporting[i + 3][i] - m_collisionMargin; } #else for (int i=0;i<3;i++) { btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.)); vec[i] = btScalar(1.); btVector3 tmp = localGetSupportingVertex(vec); m_localAabbMax[i] = tmp[i]+m_collisionMargin; vec[i] = btScalar(-1.); tmp = localGetSupportingVertex(vec); m_localAabbMin[i] = tmp[i]-m_collisionMargin; } #endif } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btCapsuleShape.h0000644000175000017500000001332411344267705030245 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 BT_CAPSULE_SHAPE_H #define BT_CAPSULE_SHAPE_H #include "btConvexInternalShape.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types ///The btCapsuleShape represents a capsule around the Y axis, there is also the btCapsuleShapeX aligned around the X axis and btCapsuleShapeZ around the Z axis. ///The total height is height+2*radius, so the height is just the height between the center of each 'sphere' of the capsule caps. ///The btCapsuleShape is a convex hull of two spheres. The btMultiSphereShape is a more general collision shape that takes the convex hull of multiple sphere, so it can also represent a capsule when just using two spheres. class btCapsuleShape : public btConvexInternalShape { protected: int m_upAxis; protected: ///only used for btCapsuleShapeZ and btCapsuleShapeX subclasses. btCapsuleShape() : btConvexInternalShape() {m_shapeType = CAPSULE_SHAPE_PROXYTYPE;}; public: btCapsuleShape(btScalar radius,btScalar height); ///CollisionShape Interface virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; /// btConvexShape Interface virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; virtual void setMargin(btScalar collisionMargin) { //correct the m_implicitShapeDimensions for the margin btVector3 oldMargin(getMargin(),getMargin(),getMargin()); btVector3 implicitShapeDimensionsWithMargin = m_implicitShapeDimensions+oldMargin; btConvexInternalShape::setMargin(collisionMargin); btVector3 newMargin(getMargin(),getMargin(),getMargin()); m_implicitShapeDimensions = implicitShapeDimensionsWithMargin - newMargin; } virtual void getAabb (const btTransform& t, btVector3& aabbMin, btVector3& aabbMax) const { btVector3 halfExtents(getRadius(),getRadius(),getRadius()); halfExtents[m_upAxis] = getRadius() + getHalfHeight(); halfExtents += btVector3(getMargin(),getMargin(),getMargin()); btMatrix3x3 abs_b = t.getBasis().absolute(); btVector3 center = t.getOrigin(); btVector3 extent = btVector3(abs_b[0].dot(halfExtents),abs_b[1].dot(halfExtents),abs_b[2].dot(halfExtents)); aabbMin = center - extent; aabbMax = center + extent; } virtual const char* getName()const { return "CapsuleShape"; } int getUpAxis() const { return m_upAxis; } btScalar getRadius() const { int radiusAxis = (m_upAxis+2)%3; return m_implicitShapeDimensions[radiusAxis]; } btScalar getHalfHeight() const { return m_implicitShapeDimensions[m_upAxis]; } virtual void setLocalScaling(const btVector3& scaling) { btVector3 oldMargin(getMargin(),getMargin(),getMargin()); btVector3 implicitShapeDimensionsWithMargin = m_implicitShapeDimensions+oldMargin; btVector3 unScaledImplicitShapeDimensionsWithMargin = implicitShapeDimensionsWithMargin / m_localScaling; btConvexInternalShape::setLocalScaling(scaling); m_implicitShapeDimensions = (unScaledImplicitShapeDimensionsWithMargin * m_localScaling) - oldMargin; } virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; }; ///btCapsuleShapeX represents a capsule around the Z axis ///the total height is height+2*radius, so the height is just the height between the center of each 'sphere' of the capsule caps. class btCapsuleShapeX : public btCapsuleShape { public: btCapsuleShapeX(btScalar radius,btScalar height); //debugging virtual const char* getName()const { return "CapsuleX"; } }; ///btCapsuleShapeZ represents a capsule around the Z axis ///the total height is height+2*radius, so the height is just the height between the center of each 'sphere' of the capsule caps. class btCapsuleShapeZ : public btCapsuleShape { public: btCapsuleShapeZ(btScalar radius,btScalar height); //debugging virtual const char* getName()const { return "CapsuleZ"; } }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btCapsuleShapeData { btConvexInternalShapeData m_convexInternalShapeData; int m_upAxis; char m_padding[4]; }; SIMD_FORCE_INLINE int btCapsuleShape::calculateSerializeBufferSize() const { return sizeof(btCapsuleShapeData); } ///fills the dataBuffer and returns the struct name (and 0 on failure) SIMD_FORCE_INLINE const char* btCapsuleShape::serialize(void* dataBuffer, btSerializer* serializer) const { btCapsuleShapeData* shapeData = (btCapsuleShapeData*) dataBuffer; btConvexInternalShape::serialize(&shapeData->m_convexInternalShapeData,serializer); shapeData->m_upAxis = m_upAxis; return "btCapsuleShapeData"; } #endif //BT_CAPSULE_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btTetrahedronShape.cpp0000644000175000017500000001052211337071441031450 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btTetrahedronShape.h" #include "LinearMath/btMatrix3x3.h" btBU_Simplex1to4::btBU_Simplex1to4() : btPolyhedralConvexAabbCachingShape (), m_numVertices(0) { m_shapeType = TETRAHEDRAL_SHAPE_PROXYTYPE; } btBU_Simplex1to4::btBU_Simplex1to4(const btVector3& pt0) : btPolyhedralConvexAabbCachingShape (), m_numVertices(0) { m_shapeType = TETRAHEDRAL_SHAPE_PROXYTYPE; addVertex(pt0); } btBU_Simplex1to4::btBU_Simplex1to4(const btVector3& pt0,const btVector3& pt1) : btPolyhedralConvexAabbCachingShape (), m_numVertices(0) { m_shapeType = TETRAHEDRAL_SHAPE_PROXYTYPE; addVertex(pt0); addVertex(pt1); } btBU_Simplex1to4::btBU_Simplex1to4(const btVector3& pt0,const btVector3& pt1,const btVector3& pt2) : btPolyhedralConvexAabbCachingShape (), m_numVertices(0) { m_shapeType = TETRAHEDRAL_SHAPE_PROXYTYPE; addVertex(pt0); addVertex(pt1); addVertex(pt2); } btBU_Simplex1to4::btBU_Simplex1to4(const btVector3& pt0,const btVector3& pt1,const btVector3& pt2,const btVector3& pt3) : btPolyhedralConvexAabbCachingShape (), m_numVertices(0) { m_shapeType = TETRAHEDRAL_SHAPE_PROXYTYPE; addVertex(pt0); addVertex(pt1); addVertex(pt2); addVertex(pt3); } void btBU_Simplex1to4::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const { #if 1 btPolyhedralConvexAabbCachingShape::getAabb(t,aabbMin,aabbMax); #else aabbMin.setValue(BT_LARGE_FLOAT,BT_LARGE_FLOAT,BT_LARGE_FLOAT); aabbMax.setValue(-BT_LARGE_FLOAT,-BT_LARGE_FLOAT,-BT_LARGE_FLOAT); //just transform the vertices in worldspace, and take their AABB for (int i=0;i m_children; btVector3 m_localAabbMin; btVector3 m_localAabbMax; btDbvt* m_dynamicAabbTree; ///increment m_updateRevision when adding/removing/replacing child shapes, so that some caches can be updated int m_updateRevision; btScalar m_collisionMargin; protected: btVector3 m_localScaling; public: BT_DECLARE_ALIGNED_ALLOCATOR(); btCompoundShape(bool enableDynamicAabbTree = true); virtual ~btCompoundShape(); void addChildShape(const btTransform& localTransform,btCollisionShape* shape); /// Remove all children shapes that contain the specified shape virtual void removeChildShape(btCollisionShape* shape); void removeChildShapeByIndex(int childShapeindex); int getNumChildShapes() const { return int (m_children.size()); } btCollisionShape* getChildShape(int index) { return m_children[index].m_childShape; } const btCollisionShape* getChildShape(int index) const { return m_children[index].m_childShape; } btTransform& getChildTransform(int index) { return m_children[index].m_transform; } const btTransform& getChildTransform(int index) const { return m_children[index].m_transform; } ///set a new transform for a child, and update internal data structures (local aabb and dynamic tree) void updateChildTransform(int childIndex, const btTransform& newChildTransform); btCompoundShapeChild* getChildList() { return &m_children[0]; } ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; /** Re-calculate the local Aabb. Is called at the end of removeChildShapes. Use this yourself if you modify the children or their transforms. */ virtual void recalculateLocalAabb(); virtual void setLocalScaling(const btVector3& scaling); virtual const btVector3& getLocalScaling() const { return m_localScaling; } virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; virtual void setMargin(btScalar margin) { m_collisionMargin = margin; } virtual btScalar getMargin() const { return m_collisionMargin; } virtual const char* getName()const { return "Compound"; } btDbvt* getDynamicAabbTree() { return m_dynamicAabbTree; } ///computes the exact moment of inertia and the transform from the coordinate system defined by the principal axes of the moment of inertia ///and the center of mass to the current coordinate system. "masses" points to an array of masses of the children. The resulting transform ///"principal" has to be applied inversely to all children transforms in order for the local coordinate system of the compound ///shape to be centered at the center of mass and to coincide with the principal axes. This also necessitates a correction of the world transform ///of the collision object by the principal transform. void calculatePrincipalAxisTransform(btScalar* masses, btTransform& principal, btVector3& inertia) const; int getUpdateRevision() const { return m_updateRevision; } virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btCompoundShapeChildData { btTransformFloatData m_transform; btCollisionShapeData *m_childShape; int m_childShapeType; float m_childMargin; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btCompoundShapeData { btCollisionShapeData m_collisionShapeData; btCompoundShapeChildData *m_childShapePtr; int m_numChildShapes; float m_collisionMargin; }; SIMD_FORCE_INLINE int btCompoundShape::calculateSerializeBufferSize() const { return sizeof(btCompoundShapeData); } #endif //COMPOUND_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h0000644000175000017500000001173411344267705031676 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 BVH_TRIANGLE_MESH_SHAPE_H #define BVH_TRIANGLE_MESH_SHAPE_H #include "btTriangleMeshShape.h" #include "btOptimizedBvh.h" #include "LinearMath/btAlignedAllocator.h" #include "btTriangleInfoMap.h" ///The btBvhTriangleMeshShape is a static-triangle mesh shape with several optimizations, such as bounding volume hierarchy and cache friendly traversal for PlayStation 3 Cell SPU. It is recommended to enable useQuantizedAabbCompression for better memory usage. ///It takes a triangle mesh as input, for example a btTriangleMesh or btTriangleIndexVertexArray. The btBvhTriangleMeshShape class allows for triangle mesh deformations by a refit or partialRefit method. ///Instead of building the bounding volume hierarchy acceleration structure, it is also possible to serialize (save) and deserialize (load) the structure from disk. ///See Demos\ConcaveDemo\ConcavePhysicsDemo.cpp for an example. ATTRIBUTE_ALIGNED16(class) btBvhTriangleMeshShape : public btTriangleMeshShape { btOptimizedBvh* m_bvh; btTriangleInfoMap* m_triangleInfoMap; bool m_useQuantizedAabbCompression; bool m_ownsBvh; bool m_pad[11];////need padding due to alignment public: BT_DECLARE_ALIGNED_ALLOCATOR(); btBvhTriangleMeshShape() : btTriangleMeshShape(0),m_bvh(0),m_triangleInfoMap(0),m_ownsBvh(false) {m_shapeType = TRIANGLE_MESH_SHAPE_PROXYTYPE;}; btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression, bool buildBvh = true); ///optionally pass in a larger bvh aabb, used for quantization. This allows for deformations within this aabb btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression,const btVector3& bvhAabbMin,const btVector3& bvhAabbMax, bool buildBvh = true); virtual ~btBvhTriangleMeshShape(); bool getOwnsBvh () const { return m_ownsBvh; } void performRaycast (btTriangleCallback* callback, const btVector3& raySource, const btVector3& rayTarget); void performConvexcast (btTriangleCallback* callback, const btVector3& boxSource, const btVector3& boxTarget, const btVector3& boxMin, const btVector3& boxMax); virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const; void refitTree(const btVector3& aabbMin,const btVector3& aabbMax); ///for a fast incremental refit of parts of the tree. Note: the entire AABB of the tree will become more conservative, it never shrinks void partialRefitTree(const btVector3& aabbMin,const btVector3& aabbMax); //debugging virtual const char* getName()const {return "BVHTRIANGLEMESH";} virtual void setLocalScaling(const btVector3& scaling); btOptimizedBvh* getOptimizedBvh() { return m_bvh; } void setOptimizedBvh(btOptimizedBvh* bvh, const btVector3& localScaling=btVector3(1,1,1)); void buildOptimizedBvh(); bool usesQuantizedAabbCompression() const { return m_useQuantizedAabbCompression; } void setTriangleInfoMap(btTriangleInfoMap* triangleInfoMap) { m_triangleInfoMap = triangleInfoMap; } const btTriangleInfoMap* getTriangleInfoMap() const { return m_triangleInfoMap; } btTriangleInfoMap* getTriangleInfoMap() { return m_triangleInfoMap; } virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; virtual void serializeSingleBvh(btSerializer* serializer) const; virtual void serializeSingleTriangleInfoMap(btSerializer* serializer) const; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btTriangleMeshShapeData { btCollisionShapeData m_collisionShapeData; btStridingMeshInterfaceData m_meshInterface; btQuantizedBvhFloatData *m_quantizedFloatBvh; btQuantizedBvhDoubleData *m_quantizedDoubleBvh; btTriangleInfoMapData *m_triangleInfoMap; float m_collisionMargin; char m_pad3[4]; }; SIMD_FORCE_INLINE int btBvhTriangleMeshShape::calculateSerializeBufferSize() const { return sizeof(btTriangleMeshShapeData); } #endif //BVH_TRIANGLE_MESH_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btCollisionShape.h0000644000175000017500000001065111344267705030604 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 COLLISION_SHAPE_H #define COLLISION_SHAPE_H #include "LinearMath/btTransform.h" #include "LinearMath/btVector3.h" #include "LinearMath/btMatrix3x3.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" //for the shape types class btSerializer; ///The btCollisionShape class provides an interface for collision shapes that can be shared among btCollisionObjects. class btCollisionShape { protected: int m_shapeType; void* m_userPointer; public: btCollisionShape() : m_shapeType (INVALID_SHAPE_PROXYTYPE), m_userPointer(0) { } virtual ~btCollisionShape() { } ///getAabb returns the axis aligned bounding box in the coordinate frame of the given transform t. virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const =0; virtual void getBoundingSphere(btVector3& center,btScalar& radius) const; ///getAngularMotionDisc returns the maximus radius needed for Conservative Advancement to handle time-of-impact with rotations. virtual btScalar getAngularMotionDisc() const; virtual btScalar getContactBreakingThreshold(btScalar defaultContactThresholdFactor) const; ///calculateTemporalAabb calculates the enclosing aabb for the moving object over interval [0..timeStep) ///result is conservative void calculateTemporalAabb(const btTransform& curTrans,const btVector3& linvel,const btVector3& angvel,btScalar timeStep, btVector3& temporalAabbMin,btVector3& temporalAabbMax) const; SIMD_FORCE_INLINE bool isPolyhedral() const { return btBroadphaseProxy::isPolyhedral(getShapeType()); } SIMD_FORCE_INLINE bool isConvex2d() const { return btBroadphaseProxy::isConvex2d(getShapeType()); } SIMD_FORCE_INLINE bool isConvex() const { return btBroadphaseProxy::isConvex(getShapeType()); } SIMD_FORCE_INLINE bool isNonMoving() const { return btBroadphaseProxy::isNonMoving(getShapeType()); } SIMD_FORCE_INLINE bool isConcave() const { return btBroadphaseProxy::isConcave(getShapeType()); } SIMD_FORCE_INLINE bool isCompound() const { return btBroadphaseProxy::isCompound(getShapeType()); } SIMD_FORCE_INLINE bool isSoftBody() const { return btBroadphaseProxy::isSoftBody(getShapeType()); } ///isInfinite is used to catch simulation error (aabb check) SIMD_FORCE_INLINE bool isInfinite() const { return btBroadphaseProxy::isInfinite(getShapeType()); } #ifndef __SPU__ virtual void setLocalScaling(const btVector3& scaling) =0; virtual const btVector3& getLocalScaling() const =0; virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const = 0; //debugging support virtual const char* getName()const =0 ; #endif //__SPU__ int getShapeType() const { return m_shapeType; } virtual void setMargin(btScalar margin) = 0; virtual btScalar getMargin() const = 0; ///optional user data pointer void setUserPointer(void* userPtr) { m_userPointer = userPtr; } void* getUserPointer() const { return m_userPointer; } virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; virtual void serializeSingleShape(btSerializer* serializer) const; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btCollisionShapeData { char *m_name; int m_shapeType; char m_padding[4]; }; SIMD_FORCE_INLINE int btCollisionShape::calculateSerializeBufferSize() const { return sizeof(btCollisionShapeData); } #endif //COLLISION_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btConcaveShape.h0000644000175000017500000000401411337071441030213 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 CONCAVE_SHAPE_H #define CONCAVE_SHAPE_H #include "btCollisionShape.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types #include "btTriangleCallback.h" /// PHY_ScalarType enumerates possible scalar types. /// See the btStridingMeshInterface or btHeightfieldTerrainShape for its use typedef enum PHY_ScalarType { PHY_FLOAT, PHY_DOUBLE, PHY_INTEGER, PHY_SHORT, PHY_FIXEDPOINT88, PHY_UCHAR } PHY_ScalarType; ///The btConcaveShape class provides an interface for non-moving (static) concave shapes. ///It has been implemented by the btStaticPlaneShape, btBvhTriangleMeshShape and btHeightfieldTerrainShape. class btConcaveShape : public btCollisionShape { protected: btScalar m_collisionMargin; public: btConcaveShape(); virtual ~btConcaveShape(); virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const = 0; virtual btScalar getMargin() const { return m_collisionMargin; } virtual void setMargin(btScalar collisionMargin) { m_collisionMargin = collisionMargin; } }; #endif //CONCAVE_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btMultiSphereShape.h0000644000175000017500000000577711344267705031127 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 MULTI_SPHERE_MINKOWSKI_H #define MULTI_SPHERE_MINKOWSKI_H #include "btConvexInternalShape.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types #include "LinearMath/btAlignedObjectArray.h" #include "LinearMath/btAabbUtil2.h" ///The btMultiSphereShape represents the convex hull of a collection of spheres. You can create special capsules or other smooth volumes. ///It is possible to animate the spheres for deformation, but call 'recalcLocalAabb' after changing any sphere position/radius class btMultiSphereShape : public btConvexInternalAabbCachingShape { btAlignedObjectArray m_localPositionArray; btAlignedObjectArray m_radiArray; public: btMultiSphereShape (const btVector3* positions,const btScalar* radi,int numSpheres); ///CollisionShape Interface virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; /// btConvexShape Interface virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; int getSphereCount() const { return m_localPositionArray.size(); } const btVector3& getSpherePosition(int index) const { return m_localPositionArray[index]; } btScalar getSphereRadius(int index) const { return m_radiArray[index]; } virtual const char* getName()const { return "MultiSphere"; } virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; }; struct btPositionAndRadius { btVector3FloatData m_pos; float m_radius; }; struct btMultiSphereShapeData { btConvexInternalShapeData m_convexInternalShapeData; btPositionAndRadius *m_localPositionArrayPtr; int m_localPositionArraySize; char m_padding[4]; }; SIMD_FORCE_INLINE int btMultiSphereShape::calculateSerializeBufferSize() const { return sizeof(btMultiSphereShapeData); } #endif //MULTI_SPHERE_MINKOWSKI_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btSphereShape.h0000644000175000017500000000517311337071441030072 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 SPHERE_MINKOWSKI_H #define SPHERE_MINKOWSKI_H #include "btConvexInternalShape.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types ///The btSphereShape implements an implicit sphere, centered around a local origin with radius. ATTRIBUTE_ALIGNED16(class) btSphereShape : public btConvexInternalShape { public: BT_DECLARE_ALIGNED_ALLOCATOR(); btSphereShape (btScalar radius) : btConvexInternalShape () { m_shapeType = SPHERE_SHAPE_PROXYTYPE; m_implicitShapeDimensions.setX(radius); m_collisionMargin = radius; } virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; //notice that the vectors should be unit length virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; btScalar getRadius() const { return m_implicitShapeDimensions.getX() * m_localScaling.getX();} void setUnscaledRadius(btScalar radius) { m_implicitShapeDimensions.setX(radius); btConvexInternalShape::setMargin(radius); } //debugging virtual const char* getName()const {return "SPHERE";} virtual void setMargin(btScalar margin) { btConvexInternalShape::setMargin(margin); } virtual btScalar getMargin() const { //to improve gjk behaviour, use radius+margin as the full margin, so never get into the penetration case //this means, non-uniform scaling is not supported anymore return getRadius(); } }; #endif //SPHERE_MINKOWSKI_H ././@LongLink0000000000000000000000000000014700000000000011567 Lustar rootrootcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.cppcritterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btScaledBvhTriangleMeshShape.c0000644000175000017500000001152611337071441032774 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btScaledBvhTriangleMeshShape.h" btScaledBvhTriangleMeshShape::btScaledBvhTriangleMeshShape(btBvhTriangleMeshShape* childShape,const btVector3& localScaling) :m_localScaling(localScaling),m_bvhTriMeshShape(childShape) { m_shapeType = SCALED_TRIANGLE_MESH_SHAPE_PROXYTYPE; } btScaledBvhTriangleMeshShape::~btScaledBvhTriangleMeshShape() { } class btScaledTriangleCallback : public btTriangleCallback { btTriangleCallback* m_originalCallback; btVector3 m_localScaling; public: btScaledTriangleCallback(btTriangleCallback* originalCallback,const btVector3& localScaling) :m_originalCallback(originalCallback), m_localScaling(localScaling) { } virtual void processTriangle(btVector3* triangle, int partId, int triangleIndex) { btVector3 newTriangle[3]; newTriangle[0] = triangle[0]*m_localScaling; newTriangle[1] = triangle[1]*m_localScaling; newTriangle[2] = triangle[2]*m_localScaling; m_originalCallback->processTriangle(&newTriangle[0],partId,triangleIndex); } }; void btScaledBvhTriangleMeshShape::processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const { btScaledTriangleCallback scaledCallback(callback,m_localScaling); btVector3 invLocalScaling(1.f/m_localScaling.getX(),1.f/m_localScaling.getY(),1.f/m_localScaling.getZ()); btVector3 scaledAabbMin,scaledAabbMax; ///support negative scaling scaledAabbMin[0] = m_localScaling.getX() >= 0. ? aabbMin[0] * invLocalScaling[0] : aabbMax[0] * invLocalScaling[0]; scaledAabbMin[1] = m_localScaling.getY() >= 0. ? aabbMin[1] * invLocalScaling[1] : aabbMax[1] * invLocalScaling[1]; scaledAabbMin[2] = m_localScaling.getZ() >= 0. ? aabbMin[2] * invLocalScaling[2] : aabbMax[2] * invLocalScaling[2]; scaledAabbMax[0] = m_localScaling.getX() <= 0. ? aabbMin[0] * invLocalScaling[0] : aabbMax[0] * invLocalScaling[0]; scaledAabbMax[1] = m_localScaling.getY() <= 0. ? aabbMin[1] * invLocalScaling[1] : aabbMax[1] * invLocalScaling[1]; scaledAabbMax[2] = m_localScaling.getZ() <= 0. ? aabbMin[2] * invLocalScaling[2] : aabbMax[2] * invLocalScaling[2]; m_bvhTriMeshShape->processAllTriangles(&scaledCallback,scaledAabbMin,scaledAabbMax); } void btScaledBvhTriangleMeshShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax) const { btVector3 localAabbMin = m_bvhTriMeshShape->getLocalAabbMin(); btVector3 localAabbMax = m_bvhTriMeshShape->getLocalAabbMax(); btVector3 tmpLocalAabbMin = localAabbMin * m_localScaling; btVector3 tmpLocalAabbMax = localAabbMax * m_localScaling; localAabbMin[0] = (m_localScaling.getX() >= 0.) ? tmpLocalAabbMin[0] : tmpLocalAabbMax[0]; localAabbMin[1] = (m_localScaling.getY() >= 0.) ? tmpLocalAabbMin[1] : tmpLocalAabbMax[1]; localAabbMin[2] = (m_localScaling.getZ() >= 0.) ? tmpLocalAabbMin[2] : tmpLocalAabbMax[2]; localAabbMax[0] = (m_localScaling.getX() <= 0.) ? tmpLocalAabbMin[0] : tmpLocalAabbMax[0]; localAabbMax[1] = (m_localScaling.getY() <= 0.) ? tmpLocalAabbMin[1] : tmpLocalAabbMax[1]; localAabbMax[2] = (m_localScaling.getZ() <= 0.) ? tmpLocalAabbMin[2] : tmpLocalAabbMax[2]; btVector3 localHalfExtents = btScalar(0.5)*(localAabbMax-localAabbMin); btScalar margin = m_bvhTriMeshShape->getMargin(); localHalfExtents += btVector3(margin,margin,margin); btVector3 localCenter = btScalar(0.5)*(localAabbMax+localAabbMin); btMatrix3x3 abs_b = trans.getBasis().absolute(); btVector3 center = trans(localCenter); btVector3 extent = btVector3(abs_b[0].dot(localHalfExtents), abs_b[1].dot(localHalfExtents), abs_b[2].dot(localHalfExtents)); aabbMin = center - extent; aabbMax = center + extent; } void btScaledBvhTriangleMeshShape::setLocalScaling(const btVector3& scaling) { m_localScaling = scaling; } const btVector3& btScaledBvhTriangleMeshShape::getLocalScaling() const { return m_localScaling; } void btScaledBvhTriangleMeshShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const { ///don't make this a movable object! // btAssert(0); } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btConeShape.h0000644000175000017500000000632411337071441027527 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 CONE_MINKOWSKI_H #define CONE_MINKOWSKI_H #include "btConvexInternalShape.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types ///The btConeShape implements a cone shape primitive, centered around the origin and aligned with the Y axis. The btConeShapeX is aligned around the X axis and btConeShapeZ around the Z axis. class btConeShape : public btConvexInternalShape { btScalar m_sinAngle; btScalar m_radius; btScalar m_height; int m_coneIndices[3]; btVector3 coneLocalSupport(const btVector3& v) const; public: btConeShape (btScalar radius,btScalar height); virtual btVector3 localGetSupportingVertex(const btVector3& vec) const; virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec) const; virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; btScalar getRadius() const { return m_radius;} btScalar getHeight() const { return m_height;} virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const { btTransform identity; identity.setIdentity(); btVector3 aabbMin,aabbMax; getAabb(identity,aabbMin,aabbMax); btVector3 halfExtents = (aabbMax-aabbMin)*btScalar(0.5); btScalar margin = getMargin(); btScalar lx=btScalar(2.)*(halfExtents.x()+margin); btScalar ly=btScalar(2.)*(halfExtents.y()+margin); btScalar lz=btScalar(2.)*(halfExtents.z()+margin); const btScalar x2 = lx*lx; const btScalar y2 = ly*ly; const btScalar z2 = lz*lz; const btScalar scaledmass = mass * btScalar(0.08333333); inertia = scaledmass * (btVector3(y2+z2,x2+z2,x2+y2)); // inertia.x() = scaledmass * (y2+z2); // inertia.y() = scaledmass * (x2+z2); // inertia.z() = scaledmass * (x2+y2); } virtual const char* getName()const { return "Cone"; } ///choose upAxis index void setConeUpIndex(int upIndex); int getConeUpIndex() const { return m_coneIndices[1]; } }; ///btConeShape implements a Cone shape, around the X axis class btConeShapeX : public btConeShape { public: btConeShapeX(btScalar radius,btScalar height); }; ///btConeShapeZ implements a Cone shape, around the Z axis class btConeShapeZ : public btConeShape { public: btConeShapeZ(btScalar radius,btScalar height); }; #endif //CONE_MINKOWSKI_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btConvexHullShape.cpp0000644000175000017500000001333611344267705031276 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btConvexHullShape.h" #include "BulletCollision/CollisionShapes/btCollisionMargin.h" #include "LinearMath/btQuaternion.h" #include "LinearMath/btSerializer.h" btConvexHullShape ::btConvexHullShape (const btScalar* points,int numPoints,int stride) : btPolyhedralConvexAabbCachingShape () { m_shapeType = CONVEX_HULL_SHAPE_PROXYTYPE; m_unscaledPoints.resize(numPoints); unsigned char* pointsAddress = (unsigned char*)points; for (int i=0;i maxDot) { maxDot = newDot; supVec = vtx; } } return supVec; } void btConvexHullShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const { btScalar newDot; //use 'w' component of supportVerticesOut? { for (int i=0;i supportVerticesOut[j][3]) { //WARNING: don't swap next lines, the w component would get overwritten! supportVerticesOut[j] = vtx; supportVerticesOut[j][3] = newDot; } } } } btVector3 btConvexHullShape::localGetSupportingVertex(const btVector3& vec)const { btVector3 supVertex = localGetSupportingVertexWithoutMargin(vec); if ( getMargin()!=btScalar(0.) ) { btVector3 vecnorm = vec; if (vecnorm .length2() < (SIMD_EPSILON*SIMD_EPSILON)) { vecnorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.)); } vecnorm.normalize(); supVertex+= getMargin() * vecnorm; } return supVertex; } //currently just for debugging (drawing), perhaps future support for algebraic continuous collision detection //Please note that you can debug-draw btConvexHullShape with the Raytracer Demo int btConvexHullShape::getNumVertices() const { return m_unscaledPoints.size(); } int btConvexHullShape::getNumEdges() const { return m_unscaledPoints.size(); } void btConvexHullShape::getEdge(int i,btVector3& pa,btVector3& pb) const { int index0 = i%m_unscaledPoints.size(); int index1 = (i+1)%m_unscaledPoints.size(); pa = getScaledPoint(index0); pb = getScaledPoint(index1); } void btConvexHullShape::getVertex(int i,btVector3& vtx) const { vtx = getScaledPoint(i); } int btConvexHullShape::getNumPlanes() const { return 0; } void btConvexHullShape::getPlane(btVector3& ,btVector3& ,int ) const { btAssert(0); } //not yet bool btConvexHullShape::isInside(const btVector3& ,btScalar ) const { btAssert(0); return false; } ///fills the dataBuffer and returns the struct name (and 0 on failure) const char* btConvexHullShape::serialize(void* dataBuffer, btSerializer* serializer) const { //int szc = sizeof(btConvexHullShapeData); btConvexHullShapeData* shapeData = (btConvexHullShapeData*) dataBuffer; btConvexInternalShape::serialize(&shapeData->m_convexInternalShapeData, serializer); int numElem = m_unscaledPoints.size(); shapeData->m_numUnscaledPoints = numElem; #ifdef BT_USE_DOUBLE_PRECISION shapeData->m_unscaledPointsFloatPtr = 0; shapeData->m_unscaledPointsDoublePtr = numElem ? (btVector3Data*)serializer->getUniquePointer((void*)&m_unscaledPoints[0]): 0; #else shapeData->m_unscaledPointsFloatPtr = numElem ? (btVector3Data*)serializer->getUniquePointer((void*)&m_unscaledPoints[0]): 0; shapeData->m_unscaledPointsDoublePtr = 0; #endif if (numElem) { int sz = sizeof(btVector3Data); // int sz2 = sizeof(btVector3DoubleData); // int sz3 = sizeof(btVector3FloatData); btChunk* chunk = serializer->allocate(sz,numElem); btVector3Data* memPtr = (btVector3Data*)chunk->m_oldPtr; for (int i=0;ifinalizeChunk(chunk,btVector3DataName,BT_ARRAY_CODE,(void*)&m_unscaledPoints[0]); } return "btConvexHullShapeData"; } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btBox2dShape.cpp0000644000175000017500000000320411337071441030146 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btBox2dShape.h" //{ void btBox2dShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const { btTransformAabb(getHalfExtentsWithoutMargin(),getMargin(),t,aabbMin,aabbMax); } void btBox2dShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const { //btScalar margin = btScalar(0.); btVector3 halfExtents = getHalfExtentsWithMargin(); btScalar lx=btScalar(2.)*(halfExtents.x()); btScalar ly=btScalar(2.)*(halfExtents.y()); btScalar lz=btScalar(2.)*(halfExtents.z()); inertia.setValue(mass/(btScalar(12.0)) * (ly*ly + lz*lz), mass/(btScalar(12.0)) * (lx*lx + lz*lz), mass/(btScalar(12.0)) * (lx*lx + ly*ly)); } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btBvhTriangleMeshShape.cpp0000644000175000017500000003373011344267705032231 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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. */ //#define DISABLE_BVH #include "BulletCollision/CollisionShapes/btBvhTriangleMeshShape.h" #include "BulletCollision/CollisionShapes/btOptimizedBvh.h" #include "LinearMath/btSerializer.h" ///Bvh Concave triangle mesh is a static-triangle mesh shape with Bounding Volume Hierarchy optimization. ///Uses an interface to access the triangles to allow for sharing graphics/physics triangles. btBvhTriangleMeshShape::btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression, bool buildBvh) :btTriangleMeshShape(meshInterface), m_bvh(0), m_triangleInfoMap(0), m_useQuantizedAabbCompression(useQuantizedAabbCompression), m_ownsBvh(false) { m_shapeType = TRIANGLE_MESH_SHAPE_PROXYTYPE; //construct bvh from meshInterface #ifndef DISABLE_BVH if (buildBvh) { buildOptimizedBvh(); } #endif //DISABLE_BVH } btBvhTriangleMeshShape::btBvhTriangleMeshShape(btStridingMeshInterface* meshInterface, bool useQuantizedAabbCompression,const btVector3& bvhAabbMin,const btVector3& bvhAabbMax,bool buildBvh) :btTriangleMeshShape(meshInterface), m_bvh(0), m_triangleInfoMap(0), m_useQuantizedAabbCompression(useQuantizedAabbCompression), m_ownsBvh(false) { m_shapeType = TRIANGLE_MESH_SHAPE_PROXYTYPE; //construct bvh from meshInterface #ifndef DISABLE_BVH if (buildBvh) { void* mem = btAlignedAlloc(sizeof(btOptimizedBvh),16); m_bvh = new (mem) btOptimizedBvh(); m_bvh->build(meshInterface,m_useQuantizedAabbCompression,bvhAabbMin,bvhAabbMax); m_ownsBvh = true; } #endif //DISABLE_BVH } void btBvhTriangleMeshShape::partialRefitTree(const btVector3& aabbMin,const btVector3& aabbMax) { m_bvh->refitPartial( m_meshInterface,aabbMin,aabbMax ); m_localAabbMin.setMin(aabbMin); m_localAabbMax.setMax(aabbMax); } void btBvhTriangleMeshShape::refitTree(const btVector3& aabbMin,const btVector3& aabbMax) { m_bvh->refit( m_meshInterface, aabbMin,aabbMax ); recalcLocalAabb(); } btBvhTriangleMeshShape::~btBvhTriangleMeshShape() { if (m_ownsBvh) { m_bvh->~btOptimizedBvh(); btAlignedFree(m_bvh); } } void btBvhTriangleMeshShape::performRaycast (btTriangleCallback* callback, const btVector3& raySource, const btVector3& rayTarget) { struct MyNodeOverlapCallback : public btNodeOverlapCallback { btStridingMeshInterface* m_meshInterface; btTriangleCallback* m_callback; MyNodeOverlapCallback(btTriangleCallback* callback,btStridingMeshInterface* meshInterface) :m_meshInterface(meshInterface), m_callback(callback) { } virtual void processNode(int nodeSubPart, int nodeTriangleIndex) { btVector3 m_triangle[3]; const unsigned char *vertexbase; int numverts; PHY_ScalarType type; int stride; const unsigned char *indexbase; int indexstride; int numfaces; PHY_ScalarType indicestype; m_meshInterface->getLockedReadOnlyVertexIndexBase( &vertexbase, numverts, type, stride, &indexbase, indexstride, numfaces, indicestype, nodeSubPart); unsigned int* gfxbase = (unsigned int*)(indexbase+nodeTriangleIndex*indexstride); btAssert(indicestype==PHY_INTEGER||indicestype==PHY_SHORT); const btVector3& meshScaling = m_meshInterface->getScaling(); for (int j=2;j>=0;j--) { int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j]; if (type == PHY_FLOAT) { float* graphicsbase = (float*)(vertexbase+graphicsindex*stride); m_triangle[j] = btVector3(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ()); } else { double* graphicsbase = (double*)(vertexbase+graphicsindex*stride); m_triangle[j] = btVector3(btScalar(graphicsbase[0])*meshScaling.getX(),btScalar(graphicsbase[1])*meshScaling.getY(),btScalar(graphicsbase[2])*meshScaling.getZ()); } } /* Perform ray vs. triangle collision here */ m_callback->processTriangle(m_triangle,nodeSubPart,nodeTriangleIndex); m_meshInterface->unLockReadOnlyVertexBase(nodeSubPart); } }; MyNodeOverlapCallback myNodeCallback(callback,m_meshInterface); m_bvh->reportRayOverlappingNodex(&myNodeCallback,raySource,rayTarget); } void btBvhTriangleMeshShape::performConvexcast (btTriangleCallback* callback, const btVector3& raySource, const btVector3& rayTarget, const btVector3& aabbMin, const btVector3& aabbMax) { struct MyNodeOverlapCallback : public btNodeOverlapCallback { btStridingMeshInterface* m_meshInterface; btTriangleCallback* m_callback; MyNodeOverlapCallback(btTriangleCallback* callback,btStridingMeshInterface* meshInterface) :m_meshInterface(meshInterface), m_callback(callback) { } virtual void processNode(int nodeSubPart, int nodeTriangleIndex) { btVector3 m_triangle[3]; const unsigned char *vertexbase; int numverts; PHY_ScalarType type; int stride; const unsigned char *indexbase; int indexstride; int numfaces; PHY_ScalarType indicestype; m_meshInterface->getLockedReadOnlyVertexIndexBase( &vertexbase, numverts, type, stride, &indexbase, indexstride, numfaces, indicestype, nodeSubPart); unsigned int* gfxbase = (unsigned int*)(indexbase+nodeTriangleIndex*indexstride); btAssert(indicestype==PHY_INTEGER||indicestype==PHY_SHORT); const btVector3& meshScaling = m_meshInterface->getScaling(); for (int j=2;j>=0;j--) { int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j]; if (type == PHY_FLOAT) { float* graphicsbase = (float*)(vertexbase+graphicsindex*stride); m_triangle[j] = btVector3(graphicsbase[0]*meshScaling.getX(),graphicsbase[1]*meshScaling.getY(),graphicsbase[2]*meshScaling.getZ()); } else { double* graphicsbase = (double*)(vertexbase+graphicsindex*stride); m_triangle[j] = btVector3(btScalar(graphicsbase[0])*meshScaling.getX(),btScalar(graphicsbase[1])*meshScaling.getY(),btScalar(graphicsbase[2])*meshScaling.getZ()); } } /* Perform ray vs. triangle collision here */ m_callback->processTriangle(m_triangle,nodeSubPart,nodeTriangleIndex); m_meshInterface->unLockReadOnlyVertexBase(nodeSubPart); } }; MyNodeOverlapCallback myNodeCallback(callback,m_meshInterface); m_bvh->reportBoxCastOverlappingNodex (&myNodeCallback, raySource, rayTarget, aabbMin, aabbMax); } //perform bvh tree traversal and report overlapping triangles to 'callback' void btBvhTriangleMeshShape::processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const { #ifdef DISABLE_BVH //brute force traverse all triangles btTriangleMeshShape::processAllTriangles(callback,aabbMin,aabbMax); #else //first get all the nodes struct MyNodeOverlapCallback : public btNodeOverlapCallback { btStridingMeshInterface* m_meshInterface; btTriangleCallback* m_callback; btVector3 m_triangle[3]; MyNodeOverlapCallback(btTriangleCallback* callback,btStridingMeshInterface* meshInterface) :m_meshInterface(meshInterface), m_callback(callback) { } virtual void processNode(int nodeSubPart, int nodeTriangleIndex) { const unsigned char *vertexbase; int numverts; PHY_ScalarType type; int stride; const unsigned char *indexbase; int indexstride; int numfaces; PHY_ScalarType indicestype; m_meshInterface->getLockedReadOnlyVertexIndexBase( &vertexbase, numverts, type, stride, &indexbase, indexstride, numfaces, indicestype, nodeSubPart); unsigned int* gfxbase = (unsigned int*)(indexbase+nodeTriangleIndex*indexstride); btAssert(indicestype==PHY_INTEGER||indicestype==PHY_SHORT); const btVector3& meshScaling = m_meshInterface->getScaling(); for (int j=2;j>=0;j--) { int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j]; #ifdef DEBUG_TRIANGLE_MESH printf("%d ,",graphicsindex); #endif //DEBUG_TRIANGLE_MESH if (type == PHY_FLOAT) { float* graphicsbase = (float*)(vertexbase+graphicsindex*stride); m_triangle[j] = btVector3( graphicsbase[0]*meshScaling.getX(), graphicsbase[1]*meshScaling.getY(), graphicsbase[2]*meshScaling.getZ()); } else { double* graphicsbase = (double*)(vertexbase+graphicsindex*stride); m_triangle[j] = btVector3( btScalar(graphicsbase[0])*meshScaling.getX(), btScalar(graphicsbase[1])*meshScaling.getY(), btScalar(graphicsbase[2])*meshScaling.getZ()); } #ifdef DEBUG_TRIANGLE_MESH printf("triangle vertices:%f,%f,%f\n",triangle[j].x(),triangle[j].y(),triangle[j].z()); #endif //DEBUG_TRIANGLE_MESH } m_callback->processTriangle(m_triangle,nodeSubPart,nodeTriangleIndex); m_meshInterface->unLockReadOnlyVertexBase(nodeSubPart); } }; MyNodeOverlapCallback myNodeCallback(callback,m_meshInterface); m_bvh->reportAabbOverlappingNodex(&myNodeCallback,aabbMin,aabbMax); #endif//DISABLE_BVH } void btBvhTriangleMeshShape::setLocalScaling(const btVector3& scaling) { if ((getLocalScaling() -scaling).length2() > SIMD_EPSILON) { btTriangleMeshShape::setLocalScaling(scaling); buildOptimizedBvh(); } } void btBvhTriangleMeshShape::buildOptimizedBvh() { if (m_ownsBvh) { m_bvh->~btOptimizedBvh(); btAlignedFree(m_bvh); } ///m_localAabbMin/m_localAabbMax is already re-calculated in btTriangleMeshShape. We could just scale aabb, but this needs some more work void* mem = btAlignedAlloc(sizeof(btOptimizedBvh),16); m_bvh = new(mem) btOptimizedBvh(); //rebuild the bvh... m_bvh->build(m_meshInterface,m_useQuantizedAabbCompression,m_localAabbMin,m_localAabbMax); m_ownsBvh = true; } void btBvhTriangleMeshShape::setOptimizedBvh(btOptimizedBvh* bvh, const btVector3& scaling) { btAssert(!m_bvh); btAssert(!m_ownsBvh); m_bvh = bvh; m_ownsBvh = false; // update the scaling without rebuilding the bvh if ((getLocalScaling() -scaling).length2() > SIMD_EPSILON) { btTriangleMeshShape::setLocalScaling(scaling); } } ///fills the dataBuffer and returns the struct name (and 0 on failure) const char* btBvhTriangleMeshShape::serialize(void* dataBuffer, btSerializer* serializer) const { btTriangleMeshShapeData* trimeshData = (btTriangleMeshShapeData*) dataBuffer; btCollisionShape::serialize(&trimeshData->m_collisionShapeData,serializer); m_meshInterface->serialize(&trimeshData->m_meshInterface, serializer); trimeshData->m_collisionMargin = float(m_collisionMargin); if (m_bvh && !(serializer->getSerializationFlags()&BT_SERIALIZE_NO_BVH)) { void* chunk = serializer->findPointer(m_bvh); if (chunk) { #ifdef BT_USE_DOUBLE_PRECISION trimeshData->m_quantizedDoubleBvh = (btQuantizedBvhData*)chunk; trimeshData->m_quantizedFloatBvh = 0; #else trimeshData->m_quantizedFloatBvh = (btQuantizedBvhData*)chunk; trimeshData->m_quantizedDoubleBvh= 0; #endif //BT_USE_DOUBLE_PRECISION } else { #ifdef BT_USE_DOUBLE_PRECISION trimeshData->m_quantizedDoubleBvh = (btQuantizedBvhData*)serializer->getUniquePointer(m_bvh); trimeshData->m_quantizedFloatBvh = 0; #else trimeshData->m_quantizedFloatBvh = (btQuantizedBvhData*)serializer->getUniquePointer(m_bvh); trimeshData->m_quantizedDoubleBvh= 0; #endif //BT_USE_DOUBLE_PRECISION int sz = m_bvh->calculateSerializeBufferSizeNew(); btChunk* chunk = serializer->allocate(sz,1); const char* structType = m_bvh->serialize(chunk->m_oldPtr, serializer); serializer->finalizeChunk(chunk,structType,BT_QUANTIZED_BVH_CODE,m_bvh); } } else { trimeshData->m_quantizedFloatBvh = 0; trimeshData->m_quantizedDoubleBvh = 0; } if (m_triangleInfoMap && !(serializer->getSerializationFlags()&BT_SERIALIZE_NO_TRIANGLEINFOMAP)) { void* chunk = serializer->findPointer(m_triangleInfoMap); if (chunk) { trimeshData->m_triangleInfoMap = (btTriangleInfoMapData*)chunk; } else { trimeshData->m_triangleInfoMap = (btTriangleInfoMapData*)serializer->getUniquePointer(m_triangleInfoMap); int sz = m_triangleInfoMap->calculateSerializeBufferSize(); btChunk* chunk = serializer->allocate(sz,1); const char* structType = m_triangleInfoMap->serialize(chunk->m_oldPtr, serializer); serializer->finalizeChunk(chunk,structType,BT_TRIANLGE_INFO_MAP,m_triangleInfoMap); } } else { trimeshData->m_triangleInfoMap = 0; } return "btTriangleMeshShapeData"; } void btBvhTriangleMeshShape::serializeSingleBvh(btSerializer* serializer) const { if (m_bvh) { int len = m_bvh->calculateSerializeBufferSizeNew(); //make sure not to use calculateSerializeBufferSize because it is used for in-place btChunk* chunk = serializer->allocate(len,1); const char* structType = m_bvh->serialize(chunk->m_oldPtr, serializer); serializer->finalizeChunk(chunk,structType,BT_QUANTIZED_BVH_CODE,(void*)m_bvh); } } void btBvhTriangleMeshShape::serializeSingleTriangleInfoMap(btSerializer* serializer) const { if (m_triangleInfoMap) { int len = m_triangleInfoMap->calculateSerializeBufferSize(); btChunk* chunk = serializer->allocate(len,1); const char* structType = m_triangleInfoMap->serialize(chunk->m_oldPtr, serializer); serializer->finalizeChunk(chunk,structType,BT_TRIANLGE_INFO_MAP,(void*)m_triangleInfoMap); } } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btTriangleMesh.h0000644000175000017500000000605111337071441030241 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 TRIANGLE_MESH_H #define TRIANGLE_MESH_H #include "btTriangleIndexVertexArray.h" #include "LinearMath/btVector3.h" #include "LinearMath/btAlignedObjectArray.h" ///The btTriangleMesh class is a convenience class derived from btTriangleIndexVertexArray, that provides storage for a concave triangle mesh. It can be used as data for the btBvhTriangleMeshShape. ///It allows either 32bit or 16bit indices, and 4 (x-y-z-w) or 3 (x-y-z) component vertices. ///If you want to share triangle/index data between graphics mesh and collision mesh (btBvhTriangleMeshShape), you can directly use btTriangleIndexVertexArray or derive your own class from btStridingMeshInterface. ///Performance of btTriangleMesh and btTriangleIndexVertexArray used in a btBvhTriangleMeshShape is the same. class btTriangleMesh : public btTriangleIndexVertexArray { btAlignedObjectArray m_4componentVertices; btAlignedObjectArray m_3componentVertices; btAlignedObjectArray m_32bitIndices; btAlignedObjectArray m_16bitIndices; bool m_use32bitIndices; bool m_use4componentVertices; public: btScalar m_weldingThreshold; btTriangleMesh (bool use32bitIndices=true,bool use4componentVertices=true); bool getUse32bitIndices() const { return m_use32bitIndices; } bool getUse4componentVertices() const { return m_use4componentVertices; } ///By default addTriangle won't search for duplicate vertices, because the search is very slow for large triangle meshes. ///In general it is better to directly use btTriangleIndexVertexArray instead. void addTriangle(const btVector3& vertex0,const btVector3& vertex1,const btVector3& vertex2, bool removeDuplicateVertices=false); int getNumTriangles() const; virtual void preallocateVertices(int numverts){(void) numverts;} virtual void preallocateIndices(int numindices){(void) numindices;} ///findOrAddVertex is an internal method, use addTriangle instead int findOrAddVertex(const btVector3& vertex, bool removeDuplicateVertices); ///addIndex is an internal method, use addTriangle instead void addIndex(int index); }; #endif //TRIANGLE_MESH_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btStridingMeshInterface.cpp0000644000175000017500000003055211344267705032446 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btStridingMeshInterface.h" #include "LinearMath/btSerializer.h" btStridingMeshInterface::~btStridingMeshInterface() { } void btStridingMeshInterface::InternalProcessAllTriangles(btInternalTriangleIndexCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const { (void)aabbMin; (void)aabbMax; int numtotalphysicsverts = 0; int part,graphicssubparts = getNumSubParts(); const unsigned char * vertexbase; const unsigned char * indexbase; int indexstride; PHY_ScalarType type; PHY_ScalarType gfxindextype; int stride,numverts,numtriangles; int gfxindex; btVector3 triangle[3]; btVector3 meshScaling = getScaling(); ///if the number of parts is big, the performance might drop due to the innerloop switch on indextype for (part=0;partinternalProcessTriangleIndex(triangle,part,gfxindex); } break; } case PHY_SHORT: { for (gfxindex=0;gfxindexinternalProcessTriangleIndex(triangle,part,gfxindex); } break; } default: btAssert((gfxindextype == PHY_INTEGER) || (gfxindextype == PHY_SHORT)); } break; } case PHY_DOUBLE: { double* graphicsbase; switch (gfxindextype) { case PHY_INTEGER: { for (gfxindex=0;gfxindexinternalProcessTriangleIndex(triangle,part,gfxindex); } break; } case PHY_SHORT: { for (gfxindex=0;gfxindexinternalProcessTriangleIndex(triangle,part,gfxindex); } break; } default: btAssert((gfxindextype == PHY_INTEGER) || (gfxindextype == PHY_SHORT)); } break; } default: btAssert((type == PHY_FLOAT) || (type == PHY_DOUBLE)); } unLockReadOnlyVertexBase(part); } } void btStridingMeshInterface::calculateAabbBruteForce(btVector3& aabbMin,btVector3& aabbMax) { struct AabbCalculationCallback : public btInternalTriangleIndexCallback { btVector3 m_aabbMin; btVector3 m_aabbMax; AabbCalculationCallback() { m_aabbMin.setValue(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); m_aabbMax.setValue(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); } virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex) { (void)partId; (void)triangleIndex; m_aabbMin.setMin(triangle[0]); m_aabbMax.setMax(triangle[0]); m_aabbMin.setMin(triangle[1]); m_aabbMax.setMax(triangle[1]); m_aabbMin.setMin(triangle[2]); m_aabbMax.setMax(triangle[2]); } }; //first calculate the total aabb for all triangles AabbCalculationCallback aabbCallback; aabbMin.setValue(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); aabbMax.setValue(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); InternalProcessAllTriangles(&aabbCallback,aabbMin,aabbMax); aabbMin = aabbCallback.m_aabbMin; aabbMax = aabbCallback.m_aabbMax; } ///fills the dataBuffer and returns the struct name (and 0 on failure) const char* btStridingMeshInterface::serialize(void* dataBuffer, btSerializer* serializer) const { btStridingMeshInterfaceData* trimeshData = (btStridingMeshInterfaceData*) dataBuffer; trimeshData->m_numMeshParts = getNumSubParts(); //void* uniquePtr = 0; trimeshData->m_meshPartsPtr = 0; if (trimeshData->m_numMeshParts) { btChunk* chunk = serializer->allocate(sizeof(btMeshPartData),trimeshData->m_numMeshParts); btMeshPartData* memPtr = (btMeshPartData*)chunk->m_oldPtr; trimeshData->m_meshPartsPtr = (btMeshPartData *)serializer->getUniquePointer(memPtr); // int numtotalphysicsverts = 0; int part,graphicssubparts = getNumSubParts(); const unsigned char * vertexbase; const unsigned char * indexbase; int indexstride; PHY_ScalarType type; PHY_ScalarType gfxindextype; int stride,numverts,numtriangles; int gfxindex; // btVector3 triangle[3]; btVector3 meshScaling = getScaling(); ///if the number of parts is big, the performance might drop due to the innerloop switch on indextype for (part=0;partm_numTriangles = numtriangles;//indices = 3*numtriangles memPtr->m_numVertices = numverts; memPtr->m_indices16 = 0; memPtr->m_indices32 = 0; memPtr->m_3indices16 = 0; memPtr->m_vertices3f = 0; memPtr->m_vertices3d = 0; switch (gfxindextype) { case PHY_INTEGER: { int numindices = numtriangles*3; if (numindices) { btChunk* chunk = serializer->allocate(sizeof(btIntIndexData),numindices); btIntIndexData* tmpIndices = (btIntIndexData*)chunk->m_oldPtr; memPtr->m_indices32 = (btIntIndexData*)serializer->getUniquePointer(tmpIndices); for (gfxindex=0;gfxindexfinalizeChunk(chunk,"btIntIndexData",BT_ARRAY_CODE,(void*)chunk->m_oldPtr); } break; } case PHY_SHORT: { if (numtriangles) { btChunk* chunk = serializer->allocate(sizeof(btShortIntIndexTripletData),numtriangles); btShortIntIndexTripletData* tmpIndices = (btShortIntIndexTripletData*)chunk->m_oldPtr; memPtr->m_3indices16 = (btShortIntIndexTripletData*) serializer->getUniquePointer(tmpIndices); for (gfxindex=0;gfxindexfinalizeChunk(chunk,"btShortIntIndexTripletData",BT_ARRAY_CODE,(void*)chunk->m_oldPtr); } break; } default: { btAssert(0); //unknown index type } } switch (type) { case PHY_FLOAT: { float* graphicsbase; if (numverts) { btChunk* chunk = serializer->allocate(sizeof(btVector3FloatData),numverts); btVector3FloatData* tmpVertices = (btVector3FloatData*) chunk->m_oldPtr; memPtr->m_vertices3f = (btVector3FloatData *)serializer->getUniquePointer(tmpVertices); for (int i=0;ifinalizeChunk(chunk,"btVector3FloatData",BT_ARRAY_CODE,(void*)chunk->m_oldPtr); } break; } case PHY_DOUBLE: { if (numverts) { btChunk* chunk = serializer->allocate(sizeof(btVector3DoubleData),numverts); btVector3DoubleData* tmpVertices = (btVector3DoubleData*) chunk->m_oldPtr; memPtr->m_vertices3d = (btVector3DoubleData *) serializer->getUniquePointer(tmpVertices); for (int i=0;ifinalizeChunk(chunk,"btVector3DoubleData",BT_ARRAY_CODE,(void*)chunk->m_oldPtr); } break; } default: btAssert((type == PHY_FLOAT) || (type == PHY_DOUBLE)); } unLockReadOnlyVertexBase(part); } serializer->finalizeChunk(chunk,"btMeshPartData",BT_ARRAY_CODE,chunk->m_oldPtr); } m_scaling.serializeFloat(trimeshData->m_scaling); return "btStridingMeshInterfaceData"; } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btBoxShape.h0000644000175000017500000002036211344267705027401 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 OBB_BOX_MINKOWSKI_H #define OBB_BOX_MINKOWSKI_H #include "btPolyhedralConvexShape.h" #include "btCollisionMargin.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" #include "LinearMath/btVector3.h" #include "LinearMath/btMinMax.h" ///The btBoxShape is a box primitive around the origin, its sides axis aligned with length specified by half extents, in local shape coordinates. When used as part of a btCollisionObject or btRigidBody it will be an oriented box in world space. class btBoxShape: public btPolyhedralConvexShape { //btVector3 m_boxHalfExtents1; //use m_implicitShapeDimensions instead public: btVector3 getHalfExtentsWithMargin() const { btVector3 halfExtents = getHalfExtentsWithoutMargin(); btVector3 margin(getMargin(),getMargin(),getMargin()); halfExtents += margin; return halfExtents; } const btVector3& getHalfExtentsWithoutMargin() const { return m_implicitShapeDimensions;//scaling is included, margin is not } virtual btVector3 localGetSupportingVertex(const btVector3& vec) const { btVector3 halfExtents = getHalfExtentsWithoutMargin(); btVector3 margin(getMargin(),getMargin(),getMargin()); halfExtents += margin; return btVector3(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()), btFsels(vec.y(), halfExtents.y(), -halfExtents.y()), btFsels(vec.z(), halfExtents.z(), -halfExtents.z())); } SIMD_FORCE_INLINE btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const { const btVector3& halfExtents = getHalfExtentsWithoutMargin(); return btVector3(btFsels(vec.x(), halfExtents.x(), -halfExtents.x()), btFsels(vec.y(), halfExtents.y(), -halfExtents.y()), btFsels(vec.z(), halfExtents.z(), -halfExtents.z())); } virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const { const btVector3& halfExtents = getHalfExtentsWithoutMargin(); for (int i=0;i>1)) - halfExtents.y() * ((i&2)>>1), halfExtents.z() * (1-((i&4)>>2)) - halfExtents.z() * ((i&4)>>2)); } virtual void getPlaneEquation(btVector4& plane,int i) const { btVector3 halfExtents = getHalfExtentsWithoutMargin(); switch (i) { case 0: plane.setValue(btScalar(1.),btScalar(0.),btScalar(0.),-halfExtents.x()); break; case 1: plane.setValue(btScalar(-1.),btScalar(0.),btScalar(0.),-halfExtents.x()); break; case 2: plane.setValue(btScalar(0.),btScalar(1.),btScalar(0.),-halfExtents.y()); break; case 3: plane.setValue(btScalar(0.),btScalar(-1.),btScalar(0.),-halfExtents.y()); break; case 4: plane.setValue(btScalar(0.),btScalar(0.),btScalar(1.),-halfExtents.z()); break; case 5: plane.setValue(btScalar(0.),btScalar(0.),btScalar(-1.),-halfExtents.z()); break; default: btAssert(0); } } virtual void getEdge(int i,btVector3& pa,btVector3& pb) const //virtual void getEdge(int i,Edge& edge) const { int edgeVert0 = 0; int edgeVert1 = 0; switch (i) { case 0: edgeVert0 = 0; edgeVert1 = 1; break; case 1: edgeVert0 = 0; edgeVert1 = 2; break; case 2: edgeVert0 = 1; edgeVert1 = 3; break; case 3: edgeVert0 = 2; edgeVert1 = 3; break; case 4: edgeVert0 = 0; edgeVert1 = 4; break; case 5: edgeVert0 = 1; edgeVert1 = 5; break; case 6: edgeVert0 = 2; edgeVert1 = 6; break; case 7: edgeVert0 = 3; edgeVert1 = 7; break; case 8: edgeVert0 = 4; edgeVert1 = 5; break; case 9: edgeVert0 = 4; edgeVert1 = 6; break; case 10: edgeVert0 = 5; edgeVert1 = 7; break; case 11: edgeVert0 = 6; edgeVert1 = 7; break; default: btAssert(0); } getVertex(edgeVert0,pa ); getVertex(edgeVert1,pb ); } virtual bool isInside(const btVector3& pt,btScalar tolerance) const { btVector3 halfExtents = getHalfExtentsWithoutMargin(); //btScalar minDist = 2*tolerance; bool result = (pt.x() <= (halfExtents.x()+tolerance)) && (pt.x() >= (-halfExtents.x()-tolerance)) && (pt.y() <= (halfExtents.y()+tolerance)) && (pt.y() >= (-halfExtents.y()-tolerance)) && (pt.z() <= (halfExtents.z()+tolerance)) && (pt.z() >= (-halfExtents.z()-tolerance)); return result; } //debugging virtual const char* getName()const { return "Box"; } virtual int getNumPreferredPenetrationDirections() const { return 6; } virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const { switch (index) { case 0: penetrationVector.setValue(btScalar(1.),btScalar(0.),btScalar(0.)); break; case 1: penetrationVector.setValue(btScalar(-1.),btScalar(0.),btScalar(0.)); break; case 2: penetrationVector.setValue(btScalar(0.),btScalar(1.),btScalar(0.)); break; case 3: penetrationVector.setValue(btScalar(0.),btScalar(-1.),btScalar(0.)); break; case 4: penetrationVector.setValue(btScalar(0.),btScalar(0.),btScalar(1.)); break; case 5: penetrationVector.setValue(btScalar(0.),btScalar(0.),btScalar(-1.)); break; default: btAssert(0); } } }; #endif //OBB_BOX_MINKOWSKI_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.h0000644000175000017500000001424011337071441032400 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 HEIGHTFIELD_TERRAIN_SHAPE_H #define HEIGHTFIELD_TERRAIN_SHAPE_H #include "btConcaveShape.h" ///btHeightfieldTerrainShape simulates a 2D heightfield terrain /** The caller is responsible for maintaining the heightfield array; this class does not make a copy. The heightfield can be dynamic so long as the min/max height values capture the extremes (heights must always be in that range). The local origin of the heightfield is assumed to be the exact center (as determined by width and length and height, with each axis multiplied by the localScaling). \b NOTE: be careful with coordinates. If you have a heightfield with a local min height of -100m, and a max height of +500m, you may be tempted to place it at the origin (0,0) and expect the heights in world coordinates to be -100 to +500 meters. Actually, the heights will be -300 to +300m, because bullet will re-center the heightfield based on its AABB (which is determined by the min/max heights). So keep in mind that once you create a btHeightfieldTerrainShape object, the heights will be adjusted relative to the center of the AABB. This is different to the behavior of many rendering engines, but is useful for physics engines. Most (but not all) rendering and heightfield libraries assume upAxis = 1 (that is, the y-axis is "up"). This class allows any of the 3 coordinates to be "up". Make sure your choice of axis is consistent with your rendering system. The heightfield heights are determined from the data type used for the heightfieldData array. - PHY_UCHAR: height at a point is the uchar value at the grid point, multipled by heightScale. uchar isn't recommended because of its inability to deal with negative values, and low resolution (8-bit). - PHY_SHORT: height at a point is the short int value at that grid point, multipled by heightScale. - PHY_FLOAT: height at a point is the float value at that grid point. heightScale is ignored when using the float heightfield data type. Whatever the caller specifies as minHeight and maxHeight will be honored. The class will not inspect the heightfield to discover the actual minimum or maximum heights. These values are used to determine the heightfield's axis-aligned bounding box, multiplied by localScaling. For usage and testing see the TerrainDemo. */ class btHeightfieldTerrainShape : public btConcaveShape { protected: btVector3 m_localAabbMin; btVector3 m_localAabbMax; btVector3 m_localOrigin; ///terrain data int m_heightStickWidth; int m_heightStickLength; btScalar m_minHeight; btScalar m_maxHeight; btScalar m_width; btScalar m_length; btScalar m_heightScale; union { unsigned char* m_heightfieldDataUnsignedChar; short* m_heightfieldDataShort; btScalar* m_heightfieldDataFloat; void* m_heightfieldDataUnknown; }; PHY_ScalarType m_heightDataType; bool m_flipQuadEdges; bool m_useDiamondSubdivision; int m_upAxis; btVector3 m_localScaling; virtual btScalar getRawHeightFieldValue(int x,int y) const; void quantizeWithClamp(int* out, const btVector3& point,int isMax) const; void getVertex(int x,int y,btVector3& vertex) const; /// protected initialization /** Handles the work of constructors so that public constructors can be backwards-compatible without a lot of copy/paste. */ void initialize(int heightStickWidth, int heightStickLength, void* heightfieldData, btScalar heightScale, btScalar minHeight, btScalar maxHeight, int upAxis, PHY_ScalarType heightDataType, bool flipQuadEdges); public: /// preferred constructor /** This constructor supports a range of heightfield data types, and allows for a non-zero minimum height value. heightScale is needed for any integer-based heightfield data types. */ btHeightfieldTerrainShape(int heightStickWidth,int heightStickLength, void* heightfieldData, btScalar heightScale, btScalar minHeight, btScalar maxHeight, int upAxis, PHY_ScalarType heightDataType, bool flipQuadEdges); /// legacy constructor /** The legacy constructor assumes the heightfield has a minimum height of zero. Only unsigned char or floats are supported. For legacy compatibility reasons, heightScale is calculated as maxHeight / 65535 (and is only used when useFloatData = false). */ btHeightfieldTerrainShape(int heightStickWidth,int heightStickLength,void* heightfieldData, btScalar maxHeight,int upAxis,bool useFloatData,bool flipQuadEdges); virtual ~btHeightfieldTerrainShape(); void setUseDiamondSubdivision(bool useDiamondSubdivision=true) { m_useDiamondSubdivision = useDiamondSubdivision;} virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const; virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; virtual void setLocalScaling(const btVector3& scaling); virtual const btVector3& getLocalScaling() const; //debugging virtual const char* getName()const {return "HEIGHTFIELD";} }; #endif //HEIGHTFIELD_TERRAIN_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btConvexTriangleMeshShape.cpp0000644000175000017500000002031711337071441032741 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btConvexTriangleMeshShape.h" #include "BulletCollision/CollisionShapes/btCollisionMargin.h" #include "LinearMath/btQuaternion.h" #include "BulletCollision/CollisionShapes/btStridingMeshInterface.h" btConvexTriangleMeshShape ::btConvexTriangleMeshShape (btStridingMeshInterface* meshInterface, bool calcAabb) : btPolyhedralConvexAabbCachingShape(), m_stridingMesh(meshInterface) { m_shapeType = CONVEX_TRIANGLEMESH_SHAPE_PROXYTYPE; if ( calcAabb ) recalcLocalAabb(); } ///It's not nice to have all this virtual function overhead, so perhaps we can also gather the points once ///but then we are duplicating class LocalSupportVertexCallback: public btInternalTriangleIndexCallback { btVector3 m_supportVertexLocal; public: btScalar m_maxDot; btVector3 m_supportVecLocal; LocalSupportVertexCallback(const btVector3& supportVecLocal) : m_supportVertexLocal(btScalar(0.),btScalar(0.),btScalar(0.)), m_maxDot(btScalar(-BT_LARGE_FLOAT)), m_supportVecLocal(supportVecLocal) { } virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex) { (void)triangleIndex; (void)partId; for (int i=0;i<3;i++) { btScalar dot = m_supportVecLocal.dot(triangle[i]); if (dot > m_maxDot) { m_maxDot = dot; m_supportVertexLocal = triangle[i]; } } } btVector3 GetSupportVertexLocal() { return m_supportVertexLocal; } }; btVector3 btConvexTriangleMeshShape::localGetSupportingVertexWithoutMargin(const btVector3& vec0)const { btVector3 supVec(btScalar(0.),btScalar(0.),btScalar(0.)); btVector3 vec = vec0; btScalar lenSqr = vec.length2(); if (lenSqr < btScalar(0.0001)) { vec.setValue(1,0,0); } else { btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); vec *= rlen; } LocalSupportVertexCallback supportCallback(vec); btVector3 aabbMax(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); m_stridingMesh->InternalProcessAllTriangles(&supportCallback,-aabbMax,aabbMax); supVec = supportCallback.GetSupportVertexLocal(); return supVec; } void btConvexTriangleMeshShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const { //use 'w' component of supportVerticesOut? { for (int i=0;iInternalProcessAllTriangles(&supportCallback,-aabbMax,aabbMax); supportVerticesOut[j] = supportCallback.GetSupportVertexLocal(); } } btVector3 btConvexTriangleMeshShape::localGetSupportingVertex(const btVector3& vec)const { btVector3 supVertex = localGetSupportingVertexWithoutMargin(vec); if ( getMargin()!=btScalar(0.) ) { btVector3 vecnorm = vec; if (vecnorm .length2() < (SIMD_EPSILON*SIMD_EPSILON)) { vecnorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.)); } vecnorm.normalize(); supVertex+= getMargin() * vecnorm; } return supVertex; } //currently just for debugging (drawing), perhaps future support for algebraic continuous collision detection //Please note that you can debug-draw btConvexTriangleMeshShape with the Raytracer Demo int btConvexTriangleMeshShape::getNumVertices() const { //cache this? return 0; } int btConvexTriangleMeshShape::getNumEdges() const { return 0; } void btConvexTriangleMeshShape::getEdge(int ,btVector3& ,btVector3& ) const { btAssert(0); } void btConvexTriangleMeshShape::getVertex(int ,btVector3& ) const { btAssert(0); } int btConvexTriangleMeshShape::getNumPlanes() const { return 0; } void btConvexTriangleMeshShape::getPlane(btVector3& ,btVector3& ,int ) const { btAssert(0); } //not yet bool btConvexTriangleMeshShape::isInside(const btVector3& ,btScalar ) const { btAssert(0); return false; } void btConvexTriangleMeshShape::setLocalScaling(const btVector3& scaling) { m_stridingMesh->setScaling(scaling); recalcLocalAabb(); } const btVector3& btConvexTriangleMeshShape::getLocalScaling() const { return m_stridingMesh->getScaling(); } void btConvexTriangleMeshShape::calculatePrincipalAxisTransform(btTransform& principal, btVector3& inertia, btScalar& volume) const { class CenterCallback: public btInternalTriangleIndexCallback { bool first; btVector3 ref; btVector3 sum; btScalar volume; public: CenterCallback() : first(true), ref(0, 0, 0), sum(0, 0, 0), volume(0) { } virtual void internalProcessTriangleIndex(btVector3* triangle, int partId, int triangleIndex) { (void) triangleIndex; (void) partId; if (first) { ref = triangle[0]; first = false; } else { btScalar vol = btFabs((triangle[0] - ref).triple(triangle[1] - ref, triangle[2] - ref)); sum += (btScalar(0.25) * vol) * ((triangle[0] + triangle[1] + triangle[2] + ref)); volume += vol; } } btVector3 getCenter() { return (volume > 0) ? sum / volume : ref; } btScalar getVolume() { return volume * btScalar(1. / 6); } }; class InertiaCallback: public btInternalTriangleIndexCallback { btMatrix3x3 sum; btVector3 center; public: InertiaCallback(btVector3& center) : sum(0, 0, 0, 0, 0, 0, 0, 0, 0), center(center) { } virtual void internalProcessTriangleIndex(btVector3* triangle, int partId, int triangleIndex) { (void) triangleIndex; (void) partId; btMatrix3x3 i; btVector3 a = triangle[0] - center; btVector3 b = triangle[1] - center; btVector3 c = triangle[2] - center; btScalar volNeg = -btFabs(a.triple(b, c)) * btScalar(1. / 6); for (int j = 0; j < 3; j++) { for (int k = 0; k <= j; k++) { i[j][k] = i[k][j] = volNeg * (btScalar(0.1) * (a[j] * a[k] + b[j] * b[k] + c[j] * c[k]) + btScalar(0.05) * (a[j] * b[k] + a[k] * b[j] + a[j] * c[k] + a[k] * c[j] + b[j] * c[k] + b[k] * c[j])); } } btScalar i00 = -i[0][0]; btScalar i11 = -i[1][1]; btScalar i22 = -i[2][2]; i[0][0] = i11 + i22; i[1][1] = i22 + i00; i[2][2] = i00 + i11; sum[0] += i[0]; sum[1] += i[1]; sum[2] += i[2]; } btMatrix3x3& getInertia() { return sum; } }; CenterCallback centerCallback; btVector3 aabbMax(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); m_stridingMesh->InternalProcessAllTriangles(¢erCallback, -aabbMax, aabbMax); btVector3 center = centerCallback.getCenter(); principal.setOrigin(center); volume = centerCallback.getVolume(); InertiaCallback inertiaCallback(center); m_stridingMesh->InternalProcessAllTriangles(&inertiaCallback, -aabbMax, aabbMax); btMatrix3x3& i = inertiaCallback.getInertia(); i.diagonalize(principal.getBasis(), btScalar(0.00001), 20); inertia.setValue(i[0][0], i[1][1], i[2][2]); inertia /= volume; } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btConvex2dShape.h0000644000175000017500000000550011337071441030326 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 BT_CONVEX_2D_SHAPE_H #define BT_CONVEX_2D_SHAPE_H #include "BulletCollision/CollisionShapes/btConvexShape.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types ///The btConvex2dShape allows to use arbitrary convex shapes are 2d convex shapes, with the Z component assumed to be 0. ///For 2d boxes, the btBox2dShape is recommended. class btConvex2dShape : public btConvexShape { btConvexShape* m_childConvexShape; public: btConvex2dShape( btConvexShape* convexChildShape); virtual ~btConvex2dShape(); virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; btConvexShape* getChildShape() { return m_childConvexShape; } const btConvexShape* getChildShape() const { return m_childConvexShape; } virtual const char* getName()const { return "Convex2dShape"; } /////////////////////////// ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; virtual void getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; virtual void setLocalScaling(const btVector3& scaling) ; virtual const btVector3& getLocalScaling() const ; virtual void setMargin(btScalar margin); virtual btScalar getMargin() const; virtual int getNumPreferredPenetrationDirections() const; virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const; }; #endif //BT_CONVEX_2D_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btTriangleShape.h0000644000175000017500000001067011337071441030407 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 OBB_TRIANGLE_MINKOWSKI_H #define OBB_TRIANGLE_MINKOWSKI_H #include "btConvexShape.h" #include "btBoxShape.h" ATTRIBUTE_ALIGNED16(class) btTriangleShape : public btPolyhedralConvexShape { public: btVector3 m_vertices1[3]; virtual int getNumVertices() const { return 3; } btVector3& getVertexPtr(int index) { return m_vertices1[index]; } const btVector3& getVertexPtr(int index) const { return m_vertices1[index]; } virtual void getVertex(int index,btVector3& vert) const { vert = m_vertices1[index]; } virtual int getNumEdges() const { return 3; } virtual void getEdge(int i,btVector3& pa,btVector3& pb) const { getVertex(i,pa); getVertex((i+1)%3,pb); } virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax)const { // btAssert(0); getAabbSlow(t,aabbMin,aabbMax); } btVector3 localGetSupportingVertexWithoutMargin(const btVector3& dir)const { btVector3 dots(dir.dot(m_vertices1[0]), dir.dot(m_vertices1[1]), dir.dot(m_vertices1[2])); return m_vertices1[dots.maxAxis()]; } virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const { for (int i=0;i= -tolerance && dist <= tolerance) { //inside check on edge-planes int i; for (i=0;i<3;i++) { btVector3 pa,pb; getEdge(i,pa,pb); btVector3 edge = pb-pa; btVector3 edgeNormal = edge.cross(normal); edgeNormal.normalize(); btScalar dist = pt.dot( edgeNormal); btScalar edgeConst = pa.dot(edgeNormal); dist -= edgeConst; if (dist < -tolerance) return false; } return true; } return false; } //debugging virtual const char* getName()const { return "Triangle"; } virtual int getNumPreferredPenetrationDirections() const { return 2; } virtual void getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const { calcNormal(penetrationVector); if (index) penetrationVector *= btScalar(-1.); } }; #endif //OBB_TRIANGLE_MINKOWSKI_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btTriangleCallback.cpp0000644000175000017500000000210511337071441031370 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btTriangleCallback.h" btTriangleCallback::~btTriangleCallback() { } btInternalTriangleIndexCallback::~btInternalTriangleIndexCallback() { } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btConvex2dShape.cpp0000644000175000017500000000626211337071441030667 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btConvex2dShape.h" btConvex2dShape::btConvex2dShape( btConvexShape* convexChildShape): btConvexShape (), m_childConvexShape(convexChildShape) { m_shapeType = CONVEX_2D_SHAPE_PROXYTYPE; } btConvex2dShape::~btConvex2dShape() { } btVector3 btConvex2dShape::localGetSupportingVertexWithoutMargin(const btVector3& vec)const { return m_childConvexShape->localGetSupportingVertexWithoutMargin(vec); } void btConvex2dShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const { m_childConvexShape->batchedUnitVectorGetSupportingVertexWithoutMargin(vectors,supportVerticesOut,numVectors); } btVector3 btConvex2dShape::localGetSupportingVertex(const btVector3& vec)const { return m_childConvexShape->localGetSupportingVertex(vec); } void btConvex2dShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const { ///this linear upscaling is not realistic, but we don't deal with large mass ratios... m_childConvexShape->calculateLocalInertia(mass,inertia); } ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version void btConvex2dShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const { m_childConvexShape->getAabb(t,aabbMin,aabbMax); } void btConvex2dShape::getAabbSlow(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const { m_childConvexShape->getAabbSlow(t,aabbMin,aabbMax); } void btConvex2dShape::setLocalScaling(const btVector3& scaling) { m_childConvexShape->setLocalScaling(scaling); } const btVector3& btConvex2dShape::getLocalScaling() const { return m_childConvexShape->getLocalScaling(); } void btConvex2dShape::setMargin(btScalar margin) { m_childConvexShape->setMargin(margin); } btScalar btConvex2dShape::getMargin() const { return m_childConvexShape->getMargin(); } int btConvex2dShape::getNumPreferredPenetrationDirections() const { return m_childConvexShape->getNumPreferredPenetrationDirections(); } void btConvex2dShape::getPreferredPenetrationDirection(int index, btVector3& penetrationVector) const { m_childConvexShape->getPreferredPenetrationDirection(index,penetrationVector); } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btHeightfieldTerrainShape.cpp0000644000175000017500000002540411337071441032737 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btHeightfieldTerrainShape.h" #include "LinearMath/btTransformUtil.h" btHeightfieldTerrainShape::btHeightfieldTerrainShape ( int heightStickWidth, int heightStickLength, void* heightfieldData, btScalar heightScale, btScalar minHeight, btScalar maxHeight,int upAxis, PHY_ScalarType hdt, bool flipQuadEdges ) { initialize(heightStickWidth, heightStickLength, heightfieldData, heightScale, minHeight, maxHeight, upAxis, hdt, flipQuadEdges); } btHeightfieldTerrainShape::btHeightfieldTerrainShape(int heightStickWidth, int heightStickLength,void* heightfieldData,btScalar maxHeight,int upAxis,bool useFloatData,bool flipQuadEdges) { // legacy constructor: support only float or unsigned char, // and min height is zero PHY_ScalarType hdt = (useFloatData) ? PHY_FLOAT : PHY_UCHAR; btScalar minHeight = 0.0; // previously, height = uchar * maxHeight / 65535. // So to preserve legacy behavior, heightScale = maxHeight / 65535 btScalar heightScale = maxHeight / 65535; initialize(heightStickWidth, heightStickLength, heightfieldData, heightScale, minHeight, maxHeight, upAxis, hdt, flipQuadEdges); } void btHeightfieldTerrainShape::initialize ( int heightStickWidth, int heightStickLength, void* heightfieldData, btScalar heightScale, btScalar minHeight, btScalar maxHeight, int upAxis, PHY_ScalarType hdt, bool flipQuadEdges ) { // validation btAssert(heightStickWidth > 1 && "bad width"); btAssert(heightStickLength > 1 && "bad length"); btAssert(heightfieldData && "null heightfield data"); // btAssert(heightScale) -- do we care? Trust caller here btAssert(minHeight <= maxHeight && "bad min/max height"); btAssert(upAxis >= 0 && upAxis < 3 && "bad upAxis--should be in range [0,2]"); btAssert(hdt != PHY_UCHAR || hdt != PHY_FLOAT || hdt != PHY_SHORT && "Bad height data type enum"); // initialize member variables m_shapeType = TERRAIN_SHAPE_PROXYTYPE; m_heightStickWidth = heightStickWidth; m_heightStickLength = heightStickLength; m_minHeight = minHeight; m_maxHeight = maxHeight; m_width = (btScalar) (heightStickWidth - 1); m_length = (btScalar) (heightStickLength - 1); m_heightScale = heightScale; m_heightfieldDataUnknown = heightfieldData; m_heightDataType = hdt; m_flipQuadEdges = flipQuadEdges; m_useDiamondSubdivision = false; m_upAxis = upAxis; m_localScaling.setValue(btScalar(1.), btScalar(1.), btScalar(1.)); // determine min/max axis-aligned bounding box (aabb) values switch (m_upAxis) { case 0: { m_localAabbMin.setValue(m_minHeight, 0, 0); m_localAabbMax.setValue(m_maxHeight, m_width, m_length); break; } case 1: { m_localAabbMin.setValue(0, m_minHeight, 0); m_localAabbMax.setValue(m_width, m_maxHeight, m_length); break; }; case 2: { m_localAabbMin.setValue(0, 0, m_minHeight); m_localAabbMax.setValue(m_width, m_length, m_maxHeight); break; } default: { //need to get valid m_upAxis btAssert(0 && "Bad m_upAxis"); } } // remember origin (defined as exact middle of aabb) m_localOrigin = btScalar(0.5) * (m_localAabbMin + m_localAabbMax); } btHeightfieldTerrainShape::~btHeightfieldTerrainShape() { } void btHeightfieldTerrainShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const { btVector3 halfExtents = (m_localAabbMax-m_localAabbMin)* m_localScaling * btScalar(0.5); btVector3 localOrigin(0, 0, 0); localOrigin[m_upAxis] = (m_minHeight + m_maxHeight) * btScalar(0.5); localOrigin *= m_localScaling; btMatrix3x3 abs_b = t.getBasis().absolute(); btVector3 center = t.getOrigin(); btVector3 extent = btVector3(abs_b[0].dot(halfExtents), abs_b[1].dot(halfExtents), abs_b[2].dot(halfExtents)); extent += btVector3(getMargin(),getMargin(),getMargin()); aabbMin = center - extent; aabbMax = center + extent; } /// This returns the "raw" (user's initial) height, not the actual height. /// The actual height needs to be adjusted to be relative to the center /// of the heightfield's AABB. btScalar btHeightfieldTerrainShape::getRawHeightFieldValue(int x,int y) const { btScalar val = 0.f; switch (m_heightDataType) { case PHY_FLOAT: { val = m_heightfieldDataFloat[(y*m_heightStickWidth)+x]; break; } case PHY_UCHAR: { unsigned char heightFieldValue = m_heightfieldDataUnsignedChar[(y*m_heightStickWidth)+x]; val = heightFieldValue * m_heightScale; break; } case PHY_SHORT: { short hfValue = m_heightfieldDataShort[(y * m_heightStickWidth) + x]; val = hfValue * m_heightScale; break; } default: { btAssert(!"Bad m_heightDataType"); } } return val; } /// this returns the vertex in bullet-local coordinates void btHeightfieldTerrainShape::getVertex(int x,int y,btVector3& vertex) const { btAssert(x>=0); btAssert(y>=0); btAssert(xstartX) startX = quantizedAabbMin[1]; if (quantizedAabbMax[1]startJ) startJ = quantizedAabbMin[2]; if (quantizedAabbMax[2]startX) startX = quantizedAabbMin[0]; if (quantizedAabbMax[0]startJ) startJ = quantizedAabbMin[2]; if (quantizedAabbMax[2]startX) startX = quantizedAabbMin[0]; if (quantizedAabbMax[0]startJ) startJ = quantizedAabbMin[1]; if (quantizedAabbMax[1]processTriangle(vertices,x,j); //second triangle getVertex(x,j,vertices[0]); getVertex(x+1,j+1,vertices[1]); getVertex(x,j+1,vertices[2]); callback->processTriangle(vertices,x,j); } else { //first triangle getVertex(x,j,vertices[0]); getVertex(x,j+1,vertices[1]); getVertex(x+1,j,vertices[2]); callback->processTriangle(vertices,x,j); //second triangle getVertex(x+1,j,vertices[0]); getVertex(x,j+1,vertices[1]); getVertex(x+1,j+1,vertices[2]); callback->processTriangle(vertices,x,j); } } } } void btHeightfieldTerrainShape::calculateLocalInertia(btScalar ,btVector3& inertia) const { //moving concave objects not supported inertia.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); } void btHeightfieldTerrainShape::setLocalScaling(const btVector3& scaling) { m_localScaling = scaling; } const btVector3& btHeightfieldTerrainShape::getLocalScaling() const { return m_localScaling; } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btCompoundShape.cpp0000644000175000017500000002346611344267705031000 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btCompoundShape.h" #include "btCollisionShape.h" #include "BulletCollision/BroadphaseCollision/btDbvt.h" #include "LinearMath/btSerializer.h" btCompoundShape::btCompoundShape(bool enableDynamicAabbTree) : m_localAabbMin(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)), m_localAabbMax(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)), m_dynamicAabbTree(0), m_updateRevision(1), m_collisionMargin(btScalar(0.)), m_localScaling(btScalar(1.),btScalar(1.),btScalar(1.)) { m_shapeType = COMPOUND_SHAPE_PROXYTYPE; if (enableDynamicAabbTree) { void* mem = btAlignedAlloc(sizeof(btDbvt),16); m_dynamicAabbTree = new(mem) btDbvt(); btAssert(mem==m_dynamicAabbTree); } } btCompoundShape::~btCompoundShape() { if (m_dynamicAabbTree) { m_dynamicAabbTree->~btDbvt(); btAlignedFree(m_dynamicAabbTree); } } void btCompoundShape::addChildShape(const btTransform& localTransform,btCollisionShape* shape) { m_updateRevision++; //m_childTransforms.push_back(localTransform); //m_childShapes.push_back(shape); btCompoundShapeChild child; child.m_transform = localTransform; child.m_childShape = shape; child.m_childShapeType = shape->getShapeType(); child.m_childMargin = shape->getMargin(); //extend the local aabbMin/aabbMax btVector3 localAabbMin,localAabbMax; shape->getAabb(localTransform,localAabbMin,localAabbMax); for (int i=0;i<3;i++) { if (m_localAabbMin[i] > localAabbMin[i]) { m_localAabbMin[i] = localAabbMin[i]; } if (m_localAabbMax[i] < localAabbMax[i]) { m_localAabbMax[i] = localAabbMax[i]; } } if (m_dynamicAabbTree) { const btDbvtVolume bounds=btDbvtVolume::FromMM(localAabbMin,localAabbMax); int index = m_children.size(); child.m_node = m_dynamicAabbTree->insert(bounds,(void*)index); } m_children.push_back(child); } void btCompoundShape::updateChildTransform(int childIndex, const btTransform& newChildTransform) { m_children[childIndex].m_transform = newChildTransform; if (m_dynamicAabbTree) { ///update the dynamic aabb tree btVector3 localAabbMin,localAabbMax; m_children[childIndex].m_childShape->getAabb(newChildTransform,localAabbMin,localAabbMax); ATTRIBUTE_ALIGNED16(btDbvtVolume) bounds=btDbvtVolume::FromMM(localAabbMin,localAabbMax); //int index = m_children.size()-1; m_dynamicAabbTree->update(m_children[childIndex].m_node,bounds); } recalculateLocalAabb(); } void btCompoundShape::removeChildShapeByIndex(int childShapeIndex) { m_updateRevision++; btAssert(childShapeIndex >=0 && childShapeIndex < m_children.size()); if (m_dynamicAabbTree) { m_dynamicAabbTree->remove(m_children[childShapeIndex].m_node); } m_children.swap(childShapeIndex,m_children.size()-1); m_children.pop_back(); } void btCompoundShape::removeChildShape(btCollisionShape* shape) { m_updateRevision++; // Find the children containing the shape specified, and remove those children. //note: there might be multiple children using the same shape! for(int i = m_children.size()-1; i >= 0 ; i--) { if(m_children[i].m_childShape == shape) { removeChildShapeByIndex(i); } } recalculateLocalAabb(); } void btCompoundShape::recalculateLocalAabb() { // Recalculate the local aabb // Brute force, it iterates over all the shapes left. m_localAabbMin = btVector3(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); m_localAabbMax = btVector3(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); //extend the local aabbMin/aabbMax for (int j = 0; j < m_children.size(); j++) { btVector3 localAabbMin,localAabbMax; m_children[j].m_childShape->getAabb(m_children[j].m_transform, localAabbMin, localAabbMax); for (int i=0;i<3;i++) { if (m_localAabbMin[i] > localAabbMin[i]) m_localAabbMin[i] = localAabbMin[i]; if (m_localAabbMax[i] < localAabbMax[i]) m_localAabbMax[i] = localAabbMax[i]; } } } ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version void btCompoundShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax) const { btVector3 localHalfExtents = btScalar(0.5)*(m_localAabbMax-m_localAabbMin); btVector3 localCenter = btScalar(0.5)*(m_localAabbMax+m_localAabbMin); //avoid an illegal AABB when there are no children if (!m_children.size()) { localHalfExtents.setValue(0,0,0); localCenter.setValue(0,0,0); } localHalfExtents += btVector3(getMargin(),getMargin(),getMargin()); btMatrix3x3 abs_b = trans.getBasis().absolute(); btVector3 center = trans(localCenter); btVector3 extent = btVector3(abs_b[0].dot(localHalfExtents), abs_b[1].dot(localHalfExtents), abs_b[2].dot(localHalfExtents)); aabbMin = center-extent; aabbMax = center+extent; } void btCompoundShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const { //approximation: take the inertia from the aabb for now btTransform ident; ident.setIdentity(); btVector3 aabbMin,aabbMax; getAabb(ident,aabbMin,aabbMax); btVector3 halfExtents = (aabbMax-aabbMin)*btScalar(0.5); btScalar lx=btScalar(2.)*(halfExtents.x()); btScalar ly=btScalar(2.)*(halfExtents.y()); btScalar lz=btScalar(2.)*(halfExtents.z()); inertia[0] = mass/(btScalar(12.0)) * (ly*ly + lz*lz); inertia[1] = mass/(btScalar(12.0)) * (lx*lx + lz*lz); inertia[2] = mass/(btScalar(12.0)) * (lx*lx + ly*ly); } void btCompoundShape::calculatePrincipalAxisTransform(btScalar* masses, btTransform& principal, btVector3& inertia) const { int n = m_children.size(); btScalar totalMass = 0; btVector3 center(0, 0, 0); int k; for (k = 0; k < n; k++) { center += m_children[k].m_transform.getOrigin() * masses[k]; totalMass += masses[k]; } center /= totalMass; principal.setOrigin(center); btMatrix3x3 tensor(0, 0, 0, 0, 0, 0, 0, 0, 0); for ( k = 0; k < n; k++) { btVector3 i; m_children[k].m_childShape->calculateLocalInertia(masses[k], i); const btTransform& t = m_children[k].m_transform; btVector3 o = t.getOrigin() - center; //compute inertia tensor in coordinate system of compound shape btMatrix3x3 j = t.getBasis().transpose(); j[0] *= i[0]; j[1] *= i[1]; j[2] *= i[2]; j = t.getBasis() * j; //add inertia tensor tensor[0] += j[0]; tensor[1] += j[1]; tensor[2] += j[2]; //compute inertia tensor of pointmass at o btScalar o2 = o.length2(); j[0].setValue(o2, 0, 0); j[1].setValue(0, o2, 0); j[2].setValue(0, 0, o2); j[0] += o * -o.x(); j[1] += o * -o.y(); j[2] += o * -o.z(); //add inertia tensor of pointmass tensor[0] += masses[k] * j[0]; tensor[1] += masses[k] * j[1]; tensor[2] += masses[k] * j[2]; } tensor.diagonalize(principal.getBasis(), btScalar(0.00001), 20); inertia.setValue(tensor[0][0], tensor[1][1], tensor[2][2]); } void btCompoundShape::setLocalScaling(const btVector3& scaling) { for(int i = 0; i < m_children.size(); i++) { btTransform childTrans = getChildTransform(i); btVector3 childScale = m_children[i].m_childShape->getLocalScaling(); // childScale = childScale * (childTrans.getBasis() * scaling); childScale = childScale * scaling / m_localScaling; m_children[i].m_childShape->setLocalScaling(childScale); childTrans.setOrigin((childTrans.getOrigin())*scaling); updateChildTransform(i, childTrans); recalculateLocalAabb(); } m_localScaling = scaling; } ///fills the dataBuffer and returns the struct name (and 0 on failure) const char* btCompoundShape::serialize(void* dataBuffer, btSerializer* serializer) const { btCompoundShapeData* shapeData = (btCompoundShapeData*) dataBuffer; btCollisionShape::serialize(&shapeData->m_collisionShapeData, serializer); shapeData->m_collisionMargin = float(m_collisionMargin); shapeData->m_numChildShapes = m_children.size(); shapeData->m_childShapePtr = 0; if (shapeData->m_numChildShapes) { btChunk* chunk = serializer->allocate(sizeof(btCompoundShapeChildData),shapeData->m_numChildShapes); btCompoundShapeChildData* memPtr = (btCompoundShapeChildData*)chunk->m_oldPtr; shapeData->m_childShapePtr = (btCompoundShapeChildData*)serializer->getUniquePointer(memPtr); for (int i=0;im_numChildShapes;i++,memPtr++) { memPtr->m_childMargin = float(m_children[i].m_childMargin); memPtr->m_childShape = (btCollisionShapeData*)serializer->getUniquePointer(m_children[i].m_childShape); //don't serialize shapes that already have been serialized if (!serializer->findPointer(m_children[i].m_childShape)) { btChunk* chunk = serializer->allocate(m_children[i].m_childShape->calculateSerializeBufferSize(),1); const char* structType = m_children[i].m_childShape->serialize(chunk->m_oldPtr,serializer); serializer->finalizeChunk(chunk,structType,BT_SHAPE_CODE,m_children[i].m_childShape); } memPtr->m_childShapeType = m_children[i].m_childShapeType; m_children[i].m_transform.serializeFloat(memPtr->m_transform); } serializer->finalizeChunk(chunk,"btCompoundShapeChildData",BT_ARRAY_CODE,chunk->m_oldPtr); } return "btCompoundShapeData"; } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btConvexPointCloudShape.h0000644000175000017500000000665111337071441032111 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 BT_CONVEX_POINT_CLOUD_SHAPE_H #define BT_CONVEX_POINT_CLOUD_SHAPE_H #include "btPolyhedralConvexShape.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types #include "LinearMath/btAlignedObjectArray.h" ///The btConvexPointCloudShape implements an implicit convex hull of an array of vertices. ATTRIBUTE_ALIGNED16(class) btConvexPointCloudShape : public btPolyhedralConvexAabbCachingShape { btVector3* m_unscaledPoints; int m_numPoints; public: BT_DECLARE_ALIGNED_ALLOCATOR(); btConvexPointCloudShape() { m_localScaling.setValue(1.f,1.f,1.f); m_shapeType = CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE; m_unscaledPoints = 0; m_numPoints = 0; } btConvexPointCloudShape(btVector3* points,int numPoints, const btVector3& localScaling,bool computeAabb = true) { m_localScaling = localScaling; m_shapeType = CONVEX_POINT_CLOUD_SHAPE_PROXYTYPE; m_unscaledPoints = points; m_numPoints = numPoints; if (computeAabb) recalcLocalAabb(); } void setPoints (btVector3* points, int numPoints, bool computeAabb = true,const btVector3& localScaling=btVector3(1.f,1.f,1.f)) { m_unscaledPoints = points; m_numPoints = numPoints; m_localScaling = localScaling; if (computeAabb) recalcLocalAabb(); } SIMD_FORCE_INLINE btVector3* getUnscaledPoints() { return m_unscaledPoints; } SIMD_FORCE_INLINE const btVector3* getUnscaledPoints() const { return m_unscaledPoints; } SIMD_FORCE_INLINE int getNumPoints() const { return m_numPoints; } SIMD_FORCE_INLINE btVector3 getScaledPoint( int index) const { return m_unscaledPoints[index] * m_localScaling; } #ifndef __SPU__ virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; #endif //debugging virtual const char* getName()const {return "ConvexPointCloud";} virtual int getNumVertices() const; virtual int getNumEdges() const; virtual void getEdge(int i,btVector3& pa,btVector3& pb) const; virtual void getVertex(int i,btVector3& vtx) const; virtual int getNumPlanes() const; virtual void getPlane(btVector3& planeNormal,btVector3& planeSupport,int i ) const; virtual bool isInside(const btVector3& pt,btScalar tolerance) const; ///in case we receive negative scaling virtual void setLocalScaling(const btVector3& scaling); }; #endif //BT_CONVEX_POINT_CLOUD_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btOptimizedBvh.h0000644000175000017500000000451011344267705030271 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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. */ ///Contains contributions from Disney Studio's #ifndef OPTIMIZED_BVH_H #define OPTIMIZED_BVH_H #include "BulletCollision/BroadphaseCollision/btQuantizedBvh.h" class btStridingMeshInterface; ///The btOptimizedBvh extends the btQuantizedBvh to create AABB tree for triangle meshes, through the btStridingMeshInterface. ATTRIBUTE_ALIGNED16(class) btOptimizedBvh : public btQuantizedBvh { public: BT_DECLARE_ALIGNED_ALLOCATOR(); protected: public: btOptimizedBvh(); virtual ~btOptimizedBvh(); void build(btStridingMeshInterface* triangles,bool useQuantizedAabbCompression, const btVector3& bvhAabbMin, const btVector3& bvhAabbMax); void refit(btStridingMeshInterface* triangles,const btVector3& aabbMin,const btVector3& aabbMax); void refitPartial(btStridingMeshInterface* triangles,const btVector3& aabbMin, const btVector3& aabbMax); void updateBvhNodes(btStridingMeshInterface* meshInterface,int firstNode,int endNode,int index); /// Data buffer MUST be 16 byte aligned virtual bool serializeInPlace(void *o_alignedDataBuffer, unsigned i_dataBufferSize, bool i_swapEndian) const { return btQuantizedBvh::serialize(o_alignedDataBuffer,i_dataBufferSize,i_swapEndian); } ///deSerializeInPlace loads and initializes a BVH from a buffer in memory 'in place' static btOptimizedBvh *deSerializeInPlace(void *i_alignedDataBuffer, unsigned int i_dataBufferSize, bool i_swapEndian); }; #endif //OPTIMIZED_BVH_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btTriangleIndexVertexArray.cpp0000644000175000017500000000642511337071441033151 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btTriangleIndexVertexArray.h" btTriangleIndexVertexArray::btTriangleIndexVertexArray(int numTriangles,int* triangleIndexBase,int triangleIndexStride,int numVertices,btScalar* vertexBase,int vertexStride) : m_hasAabb(0) { btIndexedMesh mesh; mesh.m_numTriangles = numTriangles; mesh.m_triangleIndexBase = (const unsigned char *)triangleIndexBase; mesh.m_triangleIndexStride = triangleIndexStride; mesh.m_numVertices = numVertices; mesh.m_vertexBase = (const unsigned char *)vertexBase; mesh.m_vertexStride = vertexStride; addIndexedMesh(mesh); } btTriangleIndexVertexArray::~btTriangleIndexVertexArray() { } void btTriangleIndexVertexArray::getLockedVertexIndexBase(unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& vertexStride,unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart) { btAssert(subpart< getNumSubParts() ); btIndexedMesh& mesh = m_indexedMeshes[subpart]; numverts = mesh.m_numVertices; (*vertexbase) = (unsigned char *) mesh.m_vertexBase; type = mesh.m_vertexType; vertexStride = mesh.m_vertexStride; numfaces = mesh.m_numTriangles; (*indexbase) = (unsigned char *)mesh.m_triangleIndexBase; indexstride = mesh.m_triangleIndexStride; indicestype = mesh.m_indexType; } void btTriangleIndexVertexArray::getLockedReadOnlyVertexIndexBase(const unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& vertexStride,const unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart) const { const btIndexedMesh& mesh = m_indexedMeshes[subpart]; numverts = mesh.m_numVertices; (*vertexbase) = (const unsigned char *)mesh.m_vertexBase; type = mesh.m_vertexType; vertexStride = mesh.m_vertexStride; numfaces = mesh.m_numTriangles; (*indexbase) = (const unsigned char *)mesh.m_triangleIndexBase; indexstride = mesh.m_triangleIndexStride; indicestype = mesh.m_indexType; } bool btTriangleIndexVertexArray::hasPremadeAabb() const { return (m_hasAabb == 1); } void btTriangleIndexVertexArray::setPremadeAabb(const btVector3& aabbMin, const btVector3& aabbMax ) const { m_aabbMin = aabbMin; m_aabbMax = aabbMax; m_hasAabb = 1; // this is intentionally an int see notes in header } void btTriangleIndexVertexArray::getPremadeAabb(btVector3* aabbMin, btVector3* aabbMax ) const { *aabbMin = m_aabbMin; *aabbMax = m_aabbMax; } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btTriangleMesh.cpp0000644000175000017500000001052011337071441030570 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btTriangleMesh.h" btTriangleMesh::btTriangleMesh (bool use32bitIndices,bool use4componentVertices) :m_use32bitIndices(use32bitIndices), m_use4componentVertices(use4componentVertices), m_weldingThreshold(0.0) { btIndexedMesh meshIndex; meshIndex.m_numTriangles = 0; meshIndex.m_numVertices = 0; meshIndex.m_indexType = PHY_INTEGER; meshIndex.m_triangleIndexBase = 0; meshIndex.m_triangleIndexStride = 3*sizeof(int); meshIndex.m_vertexBase = 0; meshIndex.m_vertexStride = sizeof(btVector3); m_indexedMeshes.push_back(meshIndex); if (m_use32bitIndices) { m_indexedMeshes[0].m_numTriangles = m_32bitIndices.size()/3; m_indexedMeshes[0].m_triangleIndexBase = 0; m_indexedMeshes[0].m_indexType = PHY_INTEGER; m_indexedMeshes[0].m_triangleIndexStride = 3*sizeof(int); } else { m_indexedMeshes[0].m_numTriangles = m_16bitIndices.size()/3; m_indexedMeshes[0].m_triangleIndexBase = 0; m_indexedMeshes[0].m_indexType = PHY_SHORT; m_indexedMeshes[0].m_triangleIndexStride = 3*sizeof(short int); } if (m_use4componentVertices) { m_indexedMeshes[0].m_numVertices = m_4componentVertices.size(); m_indexedMeshes[0].m_vertexBase = 0; m_indexedMeshes[0].m_vertexStride = sizeof(btVector3); } else { m_indexedMeshes[0].m_numVertices = m_3componentVertices.size()/3; m_indexedMeshes[0].m_vertexBase = 0; m_indexedMeshes[0].m_vertexStride = 3*sizeof(btScalar); } } void btTriangleMesh::addIndex(int index) { if (m_use32bitIndices) { m_32bitIndices.push_back(index); m_indexedMeshes[0].m_triangleIndexBase = (unsigned char*) &m_32bitIndices[0]; } else { m_16bitIndices.push_back(index); m_indexedMeshes[0].m_triangleIndexBase = (unsigned char*) &m_16bitIndices[0]; } } int btTriangleMesh::findOrAddVertex(const btVector3& vertex, bool removeDuplicateVertices) { //return index of new/existing vertex ///@todo: could use acceleration structure for this if (m_use4componentVertices) { if (removeDuplicateVertices) { for (int i=0;i< m_4componentVertices.size();i++) { if ((m_4componentVertices[i]-vertex).length2() <= m_weldingThreshold) { return i; } } } m_indexedMeshes[0].m_numVertices++; m_4componentVertices.push_back(vertex); m_indexedMeshes[0].m_vertexBase = (unsigned char*)&m_4componentVertices[0]; return m_4componentVertices.size()-1; } else { if (removeDuplicateVertices) { for (int i=0;i< m_3componentVertices.size();i+=3) { btVector3 vtx(m_3componentVertices[i],m_3componentVertices[i+1],m_3componentVertices[i+2]); if ((vtx-vertex).length2() <= m_weldingThreshold) { return i/3; } } } m_3componentVertices.push_back((float)vertex.getX()); m_3componentVertices.push_back((float)vertex.getY()); m_3componentVertices.push_back((float)vertex.getZ()); m_indexedMeshes[0].m_numVertices++; m_indexedMeshes[0].m_vertexBase = (unsigned char*)&m_3componentVertices[0]; return (m_3componentVertices.size()/3)-1; } } void btTriangleMesh::addTriangle(const btVector3& vertex0,const btVector3& vertex1,const btVector3& vertex2,bool removeDuplicateVertices) { m_indexedMeshes[0].m_numTriangles++; addIndex(findOrAddVertex(vertex0,removeDuplicateVertices)); addIndex(findOrAddVertex(vertex1,removeDuplicateVertices)); addIndex(findOrAddVertex(vertex2,removeDuplicateVertices)); } int btTriangleMesh::getNumTriangles() const { if (m_use32bitIndices) { return m_32bitIndices.size() / 3; } return m_16bitIndices.size() / 3; } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btOptimizedBvh.cpp0000644000175000017500000003015211337071441030615 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btOptimizedBvh.h" #include "btStridingMeshInterface.h" #include "LinearMath/btAabbUtil2.h" #include "LinearMath/btIDebugDraw.h" btOptimizedBvh::btOptimizedBvh() { } btOptimizedBvh::~btOptimizedBvh() { } void btOptimizedBvh::build(btStridingMeshInterface* triangles, bool useQuantizedAabbCompression, const btVector3& bvhAabbMin, const btVector3& bvhAabbMax) { m_useQuantization = useQuantizedAabbCompression; // NodeArray triangleNodes; struct NodeTriangleCallback : public btInternalTriangleIndexCallback { NodeArray& m_triangleNodes; NodeTriangleCallback& operator=(NodeTriangleCallback& other) { m_triangleNodes = other.m_triangleNodes; return *this; } NodeTriangleCallback(NodeArray& triangleNodes) :m_triangleNodes(triangleNodes) { } virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex) { btOptimizedBvhNode node; btVector3 aabbMin,aabbMax; aabbMin.setValue(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); aabbMax.setValue(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); aabbMin.setMin(triangle[0]); aabbMax.setMax(triangle[0]); aabbMin.setMin(triangle[1]); aabbMax.setMax(triangle[1]); aabbMin.setMin(triangle[2]); aabbMax.setMax(triangle[2]); //with quantization? node.m_aabbMinOrg = aabbMin; node.m_aabbMaxOrg = aabbMax; node.m_escapeIndex = -1; //for child nodes node.m_subPart = partId; node.m_triangleIndex = triangleIndex; m_triangleNodes.push_back(node); } }; struct QuantizedNodeTriangleCallback : public btInternalTriangleIndexCallback { QuantizedNodeArray& m_triangleNodes; const btQuantizedBvh* m_optimizedTree; // for quantization QuantizedNodeTriangleCallback& operator=(QuantizedNodeTriangleCallback& other) { m_triangleNodes = other.m_triangleNodes; m_optimizedTree = other.m_optimizedTree; return *this; } QuantizedNodeTriangleCallback(QuantizedNodeArray& triangleNodes,const btQuantizedBvh* tree) :m_triangleNodes(triangleNodes),m_optimizedTree(tree) { } virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex) { // The partId and triangle index must fit in the same (positive) integer btAssert(partId < (1<=0); btQuantizedBvhNode node; btVector3 aabbMin,aabbMax; aabbMin.setValue(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); aabbMax.setValue(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); aabbMin.setMin(triangle[0]); aabbMax.setMax(triangle[0]); aabbMin.setMin(triangle[1]); aabbMax.setMax(triangle[1]); aabbMin.setMin(triangle[2]); aabbMax.setMax(triangle[2]); //PCK: add these checks for zero dimensions of aabb const btScalar MIN_AABB_DIMENSION = btScalar(0.002); const btScalar MIN_AABB_HALF_DIMENSION = btScalar(0.001); if (aabbMax.x() - aabbMin.x() < MIN_AABB_DIMENSION) { aabbMax.setX(aabbMax.x() + MIN_AABB_HALF_DIMENSION); aabbMin.setX(aabbMin.x() - MIN_AABB_HALF_DIMENSION); } if (aabbMax.y() - aabbMin.y() < MIN_AABB_DIMENSION) { aabbMax.setY(aabbMax.y() + MIN_AABB_HALF_DIMENSION); aabbMin.setY(aabbMin.y() - MIN_AABB_HALF_DIMENSION); } if (aabbMax.z() - aabbMin.z() < MIN_AABB_DIMENSION) { aabbMax.setZ(aabbMax.z() + MIN_AABB_HALF_DIMENSION); aabbMin.setZ(aabbMin.z() - MIN_AABB_HALF_DIMENSION); } m_optimizedTree->quantize(&node.m_quantizedAabbMin[0],aabbMin,0); m_optimizedTree->quantize(&node.m_quantizedAabbMax[0],aabbMax,1); node.m_escapeIndexOrTriangleIndex = (partId<<(31-MAX_NUM_PARTS_IN_BITS)) | triangleIndex; m_triangleNodes.push_back(node); } }; int numLeafNodes = 0; if (m_useQuantization) { //initialize quantization values setQuantizationValues(bvhAabbMin,bvhAabbMax); QuantizedNodeTriangleCallback callback(m_quantizedLeafNodes,this); triangles->InternalProcessAllTriangles(&callback,m_bvhAabbMin,m_bvhAabbMax); //now we have an array of leafnodes in m_leafNodes numLeafNodes = m_quantizedLeafNodes.size(); m_quantizedContiguousNodes.resize(2*numLeafNodes); } else { NodeTriangleCallback callback(m_leafNodes); btVector3 aabbMin(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); btVector3 aabbMax(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); triangles->InternalProcessAllTriangles(&callback,aabbMin,aabbMax); //now we have an array of leafnodes in m_leafNodes numLeafNodes = m_leafNodes.size(); m_contiguousNodes.resize(2*numLeafNodes); } m_curNodeIndex = 0; buildTree(0,numLeafNodes); ///if the entire tree is small then subtree size, we need to create a header info for the tree if(m_useQuantization && !m_SubtreeHeaders.size()) { btBvhSubtreeInfo& subtree = m_SubtreeHeaders.expand(); subtree.setAabbFromQuantizeNode(m_quantizedContiguousNodes[0]); subtree.m_rootNodeIndex = 0; subtree.m_subtreeSize = m_quantizedContiguousNodes[0].isLeafNode() ? 1 : m_quantizedContiguousNodes[0].getEscapeIndex(); } //PCK: update the copy of the size m_subtreeHeaderCount = m_SubtreeHeaders.size(); //PCK: clear m_quantizedLeafNodes and m_leafNodes, they are temporary m_quantizedLeafNodes.clear(); m_leafNodes.clear(); } void btOptimizedBvh::refit(btStridingMeshInterface* meshInterface,const btVector3& aabbMin,const btVector3& aabbMax) { if (m_useQuantization) { setQuantizationValues(aabbMin,aabbMax); updateBvhNodes(meshInterface,0,m_curNodeIndex,0); ///now update all subtree headers int i; for (i=0;i m_bvhAabbMin.getX()); btAssert(aabbMin.getY() > m_bvhAabbMin.getY()); btAssert(aabbMin.getZ() > m_bvhAabbMin.getZ()); btAssert(aabbMax.getX() < m_bvhAabbMax.getX()); btAssert(aabbMax.getY() < m_bvhAabbMax.getY()); btAssert(aabbMax.getZ() < m_bvhAabbMax.getZ()); ///we should update all quantization values, using updateBvhNodes(meshInterface); ///but we only update chunks that overlap the given aabb unsigned short quantizedQueryAabbMin[3]; unsigned short quantizedQueryAabbMax[3]; quantize(&quantizedQueryAabbMin[0],aabbMin,0); quantize(&quantizedQueryAabbMax[0],aabbMax,1); int i; for (i=0;im_SubtreeHeaders.size();i++) { btBvhSubtreeInfo& subtree = m_SubtreeHeaders[i]; //PCK: unsigned instead of bool unsigned overlap = testQuantizedAabbAgainstQuantizedAabb(quantizedQueryAabbMin,quantizedQueryAabbMax,subtree.m_quantizedAabbMin,subtree.m_quantizedAabbMax); if (overlap != 0) { updateBvhNodes(meshInterface,subtree.m_rootNodeIndex,subtree.m_rootNodeIndex+subtree.m_subtreeSize,i); subtree.setAabbFromQuantizeNode(m_quantizedContiguousNodes[subtree.m_rootNodeIndex]); } } } void btOptimizedBvh::updateBvhNodes(btStridingMeshInterface* meshInterface,int firstNode,int endNode,int index) { (void)index; btAssert(m_useQuantization); int curNodeSubPart=-1; //get access info to trianglemesh data const unsigned char *vertexbase = 0; int numverts = 0; PHY_ScalarType type = PHY_INTEGER; int stride = 0; const unsigned char *indexbase = 0; int indexstride = 0; int numfaces = 0; PHY_ScalarType indicestype = PHY_INTEGER; btVector3 triangleVerts[3]; btVector3 aabbMin,aabbMax; const btVector3& meshScaling = meshInterface->getScaling(); int i; for (i=endNode-1;i>=firstNode;i--) { btQuantizedBvhNode& curNode = m_quantizedContiguousNodes[i]; if (curNode.isLeafNode()) { //recalc aabb from triangle data int nodeSubPart = curNode.getPartId(); int nodeTriangleIndex = curNode.getTriangleIndex(); if (nodeSubPart != curNodeSubPart) { if (curNodeSubPart >= 0) meshInterface->unLockReadOnlyVertexBase(curNodeSubPart); meshInterface->getLockedReadOnlyVertexIndexBase(&vertexbase,numverts, type,stride,&indexbase,indexstride,numfaces,indicestype,nodeSubPart); curNodeSubPart = nodeSubPart; btAssert(indicestype==PHY_INTEGER||indicestype==PHY_SHORT); } //triangles->getLockedReadOnlyVertexIndexBase(vertexBase,numVerts, unsigned int* gfxbase = (unsigned int*)(indexbase+nodeTriangleIndex*indexstride); for (int j=2;j>=0;j--) { int graphicsindex = indicestype==PHY_SHORT?((unsigned short*)gfxbase)[j]:gfxbase[j]; if (type == PHY_FLOAT) { float* graphicsbase = (float*)(vertexbase+graphicsindex*stride); triangleVerts[j] = btVector3( graphicsbase[0]*meshScaling.getX(), graphicsbase[1]*meshScaling.getY(), graphicsbase[2]*meshScaling.getZ()); } else { double* graphicsbase = (double*)(vertexbase+graphicsindex*stride); triangleVerts[j] = btVector3( btScalar(graphicsbase[0]*meshScaling.getX()), btScalar(graphicsbase[1]*meshScaling.getY()), btScalar(graphicsbase[2]*meshScaling.getZ())); } } aabbMin.setValue(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); aabbMax.setValue(btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT),btScalar(-BT_LARGE_FLOAT)); aabbMin.setMin(triangleVerts[0]); aabbMax.setMax(triangleVerts[0]); aabbMin.setMin(triangleVerts[1]); aabbMax.setMax(triangleVerts[1]); aabbMin.setMin(triangleVerts[2]); aabbMax.setMax(triangleVerts[2]); quantize(&curNode.m_quantizedAabbMin[0],aabbMin,0); quantize(&curNode.m_quantizedAabbMax[0],aabbMax,1); } else { //combine aabb from both children btQuantizedBvhNode* leftChildNode = &m_quantizedContiguousNodes[i+1]; btQuantizedBvhNode* rightChildNode = leftChildNode->isLeafNode() ? &m_quantizedContiguousNodes[i+2] : &m_quantizedContiguousNodes[i+1+leftChildNode->getEscapeIndex()]; { for (int i=0;i<3;i++) { curNode.m_quantizedAabbMin[i] = leftChildNode->m_quantizedAabbMin[i]; if (curNode.m_quantizedAabbMin[i]>rightChildNode->m_quantizedAabbMin[i]) curNode.m_quantizedAabbMin[i]=rightChildNode->m_quantizedAabbMin[i]; curNode.m_quantizedAabbMax[i] = leftChildNode->m_quantizedAabbMax[i]; if (curNode.m_quantizedAabbMax[i] < rightChildNode->m_quantizedAabbMax[i]) curNode.m_quantizedAabbMax[i] = rightChildNode->m_quantizedAabbMax[i]; } } } } if (curNodeSubPart >= 0) meshInterface->unLockReadOnlyVertexBase(curNodeSubPart); } ///deSerializeInPlace loads and initializes a BVH from a buffer in memory 'in place' btOptimizedBvh* btOptimizedBvh::deSerializeInPlace(void *i_alignedDataBuffer, unsigned int i_dataBufferSize, bool i_swapEndian) { btQuantizedBvh* bvh = btQuantizedBvh::deSerializeInPlace(i_alignedDataBuffer,i_dataBufferSize,i_swapEndian); //we don't add additional data so just do a static upcast return static_cast(bvh); } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btPolyhedralConvexShape.h0000644000175000017500000000615211337071441032130 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 BU_SHAPE #define BU_SHAPE #include "LinearMath/btMatrix3x3.h" #include "btConvexInternalShape.h" ///The btPolyhedralConvexShape is an internal interface class for polyhedral convex shapes. class btPolyhedralConvexShape : public btConvexInternalShape { protected: public: btPolyhedralConvexShape(); //brute force implementations virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; virtual int getNumVertices() const = 0 ; virtual int getNumEdges() const = 0; virtual void getEdge(int i,btVector3& pa,btVector3& pb) const = 0; virtual void getVertex(int i,btVector3& vtx) const = 0; virtual int getNumPlanes() const = 0; virtual void getPlane(btVector3& planeNormal,btVector3& planeSupport,int i ) const = 0; // virtual int getIndex(int i) const = 0 ; virtual bool isInside(const btVector3& pt,btScalar tolerance) const = 0; }; ///The btPolyhedralConvexAabbCachingShape adds aabb caching to the btPolyhedralConvexShape class btPolyhedralConvexAabbCachingShape : public btPolyhedralConvexShape { btVector3 m_localAabbMin; btVector3 m_localAabbMax; bool m_isLocalAabbValid; protected: void setCachedLocalAabb (const btVector3& aabbMin, const btVector3& aabbMax) { m_isLocalAabbValid = true; m_localAabbMin = aabbMin; m_localAabbMax = aabbMax; } inline void getCachedLocalAabb (btVector3& aabbMin, btVector3& aabbMax) const { btAssert(m_isLocalAabbValid); aabbMin = m_localAabbMin; aabbMax = m_localAabbMax; } public: btPolyhedralConvexAabbCachingShape(); inline void getNonvirtualAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax, btScalar margin) const { //lazy evaluation of local aabb btAssert(m_isLocalAabbValid); btTransformAabb(m_localAabbMin,m_localAabbMax,margin,trans,aabbMin,aabbMax); } virtual void setLocalScaling(const btVector3& scaling); virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; void recalcLocalAabb(); }; #endif //BU_SHAPE critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btCapsuleShape.cpp0000644000175000017500000001004411337071441030564 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btCapsuleShape.h" #include "BulletCollision/CollisionShapes/btCollisionMargin.h" #include "LinearMath/btQuaternion.h" btCapsuleShape::btCapsuleShape(btScalar radius, btScalar height) : btConvexInternalShape () { m_shapeType = CAPSULE_SHAPE_PROXYTYPE; m_upAxis = 1; m_implicitShapeDimensions.setValue(radius,0.5f*height,radius); } btVector3 btCapsuleShape::localGetSupportingVertexWithoutMargin(const btVector3& vec0)const { btVector3 supVec(0,0,0); btScalar maxDot(btScalar(-BT_LARGE_FLOAT)); btVector3 vec = vec0; btScalar lenSqr = vec.length2(); if (lenSqr < btScalar(0.0001)) { vec.setValue(1,0,0); } else { btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); vec *= rlen; } btVector3 vtx; btScalar newDot; btScalar radius = getRadius(); { btVector3 pos(0,0,0); pos[getUpAxis()] = getHalfHeight(); vtx = pos +vec*m_localScaling*(radius) - vec * getMargin(); newDot = vec.dot(vtx); if (newDot > maxDot) { maxDot = newDot; supVec = vtx; } } { btVector3 pos(0,0,0); pos[getUpAxis()] = -getHalfHeight(); vtx = pos +vec*m_localScaling*(radius) - vec * getMargin(); newDot = vec.dot(vtx); if (newDot > maxDot) { maxDot = newDot; supVec = vtx; } } return supVec; } void btCapsuleShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const { btScalar radius = getRadius(); for (int j=0;j maxDot) { maxDot = newDot; supportVerticesOut[j] = vtx; } } { btVector3 pos(0,0,0); pos[getUpAxis()] = -getHalfHeight(); vtx = pos +vec*m_localScaling*(radius) - vec * getMargin(); newDot = vec.dot(vtx); if (newDot > maxDot) { maxDot = newDot; supportVerticesOut[j] = vtx; } } } } void btCapsuleShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const { //as an approximation, take the inertia of the box that bounds the spheres btTransform ident; ident.setIdentity(); btScalar radius = getRadius(); btVector3 halfExtents(radius,radius,radius); halfExtents[getUpAxis()]+=getHalfHeight(); btScalar margin = CONVEX_DISTANCE_MARGIN; btScalar lx=btScalar(2.)*(halfExtents[0]+margin); btScalar ly=btScalar(2.)*(halfExtents[1]+margin); btScalar lz=btScalar(2.)*(halfExtents[2]+margin); const btScalar x2 = lx*lx; const btScalar y2 = ly*ly; const btScalar z2 = lz*lz; const btScalar scaledmass = mass * btScalar(.08333333); inertia[0] = scaledmass * (y2+z2); inertia[1] = scaledmass * (x2+z2); inertia[2] = scaledmass * (x2+y2); } btCapsuleShapeX::btCapsuleShapeX(btScalar radius,btScalar height) { m_upAxis = 0; m_implicitShapeDimensions.setValue(0.5f*height, radius,radius); } btCapsuleShapeZ::btCapsuleShapeZ(btScalar radius,btScalar height) { m_upAxis = 2; m_implicitShapeDimensions.setValue(radius,radius,0.5f*height); } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btTriangleInfoMap.h0000644000175000017500000002021011344271164030671 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2010 Erwin Coumans http://bulletphysics.org 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 _BT_TRIANGLE_INFO_MAP_H #define _BT_TRIANGLE_INFO_MAP_H #include "LinearMath/btHashMap.h" #include "LinearMath/btSerializer.h" ///for btTriangleInfo m_flags #define TRI_INFO_V0V1_CONVEX 1 #define TRI_INFO_V1V2_CONVEX 2 #define TRI_INFO_V2V0_CONVEX 4 #define TRI_INFO_V0V1_SWAP_NORMALB 8 #define TRI_INFO_V1V2_SWAP_NORMALB 16 #define TRI_INFO_V2V0_SWAP_NORMALB 32 ///The btTriangleInfo structure stores information to adjust collision normals to avoid collisions against internal edges ///it can be generated using struct btTriangleInfo { btTriangleInfo() { m_edgeV0V1Angle = SIMD_2_PI; m_edgeV1V2Angle = SIMD_2_PI; m_edgeV2V0Angle = SIMD_2_PI; m_flags=0; } int m_flags; btScalar m_edgeV0V1Angle; btScalar m_edgeV1V2Angle; btScalar m_edgeV2V0Angle; }; typedef btHashMap btInternalTriangleInfoMap; ///The btTriangleInfoMap stores edge angle information for some triangles. You can compute this information yourself or using btGenerateInternalEdgeInfo. struct btTriangleInfoMap : public btInternalTriangleInfoMap { btScalar m_convexEpsilon;///used to determine if an edge or contact normal is convex, using the dot product btScalar m_planarEpsilon; ///used to determine if a triangle edge is planar with zero angle btScalar m_equalVertexThreshold; ///used to compute connectivity: if the distance between two vertices is smaller than m_equalVertexThreshold, they are considered to be 'shared' btScalar m_edgeDistanceThreshold; ///used to determine edge contacts: if the closest distance between a contact point and an edge is smaller than this distance threshold it is considered to "hit the edge" btScalar m_zeroAreaThreshold; ///used to determine if a triangle is degenerate (length squared of cross product of 2 triangle edges < threshold) btTriangleInfoMap() { m_convexEpsilon = 0.00f; m_planarEpsilon = 0.0001f; m_equalVertexThreshold = btScalar(0.0001)*btScalar(0.0001); m_edgeDistanceThreshold = btScalar(0.1); m_zeroAreaThreshold = btScalar(0.0001)*btScalar(0.0001); } virtual ~btTriangleInfoMap() {} virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; void deSerialize(struct btTriangleInfoMapData& data); }; struct btTriangleInfoData { int m_flags; float m_edgeV0V1Angle; float m_edgeV1V2Angle; float m_edgeV2V0Angle; }; struct btTriangleInfoMapData { int *m_hashTablePtr; int *m_nextPtr; btTriangleInfoData *m_valueArrayPtr; int *m_keyArrayPtr; float m_convexEpsilon; float m_planarEpsilon; float m_equalVertexThreshold; float m_edgeDistanceThreshold; float m_zeroAreaThreshold; int m_nextSize; int m_hashTableSize; int m_numValues; int m_numKeys; char m_padding[4]; }; SIMD_FORCE_INLINE int btTriangleInfoMap::calculateSerializeBufferSize() const { return sizeof(btTriangleInfoMapData); } ///fills the dataBuffer and returns the struct name (and 0 on failure) SIMD_FORCE_INLINE const char* btTriangleInfoMap::serialize(void* dataBuffer, btSerializer* serializer) const { btTriangleInfoMapData* tmapData = (btTriangleInfoMapData*) dataBuffer; tmapData->m_convexEpsilon = m_convexEpsilon; tmapData->m_planarEpsilon = m_planarEpsilon; tmapData->m_equalVertexThreshold = m_equalVertexThreshold; tmapData->m_edgeDistanceThreshold = m_edgeDistanceThreshold; tmapData->m_zeroAreaThreshold = m_zeroAreaThreshold; tmapData->m_hashTableSize = m_hashTable.size(); tmapData->m_hashTablePtr = tmapData->m_hashTableSize ? (int*)serializer->getUniquePointer((void*)&m_hashTable[0]) : 0; if (tmapData->m_hashTablePtr) { //serialize an int buffer int sz = sizeof(int); int numElem = tmapData->m_hashTableSize; btChunk* chunk = serializer->allocate(sz,numElem); int* memPtr = (int*)chunk->m_oldPtr; for (int i=0;ifinalizeChunk(chunk,"int",BT_ARRAY_CODE,(void*)&m_hashTable[0]); } tmapData->m_nextSize = m_next.size(); tmapData->m_nextPtr = tmapData->m_nextSize? (int*)serializer->getUniquePointer((void*)&m_next[0]): 0; if (tmapData->m_nextPtr) { int sz = sizeof(int); int numElem = tmapData->m_nextSize; btChunk* chunk = serializer->allocate(sz,numElem); int* memPtr = (int*)chunk->m_oldPtr; for (int i=0;ifinalizeChunk(chunk,"int",BT_ARRAY_CODE,(void*)&m_next[0]); } tmapData->m_numValues = m_valueArray.size(); tmapData->m_valueArrayPtr = tmapData->m_numValues ? (btTriangleInfoData*)serializer->getUniquePointer((void*)&m_valueArray[0]): 0; if (tmapData->m_valueArrayPtr) { int sz = sizeof(btTriangleInfoData); int numElem = tmapData->m_numValues; btChunk* chunk = serializer->allocate(sz,numElem); btTriangleInfoData* memPtr = (btTriangleInfoData*)chunk->m_oldPtr; for (int i=0;im_edgeV0V1Angle = m_valueArray[i].m_edgeV0V1Angle; memPtr->m_edgeV1V2Angle = m_valueArray[i].m_edgeV1V2Angle; memPtr->m_edgeV2V0Angle = m_valueArray[i].m_edgeV2V0Angle; memPtr->m_flags = m_valueArray[i].m_flags; } serializer->finalizeChunk(chunk,"btTriangleInfoData",BT_ARRAY_CODE,(void*) &m_valueArray[0]); } tmapData->m_numKeys = m_keyArray.size(); tmapData->m_keyArrayPtr = tmapData->m_numKeys ? (int*)serializer->getUniquePointer((void*)&m_keyArray[0]) : 0; if (tmapData->m_keyArrayPtr) { int sz = sizeof(int); int numElem = tmapData->m_numValues; btChunk* chunk = serializer->allocate(sz,numElem); int* memPtr = (int*)chunk->m_oldPtr; for (int i=0;ifinalizeChunk(chunk,"int",BT_ARRAY_CODE,(void*) &m_keyArray[0]); } return "btTriangleInfoMapData"; } ///fills the dataBuffer and returns the struct name (and 0 on failure) SIMD_FORCE_INLINE void btTriangleInfoMap::deSerialize(btTriangleInfoMapData& tmapData ) { m_convexEpsilon = tmapData.m_convexEpsilon; m_planarEpsilon = tmapData.m_planarEpsilon; m_equalVertexThreshold = tmapData.m_equalVertexThreshold; m_edgeDistanceThreshold = tmapData.m_edgeDistanceThreshold; m_zeroAreaThreshold = tmapData.m_zeroAreaThreshold; m_hashTable.resize(tmapData.m_hashTableSize); int i =0; for (i=0;i IndexedMeshArray; ///The btTriangleIndexVertexArray allows to access multiple triangle meshes, by indexing into existing triangle/index arrays. ///Additional meshes can be added using addIndexedMesh ///No duplcate is made of the vertex/index data, it only indexes into external vertex/index arrays. ///So keep those arrays around during the lifetime of this btTriangleIndexVertexArray. ATTRIBUTE_ALIGNED16( class) btTriangleIndexVertexArray : public btStridingMeshInterface { protected: IndexedMeshArray m_indexedMeshes; int m_pad[2]; mutable int m_hasAabb; // using int instead of bool to maintain alignment mutable btVector3 m_aabbMin; mutable btVector3 m_aabbMax; public: BT_DECLARE_ALIGNED_ALLOCATOR(); btTriangleIndexVertexArray() : m_hasAabb(0) { } virtual ~btTriangleIndexVertexArray(); //just to be backwards compatible btTriangleIndexVertexArray(int numTriangles,int* triangleIndexBase,int triangleIndexStride,int numVertices,btScalar* vertexBase,int vertexStride); void addIndexedMesh(const btIndexedMesh& mesh, PHY_ScalarType indexType = PHY_INTEGER) { m_indexedMeshes.push_back(mesh); m_indexedMeshes[m_indexedMeshes.size()-1].m_indexType = indexType; } virtual void getLockedVertexIndexBase(unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& vertexStride,unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart=0); virtual void getLockedReadOnlyVertexIndexBase(const unsigned char **vertexbase, int& numverts,PHY_ScalarType& type, int& vertexStride,const unsigned char **indexbase,int & indexstride,int& numfaces,PHY_ScalarType& indicestype,int subpart=0) const; /// unLockVertexBase finishes the access to a subpart of the triangle mesh /// make a call to unLockVertexBase when the read and write access (using getLockedVertexIndexBase) is finished virtual void unLockVertexBase(int subpart) {(void)subpart;} virtual void unLockReadOnlyVertexBase(int subpart) const {(void)subpart;} /// getNumSubParts returns the number of seperate subparts /// each subpart has a continuous array of vertices and indices virtual int getNumSubParts() const { return (int)m_indexedMeshes.size(); } IndexedMeshArray& getIndexedMeshArray() { return m_indexedMeshes; } const IndexedMeshArray& getIndexedMeshArray() const { return m_indexedMeshes; } virtual void preallocateVertices(int numverts){(void) numverts;} virtual void preallocateIndices(int numindices){(void) numindices;} virtual bool hasPremadeAabb() const; virtual void setPremadeAabb(const btVector3& aabbMin, const btVector3& aabbMax ) const; virtual void getPremadeAabb(btVector3* aabbMin, btVector3* aabbMax ) const; } ; #endif //BT_TRIANGLE_INDEX_VERTEX_ARRAY_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btShapeHull.cpp0000644000175000017500000001426211344267705030112 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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. */ //btShapeHull was implemented by John McCutchan. #include "btShapeHull.h" #include "LinearMath/btConvexHull.h" #define NUM_UNITSPHERE_POINTS 42 btShapeHull::btShapeHull (const btConvexShape* shape) { m_shape = shape; m_vertices.clear (); m_indices.clear(); m_numIndices = 0; } btShapeHull::~btShapeHull () { m_indices.clear(); m_vertices.clear (); } bool btShapeHull::buildHull (btScalar /*margin*/) { int numSampleDirections = NUM_UNITSPHERE_POINTS; { int numPDA = m_shape->getNumPreferredPenetrationDirections(); if (numPDA) { for (int i=0;igetPreferredPenetrationDirection(i,norm); getUnitSpherePoints()[numSampleDirections] = norm; numSampleDirections++; } } } btVector3 supportPoints[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2]; int i; for (i = 0; i < numSampleDirections; i++) { supportPoints[i] = m_shape->localGetSupportingVertex(getUnitSpherePoints()[i]); } HullDesc hd; hd.mFlags = QF_TRIANGLES; hd.mVcount = static_cast(numSampleDirections); #ifdef BT_USE_DOUBLE_PRECISION hd.mVertices = &supportPoints[0]; hd.mVertexStride = sizeof(btVector3); #else hd.mVertices = &supportPoints[0]; hd.mVertexStride = sizeof (btVector3); #endif HullLibrary hl; HullResult hr; if (hl.CreateConvexHull (hd, hr) == QE_FAIL) { return false; } m_vertices.resize (static_cast(hr.mNumOutputVertices)); for (i = 0; i < static_cast(hr.mNumOutputVertices); i++) { m_vertices[i] = hr.m_OutputVertices[i]; } m_numIndices = hr.mNumIndices; m_indices.resize(static_cast(m_numIndices)); for (i = 0; i < static_cast(m_numIndices); i++) { m_indices[i] = hr.m_Indices[i]; } // free temporary hull result that we just copied hl.ReleaseResult (hr); return true; } int btShapeHull::numTriangles () const { return static_cast(m_numIndices / 3); } int btShapeHull::numVertices () const { return m_vertices.size (); } int btShapeHull::numIndices () const { return static_cast(m_numIndices); } btVector3* btShapeHull::getUnitSpherePoints() { static btVector3 sUnitSpherePoints[NUM_UNITSPHERE_POINTS+MAX_PREFERRED_PENETRATION_DIRECTIONS*2] = { btVector3(btScalar(0.000000) , btScalar(-0.000000),btScalar(-1.000000)), btVector3(btScalar(0.723608) , btScalar(-0.525725),btScalar(-0.447219)), btVector3(btScalar(-0.276388) , btScalar(-0.850649),btScalar(-0.447219)), btVector3(btScalar(-0.894426) , btScalar(-0.000000),btScalar(-0.447216)), btVector3(btScalar(-0.276388) , btScalar(0.850649),btScalar(-0.447220)), btVector3(btScalar(0.723608) , btScalar(0.525725),btScalar(-0.447219)), btVector3(btScalar(0.276388) , btScalar(-0.850649),btScalar(0.447220)), btVector3(btScalar(-0.723608) , btScalar(-0.525725),btScalar(0.447219)), btVector3(btScalar(-0.723608) , btScalar(0.525725),btScalar(0.447219)), btVector3(btScalar(0.276388) , btScalar(0.850649),btScalar(0.447219)), btVector3(btScalar(0.894426) , btScalar(0.000000),btScalar(0.447216)), btVector3(btScalar(-0.000000) , btScalar(0.000000),btScalar(1.000000)), btVector3(btScalar(0.425323) , btScalar(-0.309011),btScalar(-0.850654)), btVector3(btScalar(-0.162456) , btScalar(-0.499995),btScalar(-0.850654)), btVector3(btScalar(0.262869) , btScalar(-0.809012),btScalar(-0.525738)), btVector3(btScalar(0.425323) , btScalar(0.309011),btScalar(-0.850654)), btVector3(btScalar(0.850648) , btScalar(-0.000000),btScalar(-0.525736)), btVector3(btScalar(-0.525730) , btScalar(-0.000000),btScalar(-0.850652)), btVector3(btScalar(-0.688190) , btScalar(-0.499997),btScalar(-0.525736)), btVector3(btScalar(-0.162456) , btScalar(0.499995),btScalar(-0.850654)), btVector3(btScalar(-0.688190) , btScalar(0.499997),btScalar(-0.525736)), btVector3(btScalar(0.262869) , btScalar(0.809012),btScalar(-0.525738)), btVector3(btScalar(0.951058) , btScalar(0.309013),btScalar(0.000000)), btVector3(btScalar(0.951058) , btScalar(-0.309013),btScalar(0.000000)), btVector3(btScalar(0.587786) , btScalar(-0.809017),btScalar(0.000000)), btVector3(btScalar(0.000000) , btScalar(-1.000000),btScalar(0.000000)), btVector3(btScalar(-0.587786) , btScalar(-0.809017),btScalar(0.000000)), btVector3(btScalar(-0.951058) , btScalar(-0.309013),btScalar(-0.000000)), btVector3(btScalar(-0.951058) , btScalar(0.309013),btScalar(-0.000000)), btVector3(btScalar(-0.587786) , btScalar(0.809017),btScalar(-0.000000)), btVector3(btScalar(-0.000000) , btScalar(1.000000),btScalar(-0.000000)), btVector3(btScalar(0.587786) , btScalar(0.809017),btScalar(-0.000000)), btVector3(btScalar(0.688190) , btScalar(-0.499997),btScalar(0.525736)), btVector3(btScalar(-0.262869) , btScalar(-0.809012),btScalar(0.525738)), btVector3(btScalar(-0.850648) , btScalar(0.000000),btScalar(0.525736)), btVector3(btScalar(-0.262869) , btScalar(0.809012),btScalar(0.525738)), btVector3(btScalar(0.688190) , btScalar(0.499997),btScalar(0.525736)), btVector3(btScalar(0.525730) , btScalar(0.000000),btScalar(0.850652)), btVector3(btScalar(0.162456) , btScalar(-0.499995),btScalar(0.850654)), btVector3(btScalar(-0.425323) , btScalar(-0.309011),btScalar(0.850654)), btVector3(btScalar(-0.425323) , btScalar(0.309011),btScalar(0.850654)), btVector3(btScalar(0.162456) , btScalar(0.499995),btScalar(0.850654)) }; return sUnitSpherePoints; } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btConvexHullShape.h0000644000175000017500000001000111344267705030725 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 CONVEX_HULL_SHAPE_H #define CONVEX_HULL_SHAPE_H #include "btPolyhedralConvexShape.h" #include "BulletCollision/BroadphaseCollision/btBroadphaseProxy.h" // for the types #include "LinearMath/btAlignedObjectArray.h" ///The btConvexHullShape implements an implicit convex hull of an array of vertices. ///Bullet provides a general and fast collision detector for convex shapes based on GJK and EPA using localGetSupportingVertex. ATTRIBUTE_ALIGNED16(class) btConvexHullShape : public btPolyhedralConvexAabbCachingShape { btAlignedObjectArray m_unscaledPoints; public: BT_DECLARE_ALIGNED_ALLOCATOR(); ///this constructor optionally takes in a pointer to points. Each point is assumed to be 3 consecutive btScalar (x,y,z), the striding defines the number of bytes between each point, in memory. ///It is easier to not pass any points in the constructor, and just add one point at a time, using addPoint. ///btConvexHullShape make an internal copy of the points. btConvexHullShape(const btScalar* points=0,int numPoints=0, int stride=sizeof(btVector3)); void addPoint(const btVector3& point); btVector3* getUnscaledPoints() { return &m_unscaledPoints[0]; } const btVector3* getUnscaledPoints() const { return &m_unscaledPoints[0]; } ///getPoints is obsolete, please use getUnscaledPoints const btVector3* getPoints() const { return getUnscaledPoints(); } SIMD_FORCE_INLINE btVector3 getScaledPoint(int i) const { return m_unscaledPoints[i] * m_localScaling; } SIMD_FORCE_INLINE int getNumPoints() const { return m_unscaledPoints.size(); } virtual btVector3 localGetSupportingVertex(const btVector3& vec)const; virtual btVector3 localGetSupportingVertexWithoutMargin(const btVector3& vec)const; virtual void batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const; //debugging virtual const char* getName()const {return "Convex";} virtual int getNumVertices() const; virtual int getNumEdges() const; virtual void getEdge(int i,btVector3& pa,btVector3& pb) const; virtual void getVertex(int i,btVector3& vtx) const; virtual int getNumPlanes() const; virtual void getPlane(btVector3& planeNormal,btVector3& planeSupport,int i ) const; virtual bool isInside(const btVector3& pt,btScalar tolerance) const; ///in case we receive negative scaling virtual void setLocalScaling(const btVector3& scaling); virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btConvexHullShapeData { btConvexInternalShapeData m_convexInternalShapeData; btVector3FloatData *m_unscaledPointsFloatPtr; btVector3DoubleData *m_unscaledPointsDoublePtr; int m_numUnscaledPoints; char m_padding3[4]; }; SIMD_FORCE_INLINE int btConvexHullShape::calculateSerializeBufferSize() const { return sizeof(btConvexHullShapeData); } #endif //CONVEX_HULL_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btMinkowskiSumShape.cpp0000644000175000017500000000425111337071441031633 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btMinkowskiSumShape.h" btMinkowskiSumShape::btMinkowskiSumShape(const btConvexShape* shapeA,const btConvexShape* shapeB) : btConvexInternalShape (), m_shapeA(shapeA), m_shapeB(shapeB) { m_shapeType = MINKOWSKI_DIFFERENCE_SHAPE_PROXYTYPE; m_transA.setIdentity(); m_transB.setIdentity(); } btVector3 btMinkowskiSumShape::localGetSupportingVertexWithoutMargin(const btVector3& vec)const { btVector3 supVertexA = m_transA(m_shapeA->localGetSupportingVertexWithoutMargin(vec*m_transA.getBasis())); btVector3 supVertexB = m_transB(m_shapeB->localGetSupportingVertexWithoutMargin(-vec*m_transB.getBasis())); return supVertexA - supVertexB; } void btMinkowskiSumShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const { ///@todo: could make recursive use of batching. probably this shape is not used frequently. for (int i=0;igetMargin() + m_shapeB->getMargin(); } void btMinkowskiSumShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const { (void)mass; btAssert(0); inertia.setValue(0,0,0); } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btConvexInternalShape.cpp0000644000175000017500000000754011337071441032136 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btConvexInternalShape.h" btConvexInternalShape::btConvexInternalShape() : m_localScaling(btScalar(1.),btScalar(1.),btScalar(1.)), m_collisionMargin(CONVEX_DISTANCE_MARGIN) { } void btConvexInternalShape::setLocalScaling(const btVector3& scaling) { m_localScaling = scaling.absolute(); } void btConvexInternalShape::getAabbSlow(const btTransform& trans,btVector3&minAabb,btVector3&maxAabb) const { #ifndef __SPU__ //use localGetSupportingVertexWithoutMargin? btScalar margin = getMargin(); for (int i=0;i<3;i++) { btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.)); vec[i] = btScalar(1.); btVector3 sv = localGetSupportingVertex(vec*trans.getBasis()); btVector3 tmp = trans(sv); maxAabb[i] = tmp[i]+margin; vec[i] = btScalar(-1.); tmp = trans(localGetSupportingVertex(vec*trans.getBasis())); minAabb[i] = tmp[i]-margin; } #endif } btVector3 btConvexInternalShape::localGetSupportingVertex(const btVector3& vec)const { #ifndef __SPU__ btVector3 supVertex = localGetSupportingVertexWithoutMargin(vec); if ( getMargin()!=btScalar(0.) ) { btVector3 vecnorm = vec; if (vecnorm .length2() < (SIMD_EPSILON*SIMD_EPSILON)) { vecnorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.)); } vecnorm.normalize(); supVertex+= getMargin() * vecnorm; } return supVertex; #else btAssert(0); return btVector3(0,0,0); #endif //__SPU__ } btConvexInternalAabbCachingShape::btConvexInternalAabbCachingShape() : btConvexInternalShape(), m_localAabbMin(1,1,1), m_localAabbMax(-1,-1,-1), m_isLocalAabbValid(false) { } void btConvexInternalAabbCachingShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax) const { getNonvirtualAabb(trans,aabbMin,aabbMax,getMargin()); } void btConvexInternalAabbCachingShape::setLocalScaling(const btVector3& scaling) { btConvexInternalShape::setLocalScaling(scaling); recalcLocalAabb(); } void btConvexInternalAabbCachingShape::recalcLocalAabb() { m_isLocalAabbValid = true; #if 1 static const btVector3 _directions[] = { btVector3( 1., 0., 0.), btVector3( 0., 1., 0.), btVector3( 0., 0., 1.), btVector3( -1., 0., 0.), btVector3( 0., -1., 0.), btVector3( 0., 0., -1.) }; btVector3 _supporting[] = { btVector3( 0., 0., 0.), btVector3( 0., 0., 0.), btVector3( 0., 0., 0.), btVector3( 0., 0., 0.), btVector3( 0., 0., 0.), btVector3( 0., 0., 0.) }; batchedUnitVectorGetSupportingVertexWithoutMargin(_directions, _supporting, 6); for ( int i = 0; i < 3; ++i ) { m_localAabbMax[i] = _supporting[i][i] + m_collisionMargin; m_localAabbMin[i] = _supporting[i + 3][i] - m_collisionMargin; } #else for (int i=0;i<3;i++) { btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.)); vec[i] = btScalar(1.); btVector3 tmp = localGetSupportingVertex(vec); m_localAabbMax[i] = tmp[i]+m_collisionMargin; vec[i] = btScalar(-1.); tmp = localGetSupportingVertex(vec); m_localAabbMin[i] = tmp[i]-m_collisionMargin; } #endif } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btCylinderShape.cpp0000644000175000017500000001325211337071441030745 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btCylinderShape.h" btCylinderShape::btCylinderShape (const btVector3& halfExtents) :btConvexInternalShape(), m_upAxis(1) { btVector3 margin(getMargin(),getMargin(),getMargin()); m_implicitShapeDimensions = (halfExtents * m_localScaling) - margin; m_shapeType = CYLINDER_SHAPE_PROXYTYPE; } btCylinderShapeX::btCylinderShapeX (const btVector3& halfExtents) :btCylinderShape(halfExtents) { m_upAxis = 0; } btCylinderShapeZ::btCylinderShapeZ (const btVector3& halfExtents) :btCylinderShape(halfExtents) { m_upAxis = 2; } void btCylinderShape::getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const { btTransformAabb(getHalfExtentsWithoutMargin(),getMargin(),t,aabbMin,aabbMax); } void btCylinderShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const { //approximation of box shape, todo: implement cylinder shape inertia before people notice ;-) btVector3 halfExtents = getHalfExtentsWithMargin(); btScalar lx=btScalar(2.)*(halfExtents.x()); btScalar ly=btScalar(2.)*(halfExtents.y()); btScalar lz=btScalar(2.)*(halfExtents.z()); inertia.setValue(mass/(btScalar(12.0)) * (ly*ly + lz*lz), mass/(btScalar(12.0)) * (lx*lx + lz*lz), mass/(btScalar(12.0)) * (lx*lx + ly*ly)); } SIMD_FORCE_INLINE btVector3 CylinderLocalSupportX(const btVector3& halfExtents,const btVector3& v) { const int cylinderUpAxis = 0; const int XX = 1; const int YY = 0; const int ZZ = 2; //mapping depends on how cylinder local orientation is // extents of the cylinder is: X,Y is for radius, and Z for height btScalar radius = halfExtents[XX]; btScalar halfHeight = halfExtents[cylinderUpAxis]; btVector3 tmp; btScalar d ; btScalar s = btSqrt(v[XX] * v[XX] + v[ZZ] * v[ZZ]); if (s != btScalar(0.0)) { d = radius / s; tmp[XX] = v[XX] * d; tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; tmp[ZZ] = v[ZZ] * d; return tmp; } else { tmp[XX] = radius; tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; tmp[ZZ] = btScalar(0.0); return tmp; } } inline btVector3 CylinderLocalSupportY(const btVector3& halfExtents,const btVector3& v) { const int cylinderUpAxis = 1; const int XX = 0; const int YY = 1; const int ZZ = 2; btScalar radius = halfExtents[XX]; btScalar halfHeight = halfExtents[cylinderUpAxis]; btVector3 tmp; btScalar d ; btScalar s = btSqrt(v[XX] * v[XX] + v[ZZ] * v[ZZ]); if (s != btScalar(0.0)) { d = radius / s; tmp[XX] = v[XX] * d; tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; tmp[ZZ] = v[ZZ] * d; return tmp; } else { tmp[XX] = radius; tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; tmp[ZZ] = btScalar(0.0); return tmp; } } inline btVector3 CylinderLocalSupportZ(const btVector3& halfExtents,const btVector3& v) { const int cylinderUpAxis = 2; const int XX = 0; const int YY = 2; const int ZZ = 1; //mapping depends on how cylinder local orientation is // extents of the cylinder is: X,Y is for radius, and Z for height btScalar radius = halfExtents[XX]; btScalar halfHeight = halfExtents[cylinderUpAxis]; btVector3 tmp; btScalar d ; btScalar s = btSqrt(v[XX] * v[XX] + v[ZZ] * v[ZZ]); if (s != btScalar(0.0)) { d = radius / s; tmp[XX] = v[XX] * d; tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; tmp[ZZ] = v[ZZ] * d; return tmp; } else { tmp[XX] = radius; tmp[YY] = v[YY] < 0.0 ? -halfHeight : halfHeight; tmp[ZZ] = btScalar(0.0); return tmp; } } btVector3 btCylinderShapeX::localGetSupportingVertexWithoutMargin(const btVector3& vec)const { return CylinderLocalSupportX(getHalfExtentsWithoutMargin(),vec); } btVector3 btCylinderShapeZ::localGetSupportingVertexWithoutMargin(const btVector3& vec)const { return CylinderLocalSupportZ(getHalfExtentsWithoutMargin(),vec); } btVector3 btCylinderShape::localGetSupportingVertexWithoutMargin(const btVector3& vec)const { return CylinderLocalSupportY(getHalfExtentsWithoutMargin(),vec); } void btCylinderShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const { for (int i=0;i btScalar(0.)) temporalAabbMaxx += linMotion.x(); else temporalAabbMinx += linMotion.x(); if (linMotion.y() > btScalar(0.)) temporalAabbMaxy += linMotion.y(); else temporalAabbMiny += linMotion.y(); if (linMotion.z() > btScalar(0.)) temporalAabbMaxz += linMotion.z(); else temporalAabbMinz += linMotion.z(); //add conservative angular motion btScalar angularMotion = angvel.length() * getAngularMotionDisc() * timeStep; btVector3 angularMotion3d(angularMotion,angularMotion,angularMotion); temporalAabbMin = btVector3(temporalAabbMinx,temporalAabbMiny,temporalAabbMinz); temporalAabbMax = btVector3(temporalAabbMaxx,temporalAabbMaxy,temporalAabbMaxz); temporalAabbMin -= angularMotion3d; temporalAabbMax += angularMotion3d; } ///fills the dataBuffer and returns the struct name (and 0 on failure) const char* btCollisionShape::serialize(void* dataBuffer, btSerializer* serializer) const { btCollisionShapeData* shapeData = (btCollisionShapeData*) dataBuffer; char* name = (char*) serializer->findNameForPointer(this); shapeData->m_name = (char*)serializer->getUniquePointer(name); if (shapeData->m_name) { serializer->serializeName(name); } shapeData->m_shapeType = m_shapeType; //shapeData->m_padding//?? return "btCollisionShapeData"; } void btCollisionShape::serializeSingleShape(btSerializer* serializer) const { int len = calculateSerializeBufferSize(); btChunk* chunk = serializer->allocate(len,1); const char* structType = serialize(chunk->m_oldPtr, serializer); serializer->finalizeChunk(chunk,structType,BT_SHAPE_CODE,(void*)this); }critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btShapeHull.h0000644000175000017500000000402311344267705027551 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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. */ ///btShapeHull implemented by John McCutchan. #ifndef _SHAPE_HULL_H #define _SHAPE_HULL_H #include "LinearMath/btAlignedObjectArray.h" #include "BulletCollision/CollisionShapes/btConvexShape.h" ///The btShapeHull class takes a btConvexShape, builds a simplified convex hull using btConvexHull and provides triangle indices and vertices. ///It can be useful for to simplify a complex convex object and for visualization of a non-polyhedral convex object. ///It approximates the convex hull using the supporting vertex of 42 directions. class btShapeHull { protected: btAlignedObjectArray m_vertices; btAlignedObjectArray m_indices; unsigned int m_numIndices; const btConvexShape* m_shape; static btVector3* getUnitSpherePoints(); public: btShapeHull (const btConvexShape* shape); ~btShapeHull (); bool buildHull (btScalar margin); int numTriangles () const; int numVertices () const; int numIndices () const; const btVector3* getVertexPointer() const { return &m_vertices[0]; } const unsigned int* getIndexPointer() const { return &m_indices[0]; } }; #endif //_SHAPE_HULL_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btTriangleMeshShape.cpp0000644000175000017500000001235411344267705031570 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btTriangleMeshShape.h" #include "LinearMath/btVector3.h" #include "LinearMath/btQuaternion.h" #include "btStridingMeshInterface.h" #include "LinearMath/btAabbUtil2.h" #include "BulletCollision/CollisionShapes/btCollisionMargin.h" btTriangleMeshShape::btTriangleMeshShape(btStridingMeshInterface* meshInterface) : btConcaveShape (), m_meshInterface(meshInterface) { m_shapeType = TRIANGLE_MESH_SHAPE_PROXYTYPE; if(meshInterface->hasPremadeAabb()) { meshInterface->getPremadeAabb(&m_localAabbMin, &m_localAabbMax); } else { recalcLocalAabb(); } } btTriangleMeshShape::~btTriangleMeshShape() { } void btTriangleMeshShape::getAabb(const btTransform& trans,btVector3& aabbMin,btVector3& aabbMax) const { btVector3 localHalfExtents = btScalar(0.5)*(m_localAabbMax-m_localAabbMin); localHalfExtents += btVector3(getMargin(),getMargin(),getMargin()); btVector3 localCenter = btScalar(0.5)*(m_localAabbMax+m_localAabbMin); btMatrix3x3 abs_b = trans.getBasis().absolute(); btVector3 center = trans(localCenter); btVector3 extent = btVector3(abs_b[0].dot(localHalfExtents), abs_b[1].dot(localHalfExtents), abs_b[2].dot(localHalfExtents)); aabbMin = center - extent; aabbMax = center + extent; } void btTriangleMeshShape::recalcLocalAabb() { for (int i=0;i<3;i++) { btVector3 vec(btScalar(0.),btScalar(0.),btScalar(0.)); vec[i] = btScalar(1.); btVector3 tmp = localGetSupportingVertex(vec); m_localAabbMax[i] = tmp[i]+m_collisionMargin; vec[i] = btScalar(-1.); tmp = localGetSupportingVertex(vec); m_localAabbMin[i] = tmp[i]-m_collisionMargin; } } class SupportVertexCallback : public btTriangleCallback { btVector3 m_supportVertexLocal; public: btTransform m_worldTrans; btScalar m_maxDot; btVector3 m_supportVecLocal; SupportVertexCallback(const btVector3& supportVecWorld,const btTransform& trans) : m_supportVertexLocal(btScalar(0.),btScalar(0.),btScalar(0.)), m_worldTrans(trans) ,m_maxDot(btScalar(-BT_LARGE_FLOAT)) { m_supportVecLocal = supportVecWorld * m_worldTrans.getBasis(); } virtual void processTriangle( btVector3* triangle,int partId, int triangleIndex) { (void)partId; (void)triangleIndex; for (int i=0;i<3;i++) { btScalar dot = m_supportVecLocal.dot(triangle[i]); if (dot > m_maxDot) { m_maxDot = dot; m_supportVertexLocal = triangle[i]; } } } btVector3 GetSupportVertexWorldSpace() { return m_worldTrans(m_supportVertexLocal); } btVector3 GetSupportVertexLocal() { return m_supportVertexLocal; } }; void btTriangleMeshShape::setLocalScaling(const btVector3& scaling) { m_meshInterface->setScaling(scaling); recalcLocalAabb(); } const btVector3& btTriangleMeshShape::getLocalScaling() const { return m_meshInterface->getScaling(); } //#define DEBUG_TRIANGLE_MESH void btTriangleMeshShape::processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const { struct FilteredCallback : public btInternalTriangleIndexCallback { btTriangleCallback* m_callback; btVector3 m_aabbMin; btVector3 m_aabbMax; FilteredCallback(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) :m_callback(callback), m_aabbMin(aabbMin), m_aabbMax(aabbMax) { } virtual void internalProcessTriangleIndex(btVector3* triangle,int partId,int triangleIndex) { if (TestTriangleAgainstAabb2(&triangle[0],m_aabbMin,m_aabbMax)) { //check aabb in triangle-space, before doing this m_callback->processTriangle(triangle,partId,triangleIndex); } } }; FilteredCallback filterCallback(callback,aabbMin,aabbMax); m_meshInterface->InternalProcessAllTriangles(&filterCallback,aabbMin,aabbMax); } void btTriangleMeshShape::calculateLocalInertia(btScalar mass,btVector3& inertia) const { (void)mass; //moving concave objects not supported btAssert(0); inertia.setValue(btScalar(0.),btScalar(0.),btScalar(0.)); } btVector3 btTriangleMeshShape::localGetSupportingVertex(const btVector3& vec) const { btVector3 supportVertex; btTransform ident; ident.setIdentity(); SupportVertexCallback supportCallback(vec,ident); btVector3 aabbMax(btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT),btScalar(BT_LARGE_FLOAT)); processAllTriangles(&supportCallback,-aabbMax,aabbMax); supportVertex = supportCallback.GetSupportVertexLocal(); return supportVertex; } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btStaticPlaneShape.h0000644000175000017500000000632511344267705031063 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 STATIC_PLANE_SHAPE_H #define STATIC_PLANE_SHAPE_H #include "btConcaveShape.h" ///The btStaticPlaneShape simulates an infinite non-moving (static) collision plane. ATTRIBUTE_ALIGNED16(class) btStaticPlaneShape : public btConcaveShape { protected: btVector3 m_localAabbMin; btVector3 m_localAabbMax; btVector3 m_planeNormal; btScalar m_planeConstant; btVector3 m_localScaling; public: btStaticPlaneShape(const btVector3& planeNormal,btScalar planeConstant); virtual ~btStaticPlaneShape(); virtual void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; virtual void processAllTriangles(btTriangleCallback* callback,const btVector3& aabbMin,const btVector3& aabbMax) const; virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; virtual void setLocalScaling(const btVector3& scaling); virtual const btVector3& getLocalScaling() const; const btVector3& getPlaneNormal() const { return m_planeNormal; } const btScalar& getPlaneConstant() const { return m_planeConstant; } //debugging virtual const char* getName()const {return "STATICPLANE";} virtual int calculateSerializeBufferSize() const; ///fills the dataBuffer and returns the struct name (and 0 on failure) virtual const char* serialize(void* dataBuffer, btSerializer* serializer) const; }; ///do not change those serialization structures, it requires an updated sBulletDNAstr/sBulletDNAstr64 struct btStaticPlaneShapeData { btCollisionShapeData m_collisionShapeData; btVector3FloatData m_localScaling; btVector3FloatData m_planeNormal; float m_planeConstant; char m_pad[4]; }; SIMD_FORCE_INLINE int btStaticPlaneShape::calculateSerializeBufferSize() const { return sizeof(btStaticPlaneShapeData); } ///fills the dataBuffer and returns the struct name (and 0 on failure) SIMD_FORCE_INLINE const char* btStaticPlaneShape::serialize(void* dataBuffer, btSerializer* serializer) const { btStaticPlaneShapeData* planeData = (btStaticPlaneShapeData*) dataBuffer; btCollisionShape::serialize(&planeData->m_collisionShapeData,serializer); m_localScaling.serializeFloat(planeData->m_localScaling); m_planeNormal.serializeFloat(planeData->m_planeNormal); planeData->m_planeConstant = float(m_planeConstant); return "btStaticPlaneShapeData"; } #endif //STATIC_PLANE_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btEmptyShape.h0000644000175000017500000000416111337071441027736 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 EMPTY_SHAPE_H #define EMPTY_SHAPE_H #include "btConcaveShape.h" #include "LinearMath/btVector3.h" #include "LinearMath/btTransform.h" #include "LinearMath/btMatrix3x3.h" #include "btCollisionMargin.h" /// The btEmptyShape is a collision shape without actual collision detection shape, so most users should ignore this class. /// It can be replaced by another shape during runtime, but the inertia tensor should be recomputed. class btEmptyShape : public btConcaveShape { public: btEmptyShape(); virtual ~btEmptyShape(); ///getAabb's default implementation is brute force, expected derived classes to implement a fast dedicated version void getAabb(const btTransform& t,btVector3& aabbMin,btVector3& aabbMax) const; virtual void setLocalScaling(const btVector3& scaling) { m_localScaling = scaling; } virtual const btVector3& getLocalScaling() const { return m_localScaling; } virtual void calculateLocalInertia(btScalar mass,btVector3& inertia) const; virtual const char* getName()const { return "Empty"; } virtual void processAllTriangles(btTriangleCallback* ,const btVector3& ,const btVector3& ) const { } protected: btVector3 m_localScaling; }; #endif //EMPTY_SHAPE_H critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btConcaveShape.cpp0000644000175000017500000000206711337071441030554 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btConcaveShape.h" btConcaveShape::btConcaveShape() : m_collisionMargin(btScalar(0.)) { } btConcaveShape::~btConcaveShape() { } critterding-beta12.1/src/utils/bullet/BulletCollision/CollisionShapes/btConvexPointCloudShape.cpp0000644000175000017500000000734611337071441032446 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 "btConvexPointCloudShape.h" #include "BulletCollision/CollisionShapes/btCollisionMargin.h" #include "LinearMath/btQuaternion.h" void btConvexPointCloudShape::setLocalScaling(const btVector3& scaling) { m_localScaling = scaling; recalcLocalAabb(); } #ifndef __SPU__ btVector3 btConvexPointCloudShape::localGetSupportingVertexWithoutMargin(const btVector3& vec0)const { btVector3 supVec(btScalar(0.),btScalar(0.),btScalar(0.)); btScalar newDot,maxDot = btScalar(-BT_LARGE_FLOAT); btVector3 vec = vec0; btScalar lenSqr = vec.length2(); if (lenSqr < btScalar(0.0001)) { vec.setValue(1,0,0); } else { btScalar rlen = btScalar(1.) / btSqrt(lenSqr ); vec *= rlen; } for (int i=0;i maxDot) { maxDot = newDot; supVec = vtx; } } return supVec; } void btConvexPointCloudShape::batchedUnitVectorGetSupportingVertexWithoutMargin(const btVector3* vectors,btVector3* supportVerticesOut,int numVectors) const { btScalar newDot; //use 'w' component of supportVerticesOut? { for (int i=0;i supportVerticesOut[j][3]) { //WARNING: don't swap next lines, the w component would get overwritten! supportVerticesOut[j] = vtx; supportVerticesOut[j][3] = newDot; } } } } btVector3 btConvexPointCloudShape::localGetSupportingVertex(const btVector3& vec)const { btVector3 supVertex = localGetSupportingVertexWithoutMargin(vec); if ( getMargin()!=btScalar(0.) ) { btVector3 vecnorm = vec; if (vecnorm .length2() < (SIMD_EPSILON*SIMD_EPSILON)) { vecnorm.setValue(btScalar(-1.),btScalar(-1.),btScalar(-1.)); } vecnorm.normalize(); supVertex+= getMargin() * vecnorm; } return supVertex; } #endif //currently just for debugging (drawing), perhaps future support for algebraic continuous collision detection //Please note that you can debug-draw btConvexHullShape with the Raytracer Demo int btConvexPointCloudShape::getNumVertices() const { return m_numPoints; } int btConvexPointCloudShape::getNumEdges() const { return 0; } void btConvexPointCloudShape::getEdge(int i,btVector3& pa,btVector3& pb) const { btAssert (0); } void btConvexPointCloudShape::getVertex(int i,btVector3& vtx) const { vtx = m_unscaledPoints[i]*m_localScaling; } int btConvexPointCloudShape::getNumPlanes() const { return 0; } void btConvexPointCloudShape::getPlane(btVector3& ,btVector3& ,int ) const { btAssert(0); } //not yet bool btConvexPointCloudShape::isInside(const btVector3& ,btScalar ) const { btAssert(0); return false; } critterding-beta12.1/src/utils/bullet/BulletCollision/CMakeLists.txt0000644000175000017500000002435511337071441024630 0ustar bobkebobkeINCLUDE_DIRECTORIES( ${BULLET_PHYSICS_SOURCE_DIR}/src } ) SET(BulletCollision_SRCS BroadphaseCollision/btAxisSweep3.cpp BroadphaseCollision/btBroadphaseProxy.cpp BroadphaseCollision/btCollisionAlgorithm.cpp BroadphaseCollision/btDbvt.cpp BroadphaseCollision/btDbvtBroadphase.cpp BroadphaseCollision/btDispatcher.cpp BroadphaseCollision/btMultiSapBroadphase.cpp BroadphaseCollision/btOverlappingPairCache.cpp BroadphaseCollision/btQuantizedBvh.cpp BroadphaseCollision/btSimpleBroadphase.cpp CollisionDispatch/btActivatingCollisionAlgorithm.cpp CollisionDispatch/btBoxBoxCollisionAlgorithm.cpp CollisionDispatch/btBox2dBox2dCollisionAlgorithm.cpp CollisionDispatch/btBoxBoxDetector.cpp CollisionDispatch/btCollisionDispatcher.cpp CollisionDispatch/btCollisionObject.cpp CollisionDispatch/btCollisionWorld.cpp CollisionDispatch/btCompoundCollisionAlgorithm.cpp CollisionDispatch/btConvexConcaveCollisionAlgorithm.cpp CollisionDispatch/btConvexConvexAlgorithm.cpp CollisionDispatch/btConvexPlaneCollisionAlgorithm.cpp CollisionDispatch/btConvex2dConvex2dAlgorithm.cpp CollisionDispatch/btDefaultCollisionConfiguration.cpp CollisionDispatch/btEmptyCollisionAlgorithm.cpp CollisionDispatch/btGhostObject.cpp CollisionDispatch/btManifoldResult.cpp CollisionDispatch/btSimulationIslandManager.cpp CollisionDispatch/btSphereBoxCollisionAlgorithm.cpp CollisionDispatch/btSphereSphereCollisionAlgorithm.cpp CollisionDispatch/btSphereTriangleCollisionAlgorithm.cpp CollisionDispatch/btUnionFind.cpp CollisionDispatch/SphereTriangleDetector.cpp CollisionShapes/btBoxShape.cpp CollisionShapes/btBox2dShape.cpp CollisionShapes/btBvhTriangleMeshShape.cpp CollisionShapes/btCapsuleShape.cpp CollisionShapes/btCollisionShape.cpp CollisionShapes/btCompoundShape.cpp CollisionShapes/btConcaveShape.cpp CollisionShapes/btConeShape.cpp CollisionShapes/btConvexHullShape.cpp CollisionShapes/btConvexInternalShape.cpp CollisionShapes/btConvexPointCloudShape.cpp CollisionShapes/btConvexShape.cpp CollisionShapes/btConvex2dShape.cpp CollisionShapes/btConvexTriangleMeshShape.cpp CollisionShapes/btCylinderShape.cpp CollisionShapes/btEmptyShape.cpp CollisionShapes/btHeightfieldTerrainShape.cpp CollisionShapes/btMinkowskiSumShape.cpp CollisionShapes/btMultimaterialTriangleMeshShape.cpp CollisionShapes/btMultiSphereShape.cpp CollisionShapes/btOptimizedBvh.cpp CollisionShapes/btPolyhedralConvexShape.cpp CollisionShapes/btScaledBvhTriangleMeshShape.cpp CollisionShapes/btShapeHull.cpp CollisionShapes/btSphereShape.cpp CollisionShapes/btStaticPlaneShape.cpp CollisionShapes/btStridingMeshInterface.cpp CollisionShapes/btTetrahedronShape.cpp CollisionShapes/btTriangleBuffer.cpp CollisionShapes/btTriangleCallback.cpp CollisionShapes/btTriangleIndexVertexArray.cpp CollisionShapes/btTriangleIndexVertexMaterialArray.cpp CollisionShapes/btTriangleMesh.cpp CollisionShapes/btTriangleMeshShape.cpp CollisionShapes/btUniformScalingShape.cpp Gimpact/btContactProcessing.cpp Gimpact/btGenericPoolAllocator.cpp Gimpact/btGImpactBvh.cpp Gimpact/btGImpactCollisionAlgorithm.cpp Gimpact/btGImpactQuantizedBvh.cpp Gimpact/btGImpactShape.cpp Gimpact/btTriangleShapeEx.cpp Gimpact/gim_box_set.cpp Gimpact/gim_contact.cpp Gimpact/gim_memory.cpp Gimpact/gim_tri_collision.cpp NarrowPhaseCollision/btContinuousConvexCollision.cpp NarrowPhaseCollision/btConvexCast.cpp NarrowPhaseCollision/btGjkConvexCast.cpp NarrowPhaseCollision/btGjkEpa2.cpp NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.cpp NarrowPhaseCollision/btGjkPairDetector.cpp NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.cpp NarrowPhaseCollision/btPersistentManifold.cpp NarrowPhaseCollision/btRaycastCallback.cpp NarrowPhaseCollision/btSubSimplexConvexCast.cpp NarrowPhaseCollision/btVoronoiSimplexSolver.cpp ) SET(Root_HDRS ../btBulletCollisionCommon.h ) SET(BroadphaseCollision_HDRS BroadphaseCollision/btAxisSweep3.h BroadphaseCollision/btBroadphaseInterface.h BroadphaseCollision/btBroadphaseProxy.h BroadphaseCollision/btCollisionAlgorithm.h BroadphaseCollision/btDbvt.h BroadphaseCollision/btDbvtBroadphase.h BroadphaseCollision/btDispatcher.h BroadphaseCollision/btMultiSapBroadphase.h BroadphaseCollision/btOverlappingPairCache.h BroadphaseCollision/btOverlappingPairCallback.h BroadphaseCollision/btQuantizedBvh.h BroadphaseCollision/btSimpleBroadphase.h ) SET(CollisionDispatch_HDRS CollisionDispatch/btActivatingCollisionAlgorithm.h CollisionDispatch/btBoxBoxCollisionAlgorithm.h CollisionDispatch/btBox2dBox2dCollisionAlgorithm.h CollisionDispatch/btBoxBoxDetector.h CollisionDispatch/btCollisionConfiguration.h CollisionDispatch/btCollisionCreateFunc.h CollisionDispatch/btCollisionDispatcher.h CollisionDispatch/btCollisionObject.h CollisionDispatch/btCollisionWorld.h CollisionDispatch/btCompoundCollisionAlgorithm.h CollisionDispatch/btConvexConcaveCollisionAlgorithm.h CollisionDispatch/btConvexConvexAlgorithm.h CollisionDispatch/btConvex2dConvex2dAlgorithm.h CollisionDispatch/btConvexPlaneCollisionAlgorithm.h CollisionDispatch/btDefaultCollisionConfiguration.h CollisionDispatch/btEmptyCollisionAlgorithm.h CollisionDispatch/btGhostObject.h CollisionDispatch/btManifoldResult.h CollisionDispatch/btSimulationIslandManager.h CollisionDispatch/btSphereBoxCollisionAlgorithm.h CollisionDispatch/btSphereSphereCollisionAlgorithm.h CollisionDispatch/btSphereTriangleCollisionAlgorithm.h CollisionDispatch/btUnionFind.h CollisionDispatch/SphereTriangleDetector.h ) SET(CollisionShapes_HDRS CollisionShapes/btBoxShape.h CollisionShapes/btBox2dShape.h CollisionShapes/btBvhTriangleMeshShape.h CollisionShapes/btCapsuleShape.h CollisionShapes/btCollisionMargin.h CollisionShapes/btCollisionShape.h CollisionShapes/btCompoundShape.h CollisionShapes/btConcaveShape.h CollisionShapes/btConeShape.h CollisionShapes/btConvexHullShape.h CollisionShapes/btConvexInternalShape.h CollisionShapes/btConvexPointCloudShape.h CollisionShapes/btConvexShape.h CollisionShapes/btConvex2dShape.h CollisionShapes/btConvexTriangleMeshShape.h CollisionShapes/btCylinderShape.h CollisionShapes/btEmptyShape.h CollisionShapes/btHeightfieldTerrainShape.h CollisionShapes/btMaterial.h CollisionShapes/btMinkowskiSumShape.h CollisionShapes/btMultimaterialTriangleMeshShape.h CollisionShapes/btMultiSphereShape.h CollisionShapes/btOptimizedBvh.h CollisionShapes/btPolyhedralConvexShape.h CollisionShapes/btScaledBvhTriangleMeshShape.h CollisionShapes/btShapeHull.h CollisionShapes/btSphereShape.h CollisionShapes/btStaticPlaneShape.h CollisionShapes/btStridingMeshInterface.h CollisionShapes/btTetrahedronShape.h CollisionShapes/btTriangleBuffer.h CollisionShapes/btTriangleCallback.h CollisionShapes/btTriangleIndexVertexArray.h CollisionShapes/btTriangleIndexVertexMaterialArray.h CollisionShapes/btTriangleMesh.h CollisionShapes/btTriangleMeshShape.h CollisionShapes/btTriangleShape.h CollisionShapes/btUniformScalingShape.h ) SET(Gimpact_HDRS Gimpact/btBoxCollision.h Gimpact/btClipPolygon.h Gimpact/btContactProcessing.h Gimpact/btGenericPoolAllocator.h Gimpact/btGeometryOperations.h Gimpact/btGImpactBvh.h Gimpact/btGImpactCollisionAlgorithm.h Gimpact/btGImpactMassUtil.h Gimpact/btGImpactQuantizedBvh.h Gimpact/btGImpactShape.h Gimpact/btQuantization.h Gimpact/btTriangleShapeEx.h Gimpact/gim_array.h Gimpact/gim_basic_geometry_operations.h Gimpact/gim_bitset.h Gimpact/gim_box_collision.h Gimpact/gim_box_set.h Gimpact/gim_clip_polygon.h Gimpact/gim_contact.h Gimpact/gim_geom_types.h Gimpact/gim_geometry.h Gimpact/gim_hash_table.h Gimpact/gim_linear_math.h Gimpact/gim_math.h Gimpact/gim_memory.h Gimpact/gim_radixsort.h Gimpact/gim_tri_collision.h ) SET(NarrowPhaseCollision_HDRS NarrowPhaseCollision/btContinuousConvexCollision.h NarrowPhaseCollision/btConvexCast.h NarrowPhaseCollision/btConvexPenetrationDepthSolver.h NarrowPhaseCollision/btDiscreteCollisionDetectorInterface.h NarrowPhaseCollision/btGjkConvexCast.h NarrowPhaseCollision/btGjkEpa2.h NarrowPhaseCollision/btGjkEpaPenetrationDepthSolver.h NarrowPhaseCollision/btGjkPairDetector.h NarrowPhaseCollision/btManifoldPoint.h NarrowPhaseCollision/btMinkowskiPenetrationDepthSolver.h NarrowPhaseCollision/btPersistentManifold.h NarrowPhaseCollision/btPointCollector.h NarrowPhaseCollision/btRaycastCallback.h NarrowPhaseCollision/btSimplexSolverInterface.h NarrowPhaseCollision/btSubSimplexConvexCast.h NarrowPhaseCollision/btVoronoiSimplexSolver.h ) SET(BulletCollision_HDRS ${Root_HDRS} ${BroadphaseCollision_HDRS} ${CollisionDispatch_HDRS} ${CollisionShapes_HDRS} ${Gimpact_HDRS} ${NarrowPhaseCollision_HDRS} ) ADD_LIBRARY(BulletCollision ${BulletCollision_SRCS} ${BulletCollision_HDRS}) SET_TARGET_PROPERTIES(BulletCollision PROPERTIES VERSION ${BULLET_VERSION}) SET_TARGET_PROPERTIES(BulletCollision PROPERTIES SOVERSION ${BULLET_VERSION}) IF (BUILD_SHARED_LIBS) TARGET_LINK_LIBRARIES(BulletCollision LinearMath) ENDIF (BUILD_SHARED_LIBS) #INSTALL of other files requires CMake 2.6 IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) INSTALL(TARGETS BulletCollision DESTINATION .) ELSE (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) INSTALL(TARGETS BulletCollision DESTINATION lib) INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DESTINATION include FILES_MATCHING PATTERN "*.h") INSTALL(FILES ../btBulletCollisionCommon.h DESTINATION include/BulletCollision) ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) SET_TARGET_PROPERTIES(BulletCollision PROPERTIES FRAMEWORK true) SET_TARGET_PROPERTIES(BulletCollision PROPERTIES PUBLIC_HEADER "${Root_HDRS}") # Have to list out sub-directories manually: SET_PROPERTY(SOURCE ${BroadphaseCollision_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/BroadphaseCollision) SET_PROPERTY(SOURCE ${CollisionDispatch_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/CollisionDispatch) SET_PROPERTY(SOURCE ${CollisionShapes_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/CollisionShapes) SET_PROPERTY(SOURCE ${Gimpact_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/Gimpact) SET_PROPERTY(SOURCE ${NarrowPhaseCollision_HDRS} PROPERTY MACOSX_PACKAGE_LOCATION Headers/NarrowPhaseCollision) ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) critterding-beta12.1/src/utils/bullet/LinearMath/0000755000175000017500000000000011347266042021004 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/LinearMath/btTransform.h0000644000175000017500000002112511344267705023463 0ustar bobkebobke/* Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ 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 btTransform_H #define btTransform_H #include "btMatrix3x3.h" #ifdef BT_USE_DOUBLE_PRECISION #define btTransformData btTransformDoubleData #else #define btTransformData btTransformFloatData #endif /**@brief The btTransform class supports rigid transforms with only translation and rotation and no scaling/shear. *It can be used in combination with btVector3, btQuaternion and btMatrix3x3 linear algebra classes. */ class btTransform { ///Storage for the rotation btMatrix3x3 m_basis; ///Storage for the translation btVector3 m_origin; public: /**@brief No initialization constructor */ btTransform() {} /**@brief Constructor from btQuaternion (optional btVector3 ) * @param q Rotation from quaternion * @param c Translation from Vector (default 0,0,0) */ explicit SIMD_FORCE_INLINE btTransform(const btQuaternion& q, const btVector3& c = btVector3(btScalar(0), btScalar(0), btScalar(0))) : m_basis(q), m_origin(c) {} /**@brief Constructor from btMatrix3x3 (optional btVector3) * @param b Rotation from Matrix * @param c Translation from Vector default (0,0,0)*/ explicit SIMD_FORCE_INLINE btTransform(const btMatrix3x3& b, const btVector3& c = btVector3(btScalar(0), btScalar(0), btScalar(0))) : m_basis(b), m_origin(c) {} /**@brief Copy constructor */ SIMD_FORCE_INLINE btTransform (const btTransform& other) : m_basis(other.m_basis), m_origin(other.m_origin) { } /**@brief Assignment Operator */ SIMD_FORCE_INLINE btTransform& operator=(const btTransform& other) { m_basis = other.m_basis; m_origin = other.m_origin; return *this; } /**@brief Set the current transform as the value of the product of two transforms * @param t1 Transform 1 * @param t2 Transform 2 * This = Transform1 * Transform2 */ SIMD_FORCE_INLINE void mult(const btTransform& t1, const btTransform& t2) { m_basis = t1.m_basis * t2.m_basis; m_origin = t1(t2.m_origin); } /* void multInverseLeft(const btTransform& t1, const btTransform& t2) { btVector3 v = t2.m_origin - t1.m_origin; m_basis = btMultTransposeLeft(t1.m_basis, t2.m_basis); m_origin = v * t1.m_basis; } */ /**@brief Return the transform of the vector */ SIMD_FORCE_INLINE btVector3 operator()(const btVector3& x) const { return btVector3(m_basis[0].dot(x) + m_origin.x(), m_basis[1].dot(x) + m_origin.y(), m_basis[2].dot(x) + m_origin.z()); } /**@brief Return the transform of the vector */ SIMD_FORCE_INLINE btVector3 operator*(const btVector3& x) const { return (*this)(x); } /**@brief Return the transform of the btQuaternion */ SIMD_FORCE_INLINE btQuaternion operator*(const btQuaternion& q) const { return getRotation() * q; } /**@brief Return the basis matrix for the rotation */ SIMD_FORCE_INLINE btMatrix3x3& getBasis() { return m_basis; } /**@brief Return the basis matrix for the rotation */ SIMD_FORCE_INLINE const btMatrix3x3& getBasis() const { return m_basis; } /**@brief Return the origin vector translation */ SIMD_FORCE_INLINE btVector3& getOrigin() { return m_origin; } /**@brief Return the origin vector translation */ SIMD_FORCE_INLINE const btVector3& getOrigin() const { return m_origin; } /**@brief Return a quaternion representing the rotation */ btQuaternion getRotation() const { btQuaternion q; m_basis.getRotation(q); return q; } /**@brief Set from an array * @param m A pointer to a 15 element array (12 rotation(row major padded on the right by 1), and 3 translation */ void setFromOpenGLMatrix(const btScalar *m) { m_basis.setFromOpenGLSubMatrix(m); m_origin.setValue(m[12],m[13],m[14]); } /**@brief Fill an array representation * @param m A pointer to a 15 element array (12 rotation(row major padded on the right by 1), and 3 translation */ void getOpenGLMatrix(btScalar *m) const { m_basis.getOpenGLSubMatrix(m); m[12] = m_origin.x(); m[13] = m_origin.y(); m[14] = m_origin.z(); m[15] = btScalar(1.0); } /**@brief Set the translational element * @param origin The vector to set the translation to */ SIMD_FORCE_INLINE void setOrigin(const btVector3& origin) { m_origin = origin; } SIMD_FORCE_INLINE btVector3 invXform(const btVector3& inVec) const; /**@brief Set the rotational element by btMatrix3x3 */ SIMD_FORCE_INLINE void setBasis(const btMatrix3x3& basis) { m_basis = basis; } /**@brief Set the rotational element by btQuaternion */ SIMD_FORCE_INLINE void setRotation(const btQuaternion& q) { m_basis.setRotation(q); } /**@brief Set this transformation to the identity */ void setIdentity() { m_basis.setIdentity(); m_origin.setValue(btScalar(0.0), btScalar(0.0), btScalar(0.0)); } /**@brief Multiply this Transform by another(this = this * another) * @param t The other transform */ btTransform& operator*=(const btTransform& t) { m_origin += m_basis * t.m_origin; m_basis *= t.m_basis; return *this; } /**@brief Return the inverse of this transform */ btTransform inverse() const { btMatrix3x3 inv = m_basis.transpose(); return btTransform(inv, inv * -m_origin); } /**@brief Return the inverse of this transform times the other transform * @param t The other transform * return this.inverse() * the other */ btTransform inverseTimes(const btTransform& t) const; /**@brief Return the product of this transform and the other */ btTransform operator*(const btTransform& t) const; /**@brief Return an identity transform */ static const btTransform& getIdentity() { static const btTransform identityTransform(btMatrix3x3::getIdentity()); return identityTransform; } void serialize(struct btTransformData& dataOut) const; void serializeFloat(struct btTransformFloatData& dataOut) const; void deSerialize(const struct btTransformData& dataIn); void deSerializeDouble(const struct btTransformDoubleData& dataIn); void deSerializeFloat(const struct btTransformFloatData& dataIn); }; SIMD_FORCE_INLINE btVector3 btTransform::invXform(const btVector3& inVec) const { btVector3 v = inVec - m_origin; return (m_basis.transpose() * v); } SIMD_FORCE_INLINE btTransform btTransform::inverseTimes(const btTransform& t) const { btVector3 v = t.getOrigin() - m_origin; return btTransform(m_basis.transposeTimes(t.m_basis), v * m_basis); } SIMD_FORCE_INLINE btTransform btTransform::operator*(const btTransform& t) const { return btTransform(m_basis * t.m_basis, (*this)(t.m_origin)); } /**@brief Test if two transforms have all elements equal */ SIMD_FORCE_INLINE bool operator==(const btTransform& t1, const btTransform& t2) { return ( t1.getBasis() == t2.getBasis() && t1.getOrigin() == t2.getOrigin() ); } ///for serialization struct btTransformFloatData { btMatrix3x3FloatData m_basis; btVector3FloatData m_origin; }; struct btTransformDoubleData { btMatrix3x3DoubleData m_basis; btVector3DoubleData m_origin; }; SIMD_FORCE_INLINE void btTransform::serialize(btTransformData& dataOut) const { m_basis.serialize(dataOut.m_basis); m_origin.serialize(dataOut.m_origin); } SIMD_FORCE_INLINE void btTransform::serializeFloat(btTransformFloatData& dataOut) const { m_basis.serializeFloat(dataOut.m_basis); m_origin.serializeFloat(dataOut.m_origin); } SIMD_FORCE_INLINE void btTransform::deSerialize(const btTransformData& dataIn) { m_basis.deSerialize(dataIn.m_basis); m_origin.deSerialize(dataIn.m_origin); } SIMD_FORCE_INLINE void btTransform::deSerializeFloat(const btTransformFloatData& dataIn) { m_basis.deSerializeFloat(dataIn.m_basis); m_origin.deSerializeFloat(dataIn.m_origin); } SIMD_FORCE_INLINE void btTransform::deSerializeDouble(const btTransformDoubleData& dataIn) { m_basis.deSerializeDouble(dataIn.m_basis); m_origin.deSerializeDouble(dataIn.m_origin); } #endif critterding-beta12.1/src/utils/bullet/LinearMath/btSerializer.h0000644000175000017500000003035411344271164023617 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 BT_SERIALIZER_H #define BT_SERIALIZER_H #include "btScalar.h" // has definitions like SIMD_FORCE_INLINE #include "btStackAlloc.h" #include "btHashMap.h" #if !defined( __CELLOS_LV2__) && !defined(__MWERKS__) #include #endif #include ///only the 32bit versions for now extern unsigned char sBulletDNAstr[]; extern int sBulletDNAlen; extern unsigned char sBulletDNAstr64[]; extern int sBulletDNAlen64; SIMD_FORCE_INLINE int btStrLen(const char* str) { if (!str) return(0); int len = 0; while (*str != 0) { str++; len++; } return len; } class btChunk { public: int m_chunkCode; int m_length; void *m_oldPtr; int m_dna_nr; int m_number; }; enum btSerializationFlags { BT_SERIALIZE_NO_BVH = 1, BT_SERIALIZE_NO_TRIANGLEINFOMAP = 2, BT_SERIALIZE_NO_DUPLICATE_ASSERT = 4 }; class btSerializer { public: virtual ~btSerializer() {} virtual const unsigned char* getBufferPointer() const = 0; virtual int getCurrentBufferSize() const = 0; virtual btChunk* allocate(size_t size, int numElements) = 0; virtual void finalizeChunk(btChunk* chunk, const char* structType, int chunkCode,void* oldPtr)= 0; virtual void* findPointer(void* oldPtr) = 0; virtual void* getUniquePointer(void*oldPtr) = 0; virtual void startSerialization() = 0; virtual void finishSerialization() = 0; virtual const char* findNameForPointer(const void* ptr) const = 0; virtual void registerNameForPointer(const void* ptr, const char* name) = 0; virtual void serializeName(const char* ptr) = 0; virtual int getSerializationFlags() const = 0; virtual void setSerializationFlags(int flags) = 0; }; #define BT_HEADER_LENGTH 12 #if defined(__sgi) || defined (__sparc) || defined (__sparc__) || defined (__PPC__) || defined (__ppc__) || defined (__BIG_ENDIAN__) # define MAKE_ID(a,b,c,d) ( (int)(a)<<24 | (int)(b)<<16 | (c)<<8 | (d) ) #else # define MAKE_ID(a,b,c,d) ( (int)(d)<<24 | (int)(c)<<16 | (b)<<8 | (a) ) #endif #define BT_COLLISIONOBJECT_CODE MAKE_ID('C','O','B','J') #define BT_RIGIDBODY_CODE MAKE_ID('R','B','D','Y') #define BT_CONSTRAINT_CODE MAKE_ID('C','O','N','S') #define BT_BOXSHAPE_CODE MAKE_ID('B','O','X','S') #define BT_QUANTIZED_BVH_CODE MAKE_ID('Q','B','V','H') #define BT_TRIANLGE_INFO_MAP MAKE_ID('T','M','A','P') #define BT_SHAPE_CODE MAKE_ID('S','H','A','P') #define BT_ARRAY_CODE MAKE_ID('A','R','A','Y') struct btPointerUid { union { void* m_ptr; int m_uniqueIds[2]; }; }; class btDefaultSerializer : public btSerializer { btAlignedObjectArray mTypes; btAlignedObjectArray mStructs; btAlignedObjectArray mTlens; btHashMap mStructReverse; btHashMap mTypeLookup; btHashMap m_chunkP; btHashMap m_nameMap; btHashMap m_uniquePointers; int m_uniqueIdGenerator; int m_totalSize; unsigned char* m_buffer; int m_currentSize; void* m_dna; int m_dnaLength; int m_serializationFlags; btAlignedObjectArray m_chunkPtrs; protected: virtual void* findPointer(void* oldPtr) { void** ptr = m_chunkP.find(oldPtr); if (ptr && *ptr) return *ptr; return 0; } void writeDNA() { unsigned char* dnaTarget = m_buffer+m_currentSize; memcpy(dnaTarget,m_dna,m_dnaLength); m_currentSize += m_dnaLength; } int getReverseType(const char *type) const { btHashString key(type); const int* valuePtr = mTypeLookup.find(key); if (valuePtr) return *valuePtr; return -1; } void initDNA(const char* bdnaOrg,int dnalen) { ///was already initialized if (m_dna) return; int littleEndian= 1; littleEndian= ((char*)&littleEndian)[0]; m_dna = btAlignedAlloc(dnalen,16); memcpy(m_dna,bdnaOrg,dnalen); m_dnaLength = dnalen; int *intPtr=0; short *shtPtr=0; char *cp = 0;int dataLen =0;long nr=0; intPtr = (int*)m_dna; /* SDNA (4 bytes) (magic number) NAME (4 bytes) (4 bytes) amount of names (int) */ if (strncmp((const char*)m_dna, "SDNA", 4)==0) { // skip ++ NAME intPtr++; intPtr++; } // Parse names if (!littleEndian) *intPtr = btSwapEndian(*intPtr); dataLen = *intPtr; intPtr++; cp = (char*)intPtr; int i; for ( i=0; i amount of types (int) */ intPtr = (int*)cp; assert(strncmp(cp, "TYPE", 4)==0); intPtr++; if (!littleEndian) *intPtr = btSwapEndian(*intPtr); dataLen = *intPtr; intPtr++; cp = (char*)intPtr; for (i=0; i (short) the lengths of types */ // Parse type lens intPtr = (int*)cp; assert(strncmp(cp, "TLEN", 4)==0); intPtr++; dataLen = (int)mTypes.size(); shtPtr = (short*)intPtr; for (i=0; i amount of structs (int) */ intPtr = (int*)shtPtr; cp = (char*)intPtr; assert(strncmp(cp, "STRC", 4)==0); intPtr++; if (!littleEndian) *intPtr = btSwapEndian(*intPtr); dataLen = *intPtr ; intPtr++; shtPtr = (short*)intPtr; for (i=0; im_ptr; } m_uniqueIdGenerator++; btPointerUid uid; uid.m_uniqueIds[0] = m_uniqueIdGenerator; uid.m_uniqueIds[1] = m_uniqueIdGenerator; m_uniquePointers.insert(oldPtr,uid); return uid.m_ptr; } virtual const unsigned char* getBufferPointer() const { return m_buffer; } virtual int getCurrentBufferSize() const { return m_currentSize; } virtual void finalizeChunk(btChunk* chunk, const char* structType, int chunkCode,void* oldPtr) { if (!(m_serializationFlags&BT_SERIALIZE_NO_DUPLICATE_ASSERT)) { btAssert(!findPointer(oldPtr)); } chunk->m_dna_nr = getReverseType(structType); chunk->m_chunkCode = chunkCode; void* uniquePtr = getUniquePointer(oldPtr); m_chunkP.insert(oldPtr,uniquePtr);//chunk->m_oldPtr); chunk->m_oldPtr = uniquePtr;//oldPtr; } virtual btChunk* allocate(size_t size, int numElements) { unsigned char* ptr = m_buffer+m_currentSize; m_currentSize += int(size)*numElements+sizeof(btChunk); btAssert(m_currentSizem_chunkCode = 0; chunk->m_oldPtr = data; chunk->m_length = int(size)*numElements; chunk->m_number = numElements; m_chunkPtrs.push_back(chunk); return chunk; } virtual const char* findNameForPointer(const void* ptr) const { const char*const * namePtr = m_nameMap.find(ptr); if (namePtr && *namePtr) return *namePtr; return 0; } virtual void registerNameForPointer(const void* ptr, const char* name) { m_nameMap.insert(ptr,name); } virtual void serializeName(const char* name) { if (name) { //don't serialize name twice if (findPointer((void*)name)) return; int len = btStrLen(name); if (len) { int newLen = len+1; int padding = ((newLen+3)&~3)-newLen; newLen += padding; //serialize name string now btChunk* chunk = allocate(sizeof(char),newLen); char* destinationName = (char*)chunk->m_oldPtr; for (int i=0;i(m_elemSize*m_maxElements),16); unsigned char* p = m_pool; m_firstFree = p; m_freeCount = m_maxElements; int count = m_maxElements; while (--count) { *(void**)p = (p + m_elemSize); p += m_elemSize; } *(void**)p = 0; } ~btPoolAllocator() { btAlignedFree( m_pool); } int getFreeCount() const { return m_freeCount; } void* allocate(int size) { // release mode fix (void)size; btAssert(!size || size<=m_elemSize); btAssert(m_freeCount>0); void* result = m_firstFree; m_firstFree = *(void**)m_firstFree; --m_freeCount; return result; } bool validPtr(void* ptr) { if (ptr) { if (((unsigned char*)ptr >= m_pool && (unsigned char*)ptr < m_pool + m_maxElements * m_elemSize)) { return true; } } return false; } void freeMemory(void* ptr) { if (ptr) { btAssert((unsigned char*)ptr >= m_pool && (unsigned char*)ptr < m_pool + m_maxElements * m_elemSize); *(void**)ptr = m_firstFree; m_firstFree = ptr; ++m_freeCount; } } int getElementSize() const { return m_elemSize; } }; #endif //_BT_POOL_ALLOCATOR_H critterding-beta12.1/src/utils/bullet/LinearMath/btVector3.h0000644000175000017500000005013011344267705023033 0ustar bobkebobke/* Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ 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 SIMD__VECTOR3_H #define SIMD__VECTOR3_H #include "btScalar.h" #include "btMinMax.h" #ifdef BT_USE_DOUBLE_PRECISION #define btVector3Data btVector3DoubleData #define btVector3DataName "btVector3DoubleData" #else #define btVector3Data btVector3FloatData #define btVector3DataName "btVector3FloatData" #endif //BT_USE_DOUBLE_PRECISION /**@brief btVector3 can be used to represent 3D points and vectors. * It has an un-used w component to suit 16-byte alignment when btVector3 is stored in containers. This extra component can be used by derived classes (Quaternion?) or by user * Ideally, this class should be replaced by a platform optimized SIMD version that keeps the data in registers */ ATTRIBUTE_ALIGNED16(class) btVector3 { public: #if defined (__SPU__) && defined (__CELLOS_LV2__) btScalar m_floats[4]; public: SIMD_FORCE_INLINE const vec_float4& get128() const { return *((const vec_float4*)&m_floats[0]); } public: #else //__CELLOS_LV2__ __SPU__ #ifdef BT_USE_SSE // _WIN32 union { __m128 mVec128; btScalar m_floats[4]; }; SIMD_FORCE_INLINE __m128 get128() const { return mVec128; } SIMD_FORCE_INLINE void set128(__m128 v128) { mVec128 = v128; } #else btScalar m_floats[4]; #endif #endif //__CELLOS_LV2__ __SPU__ public: /**@brief No initialization constructor */ SIMD_FORCE_INLINE btVector3() {} /**@brief Constructor from scalars * @param x X value * @param y Y value * @param z Z value */ SIMD_FORCE_INLINE btVector3(const btScalar& x, const btScalar& y, const btScalar& z) { m_floats[0] = x; m_floats[1] = y; m_floats[2] = z; m_floats[3] = btScalar(0.); } /**@brief Add a vector to this one * @param The vector to add to this one */ SIMD_FORCE_INLINE btVector3& operator+=(const btVector3& v) { m_floats[0] += v.m_floats[0]; m_floats[1] += v.m_floats[1];m_floats[2] += v.m_floats[2]; return *this; } /**@brief Subtract a vector from this one * @param The vector to subtract */ SIMD_FORCE_INLINE btVector3& operator-=(const btVector3& v) { m_floats[0] -= v.m_floats[0]; m_floats[1] -= v.m_floats[1];m_floats[2] -= v.m_floats[2]; return *this; } /**@brief Scale the vector * @param s Scale factor */ SIMD_FORCE_INLINE btVector3& operator*=(const btScalar& s) { m_floats[0] *= s; m_floats[1] *= s;m_floats[2] *= s; return *this; } /**@brief Inversely scale the vector * @param s Scale factor to divide by */ SIMD_FORCE_INLINE btVector3& operator/=(const btScalar& s) { btFullAssert(s != btScalar(0.0)); return *this *= btScalar(1.0) / s; } /**@brief Return the dot product * @param v The other vector in the dot product */ SIMD_FORCE_INLINE btScalar dot(const btVector3& v) const { return m_floats[0] * v.m_floats[0] + m_floats[1] * v.m_floats[1] +m_floats[2] * v.m_floats[2]; } /**@brief Return the length of the vector squared */ SIMD_FORCE_INLINE btScalar length2() const { return dot(*this); } /**@brief Return the length of the vector */ SIMD_FORCE_INLINE btScalar length() const { return btSqrt(length2()); } /**@brief Return the distance squared between the ends of this and another vector * This is symantically treating the vector like a point */ SIMD_FORCE_INLINE btScalar distance2(const btVector3& v) const; /**@brief Return the distance between the ends of this and another vector * This is symantically treating the vector like a point */ SIMD_FORCE_INLINE btScalar distance(const btVector3& v) const; /**@brief Normalize this vector * x^2 + y^2 + z^2 = 1 */ SIMD_FORCE_INLINE btVector3& normalize() { return *this /= length(); } /**@brief Return a normalized version of this vector */ SIMD_FORCE_INLINE btVector3 normalized() const; /**@brief Rotate this vector * @param wAxis The axis to rotate about * @param angle The angle to rotate by */ SIMD_FORCE_INLINE btVector3 rotate( const btVector3& wAxis, const btScalar angle ); /**@brief Return the angle between this and another vector * @param v The other vector */ SIMD_FORCE_INLINE btScalar angle(const btVector3& v) const { btScalar s = btSqrt(length2() * v.length2()); btFullAssert(s != btScalar(0.0)); return btAcos(dot(v) / s); } /**@brief Return a vector will the absolute values of each element */ SIMD_FORCE_INLINE btVector3 absolute() const { return btVector3( btFabs(m_floats[0]), btFabs(m_floats[1]), btFabs(m_floats[2])); } /**@brief Return the cross product between this and another vector * @param v The other vector */ SIMD_FORCE_INLINE btVector3 cross(const btVector3& v) const { return btVector3( m_floats[1] * v.m_floats[2] -m_floats[2] * v.m_floats[1], m_floats[2] * v.m_floats[0] - m_floats[0] * v.m_floats[2], m_floats[0] * v.m_floats[1] - m_floats[1] * v.m_floats[0]); } SIMD_FORCE_INLINE btScalar triple(const btVector3& v1, const btVector3& v2) const { return m_floats[0] * (v1.m_floats[1] * v2.m_floats[2] - v1.m_floats[2] * v2.m_floats[1]) + m_floats[1] * (v1.m_floats[2] * v2.m_floats[0] - v1.m_floats[0] * v2.m_floats[2]) + m_floats[2] * (v1.m_floats[0] * v2.m_floats[1] - v1.m_floats[1] * v2.m_floats[0]); } /**@brief Return the axis with the smallest value * Note return values are 0,1,2 for x, y, or z */ SIMD_FORCE_INLINE int minAxis() const { return m_floats[0] < m_floats[1] ? (m_floats[0] return this, t=1 => return other) */ SIMD_FORCE_INLINE btVector3 lerp(const btVector3& v, const btScalar& t) const { return btVector3(m_floats[0] + (v.m_floats[0] - m_floats[0]) * t, m_floats[1] + (v.m_floats[1] - m_floats[1]) * t, m_floats[2] + (v.m_floats[2] -m_floats[2]) * t); } /**@brief Elementwise multiply this vector by the other * @param v The other vector */ SIMD_FORCE_INLINE btVector3& operator*=(const btVector3& v) { m_floats[0] *= v.m_floats[0]; m_floats[1] *= v.m_floats[1];m_floats[2] *= v.m_floats[2]; return *this; } /**@brief Return the x value */ SIMD_FORCE_INLINE const btScalar& getX() const { return m_floats[0]; } /**@brief Return the y value */ SIMD_FORCE_INLINE const btScalar& getY() const { return m_floats[1]; } /**@brief Return the z value */ SIMD_FORCE_INLINE const btScalar& getZ() const { return m_floats[2]; } /**@brief Set the x value */ SIMD_FORCE_INLINE void setX(btScalar x) { m_floats[0] = x;}; /**@brief Set the y value */ SIMD_FORCE_INLINE void setY(btScalar y) { m_floats[1] = y;}; /**@brief Set the z value */ SIMD_FORCE_INLINE void setZ(btScalar z) {m_floats[2] = z;}; /**@brief Set the w value */ SIMD_FORCE_INLINE void setW(btScalar w) { m_floats[3] = w;}; /**@brief Return the x value */ SIMD_FORCE_INLINE const btScalar& x() const { return m_floats[0]; } /**@brief Return the y value */ SIMD_FORCE_INLINE const btScalar& y() const { return m_floats[1]; } /**@brief Return the z value */ SIMD_FORCE_INLINE const btScalar& z() const { return m_floats[2]; } /**@brief Return the w value */ SIMD_FORCE_INLINE const btScalar& w() const { return m_floats[3]; } //SIMD_FORCE_INLINE btScalar& operator[](int i) { return (&m_floats[0])[i]; } //SIMD_FORCE_INLINE const btScalar& operator[](int i) const { return (&m_floats[0])[i]; } ///operator btScalar*() replaces operator[], using implicit conversion. We added operator != and operator == to avoid pointer comparisons. SIMD_FORCE_INLINE operator btScalar *() { return &m_floats[0]; } SIMD_FORCE_INLINE operator const btScalar *() const { return &m_floats[0]; } SIMD_FORCE_INLINE bool operator==(const btVector3& other) const { return ((m_floats[3]==other.m_floats[3]) && (m_floats[2]==other.m_floats[2]) && (m_floats[1]==other.m_floats[1]) && (m_floats[0]==other.m_floats[0])); } SIMD_FORCE_INLINE bool operator!=(const btVector3& other) const { return !(*this == other); } /**@brief Set each element to the max of the current values and the values of another btVector3 * @param other The other btVector3 to compare with */ SIMD_FORCE_INLINE void setMax(const btVector3& other) { btSetMax(m_floats[0], other.m_floats[0]); btSetMax(m_floats[1], other.m_floats[1]); btSetMax(m_floats[2], other.m_floats[2]); btSetMax(m_floats[3], other.w()); } /**@brief Set each element to the min of the current values and the values of another btVector3 * @param other The other btVector3 to compare with */ SIMD_FORCE_INLINE void setMin(const btVector3& other) { btSetMin(m_floats[0], other.m_floats[0]); btSetMin(m_floats[1], other.m_floats[1]); btSetMin(m_floats[2], other.m_floats[2]); btSetMin(m_floats[3], other.w()); } SIMD_FORCE_INLINE void setValue(const btScalar& x, const btScalar& y, const btScalar& z) { m_floats[0]=x; m_floats[1]=y; m_floats[2]=z; m_floats[3] = btScalar(0.); } void getSkewSymmetricMatrix(btVector3* v0,btVector3* v1,btVector3* v2) const { v0->setValue(0. ,-z() ,y()); v1->setValue(z() ,0. ,-x()); v2->setValue(-y() ,x() ,0.); } void setZero() { setValue(btScalar(0.),btScalar(0.),btScalar(0.)); } SIMD_FORCE_INLINE bool isZero() const { return m_floats[0] == btScalar(0) && m_floats[1] == btScalar(0) && m_floats[2] == btScalar(0); } SIMD_FORCE_INLINE bool fuzzyZero() const { return length2() < SIMD_EPSILON; } SIMD_FORCE_INLINE void serialize(struct btVector3Data& dataOut) const; SIMD_FORCE_INLINE void deSerialize(const struct btVector3Data& dataIn); SIMD_FORCE_INLINE void serializeFloat(struct btVector3FloatData& dataOut) const; SIMD_FORCE_INLINE void deSerializeFloat(const struct btVector3FloatData& dataIn); SIMD_FORCE_INLINE void serializeDouble(struct btVector3DoubleData& dataOut) const; SIMD_FORCE_INLINE void deSerializeDouble(const struct btVector3DoubleData& dataIn); }; /**@brief Return the sum of two vectors (Point symantics)*/ SIMD_FORCE_INLINE btVector3 operator+(const btVector3& v1, const btVector3& v2) { return btVector3(v1.m_floats[0] + v2.m_floats[0], v1.m_floats[1] + v2.m_floats[1], v1.m_floats[2] + v2.m_floats[2]); } /**@brief Return the elementwise product of two vectors */ SIMD_FORCE_INLINE btVector3 operator*(const btVector3& v1, const btVector3& v2) { return btVector3(v1.m_floats[0] * v2.m_floats[0], v1.m_floats[1] * v2.m_floats[1], v1.m_floats[2] * v2.m_floats[2]); } /**@brief Return the difference between two vectors */ SIMD_FORCE_INLINE btVector3 operator-(const btVector3& v1, const btVector3& v2) { return btVector3(v1.m_floats[0] - v2.m_floats[0], v1.m_floats[1] - v2.m_floats[1], v1.m_floats[2] - v2.m_floats[2]); } /**@brief Return the negative of the vector */ SIMD_FORCE_INLINE btVector3 operator-(const btVector3& v) { return btVector3(-v.m_floats[0], -v.m_floats[1], -v.m_floats[2]); } /**@brief Return the vector scaled by s */ SIMD_FORCE_INLINE btVector3 operator*(const btVector3& v, const btScalar& s) { return btVector3(v.m_floats[0] * s, v.m_floats[1] * s, v.m_floats[2] * s); } /**@brief Return the vector scaled by s */ SIMD_FORCE_INLINE btVector3 operator*(const btScalar& s, const btVector3& v) { return v * s; } /**@brief Return the vector inversely scaled by s */ SIMD_FORCE_INLINE btVector3 operator/(const btVector3& v, const btScalar& s) { btFullAssert(s != btScalar(0.0)); return v * (btScalar(1.0) / s); } /**@brief Return the vector inversely scaled by s */ SIMD_FORCE_INLINE btVector3 operator/(const btVector3& v1, const btVector3& v2) { return btVector3(v1.m_floats[0] / v2.m_floats[0],v1.m_floats[1] / v2.m_floats[1],v1.m_floats[2] / v2.m_floats[2]); } /**@brief Return the dot product between two vectors */ SIMD_FORCE_INLINE btScalar btDot(const btVector3& v1, const btVector3& v2) { return v1.dot(v2); } /**@brief Return the distance squared between two vectors */ SIMD_FORCE_INLINE btScalar btDistance2(const btVector3& v1, const btVector3& v2) { return v1.distance2(v2); } /**@brief Return the distance between two vectors */ SIMD_FORCE_INLINE btScalar btDistance(const btVector3& v1, const btVector3& v2) { return v1.distance(v2); } /**@brief Return the angle between two vectors */ SIMD_FORCE_INLINE btScalar btAngle(const btVector3& v1, const btVector3& v2) { return v1.angle(v2); } /**@brief Return the cross product of two vectors */ SIMD_FORCE_INLINE btVector3 btCross(const btVector3& v1, const btVector3& v2) { return v1.cross(v2); } SIMD_FORCE_INLINE btScalar btTriple(const btVector3& v1, const btVector3& v2, const btVector3& v3) { return v1.triple(v2, v3); } /**@brief Return the linear interpolation between two vectors * @param v1 One vector * @param v2 The other vector * @param t The ration of this to v (t = 0 => return v1, t=1 => return v2) */ SIMD_FORCE_INLINE btVector3 lerp(const btVector3& v1, const btVector3& v2, const btScalar& t) { return v1.lerp(v2, t); } SIMD_FORCE_INLINE btScalar btVector3::distance2(const btVector3& v) const { return (v - *this).length2(); } SIMD_FORCE_INLINE btScalar btVector3::distance(const btVector3& v) const { return (v - *this).length(); } SIMD_FORCE_INLINE btVector3 btVector3::normalized() const { return *this / length(); } SIMD_FORCE_INLINE btVector3 btVector3::rotate( const btVector3& wAxis, const btScalar angle ) { // wAxis must be a unit lenght vector btVector3 o = wAxis * wAxis.dot( *this ); btVector3 x = *this - o; btVector3 y; y = wAxis.cross( *this ); return ( o + x * btCos( angle ) + y * btSin( angle ) ); } class btVector4 : public btVector3 { public: SIMD_FORCE_INLINE btVector4() {} SIMD_FORCE_INLINE btVector4(const btScalar& x, const btScalar& y, const btScalar& z,const btScalar& w) : btVector3(x,y,z) { m_floats[3] = w; } SIMD_FORCE_INLINE btVector4 absolute4() const { return btVector4( btFabs(m_floats[0]), btFabs(m_floats[1]), btFabs(m_floats[2]), btFabs(m_floats[3])); } btScalar getW() const { return m_floats[3];} SIMD_FORCE_INLINE int maxAxis4() const { int maxIndex = -1; btScalar maxVal = btScalar(-BT_LARGE_FLOAT); if (m_floats[0] > maxVal) { maxIndex = 0; maxVal = m_floats[0]; } if (m_floats[1] > maxVal) { maxIndex = 1; maxVal = m_floats[1]; } if (m_floats[2] > maxVal) { maxIndex = 2; maxVal =m_floats[2]; } if (m_floats[3] > maxVal) { maxIndex = 3; maxVal = m_floats[3]; } return maxIndex; } SIMD_FORCE_INLINE int minAxis4() const { int minIndex = -1; btScalar minVal = btScalar(BT_LARGE_FLOAT); if (m_floats[0] < minVal) { minIndex = 0; minVal = m_floats[0]; } if (m_floats[1] < minVal) { minIndex = 1; minVal = m_floats[1]; } if (m_floats[2] < minVal) { minIndex = 2; minVal =m_floats[2]; } if (m_floats[3] < minVal) { minIndex = 3; minVal = m_floats[3]; } return minIndex; } SIMD_FORCE_INLINE int closestAxis4() const { return absolute4().maxAxis4(); } /**@brief Set x,y,z and zero w * @param x Value of x * @param y Value of y * @param z Value of z */ /* void getValue(btScalar *m) const { m[0] = m_floats[0]; m[1] = m_floats[1]; m[2] =m_floats[2]; } */ /**@brief Set the values * @param x Value of x * @param y Value of y * @param z Value of z * @param w Value of w */ SIMD_FORCE_INLINE void setValue(const btScalar& x, const btScalar& y, const btScalar& z,const btScalar& w) { m_floats[0]=x; m_floats[1]=y; m_floats[2]=z; m_floats[3]=w; } }; ///btSwapVector3Endian swaps vector endianness, useful for network and cross-platform serialization SIMD_FORCE_INLINE void btSwapScalarEndian(const btScalar& sourceVal, btScalar& destVal) { #ifdef BT_USE_DOUBLE_PRECISION unsigned char* dest = (unsigned char*) &destVal; unsigned char* src = (unsigned char*) &sourceVal; dest[0] = src[7]; dest[1] = src[6]; dest[2] = src[5]; dest[3] = src[4]; dest[4] = src[3]; dest[5] = src[2]; dest[6] = src[1]; dest[7] = src[0]; #else unsigned char* dest = (unsigned char*) &destVal; unsigned char* src = (unsigned char*) &sourceVal; dest[0] = src[3]; dest[1] = src[2]; dest[2] = src[1]; dest[3] = src[0]; #endif //BT_USE_DOUBLE_PRECISION } ///btSwapVector3Endian swaps vector endianness, useful for network and cross-platform serialization SIMD_FORCE_INLINE void btSwapVector3Endian(const btVector3& sourceVec, btVector3& destVec) { for (int i=0;i<4;i++) { btSwapScalarEndian(sourceVec[i],destVec[i]); } } ///btUnSwapVector3Endian swaps vector endianness, useful for network and cross-platform serialization SIMD_FORCE_INLINE void btUnSwapVector3Endian(btVector3& vector) { btVector3 swappedVec; for (int i=0;i<4;i++) { btSwapScalarEndian(vector[i],swappedVec[i]); } vector = swappedVec; } SIMD_FORCE_INLINE void btPlaneSpace1 (const btVector3& n, btVector3& p, btVector3& q) { if (btFabs(n.z()) > SIMDSQRT12) { // choose p in y-z plane btScalar a = n[1]*n[1] + n[2]*n[2]; btScalar k = btRecipSqrt (a); p.setValue(0,-n[2]*k,n[1]*k); // set q = n x p q.setValue(a*k,-n[0]*p[2],n[0]*p[1]); } else { // choose p in x-y plane btScalar a = n.x()*n.x() + n.y()*n.y(); btScalar k = btRecipSqrt (a); p.setValue(-n.y()*k,n.x()*k,0); // set q = n x p q.setValue(-n.z()*p.y(),n.z()*p.x(),a*k); } } struct btVector3FloatData { float m_floats[4]; }; struct btVector3DoubleData { double m_floats[4]; }; SIMD_FORCE_INLINE void btVector3::serializeFloat(struct btVector3FloatData& dataOut) const { ///could also do a memcpy, check if it is worth it for (int i=0;i<4;i++) dataOut.m_floats[i] = float(m_floats[i]); } SIMD_FORCE_INLINE void btVector3::deSerializeFloat(const struct btVector3FloatData& dataIn) { for (int i=0;i<4;i++) m_floats[i] = btScalar(dataIn.m_floats[i]); } SIMD_FORCE_INLINE void btVector3::serializeDouble(struct btVector3DoubleData& dataOut) const { ///could also do a memcpy, check if it is worth it for (int i=0;i<4;i++) dataOut.m_floats[i] = double(m_floats[i]); } SIMD_FORCE_INLINE void btVector3::deSerializeDouble(const struct btVector3DoubleData& dataIn) { for (int i=0;i<4;i++) m_floats[i] = btScalar(dataIn.m_floats[i]); } SIMD_FORCE_INLINE void btVector3::serialize(struct btVector3Data& dataOut) const { ///could also do a memcpy, check if it is worth it for (int i=0;i<4;i++) dataOut.m_floats[i] = m_floats[i]; } SIMD_FORCE_INLINE void btVector3::deSerialize(const struct btVector3Data& dataIn) { for (int i=0;i<4;i++) m_floats[i] = dataIn.m_floats[i]; } #endif //SIMD__VECTOR3_H critterding-beta12.1/src/utils/bullet/LinearMath/btGeometryUtil.h0000644000175000017500000000353611337071441024137 0ustar bobkebobke/* Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ 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 BT_GEOMETRY_UTIL_H #define BT_GEOMETRY_UTIL_H #include "btVector3.h" #include "btAlignedObjectArray.h" ///The btGeometryUtil helper class provides a few methods to convert between plane equations and vertices. class btGeometryUtil { public: static void getPlaneEquationsFromVertices(btAlignedObjectArray& vertices, btAlignedObjectArray& planeEquationsOut ); static void getVerticesFromPlaneEquations(const btAlignedObjectArray& planeEquations , btAlignedObjectArray& verticesOut ); static bool isInside(const btAlignedObjectArray& vertices, const btVector3& planeNormal, btScalar margin); static bool isPointInsidePlanes(const btAlignedObjectArray& planeEquations, const btVector3& point, btScalar margin); static bool areVerticesBehindPlane(const btVector3& planeNormal, const btAlignedObjectArray& vertices, btScalar margin); }; #endif //BT_GEOMETRY_UTIL_H critterding-beta12.1/src/utils/bullet/LinearMath/btQuaternion.h0000644000175000017500000003464011344267705023643 0ustar bobkebobke/* Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ 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 SIMD__QUATERNION_H_ #define SIMD__QUATERNION_H_ #include "btVector3.h" #include "btQuadWord.h" /**@brief The btQuaternion implements quaternion to perform linear algebra rotations in combination with btMatrix3x3, btVector3 and btTransform. */ class btQuaternion : public btQuadWord { public: /**@brief No initialization constructor */ btQuaternion() {} // template // explicit Quaternion(const btScalar *v) : Tuple4(v) {} /**@brief Constructor from scalars */ btQuaternion(const btScalar& x, const btScalar& y, const btScalar& z, const btScalar& w) : btQuadWord(x, y, z, w) {} /**@brief Axis angle Constructor * @param axis The axis which the rotation is around * @param angle The magnitude of the rotation around the angle (Radians) */ btQuaternion(const btVector3& axis, const btScalar& angle) { setRotation(axis, angle); } /**@brief Constructor from Euler angles * @param yaw Angle around Y unless BT_EULER_DEFAULT_ZYX defined then Z * @param pitch Angle around X unless BT_EULER_DEFAULT_ZYX defined then Y * @param roll Angle around Z unless BT_EULER_DEFAULT_ZYX defined then X */ btQuaternion(const btScalar& yaw, const btScalar& pitch, const btScalar& roll) { #ifndef BT_EULER_DEFAULT_ZYX setEuler(yaw, pitch, roll); #else setEulerZYX(yaw, pitch, roll); #endif } /**@brief Set the rotation using axis angle notation * @param axis The axis around which to rotate * @param angle The magnitude of the rotation in Radians */ void setRotation(const btVector3& axis, const btScalar& angle) { btScalar d = axis.length(); btAssert(d != btScalar(0.0)); btScalar s = btSin(angle * btScalar(0.5)) / d; setValue(axis.x() * s, axis.y() * s, axis.z() * s, btCos(angle * btScalar(0.5))); } /**@brief Set the quaternion using Euler angles * @param yaw Angle around Y * @param pitch Angle around X * @param roll Angle around Z */ void setEuler(const btScalar& yaw, const btScalar& pitch, const btScalar& roll) { btScalar halfYaw = btScalar(yaw) * btScalar(0.5); btScalar halfPitch = btScalar(pitch) * btScalar(0.5); btScalar halfRoll = btScalar(roll) * btScalar(0.5); btScalar cosYaw = btCos(halfYaw); btScalar sinYaw = btSin(halfYaw); btScalar cosPitch = btCos(halfPitch); btScalar sinPitch = btSin(halfPitch); btScalar cosRoll = btCos(halfRoll); btScalar sinRoll = btSin(halfRoll); setValue(cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw, cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw, sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw, cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw); } /**@brief Set the quaternion using euler angles * @param yaw Angle around Z * @param pitch Angle around Y * @param roll Angle around X */ void setEulerZYX(const btScalar& yaw, const btScalar& pitch, const btScalar& roll) { btScalar halfYaw = btScalar(yaw) * btScalar(0.5); btScalar halfPitch = btScalar(pitch) * btScalar(0.5); btScalar halfRoll = btScalar(roll) * btScalar(0.5); btScalar cosYaw = btCos(halfYaw); btScalar sinYaw = btSin(halfYaw); btScalar cosPitch = btCos(halfPitch); btScalar sinPitch = btSin(halfPitch); btScalar cosRoll = btCos(halfRoll); btScalar sinRoll = btSin(halfRoll); setValue(sinRoll * cosPitch * cosYaw - cosRoll * sinPitch * sinYaw, //x cosRoll * sinPitch * cosYaw + sinRoll * cosPitch * sinYaw, //y cosRoll * cosPitch * sinYaw - sinRoll * sinPitch * cosYaw, //z cosRoll * cosPitch * cosYaw + sinRoll * sinPitch * sinYaw); //formerly yzx } /**@brief Add two quaternions * @param q The quaternion to add to this one */ SIMD_FORCE_INLINE btQuaternion& operator+=(const btQuaternion& q) { m_floats[0] += q.x(); m_floats[1] += q.y(); m_floats[2] += q.z(); m_floats[3] += q.m_floats[3]; return *this; } /**@brief Subtract out a quaternion * @param q The quaternion to subtract from this one */ btQuaternion& operator-=(const btQuaternion& q) { m_floats[0] -= q.x(); m_floats[1] -= q.y(); m_floats[2] -= q.z(); m_floats[3] -= q.m_floats[3]; return *this; } /**@brief Scale this quaternion * @param s The scalar to scale by */ btQuaternion& operator*=(const btScalar& s) { m_floats[0] *= s; m_floats[1] *= s; m_floats[2] *= s; m_floats[3] *= s; return *this; } /**@brief Multiply this quaternion by q on the right * @param q The other quaternion * Equivilant to this = this * q */ btQuaternion& operator*=(const btQuaternion& q) { setValue(m_floats[3] * q.x() + m_floats[0] * q.m_floats[3] + m_floats[1] * q.z() - m_floats[2] * q.y(), m_floats[3] * q.y() + m_floats[1] * q.m_floats[3] + m_floats[2] * q.x() - m_floats[0] * q.z(), m_floats[3] * q.z() + m_floats[2] * q.m_floats[3] + m_floats[0] * q.y() - m_floats[1] * q.x(), m_floats[3] * q.m_floats[3] - m_floats[0] * q.x() - m_floats[1] * q.y() - m_floats[2] * q.z()); return *this; } /**@brief Return the dot product between this quaternion and another * @param q The other quaternion */ btScalar dot(const btQuaternion& q) const { return m_floats[0] * q.x() + m_floats[1] * q.y() + m_floats[2] * q.z() + m_floats[3] * q.m_floats[3]; } /**@brief Return the length squared of the quaternion */ btScalar length2() const { return dot(*this); } /**@brief Return the length of the quaternion */ btScalar length() const { return btSqrt(length2()); } /**@brief Normalize the quaternion * Such that x^2 + y^2 + z^2 +w^2 = 1 */ btQuaternion& normalize() { return *this /= length(); } /**@brief Return a scaled version of this quaternion * @param s The scale factor */ SIMD_FORCE_INLINE btQuaternion operator*(const btScalar& s) const { return btQuaternion(x() * s, y() * s, z() * s, m_floats[3] * s); } /**@brief Return an inversely scaled versionof this quaternion * @param s The inverse scale factor */ btQuaternion operator/(const btScalar& s) const { btAssert(s != btScalar(0.0)); return *this * (btScalar(1.0) / s); } /**@brief Inversely scale this quaternion * @param s The scale factor */ btQuaternion& operator/=(const btScalar& s) { btAssert(s != btScalar(0.0)); return *this *= btScalar(1.0) / s; } /**@brief Return a normalized version of this quaternion */ btQuaternion normalized() const { return *this / length(); } /**@brief Return the angle between this quaternion and the other * @param q The other quaternion */ btScalar angle(const btQuaternion& q) const { btScalar s = btSqrt(length2() * q.length2()); btAssert(s != btScalar(0.0)); return btAcos(dot(q) / s); } /**@brief Return the angle of rotation represented by this quaternion */ btScalar getAngle() const { btScalar s = btScalar(2.) * btAcos(m_floats[3]); return s; } /**@brief Return the axis of the rotation represented by this quaternion */ btVector3 getAxis() const { btScalar s_squared = btScalar(1.) - btPow(m_floats[3], btScalar(2.)); if (s_squared < btScalar(10.) * SIMD_EPSILON) //Check for divide by zero return btVector3(1.0, 0.0, 0.0); // Arbitrary btScalar s = btSqrt(s_squared); return btVector3(m_floats[0] / s, m_floats[1] / s, m_floats[2] / s); } /**@brief Return the inverse of this quaternion */ btQuaternion inverse() const { return btQuaternion(-m_floats[0], -m_floats[1], -m_floats[2], m_floats[3]); } /**@brief Return the sum of this quaternion and the other * @param q2 The other quaternion */ SIMD_FORCE_INLINE btQuaternion operator+(const btQuaternion& q2) const { const btQuaternion& q1 = *this; return btQuaternion(q1.x() + q2.x(), q1.y() + q2.y(), q1.z() + q2.z(), q1.m_floats[3] + q2.m_floats[3]); } /**@brief Return the difference between this quaternion and the other * @param q2 The other quaternion */ SIMD_FORCE_INLINE btQuaternion operator-(const btQuaternion& q2) const { const btQuaternion& q1 = *this; return btQuaternion(q1.x() - q2.x(), q1.y() - q2.y(), q1.z() - q2.z(), q1.m_floats[3] - q2.m_floats[3]); } /**@brief Return the negative of this quaternion * This simply negates each element */ SIMD_FORCE_INLINE btQuaternion operator-() const { const btQuaternion& q2 = *this; return btQuaternion( - q2.x(), - q2.y(), - q2.z(), - q2.m_floats[3]); } /**@todo document this and it's use */ SIMD_FORCE_INLINE btQuaternion farthest( const btQuaternion& qd) const { btQuaternion diff,sum; diff = *this - qd; sum = *this + qd; if( diff.dot(diff) > sum.dot(sum) ) return qd; return (-qd); } /**@todo document this and it's use */ SIMD_FORCE_INLINE btQuaternion nearest( const btQuaternion& qd) const { btQuaternion diff,sum; diff = *this - qd; sum = *this + qd; if( diff.dot(diff) < sum.dot(sum) ) return qd; return (-qd); } /**@brief Return the quaternion which is the result of Spherical Linear Interpolation between this and the other quaternion * @param q The other quaternion to interpolate with * @param t The ratio between this and q to interpolate. If t = 0 the result is this, if t=1 the result is q. * Slerp interpolates assuming constant velocity. */ btQuaternion slerp(const btQuaternion& q, const btScalar& t) const { btScalar theta = angle(q); if (theta != btScalar(0.0)) { btScalar d = btScalar(1.0) / btSin(theta); btScalar s0 = btSin((btScalar(1.0) - t) * theta); btScalar s1 = btSin(t * theta); if (dot(q) < 0) // Take care of long angle case see http://en.wikipedia.org/wiki/Slerp return btQuaternion((m_floats[0] * s0 + -q.x() * s1) * d, (m_floats[1] * s0 + -q.y() * s1) * d, (m_floats[2] * s0 + -q.z() * s1) * d, (m_floats[3] * s0 + -q.m_floats[3] * s1) * d); else return btQuaternion((m_floats[0] * s0 + q.x() * s1) * d, (m_floats[1] * s0 + q.y() * s1) * d, (m_floats[2] * s0 + q.z() * s1) * d, (m_floats[3] * s0 + q.m_floats[3] * s1) * d); } else { return *this; } } static const btQuaternion& getIdentity() { static const btQuaternion identityQuat(btScalar(0.),btScalar(0.),btScalar(0.),btScalar(1.)); return identityQuat; } SIMD_FORCE_INLINE const btScalar& getW() const { return m_floats[3]; } }; /**@brief Return the negative of a quaternion */ SIMD_FORCE_INLINE btQuaternion operator-(const btQuaternion& q) { return btQuaternion(-q.x(), -q.y(), -q.z(), -q.w()); } /**@brief Return the product of two quaternions */ SIMD_FORCE_INLINE btQuaternion operator*(const btQuaternion& q1, const btQuaternion& q2) { return btQuaternion(q1.w() * q2.x() + q1.x() * q2.w() + q1.y() * q2.z() - q1.z() * q2.y(), q1.w() * q2.y() + q1.y() * q2.w() + q1.z() * q2.x() - q1.x() * q2.z(), q1.w() * q2.z() + q1.z() * q2.w() + q1.x() * q2.y() - q1.y() * q2.x(), q1.w() * q2.w() - q1.x() * q2.x() - q1.y() * q2.y() - q1.z() * q2.z()); } SIMD_FORCE_INLINE btQuaternion operator*(const btQuaternion& q, const btVector3& w) { return btQuaternion( q.w() * w.x() + q.y() * w.z() - q.z() * w.y(), q.w() * w.y() + q.z() * w.x() - q.x() * w.z(), q.w() * w.z() + q.x() * w.y() - q.y() * w.x(), -q.x() * w.x() - q.y() * w.y() - q.z() * w.z()); } SIMD_FORCE_INLINE btQuaternion operator*(const btVector3& w, const btQuaternion& q) { return btQuaternion( w.x() * q.w() + w.y() * q.z() - w.z() * q.y(), w.y() * q.w() + w.z() * q.x() - w.x() * q.z(), w.z() * q.w() + w.x() * q.y() - w.y() * q.x(), -w.x() * q.x() - w.y() * q.y() - w.z() * q.z()); } /**@brief Calculate the dot product between two quaternions */ SIMD_FORCE_INLINE btScalar dot(const btQuaternion& q1, const btQuaternion& q2) { return q1.dot(q2); } /**@brief Return the length of a quaternion */ SIMD_FORCE_INLINE btScalar length(const btQuaternion& q) { return q.length(); } /**@brief Return the angle between two quaternions*/ SIMD_FORCE_INLINE btScalar angle(const btQuaternion& q1, const btQuaternion& q2) { return q1.angle(q2); } /**@brief Return the inverse of a quaternion*/ SIMD_FORCE_INLINE btQuaternion inverse(const btQuaternion& q) { return q.inverse(); } /**@brief Return the result of spherical linear interpolation betwen two quaternions * @param q1 The first quaternion * @param q2 The second quaternion * @param t The ration between q1 and q2. t = 0 return q1, t=1 returns q2 * Slerp assumes constant velocity between positions. */ SIMD_FORCE_INLINE btQuaternion slerp(const btQuaternion& q1, const btQuaternion& q2, const btScalar& t) { return q1.slerp(q2, t); } SIMD_FORCE_INLINE btVector3 quatRotate(const btQuaternion& rotation, const btVector3& v) { btQuaternion q = rotation * v; q *= rotation.inverse(); return btVector3(q.getX(),q.getY(),q.getZ()); } SIMD_FORCE_INLINE btQuaternion shortestArcQuat(const btVector3& v0, const btVector3& v1) // Game Programming Gems 2.10. make sure v0,v1 are normalized { btVector3 c = v0.cross(v1); btScalar d = v0.dot(v1); if (d < -1.0 + SIMD_EPSILON) { btVector3 n,unused; btPlaneSpace1(v0,n,unused); return btQuaternion(n.x(),n.y(),n.z(),0.0f); // just pick any vector that is orthogonal to v0 } btScalar s = btSqrt((1.0f + d) * 2.0f); btScalar rs = 1.0f / s; return btQuaternion(c.getX()*rs,c.getY()*rs,c.getZ()*rs,s * 0.5f); } SIMD_FORCE_INLINE btQuaternion shortestArcQuatNormalize2(btVector3& v0,btVector3& v1) { v0.normalize(); v1.normalize(); return shortestArcQuat(v0,v1); } #endif critterding-beta12.1/src/utils/bullet/LinearMath/btRandom.h0000644000175000017500000000265511337071441022727 0ustar bobkebobke/* Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ 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 GEN_RANDOM_H #define GEN_RANDOM_H #ifdef MT19937 #include #include #define GEN_RAND_MAX UINT_MAX SIMD_FORCE_INLINE void GEN_srand(unsigned int seed) { init_genrand(seed); } SIMD_FORCE_INLINE unsigned int GEN_rand() { return genrand_int32(); } #else #include #define GEN_RAND_MAX RAND_MAX SIMD_FORCE_INLINE void GEN_srand(unsigned int seed) { srand(seed); } SIMD_FORCE_INLINE unsigned int GEN_rand() { return rand(); } #endif #endif critterding-beta12.1/src/utils/bullet/LinearMath/btScalar.h0000644000175000017500000003724711344267705022731 0ustar bobkebobke/* Copyright (c) 2003-2009 Erwin Coumans http://bullet.googlecode.com 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 SIMD___SCALAR_H #define SIMD___SCALAR_H #ifdef BT_MANAGED_CODE //Aligned data types not supported in managed code #pragma unmanaged #endif #include #include //size_t for MSVC 6.0 #include #include #include /* SVN $Revision$ on $Date$ from http://bullet.googlecode.com*/ #define BT_BULLET_VERSION 276 inline int btGetVersion() { return BT_BULLET_VERSION; } #if defined(DEBUG) || defined (_DEBUG) #define BT_DEBUG #endif #ifdef _WIN32 #if defined(__MINGW32__) || defined(__CYGWIN__) || (defined (_MSC_VER) && _MSC_VER < 1300) #define SIMD_FORCE_INLINE inline #define ATTRIBUTE_ALIGNED16(a) a #define ATTRIBUTE_ALIGNED64(a) a #define ATTRIBUTE_ALIGNED128(a) a #else //#define BT_HAS_ALIGNED_ALLOCATOR #pragma warning(disable : 4324) // disable padding warning // #pragma warning(disable:4530) // Disable the exception disable but used in MSCV Stl warning. // #pragma warning(disable:4996) //Turn off warnings about deprecated C routines // #pragma warning(disable:4786) // Disable the "debug name too long" warning #define SIMD_FORCE_INLINE __forceinline #define ATTRIBUTE_ALIGNED16(a) __declspec(align(16)) a #define ATTRIBUTE_ALIGNED64(a) __declspec(align(64)) a #define ATTRIBUTE_ALIGNED128(a) __declspec (align(128)) a #ifdef _XBOX #define BT_USE_VMX128 #include #define BT_HAVE_NATIVE_FSEL #define btFsel(a,b,c) __fsel((a),(b),(c)) #else #if (defined (_WIN32) && (_MSC_VER) && _MSC_VER >= 1400) && (!defined (BT_USE_DOUBLE_PRECISION)) #define BT_USE_SSE #include #endif #endif//_XBOX #endif //__MINGW32__ #include #ifdef BT_DEBUG #define btAssert assert #else #define btAssert(x) #endif //btFullAssert is optional, slows down a lot #define btFullAssert(x) #define btLikely(_c) _c #define btUnlikely(_c) _c #else #if defined (__CELLOS_LV2__) #define SIMD_FORCE_INLINE inline #define ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16))) #define ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64))) #define ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128))) #ifndef assert #include #endif #ifdef BT_DEBUG #define btAssert assert #else #define btAssert(x) #endif //btFullAssert is optional, slows down a lot #define btFullAssert(x) #define btLikely(_c) _c #define btUnlikely(_c) _c #else #ifdef USE_LIBSPE2 #define SIMD_FORCE_INLINE __inline #define ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16))) #define ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64))) #define ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128))) #ifndef assert #include #endif #ifdef BT_DEBUG #define btAssert assert #else #define btAssert(x) #endif //btFullAssert is optional, slows down a lot #define btFullAssert(x) #define btLikely(_c) __builtin_expect((_c), 1) #define btUnlikely(_c) __builtin_expect((_c), 0) #else //non-windows systems #if (defined (__APPLE__) && defined (__i386__) && (!defined (BT_USE_DOUBLE_PRECISION))) #define BT_USE_SSE #include #define SIMD_FORCE_INLINE inline ///@todo: check out alignment methods for other platforms/compilers #define ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16))) #define ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64))) #define ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128))) #ifndef assert #include #endif #if defined(DEBUG) || defined (_DEBUG) #define btAssert assert #else #define btAssert(x) #endif //btFullAssert is optional, slows down a lot #define btFullAssert(x) #define btLikely(_c) _c #define btUnlikely(_c) _c #else #define SIMD_FORCE_INLINE inline ///@todo: check out alignment methods for other platforms/compilers ///#define ATTRIBUTE_ALIGNED16(a) a __attribute__ ((aligned (16))) ///#define ATTRIBUTE_ALIGNED64(a) a __attribute__ ((aligned (64))) ///#define ATTRIBUTE_ALIGNED128(a) a __attribute__ ((aligned (128))) #define ATTRIBUTE_ALIGNED16(a) a #define ATTRIBUTE_ALIGNED64(a) a #define ATTRIBUTE_ALIGNED128(a) a #ifndef assert #include #endif #if defined(DEBUG) || defined (_DEBUG) #define btAssert assert #else #define btAssert(x) #endif //btFullAssert is optional, slows down a lot #define btFullAssert(x) #define btLikely(_c) _c #define btUnlikely(_c) _c #endif //__APPLE__ #endif // LIBSPE2 #endif //__CELLOS_LV2__ #endif ///The btScalar type abstracts floating point numbers, to easily switch between double and single floating point precision. #if defined(BT_USE_DOUBLE_PRECISION) typedef double btScalar; //this number could be bigger in double precision #define BT_LARGE_FLOAT 1e30 #else typedef float btScalar; //keep BT_LARGE_FLOAT*BT_LARGE_FLOAT < FLT_MAX #define BT_LARGE_FLOAT 1e18f #endif #define BT_DECLARE_ALIGNED_ALLOCATOR() \ SIMD_FORCE_INLINE void* operator new(size_t sizeInBytes) { return btAlignedAlloc(sizeInBytes,16); } \ SIMD_FORCE_INLINE void operator delete(void* ptr) { btAlignedFree(ptr); } \ SIMD_FORCE_INLINE void* operator new(size_t, void* ptr) { return ptr; } \ SIMD_FORCE_INLINE void operator delete(void*, void*) { } \ SIMD_FORCE_INLINE void* operator new[](size_t sizeInBytes) { return btAlignedAlloc(sizeInBytes,16); } \ SIMD_FORCE_INLINE void operator delete[](void* ptr) { btAlignedFree(ptr); } \ SIMD_FORCE_INLINE void* operator new[](size_t, void* ptr) { return ptr; } \ SIMD_FORCE_INLINE void operator delete[](void*, void*) { } \ #if defined(BT_USE_DOUBLE_PRECISION) || defined(BT_FORCE_DOUBLE_FUNCTIONS) SIMD_FORCE_INLINE btScalar btSqrt(btScalar x) { return sqrt(x); } SIMD_FORCE_INLINE btScalar btFabs(btScalar x) { return fabs(x); } SIMD_FORCE_INLINE btScalar btCos(btScalar x) { return cos(x); } SIMD_FORCE_INLINE btScalar btSin(btScalar x) { return sin(x); } SIMD_FORCE_INLINE btScalar btTan(btScalar x) { return tan(x); } SIMD_FORCE_INLINE btScalar btAcos(btScalar x) { if (xbtScalar(1)) x=btScalar(1); return acos(x); } SIMD_FORCE_INLINE btScalar btAsin(btScalar x) { if (xbtScalar(1)) x=btScalar(1); return asin(x); } SIMD_FORCE_INLINE btScalar btAtan(btScalar x) { return atan(x); } SIMD_FORCE_INLINE btScalar btAtan2(btScalar x, btScalar y) { return atan2(x, y); } SIMD_FORCE_INLINE btScalar btExp(btScalar x) { return exp(x); } SIMD_FORCE_INLINE btScalar btLog(btScalar x) { return log(x); } SIMD_FORCE_INLINE btScalar btPow(btScalar x,btScalar y) { return pow(x,y); } SIMD_FORCE_INLINE btScalar btFmod(btScalar x,btScalar y) { return fmod(x,y); } #else SIMD_FORCE_INLINE btScalar btSqrt(btScalar y) { #ifdef USE_APPROXIMATION double x, z, tempf; unsigned long *tfptr = ((unsigned long *)&tempf) + 1; tempf = y; *tfptr = (0xbfcdd90a - *tfptr)>>1; /* estimate of 1/sqrt(y) */ x = tempf; z = y*btScalar(0.5); /* hoist out the /2 */ x = (btScalar(1.5)*x)-(x*x)*(x*z); /* iteration formula */ x = (btScalar(1.5)*x)-(x*x)*(x*z); x = (btScalar(1.5)*x)-(x*x)*(x*z); x = (btScalar(1.5)*x)-(x*x)*(x*z); x = (btScalar(1.5)*x)-(x*x)*(x*z); return x*y; #else return sqrtf(y); #endif } SIMD_FORCE_INLINE btScalar btFabs(btScalar x) { return fabsf(x); } SIMD_FORCE_INLINE btScalar btCos(btScalar x) { return cosf(x); } SIMD_FORCE_INLINE btScalar btSin(btScalar x) { return sinf(x); } SIMD_FORCE_INLINE btScalar btTan(btScalar x) { return tanf(x); } SIMD_FORCE_INLINE btScalar btAcos(btScalar x) { if (xbtScalar(1)) x=btScalar(1); return acosf(x); } SIMD_FORCE_INLINE btScalar btAsin(btScalar x) { if (xbtScalar(1)) x=btScalar(1); return asinf(x); } SIMD_FORCE_INLINE btScalar btAtan(btScalar x) { return atanf(x); } SIMD_FORCE_INLINE btScalar btAtan2(btScalar x, btScalar y) { return atan2f(x, y); } SIMD_FORCE_INLINE btScalar btExp(btScalar x) { return expf(x); } SIMD_FORCE_INLINE btScalar btLog(btScalar x) { return logf(x); } SIMD_FORCE_INLINE btScalar btPow(btScalar x,btScalar y) { return powf(x,y); } SIMD_FORCE_INLINE btScalar btFmod(btScalar x,btScalar y) { return fmodf(x,y); } #endif #define SIMD_2_PI btScalar(6.283185307179586232) #define SIMD_PI (SIMD_2_PI * btScalar(0.5)) #define SIMD_HALF_PI (SIMD_2_PI * btScalar(0.25)) #define SIMD_RADS_PER_DEG (SIMD_2_PI / btScalar(360.0)) #define SIMD_DEGS_PER_RAD (btScalar(360.0) / SIMD_2_PI) #define SIMDSQRT12 btScalar(0.7071067811865475244008443621048490) #define btRecipSqrt(x) ((btScalar)(btScalar(1.0)/btSqrt(btScalar(x)))) /* reciprocal square root */ #ifdef BT_USE_DOUBLE_PRECISION #define SIMD_EPSILON DBL_EPSILON #define SIMD_INFINITY DBL_MAX #else #define SIMD_EPSILON FLT_EPSILON #define SIMD_INFINITY FLT_MAX #endif SIMD_FORCE_INLINE btScalar btAtan2Fast(btScalar y, btScalar x) { btScalar coeff_1 = SIMD_PI / 4.0f; btScalar coeff_2 = 3.0f * coeff_1; btScalar abs_y = btFabs(y); btScalar angle; if (x >= 0.0f) { btScalar r = (x - abs_y) / (x + abs_y); angle = coeff_1 - coeff_1 * r; } else { btScalar r = (x + abs_y) / (abs_y - x); angle = coeff_2 - coeff_1 * r; } return (y < 0.0f) ? -angle : angle; } SIMD_FORCE_INLINE bool btFuzzyZero(btScalar x) { return btFabs(x) < SIMD_EPSILON; } SIMD_FORCE_INLINE bool btEqual(btScalar a, btScalar eps) { return (((a) <= eps) && !((a) < -eps)); } SIMD_FORCE_INLINE bool btGreaterEqual (btScalar a, btScalar eps) { return (!((a) <= eps)); } SIMD_FORCE_INLINE int btIsNegative(btScalar x) { return x < btScalar(0.0) ? 1 : 0; } SIMD_FORCE_INLINE btScalar btRadians(btScalar x) { return x * SIMD_RADS_PER_DEG; } SIMD_FORCE_INLINE btScalar btDegrees(btScalar x) { return x * SIMD_DEGS_PER_RAD; } #define BT_DECLARE_HANDLE(name) typedef struct name##__ { int unused; } *name #ifndef btFsel SIMD_FORCE_INLINE btScalar btFsel(btScalar a, btScalar b, btScalar c) { return a >= 0 ? b : c; } #endif #define btFsels(a,b,c) (btScalar)btFsel(a,b,c) SIMD_FORCE_INLINE bool btMachineIsLittleEndian() { long int i = 1; const char *p = (const char *) &i; if (p[0] == 1) // Lowest address contains the least significant byte return true; else return false; } ///btSelect avoids branches, which makes performance much better for consoles like Playstation 3 and XBox 360 ///Thanks Phil Knight. See also http://www.cellperformance.com/articles/2006/04/more_techniques_for_eliminatin_1.html SIMD_FORCE_INLINE unsigned btSelect(unsigned condition, unsigned valueIfConditionNonZero, unsigned valueIfConditionZero) { // Set testNz to 0xFFFFFFFF if condition is nonzero, 0x00000000 if condition is zero // Rely on positive value or'ed with its negative having sign bit on // and zero value or'ed with its negative (which is still zero) having sign bit off // Use arithmetic shift right, shifting the sign bit through all 32 bits unsigned testNz = (unsigned)(((int)condition | -(int)condition) >> 31); unsigned testEqz = ~testNz; return ((valueIfConditionNonZero & testNz) | (valueIfConditionZero & testEqz)); } SIMD_FORCE_INLINE int btSelect(unsigned condition, int valueIfConditionNonZero, int valueIfConditionZero) { unsigned testNz = (unsigned)(((int)condition | -(int)condition) >> 31); unsigned testEqz = ~testNz; return static_cast((valueIfConditionNonZero & testNz) | (valueIfConditionZero & testEqz)); } SIMD_FORCE_INLINE float btSelect(unsigned condition, float valueIfConditionNonZero, float valueIfConditionZero) { #ifdef BT_HAVE_NATIVE_FSEL return (float)btFsel((btScalar)condition - btScalar(1.0f), valueIfConditionNonZero, valueIfConditionZero); #else return (condition != 0) ? valueIfConditionNonZero : valueIfConditionZero; #endif } template SIMD_FORCE_INLINE void btSwap(T& a, T& b) { T tmp = a; a = b; b = tmp; } //PCK: endian swapping functions SIMD_FORCE_INLINE unsigned btSwapEndian(unsigned val) { return (((val & 0xff000000) >> 24) | ((val & 0x00ff0000) >> 8) | ((val & 0x0000ff00) << 8) | ((val & 0x000000ff) << 24)); } SIMD_FORCE_INLINE unsigned short btSwapEndian(unsigned short val) { return static_cast(((val & 0xff00) >> 8) | ((val & 0x00ff) << 8)); } SIMD_FORCE_INLINE unsigned btSwapEndian(int val) { return btSwapEndian((unsigned)val); } SIMD_FORCE_INLINE unsigned short btSwapEndian(short val) { return btSwapEndian((unsigned short) val); } ///btSwapFloat uses using char pointers to swap the endianness ////btSwapFloat/btSwapDouble will NOT return a float, because the machine might 'correct' invalid floating point values ///Not all values of sign/exponent/mantissa are valid floating point numbers according to IEEE 754. ///When a floating point unit is faced with an invalid value, it may actually change the value, or worse, throw an exception. ///In most systems, running user mode code, you wouldn't get an exception, but instead the hardware/os/runtime will 'fix' the number for you. ///so instead of returning a float/double, we return integer/long long integer SIMD_FORCE_INLINE unsigned int btSwapEndianFloat(float d) { unsigned int a = 0; unsigned char *dst = (unsigned char *)&a; unsigned char *src = (unsigned char *)&d; dst[0] = src[3]; dst[1] = src[2]; dst[2] = src[1]; dst[3] = src[0]; return a; } // unswap using char pointers SIMD_FORCE_INLINE float btUnswapEndianFloat(unsigned int a) { float d = 0.0f; unsigned char *src = (unsigned char *)&a; unsigned char *dst = (unsigned char *)&d; dst[0] = src[3]; dst[1] = src[2]; dst[2] = src[1]; dst[3] = src[0]; return d; } // swap using char pointers SIMD_FORCE_INLINE void btSwapEndianDouble(double d, unsigned char* dst) { unsigned char *src = (unsigned char *)&d; dst[0] = src[7]; dst[1] = src[6]; dst[2] = src[5]; dst[3] = src[4]; dst[4] = src[3]; dst[5] = src[2]; dst[6] = src[1]; dst[7] = src[0]; } // unswap using char pointers SIMD_FORCE_INLINE double btUnswapEndianDouble(const unsigned char *src) { double d = 0.0; unsigned char *dst = (unsigned char *)&d; dst[0] = src[7]; dst[1] = src[6]; dst[2] = src[5]; dst[3] = src[4]; dst[4] = src[3]; dst[5] = src[2]; dst[6] = src[1]; dst[7] = src[0]; return d; } // returns normalized value in range [-SIMD_PI, SIMD_PI] SIMD_FORCE_INLINE btScalar btNormalizeAngle(btScalar angleInRadians) { angleInRadians = btFmod(angleInRadians, SIMD_2_PI); if(angleInRadians < -SIMD_PI) { return angleInRadians + SIMD_2_PI; } else if(angleInRadians > SIMD_PI) { return angleInRadians - SIMD_2_PI; } else { return angleInRadians; } } ///rudimentary class to provide type info struct btTypedObject { btTypedObject(int objectType) :m_objectType(objectType) { } int m_objectType; inline int getObjectType() const { return m_objectType; } }; #endif //SIMD___SCALAR_H critterding-beta12.1/src/utils/bullet/LinearMath/btAlignedAllocator.cpp0000644000175000017500000001231111337071441025234 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btAlignedAllocator.h" int gNumAlignedAllocs = 0; int gNumAlignedFree = 0; int gTotalBytesAlignedAllocs = 0;//detect memory leaks static void *btAllocDefault(size_t size) { return malloc(size); } static void btFreeDefault(void *ptr) { free(ptr); } static btAllocFunc *sAllocFunc = btAllocDefault; static btFreeFunc *sFreeFunc = btFreeDefault; #if defined (BT_HAS_ALIGNED_ALLOCATOR) #include static void *btAlignedAllocDefault(size_t size, int alignment) { return _aligned_malloc(size, (size_t)alignment); } static void btAlignedFreeDefault(void *ptr) { _aligned_free(ptr); } #elif defined(__CELLOS_LV2__) #include static inline void *btAlignedAllocDefault(size_t size, int alignment) { return memalign(alignment, size); } static inline void btAlignedFreeDefault(void *ptr) { free(ptr); } #else static inline void *btAlignedAllocDefault(size_t size, int alignment) { void *ret; char *real; unsigned long offset; real = (char *)sAllocFunc(size + sizeof(void *) + (alignment-1)); if (real) { offset = (alignment - (unsigned long)(real + sizeof(void *))) & (alignment-1); ret = (void *)((real + sizeof(void *)) + offset); *((void **)(ret)-1) = (void *)(real); } else { ret = (void *)(real); } return (ret); } static inline void btAlignedFreeDefault(void *ptr) { void* real; if (ptr) { real = *((void **)(ptr)-1); sFreeFunc(real); } } #endif static btAlignedAllocFunc *sAlignedAllocFunc = btAlignedAllocDefault; static btAlignedFreeFunc *sAlignedFreeFunc = btAlignedFreeDefault; void btAlignedAllocSetCustomAligned(btAlignedAllocFunc *allocFunc, btAlignedFreeFunc *freeFunc) { sAlignedAllocFunc = allocFunc ? allocFunc : btAlignedAllocDefault; sAlignedFreeFunc = freeFunc ? freeFunc : btAlignedFreeDefault; } void btAlignedAllocSetCustom(btAllocFunc *allocFunc, btFreeFunc *freeFunc) { sAllocFunc = allocFunc ? allocFunc : btAllocDefault; sFreeFunc = freeFunc ? freeFunc : btFreeDefault; } #ifdef BT_DEBUG_MEMORY_ALLOCATIONS //this generic allocator provides the total allocated number of bytes #include void* btAlignedAllocInternal (size_t size, int alignment,int line,char* filename) { void *ret; char *real; unsigned long offset; gTotalBytesAlignedAllocs += size; gNumAlignedAllocs++; real = (char *)sAllocFunc(size + 2*sizeof(void *) + (alignment-1)); if (real) { offset = (alignment - (unsigned long)(real + 2*sizeof(void *))) & (alignment-1); ret = (void *)((real + 2*sizeof(void *)) + offset); *((void **)(ret)-1) = (void *)(real); *((int*)(ret)-2) = size; } else { ret = (void *)(real);//?? } printf("allocation#%d at address %x, from %s,line %d, size %d\n",gNumAlignedAllocs,real, filename,line,size); int* ptr = (int*)ret; *ptr = 12; return (ret); } void btAlignedFreeInternal (void* ptr,int line,char* filename) { void* real; gNumAlignedFree++; if (ptr) { real = *((void **)(ptr)-1); int size = *((int*)(ptr)-2); gTotalBytesAlignedAllocs -= size; printf("free #%d at address %x, from %s,line %d, size %d\n",gNumAlignedFree,real, filename,line,size); sFreeFunc(real); } else { printf("NULL ptr\n"); } } #else //BT_DEBUG_MEMORY_ALLOCATIONS void* btAlignedAllocInternal (size_t size, int alignment) { gNumAlignedAllocs++; void* ptr; #if defined (BT_HAS_ALIGNED_ALLOCATOR) || defined(__CELLOS_LV2__) ptr = sAlignedAllocFunc(size, alignment); #else char *real; unsigned long offset; real = (char *)sAllocFunc(size + sizeof(void *) + (alignment-1)); if (real) { offset = (alignment - (unsigned long)(real + sizeof(void *))) & (alignment-1); ptr = (void *)((real + sizeof(void *)) + offset); *((void **)(ptr)-1) = (void *)(real); } else { ptr = (void *)(real); } #endif // defined (BT_HAS_ALIGNED_ALLOCATOR) || defined(__CELLOS_LV2__) // printf("btAlignedAllocInternal %d, %x\n",size,ptr); return ptr; } void btAlignedFreeInternal (void* ptr) { if (!ptr) { return; } gNumAlignedFree++; // printf("btAlignedFreeInternal %x\n",ptr); #if defined (BT_HAS_ALIGNED_ALLOCATOR) || defined(__CELLOS_LV2__) sAlignedFreeFunc(ptr); #else void* real; if (ptr) { real = *((void **)(ptr)-1); sFreeFunc(real); } #endif // defined (BT_HAS_ALIGNED_ALLOCATOR) || defined(__CELLOS_LV2__) } #endif //BT_DEBUG_MEMORY_ALLOCATIONS critterding-beta12.1/src/utils/bullet/LinearMath/btAlignedObjectArray.h0000644000175000017500000002354711344267705025213 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BT_OBJECT_ARRAY__ #define BT_OBJECT_ARRAY__ #include "btScalar.h" // has definitions like SIMD_FORCE_INLINE #include "btAlignedAllocator.h" ///If the platform doesn't support placement new, you can disable BT_USE_PLACEMENT_NEW ///then the btAlignedObjectArray doesn't support objects with virtual methods, and non-trivial constructors/destructors ///You can enable BT_USE_MEMCPY, then swapping elements in the array will use memcpy instead of operator= ///see discussion here: http://continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1231 and ///http://www.continuousphysics.com/Bullet/phpBB2/viewtopic.php?t=1240 #define BT_USE_PLACEMENT_NEW 1 //#define BT_USE_MEMCPY 1 //disable, because it is cumbersome to find out for each platform where memcpy is defined. It can be in or or otherwise... #ifdef BT_USE_MEMCPY #include #include #endif //BT_USE_MEMCPY #ifdef BT_USE_PLACEMENT_NEW #include //for placement new #endif //BT_USE_PLACEMENT_NEW ///The btAlignedObjectArray template class uses a subset of the stl::vector interface for its methods ///It is developed to replace stl::vector to avoid portability issues, including STL alignment issues to add SIMD/SSE data template //template class btAlignedObjectArray { btAlignedAllocator m_allocator; int m_size; int m_capacity; T* m_data; //PCK: added this line bool m_ownsMemory; protected: SIMD_FORCE_INLINE int allocSize(int size) { return (size ? size*2 : 1); } SIMD_FORCE_INLINE void copy(int start,int end, T* dest) const { int i; for (i=start;i size()) { reserve(newsize); } #ifdef BT_USE_PLACEMENT_NEW for (int i=curSize;i void quickSortInternal(L CompareFunc,int lo, int hi) { // lo is the lower index, hi is the upper index // of the region of array a that is to be sorted int i=lo, j=hi; T x=m_data[(lo+hi)/2]; // partition do { while (CompareFunc(m_data[i],x)) i++; while (CompareFunc(x,m_data[j])) j--; if (i<=j) { swap(i,j); i++; j--; } } while (i<=j); // recursion if (lo void quickSort(L CompareFunc) { //don't sort 0 or 1 elements if (size()>1) { quickSortInternal(CompareFunc,0,size()-1); } } ///heap sort from http://www.csse.monash.edu.au/~lloyd/tildeAlgDS/Sort/Heap/ template void downHeap(T *pArr, int k, int n,L CompareFunc) { /* PRE: a[k+1..N] is a heap */ /* POST: a[k..N] is a heap */ T temp = pArr[k - 1]; /* k has child(s) */ while (k <= n/2) { int child = 2*k; if ((child < n) && CompareFunc(pArr[child - 1] , pArr[child])) { child++; } /* pick larger child */ if (CompareFunc(temp , pArr[child - 1])) { /* move child up */ pArr[k - 1] = pArr[child - 1]; k = child; } else { break; } } pArr[k - 1] = temp; } /*downHeap*/ void swap(int index0,int index1) { #ifdef BT_USE_MEMCPY char temp[sizeof(T)]; memcpy(temp,&m_data[index0],sizeof(T)); memcpy(&m_data[index0],&m_data[index1],sizeof(T)); memcpy(&m_data[index1],temp,sizeof(T)); #else T temp = m_data[index0]; m_data[index0] = m_data[index1]; m_data[index1] = temp; #endif //BT_USE_PLACEMENT_NEW } template void heapSort(L CompareFunc) { /* sort a[0..N-1], N.B. 0 to N-1 */ int k; int n = m_size; for (k = n/2; k > 0; k--) { downHeap(m_data, k, n, CompareFunc); } /* a[1..N] is now a heap */ while ( n>=1 ) { swap(0,n-1); /* largest of a[0..n-1] */ n = n - 1; /* restore a[1..i-1] heap */ downHeap(m_data, 1, n, CompareFunc); } } ///non-recursive binary search, assumes sorted array int findBinarySearch(const T& key) const { int first = 0; int last = size(); //assume sorted array while (first <= last) { int mid = (first + last) / 2; // compute mid point. if (key > m_data[mid]) first = mid + 1; // repeat search in top half. else if (key < m_data[mid]) last = mid - 1; // repeat search in bottom half. else return mid; // found it. return position ///// } return size(); // failed to find key } int findLinearSearch(const T& key) const { int index=size(); int i; for (i=0;i #include "btConvexHull.h" #include "btAlignedObjectArray.h" #include "btMinMax.h" #include "btVector3.h" template void Swap(T &a,T &b) { T tmp = a; a=b; b=tmp; } //---------------------------------- class int3 { public: int x,y,z; int3(){}; int3(int _x,int _y, int _z){x=_x;y=_y;z=_z;} const int& operator[](int i) const {return (&x)[i];} int& operator[](int i) {return (&x)[i];} }; //------- btPlane ---------- inline btPlane PlaneFlip(const btPlane &plane){return btPlane(-plane.normal,-plane.dist);} inline int operator==( const btPlane &a, const btPlane &b ) { return (a.normal==b.normal && a.dist==b.dist); } inline int coplanar( const btPlane &a, const btPlane &b ) { return (a==b || a==PlaneFlip(b)); } //--------- Utility Functions ------ btVector3 PlaneLineIntersection(const btPlane &plane, const btVector3 &p0, const btVector3 &p1); btVector3 PlaneProject(const btPlane &plane, const btVector3 &point); btVector3 ThreePlaneIntersection(const btPlane &p0,const btPlane &p1, const btPlane &p2); btVector3 ThreePlaneIntersection(const btPlane &p0,const btPlane &p1, const btPlane &p2) { btVector3 N1 = p0.normal; btVector3 N2 = p1.normal; btVector3 N3 = p2.normal; btVector3 n2n3; n2n3 = N2.cross(N3); btVector3 n3n1; n3n1 = N3.cross(N1); btVector3 n1n2; n1n2 = N1.cross(N2); btScalar quotient = (N1.dot(n2n3)); btAssert(btFabs(quotient) > btScalar(0.000001)); quotient = btScalar(-1.) / quotient; n2n3 *= p0.dist; n3n1 *= p1.dist; n1n2 *= p2.dist; btVector3 potentialVertex = n2n3; potentialVertex += n3n1; potentialVertex += n1n2; potentialVertex *= quotient; btVector3 result(potentialVertex.getX(),potentialVertex.getY(),potentialVertex.getZ()); return result; } btScalar DistanceBetweenLines(const btVector3 &ustart, const btVector3 &udir, const btVector3 &vstart, const btVector3 &vdir, btVector3 *upoint=NULL, btVector3 *vpoint=NULL); btVector3 TriNormal(const btVector3 &v0, const btVector3 &v1, const btVector3 &v2); btVector3 NormalOf(const btVector3 *vert, const int n); btVector3 PlaneLineIntersection(const btPlane &plane, const btVector3 &p0, const btVector3 &p1) { // returns the point where the line p0-p1 intersects the plane n&d static btVector3 dif; dif = p1-p0; btScalar dn= btDot(plane.normal,dif); btScalar t = -(plane.dist+btDot(plane.normal,p0) )/dn; return p0 + (dif*t); } btVector3 PlaneProject(const btPlane &plane, const btVector3 &point) { return point - plane.normal * (btDot(point,plane.normal)+plane.dist); } btVector3 TriNormal(const btVector3 &v0, const btVector3 &v1, const btVector3 &v2) { // return the normal of the triangle // inscribed by v0, v1, and v2 btVector3 cp=btCross(v1-v0,v2-v1); btScalar m=cp.length(); if(m==0) return btVector3(1,0,0); return cp*(btScalar(1.0)/m); } btScalar DistanceBetweenLines(const btVector3 &ustart, const btVector3 &udir, const btVector3 &vstart, const btVector3 &vdir, btVector3 *upoint, btVector3 *vpoint) { static btVector3 cp; cp = btCross(udir,vdir).normalized(); btScalar distu = -btDot(cp,ustart); btScalar distv = -btDot(cp,vstart); btScalar dist = (btScalar)fabs(distu-distv); if(upoint) { btPlane plane; plane.normal = btCross(vdir,cp).normalized(); plane.dist = -btDot(plane.normal,vstart); *upoint = PlaneLineIntersection(plane,ustart,ustart+udir); } if(vpoint) { btPlane plane; plane.normal = btCross(udir,cp).normalized(); plane.dist = -btDot(plane.normal,ustart); *vpoint = PlaneLineIntersection(plane,vstart,vstart+vdir); } return dist; } #define COPLANAR (0) #define UNDER (1) #define OVER (2) #define SPLIT (OVER|UNDER) #define PAPERWIDTH (btScalar(0.001)) btScalar planetestepsilon = PAPERWIDTH; typedef ConvexH::HalfEdge HalfEdge; ConvexH::ConvexH(int vertices_size,int edges_size,int facets_size) { vertices.resize(vertices_size); edges.resize(edges_size); facets.resize(facets_size); } int PlaneTest(const btPlane &p, const btVector3 &v); int PlaneTest(const btPlane &p, const btVector3 &v) { btScalar a = btDot(v,p.normal)+p.dist; int flag = (a>planetestepsilon)?OVER:((a<-planetestepsilon)?UNDER:COPLANAR); return flag; } int SplitTest(ConvexH &convex,const btPlane &plane); int SplitTest(ConvexH &convex,const btPlane &plane) { int flag=0; for(int i=0;i int maxdirfiltered(const T *p,int count,const T &dir,btAlignedObjectArray &allow) { btAssert(count); int m=-1; for(int i=0;ibtDot(p[m],dir)) m=i; } btAssert(m!=-1); return m; } btVector3 orth(const btVector3 &v); btVector3 orth(const btVector3 &v) { btVector3 a=btCross(v,btVector3(0,0,1)); btVector3 b=btCross(v,btVector3(0,1,0)); if (a.length() > b.length()) { return a.normalized(); } else { return b.normalized(); } } template int maxdirsterid(const T *p,int count,const T &dir,btAlignedObjectArray &allow) { int m=-1; while(m==-1) { m = maxdirfiltered(p,count,dir,allow); if(allow[m]==3) return m; T u = orth(dir); T v = btCross(u,dir); int ma=-1; for(btScalar x = btScalar(0.0) ; x<= btScalar(360.0) ; x+= btScalar(45.0)) { btScalar s = btSin(SIMD_RADS_PER_DEG*(x)); btScalar c = btCos(SIMD_RADS_PER_DEG*(x)); int mb = maxdirfiltered(p,count,dir+(u*s+v*c)*btScalar(0.025),allow); if(ma==m && mb==m) { allow[m]=3; return m; } if(ma!=-1 && ma!=mb) // Yuck - this is really ugly { int mc = ma; for(btScalar xx = x-btScalar(40.0) ; xx <= x ; xx+= btScalar(5.0)) { btScalar s = btSin(SIMD_RADS_PER_DEG*(xx)); btScalar c = btCos(SIMD_RADS_PER_DEG*(xx)); int md = maxdirfiltered(p,count,dir+(u*s+v*c)*btScalar(0.025),allow); if(mc==m && md==m) { allow[m]=3; return m; } mc=md; } } ma=mb; } allow[m]=0; m=-1; } btAssert(0); return m; } int operator ==(const int3 &a,const int3 &b); int operator ==(const int3 &a,const int3 &b) { for(int i=0;i<3;i++) { if(a[i]!=b[i]) return 0; } return 1; } int above(btVector3* vertices,const int3& t, const btVector3 &p, btScalar epsilon); int above(btVector3* vertices,const int3& t, const btVector3 &p, btScalar epsilon) { btVector3 n=TriNormal(vertices[t[0]],vertices[t[1]],vertices[t[2]]); return (btDot(n,p-vertices[t[0]]) > epsilon); // EPSILON??? } int hasedge(const int3 &t, int a,int b); int hasedge(const int3 &t, int a,int b) { for(int i=0;i<3;i++) { int i1= (i+1)%3; if(t[i]==a && t[i1]==b) return 1; } return 0; } int hasvert(const int3 &t, int v); int hasvert(const int3 &t, int v) { return (t[0]==v || t[1]==v || t[2]==v) ; } int shareedge(const int3 &a,const int3 &b); int shareedge(const int3 &a,const int3 &b) { int i; for(i=0;i<3;i++) { int i1= (i+1)%3; if(hasedge(a,b[i1],b[i])) return 1; } return 0; } class btHullTriangle; class btHullTriangle : public int3 { public: int3 n; int id; int vmax; btScalar rise; btHullTriangle(int a,int b,int c):int3(a,b,c),n(-1,-1,-1) { vmax=-1; rise = btScalar(0.0); } ~btHullTriangle() { } int &neib(int a,int b); }; int &btHullTriangle::neib(int a,int b) { static int er=-1; int i; for(i=0;i<3;i++) { int i1=(i+1)%3; int i2=(i+2)%3; if((*this)[i]==a && (*this)[i1]==b) return n[i2]; if((*this)[i]==b && (*this)[i1]==a) return n[i2]; } btAssert(0); return er; } void HullLibrary::b2bfix(btHullTriangle* s,btHullTriangle*t) { int i; for(i=0;i<3;i++) { int i1=(i+1)%3; int i2=(i+2)%3; int a = (*s)[i1]; int b = (*s)[i2]; btAssert(m_tris[s->neib(a,b)]->neib(b,a) == s->id); btAssert(m_tris[t->neib(a,b)]->neib(b,a) == t->id); m_tris[s->neib(a,b)]->neib(b,a) = t->neib(b,a); m_tris[t->neib(b,a)]->neib(a,b) = s->neib(a,b); } } void HullLibrary::removeb2b(btHullTriangle* s,btHullTriangle*t) { b2bfix(s,t); deAllocateTriangle(s); deAllocateTriangle(t); } void HullLibrary::checkit(btHullTriangle *t) { (void)t; int i; btAssert(m_tris[t->id]==t); for(i=0;i<3;i++) { int i1=(i+1)%3; int i2=(i+2)%3; int a = (*t)[i1]; int b = (*t)[i2]; // release compile fix (void)i1; (void)i2; (void)a; (void)b; btAssert(a!=b); btAssert( m_tris[t->n[i]]->neib(b,a) == t->id); } } btHullTriangle* HullLibrary::allocateTriangle(int a,int b,int c) { void* mem = btAlignedAlloc(sizeof(btHullTriangle),16); btHullTriangle* tr = new (mem)btHullTriangle(a,b,c); tr->id = m_tris.size(); m_tris.push_back(tr); return tr; } void HullLibrary::deAllocateTriangle(btHullTriangle* tri) { btAssert(m_tris[tri->id]==tri); m_tris[tri->id]=NULL; tri->~btHullTriangle(); btAlignedFree(tri); } void HullLibrary::extrude(btHullTriangle *t0,int v) { int3 t= *t0; int n = m_tris.size(); btHullTriangle* ta = allocateTriangle(v,t[1],t[2]); ta->n = int3(t0->n[0],n+1,n+2); m_tris[t0->n[0]]->neib(t[1],t[2]) = n+0; btHullTriangle* tb = allocateTriangle(v,t[2],t[0]); tb->n = int3(t0->n[1],n+2,n+0); m_tris[t0->n[1]]->neib(t[2],t[0]) = n+1; btHullTriangle* tc = allocateTriangle(v,t[0],t[1]); tc->n = int3(t0->n[2],n+0,n+1); m_tris[t0->n[2]]->neib(t[0],t[1]) = n+2; checkit(ta); checkit(tb); checkit(tc); if(hasvert(*m_tris[ta->n[0]],v)) removeb2b(ta,m_tris[ta->n[0]]); if(hasvert(*m_tris[tb->n[0]],v)) removeb2b(tb,m_tris[tb->n[0]]); if(hasvert(*m_tris[tc->n[0]],v)) removeb2b(tc,m_tris[tc->n[0]]); deAllocateTriangle(t0); } btHullTriangle* HullLibrary::extrudable(btScalar epsilon) { int i; btHullTriangle *t=NULL; for(i=0;iriserise)) { t = m_tris[i]; } } return (t->rise >epsilon)?t:NULL ; } int4 HullLibrary::FindSimplex(btVector3 *verts,int verts_count,btAlignedObjectArray &allow) { btVector3 basis[3]; basis[0] = btVector3( btScalar(0.01), btScalar(0.02), btScalar(1.0) ); int p0 = maxdirsterid(verts,verts_count, basis[0],allow); int p1 = maxdirsterid(verts,verts_count,-basis[0],allow); basis[0] = verts[p0]-verts[p1]; if(p0==p1 || basis[0]==btVector3(0,0,0)) return int4(-1,-1,-1,-1); basis[1] = btCross(btVector3( btScalar(1),btScalar(0.02), btScalar(0)),basis[0]); basis[2] = btCross(btVector3(btScalar(-0.02), btScalar(1), btScalar(0)),basis[0]); if (basis[1].length() > basis[2].length()) { basis[1].normalize(); } else { basis[1] = basis[2]; basis[1].normalize (); } int p2 = maxdirsterid(verts,verts_count,basis[1],allow); if(p2 == p0 || p2 == p1) { p2 = maxdirsterid(verts,verts_count,-basis[1],allow); } if(p2 == p0 || p2 == p1) return int4(-1,-1,-1,-1); basis[1] = verts[p2] - verts[p0]; basis[2] = btCross(basis[1],basis[0]).normalized(); int p3 = maxdirsterid(verts,verts_count,basis[2],allow); if(p3==p0||p3==p1||p3==p2) p3 = maxdirsterid(verts,verts_count,-basis[2],allow); if(p3==p0||p3==p1||p3==p2) return int4(-1,-1,-1,-1); btAssert(!(p0==p1||p0==p2||p0==p3||p1==p2||p1==p3||p2==p3)); if(btDot(verts[p3]-verts[p0],btCross(verts[p1]-verts[p0],verts[p2]-verts[p0])) <0) {Swap(p2,p3);} return int4(p0,p1,p2,p3); } int HullLibrary::calchullgen(btVector3 *verts,int verts_count, int vlimit) { if(verts_count <4) return 0; if(vlimit==0) vlimit=1000000000; int j; btVector3 bmin(*verts),bmax(*verts); btAlignedObjectArray isextreme; isextreme.reserve(verts_count); btAlignedObjectArray allow; allow.reserve(verts_count); for(j=0;jn=int3(2,3,1); btHullTriangle *t1 = allocateTriangle(p[3],p[2],p[0]); t1->n=int3(3,2,0); btHullTriangle *t2 = allocateTriangle(p[0],p[1],p[3]); t2->n=int3(0,1,3); btHullTriangle *t3 = allocateTriangle(p[1],p[0],p[2]); t3->n=int3(1,0,2); isextreme[p[0]]=isextreme[p[1]]=isextreme[p[2]]=isextreme[p[3]]=1; checkit(t0);checkit(t1);checkit(t2);checkit(t3); for(j=0;jvmax<0); btVector3 n=TriNormal(verts[(*t)[0]],verts[(*t)[1]],verts[(*t)[2]]); t->vmax = maxdirsterid(verts,verts_count,n,allow); t->rise = btDot(n,verts[t->vmax]-verts[(*t)[0]]); } btHullTriangle *te; vlimit-=4; while(vlimit >0 && ((te=extrudable(epsilon)) != 0)) { int3 ti=*te; int v=te->vmax; btAssert(v != -1); btAssert(!isextreme[v]); // wtf we've already done this vertex isextreme[v]=1; //if(v==p0 || v==p1 || v==p2 || v==p3) continue; // done these already j=m_tris.size(); while(j--) { if(!m_tris[j]) continue; int3 t=*m_tris[j]; if(above(verts,t,verts[v],btScalar(0.01)*epsilon)) { extrude(m_tris[j],v); } } // now check for those degenerate cases where we have a flipped triangle or a really skinny triangle j=m_tris.size(); while(j--) { if(!m_tris[j]) continue; if(!hasvert(*m_tris[j],v)) break; int3 nt=*m_tris[j]; if(above(verts,nt,center,btScalar(0.01)*epsilon) || btCross(verts[nt[1]]-verts[nt[0]],verts[nt[2]]-verts[nt[1]]).length()< epsilon*epsilon*btScalar(0.1) ) { btHullTriangle *nb = m_tris[m_tris[j]->n[0]]; btAssert(nb);btAssert(!hasvert(*nb,v));btAssert(nb->idvmax>=0) break; btVector3 n=TriNormal(verts[(*t)[0]],verts[(*t)[1]],verts[(*t)[2]]); t->vmax = maxdirsterid(verts,verts_count,n,allow); if(isextreme[t->vmax]) { t->vmax=-1; // already done that vertex - algorithm needs to be able to terminate. } else { t->rise = btDot(n,verts[t->vmax]-verts[(*t)[0]]); } } vlimit --; } return 1; } int HullLibrary::calchull(btVector3 *verts,int verts_count, TUIntArray& tris_out, int &tris_count,int vlimit) { int rc=calchullgen(verts,verts_count, vlimit) ; if(!rc) return 0; btAlignedObjectArray ts; int i; for(i=0;i(ts[i]); } m_tris.resize(0); return 1; } bool HullLibrary::ComputeHull(unsigned int vcount,const btVector3 *vertices,PHullResult &result,unsigned int vlimit) { int tris_count; int ret = calchull( (btVector3 *) vertices, (int) vcount, result.m_Indices, tris_count, static_cast(vlimit) ); if(!ret) return false; result.mIndexCount = (unsigned int) (tris_count*3); result.mFaceCount = (unsigned int) tris_count; result.mVertices = (btVector3*) vertices; result.mVcount = (unsigned int) vcount; return true; } void ReleaseHull(PHullResult &result); void ReleaseHull(PHullResult &result) { if ( result.m_Indices.size() ) { result.m_Indices.clear(); } result.mVcount = 0; result.mIndexCount = 0; result.mVertices = 0; } //********************************************************************* //********************************************************************* //******** HullLib header //********************************************************************* //********************************************************************* //********************************************************************* //********************************************************************* //******** HullLib implementation //********************************************************************* //********************************************************************* HullError HullLibrary::CreateConvexHull(const HullDesc &desc, // describes the input request HullResult &result) // contains the resulst { HullError ret = QE_FAIL; PHullResult hr; unsigned int vcount = desc.mVcount; if ( vcount < 8 ) vcount = 8; btAlignedObjectArray vertexSource; vertexSource.resize(static_cast(vcount)); btVector3 scale; unsigned int ovcount; bool ok = CleanupVertices(desc.mVcount,desc.mVertices, desc.mVertexStride, ovcount, &vertexSource[0], desc.mNormalEpsilon, scale ); // normalize point cloud, remove duplicates! if ( ok ) { // if ( 1 ) // scale vertices back to their original size. { for (unsigned int i=0; i(i)]; v[0]*=scale[0]; v[1]*=scale[1]; v[2]*=scale[2]; } } ok = ComputeHull(ovcount,&vertexSource[0],hr,desc.mMaxVertices); if ( ok ) { // re-index triangle mesh so it refers to only used vertices, rebuild a new vertex table. btAlignedObjectArray vertexScratch; vertexScratch.resize(static_cast(hr.mVcount)); BringOutYourDead(hr.mVertices,hr.mVcount, &vertexScratch[0], ovcount, &hr.m_Indices[0], hr.mIndexCount ); ret = QE_OK; if ( desc.HasHullFlag(QF_TRIANGLES) ) // if he wants the results as triangle! { result.mPolygons = false; result.mNumOutputVertices = ovcount; result.m_OutputVertices.resize(static_cast(ovcount)); result.mNumFaces = hr.mFaceCount; result.mNumIndices = hr.mIndexCount; result.m_Indices.resize(static_cast(hr.mIndexCount)); memcpy(&result.m_OutputVertices[0], &vertexScratch[0], sizeof(btVector3)*ovcount ); if ( desc.HasHullFlag(QF_REVERSE_ORDER) ) { const unsigned int *source = &hr.m_Indices[0]; unsigned int *dest = &result.m_Indices[0]; for (unsigned int i=0; i(ovcount)); result.mNumFaces = hr.mFaceCount; result.mNumIndices = hr.mIndexCount+hr.mFaceCount; result.m_Indices.resize(static_cast(result.mNumIndices)); memcpy(&result.m_OutputVertices[0], &vertexScratch[0], sizeof(btVector3)*ovcount ); // if ( 1 ) { const unsigned int *source = &hr.m_Indices[0]; unsigned int *dest = &result.m_Indices[0]; for (unsigned int i=0; i bmax[j] ) bmax[j] = p[j]; } } } btScalar dx = bmax[0] - bmin[0]; btScalar dy = bmax[1] - bmin[1]; btScalar dz = bmax[2] - bmin[2]; btVector3 center; center[0] = dx*btScalar(0.5) + bmin[0]; center[1] = dy*btScalar(0.5) + bmin[1]; center[2] = dz*btScalar(0.5) + bmin[2]; if ( dx < EPSILON || dy < EPSILON || dz < EPSILON || svcount < 3 ) { btScalar len = FLT_MAX; if ( dx > EPSILON && dx < len ) len = dx; if ( dy > EPSILON && dy < len ) len = dy; if ( dz > EPSILON && dz < len ) len = dz; if ( len == FLT_MAX ) { dx = dy = dz = btScalar(0.01); // one centimeter } else { if ( dx < EPSILON ) dx = len * btScalar(0.05); // 1/5th the shortest non-zero edge. if ( dy < EPSILON ) dy = len * btScalar(0.05); if ( dz < EPSILON ) dz = len * btScalar(0.05); } btScalar x1 = center[0] - dx; btScalar x2 = center[0] + dx; btScalar y1 = center[1] - dy; btScalar y2 = center[1] + dy; btScalar z1 = center[2] - dz; btScalar z2 = center[2] + dz; addPoint(vcount,vertices,x1,y1,z1); addPoint(vcount,vertices,x2,y1,z1); addPoint(vcount,vertices,x2,y2,z1); addPoint(vcount,vertices,x1,y2,z1); addPoint(vcount,vertices,x1,y1,z2); addPoint(vcount,vertices,x2,y1,z2); addPoint(vcount,vertices,x2,y2,z2); addPoint(vcount,vertices,x1,y2,z2); return true; // return cube } else { if ( scale ) { scale[0] = dx; scale[1] = dy; scale[2] = dz; recip[0] = 1 / dx; recip[1] = 1 / dy; recip[2] = 1 / dz; center[0]*=recip[0]; center[1]*=recip[1]; center[2]*=recip[2]; } } vtx = (const char *) svertices; for (unsigned int i=0; igetX(); btScalar py = p->getY(); btScalar pz = p->getZ(); if ( scale ) { px = px*recip[0]; // normalize py = py*recip[1]; // normalize pz = pz*recip[2]; // normalize } // if ( 1 ) { unsigned int j; for (j=0; j dist2 ) { v[0] = px; v[1] = py; v[2] = pz; } break; } } if ( j == vcount ) { btVector3& dest = vertices[vcount]; dest[0] = px; dest[1] = py; dest[2] = pz; vcount++; } m_vertexIndexMapping.push_back(j); } } // ok..now make sure we didn't prune so many vertices it is now invalid. // if ( 1 ) { btScalar bmin[3] = { FLT_MAX, FLT_MAX, FLT_MAX }; btScalar bmax[3] = { -FLT_MAX, -FLT_MAX, -FLT_MAX }; for (unsigned int i=0; i bmax[j] ) bmax[j] = p[j]; } } btScalar dx = bmax[0] - bmin[0]; btScalar dy = bmax[1] - bmin[1]; btScalar dz = bmax[2] - bmin[2]; if ( dx < EPSILON || dy < EPSILON || dz < EPSILON || vcount < 3) { btScalar cx = dx*btScalar(0.5) + bmin[0]; btScalar cy = dy*btScalar(0.5) + bmin[1]; btScalar cz = dz*btScalar(0.5) + bmin[2]; btScalar len = FLT_MAX; if ( dx >= EPSILON && dx < len ) len = dx; if ( dy >= EPSILON && dy < len ) len = dy; if ( dz >= EPSILON && dz < len ) len = dz; if ( len == FLT_MAX ) { dx = dy = dz = btScalar(0.01); // one centimeter } else { if ( dx < EPSILON ) dx = len * btScalar(0.05); // 1/5th the shortest non-zero edge. if ( dy < EPSILON ) dy = len * btScalar(0.05); if ( dz < EPSILON ) dz = len * btScalar(0.05); } btScalar x1 = cx - dx; btScalar x2 = cx + dx; btScalar y1 = cy - dy; btScalar y2 = cy + dy; btScalar z1 = cz - dz; btScalar z2 = cz + dz; vcount = 0; // add box addPoint(vcount,vertices,x1,y1,z1); addPoint(vcount,vertices,x2,y1,z1); addPoint(vcount,vertices,x2,y2,z1); addPoint(vcount,vertices,x1,y2,z1); addPoint(vcount,vertices,x1,y1,z2); addPoint(vcount,vertices,x2,y1,z2); addPoint(vcount,vertices,x2,y2,z2); addPoint(vcount,vertices,x1,y2,z2); return true; } } return true; } void HullLibrary::BringOutYourDead(const btVector3* verts,unsigned int vcount, btVector3* overts,unsigned int &ocount,unsigned int *indices,unsigned indexcount) { btAlignedObjectArraytmpIndices; tmpIndices.resize(m_vertexIndexMapping.size()); int i; for (i=0;i(vcount)); memset(&usedIndices[0],0,sizeof(unsigned int)*vcount); ocount = 0; for (i=0; i= 0 && v < vcount ); if ( usedIndices[static_cast(v)] ) // if already remapped { indices[i] = usedIndices[static_cast(v)]-1; // index to new array } else { indices[i] = ocount; // new index mapping overts[ocount][0] = verts[v][0]; // copy old vert to new vert array overts[ocount][1] = verts[v][1]; overts[ocount][2] = verts[v][2]; for (int k=0;k=0 && ocount <= vcount ); usedIndices[static_cast(v)] = ocount; // assign new index remapping } } } critterding-beta12.1/src/utils/bullet/LinearMath/Jamfile0000644000175000017500000000024211337071441022270 0ustar bobkebobke SubDir TOP src LinearMath ; Description bulletmath : "Bullet Math Library" ; Library bulletmath : [ Wildcard *.h *.cpp ] ; #InstallHeader [ Wildcard *.h ] ; critterding-beta12.1/src/utils/bullet/LinearMath/btAlignedAllocator.h0000644000175000017500000001051711337071441024707 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BT_ALIGNED_ALLOCATOR #define BT_ALIGNED_ALLOCATOR ///we probably replace this with our own aligned memory allocator ///so we replace _aligned_malloc and _aligned_free with our own ///that is better portable and more predictable #include "btScalar.h" //#define BT_DEBUG_MEMORY_ALLOCATIONS 1 #ifdef BT_DEBUG_MEMORY_ALLOCATIONS #define btAlignedAlloc(a,b) \ btAlignedAllocInternal(a,b,__LINE__,__FILE__) #define btAlignedFree(ptr) \ btAlignedFreeInternal(ptr,__LINE__,__FILE__) void* btAlignedAllocInternal (size_t size, int alignment,int line,char* filename); void btAlignedFreeInternal (void* ptr,int line,char* filename); #else void* btAlignedAllocInternal (size_t size, int alignment); void btAlignedFreeInternal (void* ptr); #define btAlignedAlloc(size,alignment) btAlignedAllocInternal(size,alignment) #define btAlignedFree(ptr) btAlignedFreeInternal(ptr) #endif typedef int size_type; typedef void *(btAlignedAllocFunc)(size_t size, int alignment); typedef void (btAlignedFreeFunc)(void *memblock); typedef void *(btAllocFunc)(size_t size); typedef void (btFreeFunc)(void *memblock); ///The developer can let all Bullet memory allocations go through a custom memory allocator, using btAlignedAllocSetCustom void btAlignedAllocSetCustom(btAllocFunc *allocFunc, btFreeFunc *freeFunc); ///If the developer has already an custom aligned allocator, then btAlignedAllocSetCustomAligned can be used. The default aligned allocator pre-allocates extra memory using the non-aligned allocator, and instruments it. void btAlignedAllocSetCustomAligned(btAlignedAllocFunc *allocFunc, btAlignedFreeFunc *freeFunc); ///The btAlignedAllocator is a portable class for aligned memory allocations. ///Default implementations for unaligned and aligned allocations can be overridden by a custom allocator using btAlignedAllocSetCustom and btAlignedAllocSetCustomAligned. template < typename T , unsigned Alignment > class btAlignedAllocator { typedef btAlignedAllocator< T , Alignment > self_type; public: //just going down a list: btAlignedAllocator() {} /* btAlignedAllocator( const self_type & ) {} */ template < typename Other > btAlignedAllocator( const btAlignedAllocator< Other , Alignment > & ) {} typedef const T* const_pointer; typedef const T& const_reference; typedef T* pointer; typedef T& reference; typedef T value_type; pointer address ( reference ref ) const { return &ref; } const_pointer address ( const_reference ref ) const { return &ref; } pointer allocate ( size_type n , const_pointer * hint = 0 ) { (void)hint; return reinterpret_cast< pointer >(btAlignedAlloc( sizeof(value_type) * n , Alignment )); } void construct ( pointer ptr , const value_type & value ) { new (ptr) value_type( value ); } void deallocate( pointer ptr ) { btAlignedFree( reinterpret_cast< void * >( ptr ) ); } void destroy ( pointer ptr ) { ptr->~value_type(); } template < typename O > struct rebind { typedef btAlignedAllocator< O , Alignment > other; }; template < typename O > self_type & operator=( const btAlignedAllocator< O , Alignment > & ) { return *this; } friend bool operator==( const self_type & , const self_type & ) { return true; } }; #endif //BT_ALIGNED_ALLOCATOR critterding-beta12.1/src/utils/bullet/LinearMath/btDefaultMotionState.h0000644000175000017500000000227211344267705025265 0ustar bobkebobke#ifndef DEFAULT_MOTION_STATE_H #define DEFAULT_MOTION_STATE_H #include "btMotionState.h" ///The btDefaultMotionState provides a common implementation to synchronize world transforms with offsets. struct btDefaultMotionState : public btMotionState { btTransform m_graphicsWorldTrans; btTransform m_centerOfMassOffset; btTransform m_startWorldTrans; void* m_userPointer; btDefaultMotionState(const btTransform& startTrans = btTransform::getIdentity(),const btTransform& centerOfMassOffset = btTransform::getIdentity()) : m_graphicsWorldTrans(startTrans), m_centerOfMassOffset(centerOfMassOffset), m_startWorldTrans(startTrans), m_userPointer(0) { } ///synchronizes world transform from user to physics virtual void getWorldTransform(btTransform& centerOfMassWorldTrans ) const { centerOfMassWorldTrans = m_centerOfMassOffset.inverse() * m_graphicsWorldTrans ; } ///synchronizes world transform from physics to user ///Bullet only calls the update of worldtransform for active objects virtual void setWorldTransform(const btTransform& centerOfMassWorldTrans) { m_graphicsWorldTrans = centerOfMassWorldTrans * m_centerOfMassOffset ; } }; #endif //DEFAULT_MOTION_STATE_H critterding-beta12.1/src/utils/bullet/LinearMath/btQuickprof.h0000644000175000017500000002225711344267705023462 0ustar bobkebobke /*************************************************************************************************** ** ** Real-Time Hierarchical Profiling for Game Programming Gems 3 ** ** by Greg Hjelstrom & Byon Garrabrant ** ***************************************************************************************************/ // Credits: The Clock class was inspired by the Timer classes in // Ogre (www.ogre3d.org). #ifndef QUICK_PROF_H #define QUICK_PROF_H //To disable built-in profiling, please comment out next line //#define BT_NO_PROFILE 1 #ifndef BT_NO_PROFILE #include "btScalar.h" #include "btAlignedAllocator.h" #include //if you don't need btClock, you can comment next line #define USE_BT_CLOCK 1 #ifdef USE_BT_CLOCK #ifdef __CELLOS_LV2__ #include #include #include #endif #if defined (SUNOS) || defined (__SUNOS__) #include #endif #if defined(WIN32) || defined(_WIN32) #define USE_WINDOWS_TIMERS #define WIN32_LEAN_AND_MEAN #define NOWINRES #define NOMCX #define NOIME #ifdef _XBOX #include #else #include #endif #include #else #include #endif #define mymin(a,b) (a > b ? a : b) ///The btClock is a portable basic clock that measures accurate time in seconds, use for profiling. class btClock { public: btClock() { #ifdef USE_WINDOWS_TIMERS QueryPerformanceFrequency(&mClockFrequency); #endif reset(); } ~btClock() { } /// Resets the initial reference time. void reset() { #ifdef USE_WINDOWS_TIMERS QueryPerformanceCounter(&mStartTime); mStartTick = GetTickCount(); mPrevElapsedTime = 0; #else #ifdef __CELLOS_LV2__ typedef uint64_t ClockSize; ClockSize newTime; //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory"); SYS_TIMEBASE_GET( newTime ); mStartTime = newTime; #else gettimeofday(&mStartTime, 0); #endif #endif } /// Returns the time in ms since the last call to reset or since /// the btClock was created. unsigned long int getTimeMilliseconds() { #ifdef USE_WINDOWS_TIMERS LARGE_INTEGER currentTime; QueryPerformanceCounter(¤tTime); LONGLONG elapsedTime = currentTime.QuadPart - mStartTime.QuadPart; // Compute the number of millisecond ticks elapsed. unsigned long msecTicks = (unsigned long)(1000 * elapsedTime / mClockFrequency.QuadPart); // Check for unexpected leaps in the Win32 performance counter. // (This is caused by unexpected data across the PCI to ISA // bridge, aka south bridge. See Microsoft KB274323.) unsigned long elapsedTicks = GetTickCount() - mStartTick; signed long msecOff = (signed long)(msecTicks - elapsedTicks); if (msecOff < -100 || msecOff > 100) { // Adjust the starting time forwards. LONGLONG msecAdjustment = mymin(msecOff * mClockFrequency.QuadPart / 1000, elapsedTime - mPrevElapsedTime); mStartTime.QuadPart += msecAdjustment; elapsedTime -= msecAdjustment; // Recompute the number of millisecond ticks elapsed. msecTicks = (unsigned long)(1000 * elapsedTime / mClockFrequency.QuadPart); } // Store the current elapsed time for adjustments next time. mPrevElapsedTime = elapsedTime; return msecTicks; #else #ifdef __CELLOS_LV2__ uint64_t freq=sys_time_get_timebase_frequency(); double dFreq=((double) freq) / 1000.0; typedef uint64_t ClockSize; ClockSize newTime; SYS_TIMEBASE_GET( newTime ); //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory"); return (unsigned long int)((double(newTime-mStartTime)) / dFreq); #else struct timeval currentTime; gettimeofday(¤tTime, 0); return (currentTime.tv_sec - mStartTime.tv_sec) * 1000 + (currentTime.tv_usec - mStartTime.tv_usec) / 1000; #endif //__CELLOS_LV2__ #endif } /// Returns the time in us since the last call to reset or since /// the Clock was created. unsigned long int getTimeMicroseconds() { #ifdef USE_WINDOWS_TIMERS LARGE_INTEGER currentTime; QueryPerformanceCounter(¤tTime); LONGLONG elapsedTime = currentTime.QuadPart - mStartTime.QuadPart; // Compute the number of millisecond ticks elapsed. unsigned long msecTicks = (unsigned long)(1000 * elapsedTime / mClockFrequency.QuadPart); // Check for unexpected leaps in the Win32 performance counter. // (This is caused by unexpected data across the PCI to ISA // bridge, aka south bridge. See Microsoft KB274323.) unsigned long elapsedTicks = GetTickCount() - mStartTick; signed long msecOff = (signed long)(msecTicks - elapsedTicks); if (msecOff < -100 || msecOff > 100) { // Adjust the starting time forwards. LONGLONG msecAdjustment = mymin(msecOff * mClockFrequency.QuadPart / 1000, elapsedTime - mPrevElapsedTime); mStartTime.QuadPart += msecAdjustment; elapsedTime -= msecAdjustment; } // Store the current elapsed time for adjustments next time. mPrevElapsedTime = elapsedTime; // Convert to microseconds. unsigned long usecTicks = (unsigned long)(1000000 * elapsedTime / mClockFrequency.QuadPart); return usecTicks; #else #ifdef __CELLOS_LV2__ uint64_t freq=sys_time_get_timebase_frequency(); double dFreq=((double) freq)/ 1000000.0; typedef uint64_t ClockSize; ClockSize newTime; //__asm __volatile__( "mftb %0" : "=r" (newTime) : : "memory"); SYS_TIMEBASE_GET( newTime ); return (unsigned long int)((double(newTime-mStartTime)) / dFreq); #else struct timeval currentTime; gettimeofday(¤tTime, 0); return (currentTime.tv_sec - mStartTime.tv_sec) * 1000000 + (currentTime.tv_usec - mStartTime.tv_usec); #endif//__CELLOS_LV2__ #endif } private: #ifdef USE_WINDOWS_TIMERS LARGE_INTEGER mClockFrequency; DWORD mStartTick; LONGLONG mPrevElapsedTime; LARGE_INTEGER mStartTime; #else #ifdef __CELLOS_LV2__ uint64_t mStartTime; #else struct timeval mStartTime; #endif #endif //__CELLOS_LV2__ }; #endif //USE_BT_CLOCK ///A node in the Profile Hierarchy Tree class CProfileNode { public: CProfileNode( const char * name, CProfileNode * parent ); ~CProfileNode( void ); CProfileNode * Get_Sub_Node( const char * name ); CProfileNode * Get_Parent( void ) { return Parent; } CProfileNode * Get_Sibling( void ) { return Sibling; } CProfileNode * Get_Child( void ) { return Child; } void CleanupMemory(); void Reset( void ); void Call( void ); bool Return( void ); const char * Get_Name( void ) { return Name; } int Get_Total_Calls( void ) { return TotalCalls; } float Get_Total_Time( void ) { return TotalTime; } protected: const char * Name; int TotalCalls; float TotalTime; unsigned long int StartTime; int RecursionCounter; CProfileNode * Parent; CProfileNode * Child; CProfileNode * Sibling; }; ///An iterator to navigate through the tree class CProfileIterator { public: // Access all the children of the current parent void First(void); void Next(void); bool Is_Done(void); bool Is_Root(void) { return (CurrentParent->Get_Parent() == 0); } void Enter_Child( int index ); // Make the given child the new parent void Enter_Largest_Child( void ); // Make the largest child the new parent void Enter_Parent( void ); // Make the current parent's parent the new parent // Access the current child const char * Get_Current_Name( void ) { return CurrentChild->Get_Name(); } int Get_Current_Total_Calls( void ) { return CurrentChild->Get_Total_Calls(); } float Get_Current_Total_Time( void ) { return CurrentChild->Get_Total_Time(); } // Access the current parent const char * Get_Current_Parent_Name( void ) { return CurrentParent->Get_Name(); } int Get_Current_Parent_Total_Calls( void ) { return CurrentParent->Get_Total_Calls(); } float Get_Current_Parent_Total_Time( void ) { return CurrentParent->Get_Total_Time(); } protected: CProfileNode * CurrentParent; CProfileNode * CurrentChild; CProfileIterator( CProfileNode * start ); friend class CProfileManager; }; ///The Manager for the Profile system class CProfileManager { public: static void Start_Profile( const char * name ); static void Stop_Profile( void ); static void CleanupMemory(void) { Root.CleanupMemory(); } static void Reset( void ); static void Increment_Frame_Counter( void ); static int Get_Frame_Count_Since_Reset( void ) { return FrameCounter; } static float Get_Time_Since_Reset( void ); static CProfileIterator * Get_Iterator( void ) { return new CProfileIterator( &Root ); } static void Release_Iterator( CProfileIterator * iterator ) { delete ( iterator); } static void dumpRecursive(CProfileIterator* profileIterator, int spacing); static void dumpAll(); private: static CProfileNode Root; static CProfileNode * CurrentNode; static int FrameCounter; static unsigned long int ResetTime; }; ///ProfileSampleClass is a simple way to profile a function's scope ///Use the BT_PROFILE macro at the start of scope to time class CProfileSample { public: CProfileSample( const char * name ) { CProfileManager::Start_Profile( name ); } ~CProfileSample( void ) { CProfileManager::Stop_Profile(); } }; #define BT_PROFILE( name ) CProfileSample __profile( name ) #else #define BT_PROFILE( name ) #endif //#ifndef BT_NO_PROFILE #endif //QUICK_PROF_H critterding-beta12.1/src/utils/bullet/LinearMath/btHashMap.h0000644000175000017500000002037211344267705023034 0ustar bobkebobke#ifndef BT_HASH_MAP_H #define BT_HASH_MAP_H #include "btAlignedObjectArray.h" ///very basic hashable string implementation, compatible with btHashMap struct btHashString { const char* m_string; unsigned int m_hash; SIMD_FORCE_INLINE unsigned int getHash()const { return m_hash; } btHashString(const char* name) :m_string(name) { /* magic numbers from http://www.isthe.com/chongo/tech/comp/fnv/ */ static const unsigned int InitialFNV = 2166136261u; static const unsigned int FNVMultiple = 16777619u; /* Fowler / Noll / Vo (FNV) Hash */ unsigned int hash = InitialFNV; for(int i = 0; m_string[i]; i++) { hash = hash ^ (m_string[i]); /* xor the low 8 bits */ hash = hash * FNVMultiple; /* multiply by the magic number */ } m_hash = hash; } int portableStringCompare(const char* src, const char* dst) const { int ret = 0 ; while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst) ++src, ++dst; if ( ret < 0 ) ret = -1 ; else if ( ret > 0 ) ret = 1 ; return( ret ); } bool equals(const btHashString& other) const { return (m_string == other.m_string) || (0==portableStringCompare(m_string,other.m_string)); } }; const int BT_HASH_NULL=0xffffffff; class btHashInt { int m_uid; public: btHashInt(int uid) :m_uid(uid) { } int getUid1() const { return m_uid; } void setUid1(int uid) { m_uid = uid; } bool equals(const btHashInt& other) const { return getUid1() == other.getUid1(); } //to our success SIMD_FORCE_INLINE unsigned int getHash()const { int key = m_uid; // Thomas Wang's hash key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); return key; } }; class btHashPtr { union { const void* m_pointer; int m_hashValues[2]; }; public: btHashPtr(const void* ptr) :m_pointer(ptr) { } const void* getPointer() const { return m_pointer; } bool equals(const btHashPtr& other) const { return getPointer() == other.getPointer(); } //to our success SIMD_FORCE_INLINE unsigned int getHash()const { const bool VOID_IS_8 = ((sizeof(void*)==8)); int key = VOID_IS_8? m_hashValues[0]+m_hashValues[1] : m_hashValues[0]; // Thomas Wang's hash key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); return key; } }; template class btHashKeyPtr { int m_uid; public: btHashKeyPtr(int uid) :m_uid(uid) { } int getUid1() const { return m_uid; } bool equals(const btHashKeyPtr& other) const { return getUid1() == other.getUid1(); } //to our success SIMD_FORCE_INLINE unsigned int getHash()const { int key = m_uid; // Thomas Wang's hash key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); return key; } }; template class btHashKey { int m_uid; public: btHashKey(int uid) :m_uid(uid) { } int getUid1() const { return m_uid; } bool equals(const btHashKey& other) const { return getUid1() == other.getUid1(); } //to our success SIMD_FORCE_INLINE unsigned int getHash()const { int key = m_uid; // Thomas Wang's hash key += ~(key << 15); key ^= (key >> 10); key += (key << 3); key ^= (key >> 6); key += ~(key << 11); key ^= (key >> 16); return key; } }; ///The btHashMap template class implements a generic and lightweight hashmap. ///A basic sample of how to use btHashMap is located in Demos\BasicDemo\main.cpp template class btHashMap { protected: btAlignedObjectArray m_hashTable; btAlignedObjectArray m_next; btAlignedObjectArray m_valueArray; btAlignedObjectArray m_keyArray; void growTables(const Key& key) { int newCapacity = m_valueArray.capacity(); if (m_hashTable.size() < newCapacity) { //grow hashtable and next table int curHashtableSize = m_hashTable.size(); m_hashTable.resize(newCapacity); m_next.resize(newCapacity); int i; for (i= 0; i < newCapacity; ++i) { m_hashTable[i] = BT_HASH_NULL; } for (i = 0; i < newCapacity; ++i) { m_next[i] = BT_HASH_NULL; } for(i=0;i= (unsigned int)m_hashTable.size()) { return BT_HASH_NULL; } int index = m_hashTable[hash]; while ((index != BT_HASH_NULL) && key.equals(m_keyArray[index]) == false) { index = m_next[index]; } return index; } void clear() { m_hashTable.clear(); m_next.clear(); m_valueArray.clear(); m_keyArray.clear(); } }; #endif //BT_HASH_MAP_H critterding-beta12.1/src/utils/bullet/LinearMath/btQuadWord.h0000644000175000017500000001353211337071441023231 0ustar bobkebobke/* Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ 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 SIMD_QUADWORD_H #define SIMD_QUADWORD_H #include "btScalar.h" #include "btMinMax.h" #if defined (__CELLOS_LV2) && defined (__SPU__) #include #endif /**@brief The btQuadWord class is base class for btVector3 and btQuaternion. * Some issues under PS3 Linux with IBM 2.1 SDK, gcc compiler prevent from using aligned quadword. */ #ifndef USE_LIBSPE2 ATTRIBUTE_ALIGNED16(class) btQuadWord #else class btQuadWord #endif { protected: #if defined (__SPU__) && defined (__CELLOS_LV2__) union { vec_float4 mVec128; btScalar m_floats[4]; }; public: vec_float4 get128() const { return mVec128; } protected: #else //__CELLOS_LV2__ __SPU__ btScalar m_floats[4]; #endif //__CELLOS_LV2__ __SPU__ public: /**@brief Return the x value */ SIMD_FORCE_INLINE const btScalar& getX() const { return m_floats[0]; } /**@brief Return the y value */ SIMD_FORCE_INLINE const btScalar& getY() const { return m_floats[1]; } /**@brief Return the z value */ SIMD_FORCE_INLINE const btScalar& getZ() const { return m_floats[2]; } /**@brief Set the x value */ SIMD_FORCE_INLINE void setX(btScalar x) { m_floats[0] = x;}; /**@brief Set the y value */ SIMD_FORCE_INLINE void setY(btScalar y) { m_floats[1] = y;}; /**@brief Set the z value */ SIMD_FORCE_INLINE void setZ(btScalar z) { m_floats[2] = z;}; /**@brief Set the w value */ SIMD_FORCE_INLINE void setW(btScalar w) { m_floats[3] = w;}; /**@brief Return the x value */ SIMD_FORCE_INLINE const btScalar& x() const { return m_floats[0]; } /**@brief Return the y value */ SIMD_FORCE_INLINE const btScalar& y() const { return m_floats[1]; } /**@brief Return the z value */ SIMD_FORCE_INLINE const btScalar& z() const { return m_floats[2]; } /**@brief Return the w value */ SIMD_FORCE_INLINE const btScalar& w() const { return m_floats[3]; } //SIMD_FORCE_INLINE btScalar& operator[](int i) { return (&m_floats[0])[i]; } //SIMD_FORCE_INLINE const btScalar& operator[](int i) const { return (&m_floats[0])[i]; } ///operator btScalar*() replaces operator[], using implicit conversion. We added operator != and operator == to avoid pointer comparisons. SIMD_FORCE_INLINE operator btScalar *() { return &m_floats[0]; } SIMD_FORCE_INLINE operator const btScalar *() const { return &m_floats[0]; } SIMD_FORCE_INLINE bool operator==(const btQuadWord& other) const { return ((m_floats[3]==other.m_floats[3]) && (m_floats[2]==other.m_floats[2]) && (m_floats[1]==other.m_floats[1]) && (m_floats[0]==other.m_floats[0])); } SIMD_FORCE_INLINE bool operator!=(const btQuadWord& other) const { return !(*this == other); } /**@brief Set x,y,z and zero w * @param x Value of x * @param y Value of y * @param z Value of z */ SIMD_FORCE_INLINE void setValue(const btScalar& x, const btScalar& y, const btScalar& z) { m_floats[0]=x; m_floats[1]=y; m_floats[2]=z; m_floats[3] = 0.f; } /* void getValue(btScalar *m) const { m[0] = m_floats[0]; m[1] = m_floats[1]; m[2] = m_floats[2]; } */ /**@brief Set the values * @param x Value of x * @param y Value of y * @param z Value of z * @param w Value of w */ SIMD_FORCE_INLINE void setValue(const btScalar& x, const btScalar& y, const btScalar& z,const btScalar& w) { m_floats[0]=x; m_floats[1]=y; m_floats[2]=z; m_floats[3]=w; } /**@brief No initialization constructor */ SIMD_FORCE_INLINE btQuadWord() // :m_floats[0](btScalar(0.)),m_floats[1](btScalar(0.)),m_floats[2](btScalar(0.)),m_floats[3](btScalar(0.)) { } /**@brief Three argument constructor (zeros w) * @param x Value of x * @param y Value of y * @param z Value of z */ SIMD_FORCE_INLINE btQuadWord(const btScalar& x, const btScalar& y, const btScalar& z) { m_floats[0] = x, m_floats[1] = y, m_floats[2] = z, m_floats[3] = 0.0f; } /**@brief Initializing constructor * @param x Value of x * @param y Value of y * @param z Value of z * @param w Value of w */ SIMD_FORCE_INLINE btQuadWord(const btScalar& x, const btScalar& y, const btScalar& z,const btScalar& w) { m_floats[0] = x, m_floats[1] = y, m_floats[2] = z, m_floats[3] = w; } /**@brief Set each element to the max of the current values and the values of another btQuadWord * @param other The other btQuadWord to compare with */ SIMD_FORCE_INLINE void setMax(const btQuadWord& other) { btSetMax(m_floats[0], other.m_floats[0]); btSetMax(m_floats[1], other.m_floats[1]); btSetMax(m_floats[2], other.m_floats[2]); btSetMax(m_floats[3], other.m_floats[3]); } /**@brief Set each element to the min of the current values and the values of another btQuadWord * @param other The other btQuadWord to compare with */ SIMD_FORCE_INLINE void setMin(const btQuadWord& other) { btSetMin(m_floats[0], other.m_floats[0]); btSetMin(m_floats[1], other.m_floats[1]); btSetMin(m_floats[2], other.m_floats[2]); btSetMin(m_floats[3], other.m_floats[3]); } }; #endif //SIMD_QUADWORD_H critterding-beta12.1/src/utils/bullet/LinearMath/btAabbUtil2.h0000644000175000017500000002067311337071441023254 0ustar bobkebobke/* Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ 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 AABB_UTIL2 #define AABB_UTIL2 #include "btTransform.h" #include "btVector3.h" #include "btMinMax.h" SIMD_FORCE_INLINE void AabbExpand (btVector3& aabbMin, btVector3& aabbMax, const btVector3& expansionMin, const btVector3& expansionMax) { aabbMin = aabbMin + expansionMin; aabbMax = aabbMax + expansionMax; } /// conservative test for overlap between two aabbs SIMD_FORCE_INLINE bool TestPointAgainstAabb2(const btVector3 &aabbMin1, const btVector3 &aabbMax1, const btVector3 &point) { bool overlap = true; overlap = (aabbMin1.getX() > point.getX() || aabbMax1.getX() < point.getX()) ? false : overlap; overlap = (aabbMin1.getZ() > point.getZ() || aabbMax1.getZ() < point.getZ()) ? false : overlap; overlap = (aabbMin1.getY() > point.getY() || aabbMax1.getY() < point.getY()) ? false : overlap; return overlap; } /// conservative test for overlap between two aabbs SIMD_FORCE_INLINE bool TestAabbAgainstAabb2(const btVector3 &aabbMin1, const btVector3 &aabbMax1, const btVector3 &aabbMin2, const btVector3 &aabbMax2) { bool overlap = true; overlap = (aabbMin1.getX() > aabbMax2.getX() || aabbMax1.getX() < aabbMin2.getX()) ? false : overlap; overlap = (aabbMin1.getZ() > aabbMax2.getZ() || aabbMax1.getZ() < aabbMin2.getZ()) ? false : overlap; overlap = (aabbMin1.getY() > aabbMax2.getY() || aabbMax1.getY() < aabbMin2.getY()) ? false : overlap; return overlap; } /// conservative test for overlap between triangle and aabb SIMD_FORCE_INLINE bool TestTriangleAgainstAabb2(const btVector3 *vertices, const btVector3 &aabbMin, const btVector3 &aabbMax) { const btVector3 &p1 = vertices[0]; const btVector3 &p2 = vertices[1]; const btVector3 &p3 = vertices[2]; if (btMin(btMin(p1[0], p2[0]), p3[0]) > aabbMax[0]) return false; if (btMax(btMax(p1[0], p2[0]), p3[0]) < aabbMin[0]) return false; if (btMin(btMin(p1[2], p2[2]), p3[2]) > aabbMax[2]) return false; if (btMax(btMax(p1[2], p2[2]), p3[2]) < aabbMin[2]) return false; if (btMin(btMin(p1[1], p2[1]), p3[1]) > aabbMax[1]) return false; if (btMax(btMax(p1[1], p2[1]), p3[1]) < aabbMin[1]) return false; return true; } SIMD_FORCE_INLINE int btOutcode(const btVector3& p,const btVector3& halfExtent) { return (p.getX() < -halfExtent.getX() ? 0x01 : 0x0) | (p.getX() > halfExtent.getX() ? 0x08 : 0x0) | (p.getY() < -halfExtent.getY() ? 0x02 : 0x0) | (p.getY() > halfExtent.getY() ? 0x10 : 0x0) | (p.getZ() < -halfExtent.getZ() ? 0x4 : 0x0) | (p.getZ() > halfExtent.getZ() ? 0x20 : 0x0); } SIMD_FORCE_INLINE bool btRayAabb2(const btVector3& rayFrom, const btVector3& rayInvDirection, const unsigned int raySign[3], const btVector3 bounds[2], btScalar& tmin, btScalar lambda_min, btScalar lambda_max) { btScalar tmax, tymin, tymax, tzmin, tzmax; tmin = (bounds[raySign[0]].getX() - rayFrom.getX()) * rayInvDirection.getX(); tmax = (bounds[1-raySign[0]].getX() - rayFrom.getX()) * rayInvDirection.getX(); tymin = (bounds[raySign[1]].getY() - rayFrom.getY()) * rayInvDirection.getY(); tymax = (bounds[1-raySign[1]].getY() - rayFrom.getY()) * rayInvDirection.getY(); if ( (tmin > tymax) || (tymin > tmax) ) return false; if (tymin > tmin) tmin = tymin; if (tymax < tmax) tmax = tymax; tzmin = (bounds[raySign[2]].getZ() - rayFrom.getZ()) * rayInvDirection.getZ(); tzmax = (bounds[1-raySign[2]].getZ() - rayFrom.getZ()) * rayInvDirection.getZ(); if ( (tmin > tzmax) || (tzmin > tmax) ) return false; if (tzmin > tmin) tmin = tzmin; if (tzmax < tmax) tmax = tzmax; return ( (tmin < lambda_max) && (tmax > lambda_min) ); } SIMD_FORCE_INLINE bool btRayAabb(const btVector3& rayFrom, const btVector3& rayTo, const btVector3& aabbMin, const btVector3& aabbMax, btScalar& param, btVector3& normal) { btVector3 aabbHalfExtent = (aabbMax-aabbMin)* btScalar(0.5); btVector3 aabbCenter = (aabbMax+aabbMin)* btScalar(0.5); btVector3 source = rayFrom - aabbCenter; btVector3 target = rayTo - aabbCenter; int sourceOutcode = btOutcode(source,aabbHalfExtent); int targetOutcode = btOutcode(target,aabbHalfExtent); if ((sourceOutcode & targetOutcode) == 0x0) { btScalar lambda_enter = btScalar(0.0); btScalar lambda_exit = param; btVector3 r = target - source; int i; btScalar normSign = 1; btVector3 hitNormal(0,0,0); int bit=1; for (int j=0;j<2;j++) { for (i = 0; i != 3; ++i) { if (sourceOutcode & bit) { btScalar lambda = (-source[i] - aabbHalfExtent[i]*normSign) / r[i]; if (lambda_enter <= lambda) { lambda_enter = lambda; hitNormal.setValue(0,0,0); hitNormal[i] = normSign; } } else if (targetOutcode & bit) { btScalar lambda = (-source[i] - aabbHalfExtent[i]*normSign) / r[i]; btSetMin(lambda_exit, lambda); } bit<<=1; } normSign = btScalar(-1.); } if (lambda_enter <= lambda_exit) { param = lambda_enter; normal = hitNormal; return true; } } return false; } SIMD_FORCE_INLINE void btTransformAabb(const btVector3& halfExtents, btScalar margin,const btTransform& t,btVector3& aabbMinOut,btVector3& aabbMaxOut) { btVector3 halfExtentsWithMargin = halfExtents+btVector3(margin,margin,margin); btMatrix3x3 abs_b = t.getBasis().absolute(); btVector3 center = t.getOrigin(); btVector3 extent = btVector3(abs_b[0].dot(halfExtentsWithMargin), abs_b[1].dot(halfExtentsWithMargin), abs_b[2].dot(halfExtentsWithMargin)); aabbMinOut = center - extent; aabbMaxOut = center + extent; } SIMD_FORCE_INLINE void btTransformAabb(const btVector3& localAabbMin,const btVector3& localAabbMax, btScalar margin,const btTransform& trans,btVector3& aabbMinOut,btVector3& aabbMaxOut) { btAssert(localAabbMin.getX() <= localAabbMax.getX()); btAssert(localAabbMin.getY() <= localAabbMax.getY()); btAssert(localAabbMin.getZ() <= localAabbMax.getZ()); btVector3 localHalfExtents = btScalar(0.5)*(localAabbMax-localAabbMin); localHalfExtents+=btVector3(margin,margin,margin); btVector3 localCenter = btScalar(0.5)*(localAabbMax+localAabbMin); btMatrix3x3 abs_b = trans.getBasis().absolute(); btVector3 center = trans(localCenter); btVector3 extent = btVector3(abs_b[0].dot(localHalfExtents), abs_b[1].dot(localHalfExtents), abs_b[2].dot(localHalfExtents)); aabbMinOut = center-extent; aabbMaxOut = center+extent; } #define USE_BANCHLESS 1 #ifdef USE_BANCHLESS //This block replaces the block below and uses no branches, and replaces the 8 bit return with a 32 bit return for improved performance (~3x on XBox 360) SIMD_FORCE_INLINE unsigned testQuantizedAabbAgainstQuantizedAabb(const unsigned short int* aabbMin1,const unsigned short int* aabbMax1,const unsigned short int* aabbMin2,const unsigned short int* aabbMax2) { return static_cast(btSelect((unsigned)((aabbMin1[0] <= aabbMax2[0]) & (aabbMax1[0] >= aabbMin2[0]) & (aabbMin1[2] <= aabbMax2[2]) & (aabbMax1[2] >= aabbMin2[2]) & (aabbMin1[1] <= aabbMax2[1]) & (aabbMax1[1] >= aabbMin2[1])), 1, 0)); } #else SIMD_FORCE_INLINE bool testQuantizedAabbAgainstQuantizedAabb(const unsigned short int* aabbMin1,const unsigned short int* aabbMax1,const unsigned short int* aabbMin2,const unsigned short int* aabbMax2) { bool overlap = true; overlap = (aabbMin1[0] > aabbMax2[0] || aabbMax1[0] < aabbMin2[0]) ? false : overlap; overlap = (aabbMin1[2] > aabbMax2[2] || aabbMax1[2] < aabbMin2[2]) ? false : overlap; overlap = (aabbMin1[1] > aabbMax2[1] || aabbMax1[1] < aabbMin2[1]) ? false : overlap; return overlap; } #endif //USE_BANCHLESS #endif critterding-beta12.1/src/utils/bullet/LinearMath/btMatrix3x3.h0000644000175000017500000005120211344267705023311 0ustar bobkebobke/* Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ 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 BT_MATRIX3x3_H #define BT_MATRIX3x3_H #include "btVector3.h" #include "btQuaternion.h" #ifdef BT_USE_DOUBLE_PRECISION #define btMatrix3x3Data btMatrix3x3DoubleData #else #define btMatrix3x3Data btMatrix3x3FloatData #endif //BT_USE_DOUBLE_PRECISION /**@brief The btMatrix3x3 class implements a 3x3 rotation matrix, to perform linear algebra in combination with btQuaternion, btTransform and btVector3. * Make sure to only include a pure orthogonal matrix without scaling. */ class btMatrix3x3 { ///Data storage for the matrix, each vector is a row of the matrix btVector3 m_el[3]; public: /** @brief No initializaion constructor */ btMatrix3x3 () {} // explicit btMatrix3x3(const btScalar *m) { setFromOpenGLSubMatrix(m); } /**@brief Constructor from Quaternion */ explicit btMatrix3x3(const btQuaternion& q) { setRotation(q); } /* template Matrix3x3(const btScalar& yaw, const btScalar& pitch, const btScalar& roll) { setEulerYPR(yaw, pitch, roll); } */ /** @brief Constructor with row major formatting */ btMatrix3x3(const btScalar& xx, const btScalar& xy, const btScalar& xz, const btScalar& yx, const btScalar& yy, const btScalar& yz, const btScalar& zx, const btScalar& zy, const btScalar& zz) { setValue(xx, xy, xz, yx, yy, yz, zx, zy, zz); } /** @brief Copy constructor */ SIMD_FORCE_INLINE btMatrix3x3 (const btMatrix3x3& other) { m_el[0] = other.m_el[0]; m_el[1] = other.m_el[1]; m_el[2] = other.m_el[2]; } /** @brief Assignment Operator */ SIMD_FORCE_INLINE btMatrix3x3& operator=(const btMatrix3x3& other) { m_el[0] = other.m_el[0]; m_el[1] = other.m_el[1]; m_el[2] = other.m_el[2]; return *this; } /** @brief Get a column of the matrix as a vector * @param i Column number 0 indexed */ SIMD_FORCE_INLINE btVector3 getColumn(int i) const { return btVector3(m_el[0][i],m_el[1][i],m_el[2][i]); } /** @brief Get a row of the matrix as a vector * @param i Row number 0 indexed */ SIMD_FORCE_INLINE const btVector3& getRow(int i) const { btFullAssert(0 <= i && i < 3); return m_el[i]; } /** @brief Get a mutable reference to a row of the matrix as a vector * @param i Row number 0 indexed */ SIMD_FORCE_INLINE btVector3& operator[](int i) { btFullAssert(0 <= i && i < 3); return m_el[i]; } /** @brief Get a const reference to a row of the matrix as a vector * @param i Row number 0 indexed */ SIMD_FORCE_INLINE const btVector3& operator[](int i) const { btFullAssert(0 <= i && i < 3); return m_el[i]; } /** @brief Multiply by the target matrix on the right * @param m Rotation matrix to be applied * Equivilant to this = this * m */ btMatrix3x3& operator*=(const btMatrix3x3& m); /** @brief Set from a carray of btScalars * @param m A pointer to the beginning of an array of 9 btScalars */ void setFromOpenGLSubMatrix(const btScalar *m) { m_el[0].setValue(m[0],m[4],m[8]); m_el[1].setValue(m[1],m[5],m[9]); m_el[2].setValue(m[2],m[6],m[10]); } /** @brief Set the values of the matrix explicitly (row major) * @param xx Top left * @param xy Top Middle * @param xz Top Right * @param yx Middle Left * @param yy Middle Middle * @param yz Middle Right * @param zx Bottom Left * @param zy Bottom Middle * @param zz Bottom Right*/ void setValue(const btScalar& xx, const btScalar& xy, const btScalar& xz, const btScalar& yx, const btScalar& yy, const btScalar& yz, const btScalar& zx, const btScalar& zy, const btScalar& zz) { m_el[0].setValue(xx,xy,xz); m_el[1].setValue(yx,yy,yz); m_el[2].setValue(zx,zy,zz); } /** @brief Set the matrix from a quaternion * @param q The Quaternion to match */ void setRotation(const btQuaternion& q) { btScalar d = q.length2(); btFullAssert(d != btScalar(0.0)); btScalar s = btScalar(2.0) / d; btScalar xs = q.x() * s, ys = q.y() * s, zs = q.z() * s; btScalar wx = q.w() * xs, wy = q.w() * ys, wz = q.w() * zs; btScalar xx = q.x() * xs, xy = q.x() * ys, xz = q.x() * zs; btScalar yy = q.y() * ys, yz = q.y() * zs, zz = q.z() * zs; setValue(btScalar(1.0) - (yy + zz), xy - wz, xz + wy, xy + wz, btScalar(1.0) - (xx + zz), yz - wx, xz - wy, yz + wx, btScalar(1.0) - (xx + yy)); } /** @brief Set the matrix from euler angles using YPR around YXZ respectively * @param yaw Yaw about Y axis * @param pitch Pitch about X axis * @param roll Roll about Z axis */ void setEulerYPR(const btScalar& yaw, const btScalar& pitch, const btScalar& roll) { setEulerZYX(roll, pitch, yaw); } /** @brief Set the matrix from euler angles YPR around ZYX axes * @param eulerX Roll about X axis * @param eulerY Pitch around Y axis * @param eulerZ Yaw aboud Z axis * * These angles are used to produce a rotation matrix. The euler * angles are applied in ZYX order. I.e a vector is first rotated * about X then Y and then Z **/ void setEulerZYX(btScalar eulerX,btScalar eulerY,btScalar eulerZ) { ///@todo proposed to reverse this since it's labeled zyx but takes arguments xyz and it will match all other parts of the code btScalar ci ( btCos(eulerX)); btScalar cj ( btCos(eulerY)); btScalar ch ( btCos(eulerZ)); btScalar si ( btSin(eulerX)); btScalar sj ( btSin(eulerY)); btScalar sh ( btSin(eulerZ)); btScalar cc = ci * ch; btScalar cs = ci * sh; btScalar sc = si * ch; btScalar ss = si * sh; setValue(cj * ch, sj * sc - cs, sj * cc + ss, cj * sh, sj * ss + cc, sj * cs - sc, -sj, cj * si, cj * ci); } /**@brief Set the matrix to the identity */ void setIdentity() { setValue(btScalar(1.0), btScalar(0.0), btScalar(0.0), btScalar(0.0), btScalar(1.0), btScalar(0.0), btScalar(0.0), btScalar(0.0), btScalar(1.0)); } static const btMatrix3x3& getIdentity() { static const btMatrix3x3 identityMatrix(btScalar(1.0), btScalar(0.0), btScalar(0.0), btScalar(0.0), btScalar(1.0), btScalar(0.0), btScalar(0.0), btScalar(0.0), btScalar(1.0)); return identityMatrix; } /**@brief Fill the values of the matrix into a 9 element array * @param m The array to be filled */ void getOpenGLSubMatrix(btScalar *m) const { m[0] = btScalar(m_el[0].x()); m[1] = btScalar(m_el[1].x()); m[2] = btScalar(m_el[2].x()); m[3] = btScalar(0.0); m[4] = btScalar(m_el[0].y()); m[5] = btScalar(m_el[1].y()); m[6] = btScalar(m_el[2].y()); m[7] = btScalar(0.0); m[8] = btScalar(m_el[0].z()); m[9] = btScalar(m_el[1].z()); m[10] = btScalar(m_el[2].z()); m[11] = btScalar(0.0); } /**@brief Get the matrix represented as a quaternion * @param q The quaternion which will be set */ void getRotation(btQuaternion& q) const { btScalar trace = m_el[0].x() + m_el[1].y() + m_el[2].z(); btScalar temp[4]; if (trace > btScalar(0.0)) { btScalar s = btSqrt(trace + btScalar(1.0)); temp[3]=(s * btScalar(0.5)); s = btScalar(0.5) / s; temp[0]=((m_el[2].y() - m_el[1].z()) * s); temp[1]=((m_el[0].z() - m_el[2].x()) * s); temp[2]=((m_el[1].x() - m_el[0].y()) * s); } else { int i = m_el[0].x() < m_el[1].y() ? (m_el[1].y() < m_el[2].z() ? 2 : 1) : (m_el[0].x() < m_el[2].z() ? 2 : 0); int j = (i + 1) % 3; int k = (i + 2) % 3; btScalar s = btSqrt(m_el[i][i] - m_el[j][j] - m_el[k][k] + btScalar(1.0)); temp[i] = s * btScalar(0.5); s = btScalar(0.5) / s; temp[3] = (m_el[k][j] - m_el[j][k]) * s; temp[j] = (m_el[j][i] + m_el[i][j]) * s; temp[k] = (m_el[k][i] + m_el[i][k]) * s; } q.setValue(temp[0],temp[1],temp[2],temp[3]); } /**@brief Get the matrix represented as euler angles around YXZ, roundtrip with setEulerYPR * @param yaw Yaw around Y axis * @param pitch Pitch around X axis * @param roll around Z axis */ void getEulerYPR(btScalar& yaw, btScalar& pitch, btScalar& roll) const { // first use the normal calculus yaw = btScalar(btAtan2(m_el[1].x(), m_el[0].x())); pitch = btScalar(btAsin(-m_el[2].x())); roll = btScalar(btAtan2(m_el[2].y(), m_el[2].z())); // on pitch = +/-HalfPI if (btFabs(pitch)==SIMD_HALF_PI) { if (yaw>0) yaw-=SIMD_PI; else yaw+=SIMD_PI; if (roll>0) roll-=SIMD_PI; else roll+=SIMD_PI; } }; /**@brief Get the matrix represented as euler angles around ZYX * @param yaw Yaw around X axis * @param pitch Pitch around Y axis * @param roll around X axis * @param solution_number Which solution of two possible solutions ( 1 or 2) are possible values*/ void getEulerZYX(btScalar& yaw, btScalar& pitch, btScalar& roll, unsigned int solution_number = 1) const { struct Euler { btScalar yaw; btScalar pitch; btScalar roll; }; Euler euler_out; Euler euler_out2; //second solution //get the pointer to the raw data // Check that pitch is not at a singularity if (btFabs(m_el[2].x()) >= 1) { euler_out.yaw = 0; euler_out2.yaw = 0; // From difference of angles formula btScalar delta = btAtan2(m_el[0].x(),m_el[0].z()); if (m_el[2].x() > 0) //gimbal locked up { euler_out.pitch = SIMD_PI / btScalar(2.0); euler_out2.pitch = SIMD_PI / btScalar(2.0); euler_out.roll = euler_out.pitch + delta; euler_out2.roll = euler_out.pitch + delta; } else // gimbal locked down { euler_out.pitch = -SIMD_PI / btScalar(2.0); euler_out2.pitch = -SIMD_PI / btScalar(2.0); euler_out.roll = -euler_out.pitch + delta; euler_out2.roll = -euler_out.pitch + delta; } } else { euler_out.pitch = - btAsin(m_el[2].x()); euler_out2.pitch = SIMD_PI - euler_out.pitch; euler_out.roll = btAtan2(m_el[2].y()/btCos(euler_out.pitch), m_el[2].z()/btCos(euler_out.pitch)); euler_out2.roll = btAtan2(m_el[2].y()/btCos(euler_out2.pitch), m_el[2].z()/btCos(euler_out2.pitch)); euler_out.yaw = btAtan2(m_el[1].x()/btCos(euler_out.pitch), m_el[0].x()/btCos(euler_out.pitch)); euler_out2.yaw = btAtan2(m_el[1].x()/btCos(euler_out2.pitch), m_el[0].x()/btCos(euler_out2.pitch)); } if (solution_number == 1) { yaw = euler_out.yaw; pitch = euler_out.pitch; roll = euler_out.roll; } else { yaw = euler_out2.yaw; pitch = euler_out2.pitch; roll = euler_out2.roll; } } /**@brief Create a scaled copy of the matrix * @param s Scaling vector The elements of the vector will scale each column */ btMatrix3x3 scaled(const btVector3& s) const { return btMatrix3x3(m_el[0].x() * s.x(), m_el[0].y() * s.y(), m_el[0].z() * s.z(), m_el[1].x() * s.x(), m_el[1].y() * s.y(), m_el[1].z() * s.z(), m_el[2].x() * s.x(), m_el[2].y() * s.y(), m_el[2].z() * s.z()); } /**@brief Return the determinant of the matrix */ btScalar determinant() const; /**@brief Return the adjoint of the matrix */ btMatrix3x3 adjoint() const; /**@brief Return the matrix with all values non negative */ btMatrix3x3 absolute() const; /**@brief Return the transpose of the matrix */ btMatrix3x3 transpose() const; /**@brief Return the inverse of the matrix */ btMatrix3x3 inverse() const; btMatrix3x3 transposeTimes(const btMatrix3x3& m) const; btMatrix3x3 timesTranspose(const btMatrix3x3& m) const; SIMD_FORCE_INLINE btScalar tdotx(const btVector3& v) const { return m_el[0].x() * v.x() + m_el[1].x() * v.y() + m_el[2].x() * v.z(); } SIMD_FORCE_INLINE btScalar tdoty(const btVector3& v) const { return m_el[0].y() * v.x() + m_el[1].y() * v.y() + m_el[2].y() * v.z(); } SIMD_FORCE_INLINE btScalar tdotz(const btVector3& v) const { return m_el[0].z() * v.x() + m_el[1].z() * v.y() + m_el[2].z() * v.z(); } /**@brief diagonalizes this matrix by the Jacobi method. * @param rot stores the rotation from the coordinate system in which the matrix is diagonal to the original * coordinate system, i.e., old_this = rot * new_this * rot^T. * @param threshold See iteration * @param iteration The iteration stops when all off-diagonal elements are less than the threshold multiplied * by the sum of the absolute values of the diagonal, or when maxSteps have been executed. * * Note that this matrix is assumed to be symmetric. */ void diagonalize(btMatrix3x3& rot, btScalar threshold, int maxSteps) { rot.setIdentity(); for (int step = maxSteps; step > 0; step--) { // find off-diagonal element [p][q] with largest magnitude int p = 0; int q = 1; int r = 2; btScalar max = btFabs(m_el[0][1]); btScalar v = btFabs(m_el[0][2]); if (v > max) { q = 2; r = 1; max = v; } v = btFabs(m_el[1][2]); if (v > max) { p = 1; q = 2; r = 0; max = v; } btScalar t = threshold * (btFabs(m_el[0][0]) + btFabs(m_el[1][1]) + btFabs(m_el[2][2])); if (max <= t) { if (max <= SIMD_EPSILON * t) { return; } step = 1; } // compute Jacobi rotation J which leads to a zero for element [p][q] btScalar mpq = m_el[p][q]; btScalar theta = (m_el[q][q] - m_el[p][p]) / (2 * mpq); btScalar theta2 = theta * theta; btScalar cos; btScalar sin; if (theta2 * theta2 < btScalar(10 / SIMD_EPSILON)) { t = (theta >= 0) ? 1 / (theta + btSqrt(1 + theta2)) : 1 / (theta - btSqrt(1 + theta2)); cos = 1 / btSqrt(1 + t * t); sin = cos * t; } else { // approximation for large theta-value, i.e., a nearly diagonal matrix t = 1 / (theta * (2 + btScalar(0.5) / theta2)); cos = 1 - btScalar(0.5) * t * t; sin = cos * t; } // apply rotation to matrix (this = J^T * this * J) m_el[p][q] = m_el[q][p] = 0; m_el[p][p] -= t * mpq; m_el[q][q] += t * mpq; btScalar mrp = m_el[r][p]; btScalar mrq = m_el[r][q]; m_el[r][p] = m_el[p][r] = cos * mrp - sin * mrq; m_el[r][q] = m_el[q][r] = cos * mrq + sin * mrp; // apply rotation to rot (rot = rot * J) for (int i = 0; i < 3; i++) { btVector3& row = rot[i]; mrp = row[p]; mrq = row[q]; row[p] = cos * mrp - sin * mrq; row[q] = cos * mrq + sin * mrp; } } } /**@brief Calculate the matrix cofactor * @param r1 The first row to use for calculating the cofactor * @param c1 The first column to use for calculating the cofactor * @param r1 The second row to use for calculating the cofactor * @param c1 The second column to use for calculating the cofactor * See http://en.wikipedia.org/wiki/Cofactor_(linear_algebra) for more details */ btScalar cofac(int r1, int c1, int r2, int c2) const { return m_el[r1][c1] * m_el[r2][c2] - m_el[r1][c2] * m_el[r2][c1]; } void serialize(struct btMatrix3x3Data& dataOut) const; void serializeFloat(struct btMatrix3x3FloatData& dataOut) const; void deSerialize(const struct btMatrix3x3Data& dataIn); void deSerializeFloat(const struct btMatrix3x3FloatData& dataIn); void deSerializeDouble(const struct btMatrix3x3DoubleData& dataIn); }; SIMD_FORCE_INLINE btMatrix3x3& btMatrix3x3::operator*=(const btMatrix3x3& m) { setValue(m.tdotx(m_el[0]), m.tdoty(m_el[0]), m.tdotz(m_el[0]), m.tdotx(m_el[1]), m.tdoty(m_el[1]), m.tdotz(m_el[1]), m.tdotx(m_el[2]), m.tdoty(m_el[2]), m.tdotz(m_el[2])); return *this; } SIMD_FORCE_INLINE btScalar btMatrix3x3::determinant() const { return btTriple((*this)[0], (*this)[1], (*this)[2]); } SIMD_FORCE_INLINE btMatrix3x3 btMatrix3x3::absolute() const { return btMatrix3x3( btFabs(m_el[0].x()), btFabs(m_el[0].y()), btFabs(m_el[0].z()), btFabs(m_el[1].x()), btFabs(m_el[1].y()), btFabs(m_el[1].z()), btFabs(m_el[2].x()), btFabs(m_el[2].y()), btFabs(m_el[2].z())); } SIMD_FORCE_INLINE btMatrix3x3 btMatrix3x3::transpose() const { return btMatrix3x3(m_el[0].x(), m_el[1].x(), m_el[2].x(), m_el[0].y(), m_el[1].y(), m_el[2].y(), m_el[0].z(), m_el[1].z(), m_el[2].z()); } SIMD_FORCE_INLINE btMatrix3x3 btMatrix3x3::adjoint() const { return btMatrix3x3(cofac(1, 1, 2, 2), cofac(0, 2, 2, 1), cofac(0, 1, 1, 2), cofac(1, 2, 2, 0), cofac(0, 0, 2, 2), cofac(0, 2, 1, 0), cofac(1, 0, 2, 1), cofac(0, 1, 2, 0), cofac(0, 0, 1, 1)); } SIMD_FORCE_INLINE btMatrix3x3 btMatrix3x3::inverse() const { btVector3 co(cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1)); btScalar det = (*this)[0].dot(co); btFullAssert(det != btScalar(0.0)); btScalar s = btScalar(1.0) / det; return btMatrix3x3(co.x() * s, cofac(0, 2, 2, 1) * s, cofac(0, 1, 1, 2) * s, co.y() * s, cofac(0, 0, 2, 2) * s, cofac(0, 2, 1, 0) * s, co.z() * s, cofac(0, 1, 2, 0) * s, cofac(0, 0, 1, 1) * s); } SIMD_FORCE_INLINE btMatrix3x3 btMatrix3x3::transposeTimes(const btMatrix3x3& m) const { return btMatrix3x3( m_el[0].x() * m[0].x() + m_el[1].x() * m[1].x() + m_el[2].x() * m[2].x(), m_el[0].x() * m[0].y() + m_el[1].x() * m[1].y() + m_el[2].x() * m[2].y(), m_el[0].x() * m[0].z() + m_el[1].x() * m[1].z() + m_el[2].x() * m[2].z(), m_el[0].y() * m[0].x() + m_el[1].y() * m[1].x() + m_el[2].y() * m[2].x(), m_el[0].y() * m[0].y() + m_el[1].y() * m[1].y() + m_el[2].y() * m[2].y(), m_el[0].y() * m[0].z() + m_el[1].y() * m[1].z() + m_el[2].y() * m[2].z(), m_el[0].z() * m[0].x() + m_el[1].z() * m[1].x() + m_el[2].z() * m[2].x(), m_el[0].z() * m[0].y() + m_el[1].z() * m[1].y() + m_el[2].z() * m[2].y(), m_el[0].z() * m[0].z() + m_el[1].z() * m[1].z() + m_el[2].z() * m[2].z()); } SIMD_FORCE_INLINE btMatrix3x3 btMatrix3x3::timesTranspose(const btMatrix3x3& m) const { return btMatrix3x3( m_el[0].dot(m[0]), m_el[0].dot(m[1]), m_el[0].dot(m[2]), m_el[1].dot(m[0]), m_el[1].dot(m[1]), m_el[1].dot(m[2]), m_el[2].dot(m[0]), m_el[2].dot(m[1]), m_el[2].dot(m[2])); } SIMD_FORCE_INLINE btVector3 operator*(const btMatrix3x3& m, const btVector3& v) { return btVector3(m[0].dot(v), m[1].dot(v), m[2].dot(v)); } SIMD_FORCE_INLINE btVector3 operator*(const btVector3& v, const btMatrix3x3& m) { return btVector3(m.tdotx(v), m.tdoty(v), m.tdotz(v)); } SIMD_FORCE_INLINE btMatrix3x3 operator*(const btMatrix3x3& m1, const btMatrix3x3& m2) { return btMatrix3x3( m2.tdotx( m1[0]), m2.tdoty( m1[0]), m2.tdotz( m1[0]), m2.tdotx( m1[1]), m2.tdoty( m1[1]), m2.tdotz( m1[1]), m2.tdotx( m1[2]), m2.tdoty( m1[2]), m2.tdotz( m1[2])); } /* SIMD_FORCE_INLINE btMatrix3x3 btMultTransposeLeft(const btMatrix3x3& m1, const btMatrix3x3& m2) { return btMatrix3x3( m1[0][0] * m2[0][0] + m1[1][0] * m2[1][0] + m1[2][0] * m2[2][0], m1[0][0] * m2[0][1] + m1[1][0] * m2[1][1] + m1[2][0] * m2[2][1], m1[0][0] * m2[0][2] + m1[1][0] * m2[1][2] + m1[2][0] * m2[2][2], m1[0][1] * m2[0][0] + m1[1][1] * m2[1][0] + m1[2][1] * m2[2][0], m1[0][1] * m2[0][1] + m1[1][1] * m2[1][1] + m1[2][1] * m2[2][1], m1[0][1] * m2[0][2] + m1[1][1] * m2[1][2] + m1[2][1] * m2[2][2], m1[0][2] * m2[0][0] + m1[1][2] * m2[1][0] + m1[2][2] * m2[2][0], m1[0][2] * m2[0][1] + m1[1][2] * m2[1][1] + m1[2][2] * m2[2][1], m1[0][2] * m2[0][2] + m1[1][2] * m2[1][2] + m1[2][2] * m2[2][2]); } */ /**@brief Equality operator between two matrices * It will test all elements are equal. */ SIMD_FORCE_INLINE bool operator==(const btMatrix3x3& m1, const btMatrix3x3& m2) { return ( m1[0][0] == m2[0][0] && m1[1][0] == m2[1][0] && m1[2][0] == m2[2][0] && m1[0][1] == m2[0][1] && m1[1][1] == m2[1][1] && m1[2][1] == m2[2][1] && m1[0][2] == m2[0][2] && m1[1][2] == m2[1][2] && m1[2][2] == m2[2][2] ); } ///for serialization struct btMatrix3x3FloatData { btVector3FloatData m_el[3]; }; ///for serialization struct btMatrix3x3DoubleData { btVector3DoubleData m_el[3]; }; SIMD_FORCE_INLINE void btMatrix3x3::serialize(struct btMatrix3x3Data& dataOut) const { for (int i=0;i<3;i++) m_el[i].serialize(dataOut.m_el[i]); } SIMD_FORCE_INLINE void btMatrix3x3::serializeFloat(struct btMatrix3x3FloatData& dataOut) const { for (int i=0;i<3;i++) m_el[i].serializeFloat(dataOut.m_el[i]); } SIMD_FORCE_INLINE void btMatrix3x3::deSerialize(const struct btMatrix3x3Data& dataIn) { for (int i=0;i<3;i++) m_el[i].deSerialize(dataIn.m_el[i]); } SIMD_FORCE_INLINE void btMatrix3x3::deSerializeFloat(const struct btMatrix3x3FloatData& dataIn) { for (int i=0;i<3;i++) m_el[i].deSerializeFloat(dataIn.m_el[i]); } SIMD_FORCE_INLINE void btMatrix3x3::deSerializeDouble(const struct btMatrix3x3DoubleData& dataIn) { for (int i=0;i<3;i++) m_el[i].deSerializeDouble(dataIn.m_el[i]); } #endif //BT_MATRIX3x3_H critterding-beta12.1/src/utils/bullet/LinearMath/btMotionState.h0000644000175000017500000000307511337071441023752 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2006 Erwin Coumans http://continuousphysics.com/Bullet/ 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 BT_MOTIONSTATE_H #define BT_MOTIONSTATE_H #include "btTransform.h" ///The btMotionState interface class allows the dynamics world to synchronize and interpolate the updated world transforms with graphics ///For optimizations, potentially only moving objects get synchronized (using setWorldPosition/setWorldOrientation) class btMotionState { public: virtual ~btMotionState() { } virtual void getWorldTransform(btTransform& worldTrans ) const =0; //Bullet only calls the update of worldtransform for active objects virtual void setWorldTransform(const btTransform& worldTrans)=0; }; #endif //BT_MOTIONSTATE_H critterding-beta12.1/src/utils/bullet/LinearMath/btQuickprof.cpp0000644000175000017500000002527611344267705024021 0ustar bobkebobke/* *************************************************************************************************** ** ** profile.cpp ** ** Real-Time Hierarchical Profiling for Game Programming Gems 3 ** ** by Greg Hjelstrom & Byon Garrabrant ** ***************************************************************************************************/ // Credits: The Clock class was inspired by the Timer classes in // Ogre (www.ogre3d.org). #include "btQuickprof.h" #ifdef USE_BT_CLOCK static btClock gProfileClock; inline void Profile_Get_Ticks(unsigned long int * ticks) { *ticks = gProfileClock.getTimeMicroseconds(); } inline float Profile_Get_Tick_Rate(void) { // return 1000000.f; return 1000.f; } /*************************************************************************************************** ** ** CProfileNode ** ***************************************************************************************************/ /*********************************************************************************************** * INPUT: * * name - pointer to a static string which is the name of this profile node * * parent - parent pointer * * * * WARNINGS: * * The name is assumed to be a static pointer, only the pointer is stored and compared for * * efficiency reasons. * *=============================================================================================*/ CProfileNode::CProfileNode( const char * name, CProfileNode * parent ) : Name( name ), TotalCalls( 0 ), TotalTime( 0 ), StartTime( 0 ), RecursionCounter( 0 ), Parent( parent ), Child( NULL ), Sibling( NULL ) { Reset(); } void CProfileNode::CleanupMemory() { delete ( Child); Child = NULL; delete ( Sibling); Sibling = NULL; } CProfileNode::~CProfileNode( void ) { delete ( Child); delete ( Sibling); } /*********************************************************************************************** * INPUT: * * name - static string pointer to the name of the node we are searching for * * * * WARNINGS: * * All profile names are assumed to be static strings so this function uses pointer compares * * to find the named node. * *=============================================================================================*/ CProfileNode * CProfileNode::Get_Sub_Node( const char * name ) { // Try to find this sub node CProfileNode * child = Child; while ( child ) { if ( child->Name == name ) { return child; } child = child->Sibling; } // We didn't find it, so add it CProfileNode * node = new CProfileNode( name, this ); node->Sibling = Child; Child = node; return node; } void CProfileNode::Reset( void ) { TotalCalls = 0; TotalTime = 0.0f; if ( Child ) { Child->Reset(); } if ( Sibling ) { Sibling->Reset(); } } void CProfileNode::Call( void ) { TotalCalls++; if (RecursionCounter++ == 0) { Profile_Get_Ticks(&StartTime); } } bool CProfileNode::Return( void ) { if ( --RecursionCounter == 0 && TotalCalls != 0 ) { unsigned long int time; Profile_Get_Ticks(&time); time-=StartTime; TotalTime += (float)time / Profile_Get_Tick_Rate(); } return ( RecursionCounter == 0 ); } /*************************************************************************************************** ** ** CProfileIterator ** ***************************************************************************************************/ CProfileIterator::CProfileIterator( CProfileNode * start ) { CurrentParent = start; CurrentChild = CurrentParent->Get_Child(); } void CProfileIterator::First(void) { CurrentChild = CurrentParent->Get_Child(); } void CProfileIterator::Next(void) { CurrentChild = CurrentChild->Get_Sibling(); } bool CProfileIterator::Is_Done(void) { return CurrentChild == NULL; } void CProfileIterator::Enter_Child( int index ) { CurrentChild = CurrentParent->Get_Child(); while ( (CurrentChild != NULL) && (index != 0) ) { index--; CurrentChild = CurrentChild->Get_Sibling(); } if ( CurrentChild != NULL ) { CurrentParent = CurrentChild; CurrentChild = CurrentParent->Get_Child(); } } void CProfileIterator::Enter_Parent( void ) { if ( CurrentParent->Get_Parent() != NULL ) { CurrentParent = CurrentParent->Get_Parent(); } CurrentChild = CurrentParent->Get_Child(); } /*************************************************************************************************** ** ** CProfileManager ** ***************************************************************************************************/ CProfileNode CProfileManager::Root( "Root", NULL ); CProfileNode * CProfileManager::CurrentNode = &CProfileManager::Root; int CProfileManager::FrameCounter = 0; unsigned long int CProfileManager::ResetTime = 0; /*********************************************************************************************** * CProfileManager::Start_Profile -- Begin a named profile * * * * Steps one level deeper into the tree, if a child already exists with the specified name * * then it accumulates the profiling; otherwise a new child node is added to the profile tree. * * * * INPUT: * * name - name of this profiling record * * * * WARNINGS: * * The string used is assumed to be a static string; pointer compares are used throughout * * the profiling code for efficiency. * *=============================================================================================*/ void CProfileManager::Start_Profile( const char * name ) { if (name != CurrentNode->Get_Name()) { CurrentNode = CurrentNode->Get_Sub_Node( name ); } CurrentNode->Call(); } /*********************************************************************************************** * CProfileManager::Stop_Profile -- Stop timing and record the results. * *=============================================================================================*/ void CProfileManager::Stop_Profile( void ) { // Return will indicate whether we should back up to our parent (we may // be profiling a recursive function) if (CurrentNode->Return()) { CurrentNode = CurrentNode->Get_Parent(); } } /*********************************************************************************************** * CProfileManager::Reset -- Reset the contents of the profiling system * * * * This resets everything except for the tree structure. All of the timing data is reset. * *=============================================================================================*/ void CProfileManager::Reset( void ) { gProfileClock.reset(); Root.Reset(); Root.Call(); FrameCounter = 0; Profile_Get_Ticks(&ResetTime); } /*********************************************************************************************** * CProfileManager::Increment_Frame_Counter -- Increment the frame counter * *=============================================================================================*/ void CProfileManager::Increment_Frame_Counter( void ) { FrameCounter++; } /*********************************************************************************************** * CProfileManager::Get_Time_Since_Reset -- returns the elapsed time since last reset * *=============================================================================================*/ float CProfileManager::Get_Time_Since_Reset( void ) { unsigned long int time; Profile_Get_Ticks(&time); time -= ResetTime; return (float)time / Profile_Get_Tick_Rate(); } #include void CProfileManager::dumpRecursive(CProfileIterator* profileIterator, int spacing) { profileIterator->First(); if (profileIterator->Is_Done()) return; float accumulated_time=0,parent_time = profileIterator->Is_Root() ? CProfileManager::Get_Time_Since_Reset() : profileIterator->Get_Current_Parent_Total_Time(); int i; int frames_since_reset = CProfileManager::Get_Frame_Count_Since_Reset(); for (i=0;iGet_Current_Parent_Name(), parent_time ); float totalTime = 0.f; int numChildren = 0; for (i = 0; !profileIterator->Is_Done(); i++,profileIterator->Next()) { numChildren++; float current_total_time = profileIterator->Get_Current_Total_Time(); accumulated_time += current_total_time; float fraction = parent_time > SIMD_EPSILON ? (current_total_time / parent_time) * 100 : 0.f; { int i; for (i=0;iGet_Current_Name(), fraction,(current_total_time / (double)frames_since_reset),profileIterator->Get_Current_Total_Calls()); totalTime += current_total_time; //recurse into children } if (parent_time < accumulated_time) { printf("what's wrong\n"); } for (i=0;i SIMD_EPSILON ? ((parent_time - accumulated_time) / parent_time) * 100 : 0.f, parent_time - accumulated_time); for (i=0;iEnter_Child(i); dumpRecursive(profileIterator,spacing+3); profileIterator->Enter_Parent(); } } void CProfileManager::dumpAll() { CProfileIterator* profileIterator = 0; profileIterator = CProfileManager::Get_Iterator(); dumpRecursive(profileIterator,0); CProfileManager::Release_Iterator(profileIterator); } #endif //USE_BT_CLOCK critterding-beta12.1/src/utils/bullet/LinearMath/btStackAlloc.h0000644000175000017500000000543611337071441023527 0ustar bobkebobke/* Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ 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. */ /* StackAlloc extracted from GJK-EPA collision solver by Nathanael Presson Nov.2006 */ #ifndef BT_STACK_ALLOC #define BT_STACK_ALLOC #include "btScalar.h" //for btAssert #include "btAlignedAllocator.h" ///The btBlock class is an internal structure for the btStackAlloc memory allocator. struct btBlock { btBlock* previous; unsigned char* address; }; ///The StackAlloc class provides some fast stack-based memory allocator (LIFO last-in first-out) class btStackAlloc { public: btStackAlloc(unsigned int size) { ctor();create(size); } ~btStackAlloc() { destroy(); } inline void create(unsigned int size) { destroy(); data = (unsigned char*) btAlignedAlloc(size,16); totalsize = size; } inline void destroy() { btAssert(usedsize==0); //Raise(L"StackAlloc is still in use"); if(usedsize==0) { if(!ischild && data) btAlignedFree(data); data = 0; usedsize = 0; } } int getAvailableMemory() const { return static_cast(totalsize - usedsize); } unsigned char* allocate(unsigned int size) { const unsigned int nus(usedsize+size); if(nusprevious = current; pb->address = data+usedsize; current = pb; return(pb); } SIMD_FORCE_INLINE void endBlock(btBlock* block) { btAssert(block==current); //Raise(L"Unmatched blocks"); if(block==current) { current = block->previous; usedsize = (unsigned int)((block->address-data)-sizeof(btBlock)); } } private: void ctor() { data = 0; totalsize = 0; usedsize = 0; current = 0; ischild = false; } unsigned char* data; unsigned int totalsize; unsigned int usedsize; btBlock* current; bool ischild; }; #endif //BT_STACK_ALLOC critterding-beta12.1/src/utils/bullet/LinearMath/btSerializer.cpp0000644000175000017500000011361311344271164024152 0ustar bobkebobkeunsigned char sBulletDNAstr64[]= { 83,68,78,65,78,65,77,69,-79,0,0,0,109,95,115,105,122,101,0,109, 95,99,97,112,97,99,105,116,121,0,42,109,95,100,97,116,97,0,109,95, 99,111,108,108,105,115,105,111,110,83,104,97,112,101,115,0,109,95,99,111, 108,108,105,115,105,111,110,79,98,106,101,99,116,115,0,109,95,99,111,110, 115,116,114,97,105,110,116,115,0,42,102,105,114,115,116,0,42,108,97,115, 116,0,109,95,102,108,111,97,116,115,91,52,93,0,109,95,101,108,91,51, 93,0,109,95,98,97,115,105,115,0,109,95,111,114,105,103,105,110,0,109, 95,114,111,111,116,78,111,100,101,73,110,100,101,120,0,109,95,115,117,98, 116,114,101,101,83,105,122,101,0,109,95,113,117,97,110,116,105,122,101,100, 65,97,98,98,77,105,110,91,51,93,0,109,95,113,117,97,110,116,105,122, 101,100,65,97,98,98,77,97,120,91,51,93,0,109,95,97,97,98,98,77, 105,110,79,114,103,0,109,95,97,97,98,98,77,97,120,79,114,103,0,109, 95,101,115,99,97,112,101,73,110,100,101,120,0,109,95,115,117,98,80,97, 114,116,0,109,95,116,114,105,97,110,103,108,101,73,110,100,101,120,0,109, 95,112,97,100,91,52,93,0,109,95,101,115,99,97,112,101,73,110,100,101, 120,79,114,84,114,105,97,110,103,108,101,73,110,100,101,120,0,109,95,98, 118,104,65,97,98,98,77,105,110,0,109,95,98,118,104,65,97,98,98,77, 97,120,0,109,95,98,118,104,81,117,97,110,116,105,122,97,116,105,111,110, 0,109,95,99,117,114,78,111,100,101,73,110,100,101,120,0,109,95,117,115, 101,81,117,97,110,116,105,122,97,116,105,111,110,0,109,95,110,117,109,67, 111,110,116,105,103,117,111,117,115,76,101,97,102,78,111,100,101,115,0,109, 95,110,117,109,81,117,97,110,116,105,122,101,100,67,111,110,116,105,103,117, 111,117,115,78,111,100,101,115,0,42,109,95,99,111,110,116,105,103,117,111, 117,115,78,111,100,101,115,80,116,114,0,42,109,95,113,117,97,110,116,105, 122,101,100,67,111,110,116,105,103,117,111,117,115,78,111,100,101,115,80,116, 114,0,42,109,95,115,117,98,84,114,101,101,73,110,102,111,80,116,114,0, 109,95,116,114,97,118,101,114,115,97,108,77,111,100,101,0,109,95,110,117, 109,83,117,98,116,114,101,101,72,101,97,100,101,114,115,0,42,109,95,110, 97,109,101,0,109,95,115,104,97,112,101,84,121,112,101,0,109,95,112,97, 100,100,105,110,103,91,52,93,0,109,95,99,111,108,108,105,115,105,111,110, 83,104,97,112,101,68,97,116,97,0,109,95,108,111,99,97,108,83,99,97, 108,105,110,103,0,109,95,112,108,97,110,101,78,111,114,109,97,108,0,109, 95,112,108,97,110,101,67,111,110,115,116,97,110,116,0,109,95,105,109,112, 108,105,99,105,116,83,104,97,112,101,68,105,109,101,110,115,105,111,110,115, 0,109,95,99,111,108,108,105,115,105,111,110,77,97,114,103,105,110,0,109, 95,112,97,100,100,105,110,103,0,109,95,112,111,115,0,109,95,114,97,100, 105,117,115,0,109,95,99,111,110,118,101,120,73,110,116,101,114,110,97,108, 83,104,97,112,101,68,97,116,97,0,42,109,95,108,111,99,97,108,80,111, 115,105,116,105,111,110,65,114,114,97,121,80,116,114,0,109,95,108,111,99, 97,108,80,111,115,105,116,105,111,110,65,114,114,97,121,83,105,122,101,0, 109,95,118,97,108,117,101,0,109,95,112,97,100,91,50,93,0,109,95,118, 97,108,117,101,115,91,51,93,0,42,109,95,118,101,114,116,105,99,101,115, 51,102,0,42,109,95,118,101,114,116,105,99,101,115,51,100,0,42,109,95, 105,110,100,105,99,101,115,51,50,0,42,109,95,51,105,110,100,105,99,101, 115,49,54,0,42,109,95,105,110,100,105,99,101,115,49,54,0,109,95,110, 117,109,84,114,105,97,110,103,108,101,115,0,109,95,110,117,109,86,101,114, 116,105,99,101,115,0,42,109,95,109,101,115,104,80,97,114,116,115,80,116, 114,0,109,95,115,99,97,108,105,110,103,0,109,95,110,117,109,77,101,115, 104,80,97,114,116,115,0,109,95,109,101,115,104,73,110,116,101,114,102,97, 99,101,0,42,109,95,113,117,97,110,116,105,122,101,100,70,108,111,97,116, 66,118,104,0,42,109,95,113,117,97,110,116,105,122,101,100,68,111,117,98, 108,101,66,118,104,0,42,109,95,116,114,105,97,110,103,108,101,73,110,102, 111,77,97,112,0,109,95,112,97,100,51,91,52,93,0,109,95,116,114,97, 110,115,102,111,114,109,0,42,109,95,99,104,105,108,100,83,104,97,112,101, 0,109,95,99,104,105,108,100,83,104,97,112,101,84,121,112,101,0,109,95, 99,104,105,108,100,77,97,114,103,105,110,0,42,109,95,99,104,105,108,100, 83,104,97,112,101,80,116,114,0,109,95,110,117,109,67,104,105,108,100,83, 104,97,112,101,115,0,109,95,117,112,65,120,105,115,0,109,95,102,108,97, 103,115,0,109,95,101,100,103,101,86,48,86,49,65,110,103,108,101,0,109, 95,101,100,103,101,86,49,86,50,65,110,103,108,101,0,109,95,101,100,103, 101,86,50,86,48,65,110,103,108,101,0,42,109,95,104,97,115,104,84,97, 98,108,101,80,116,114,0,42,109,95,110,101,120,116,80,116,114,0,42,109, 95,118,97,108,117,101,65,114,114,97,121,80,116,114,0,42,109,95,107,101, 121,65,114,114,97,121,80,116,114,0,109,95,99,111,110,118,101,120,69,112, 115,105,108,111,110,0,109,95,112,108,97,110,97,114,69,112,115,105,108,111, 110,0,109,95,101,113,117,97,108,86,101,114,116,101,120,84,104,114,101,115, 104,111,108,100,0,109,95,101,100,103,101,68,105,115,116,97,110,99,101,84, 104,114,101,115,104,111,108,100,0,109,95,122,101,114,111,65,114,101,97,84, 104,114,101,115,104,111,108,100,0,109,95,110,101,120,116,83,105,122,101,0, 109,95,104,97,115,104,84,97,98,108,101,83,105,122,101,0,109,95,110,117, 109,86,97,108,117,101,115,0,109,95,110,117,109,75,101,121,115,0,109,95, 103,105,109,112,97,99,116,83,117,98,84,121,112,101,0,42,109,95,117,110, 115,99,97,108,101,100,80,111,105,110,116,115,70,108,111,97,116,80,116,114, 0,42,109,95,117,110,115,99,97,108,101,100,80,111,105,110,116,115,68,111, 117,98,108,101,80,116,114,0,109,95,110,117,109,85,110,115,99,97,108,101, 100,80,111,105,110,116,115,0,109,95,112,97,100,100,105,110,103,51,91,52, 93,0,42,109,95,98,114,111,97,100,112,104,97,115,101,72,97,110,100,108, 101,0,42,109,95,99,111,108,108,105,115,105,111,110,83,104,97,112,101,0, 42,109,95,114,111,111,116,67,111,108,108,105,115,105,111,110,83,104,97,112, 101,0,109,95,119,111,114,108,100,84,114,97,110,115,102,111,114,109,0,109, 95,105,110,116,101,114,112,111,108,97,116,105,111,110,87,111,114,108,100,84, 114,97,110,115,102,111,114,109,0,109,95,105,110,116,101,114,112,111,108,97, 116,105,111,110,76,105,110,101,97,114,86,101,108,111,99,105,116,121,0,109, 95,105,110,116,101,114,112,111,108,97,116,105,111,110,65,110,103,117,108,97, 114,86,101,108,111,99,105,116,121,0,109,95,97,110,105,115,111,116,114,111, 112,105,99,70,114,105,99,116,105,111,110,0,109,95,99,111,110,116,97,99, 116,80,114,111,99,101,115,115,105,110,103,84,104,114,101,115,104,111,108,100, 0,109,95,100,101,97,99,116,105,118,97,116,105,111,110,84,105,109,101,0, 109,95,102,114,105,99,116,105,111,110,0,109,95,114,101,115,116,105,116,117, 116,105,111,110,0,109,95,104,105,116,70,114,97,99,116,105,111,110,0,109, 95,99,99,100,83,119,101,112,116,83,112,104,101,114,101,82,97,100,105,117, 115,0,109,95,99,99,100,77,111,116,105,111,110,84,104,114,101,115,104,111, 108,100,0,109,95,104,97,115,65,110,105,115,111,116,114,111,112,105,99,70, 114,105,99,116,105,111,110,0,109,95,99,111,108,108,105,115,105,111,110,70, 108,97,103,115,0,109,95,105,115,108,97,110,100,84,97,103,49,0,109,95, 99,111,109,112,97,110,105,111,110,73,100,0,109,95,97,99,116,105,118,97, 116,105,111,110,83,116,97,116,101,49,0,109,95,105,110,116,101,114,110,97, 108,84,121,112,101,0,109,95,99,104,101,99,107,67,111,108,108,105,100,101, 87,105,116,104,0,109,95,99,111,108,108,105,115,105,111,110,79,98,106,101, 99,116,68,97,116,97,0,109,95,105,110,118,73,110,101,114,116,105,97,84, 101,110,115,111,114,87,111,114,108,100,0,109,95,108,105,110,101,97,114,86, 101,108,111,99,105,116,121,0,109,95,97,110,103,117,108,97,114,86,101,108, 111,99,105,116,121,0,109,95,97,110,103,117,108,97,114,70,97,99,116,111, 114,0,109,95,108,105,110,101,97,114,70,97,99,116,111,114,0,109,95,103, 114,97,118,105,116,121,0,109,95,103,114,97,118,105,116,121,95,97,99,99, 101,108,101,114,97,116,105,111,110,0,109,95,105,110,118,73,110,101,114,116, 105,97,76,111,99,97,108,0,109,95,116,111,116,97,108,70,111,114,99,101, 0,109,95,116,111,116,97,108,84,111,114,113,117,101,0,109,95,105,110,118, 101,114,115,101,77,97,115,115,0,109,95,108,105,110,101,97,114,68,97,109, 112,105,110,103,0,109,95,97,110,103,117,108,97,114,68,97,109,112,105,110, 103,0,109,95,97,100,100,105,116,105,111,110,97,108,68,97,109,112,105,110, 103,70,97,99,116,111,114,0,109,95,97,100,100,105,116,105,111,110,97,108, 76,105,110,101,97,114,68,97,109,112,105,110,103,84,104,114,101,115,104,111, 108,100,83,113,114,0,109,95,97,100,100,105,116,105,111,110,97,108,65,110, 103,117,108,97,114,68,97,109,112,105,110,103,84,104,114,101,115,104,111,108, 100,83,113,114,0,109,95,97,100,100,105,116,105,111,110,97,108,65,110,103, 117,108,97,114,68,97,109,112,105,110,103,70,97,99,116,111,114,0,109,95, 108,105,110,101,97,114,83,108,101,101,112,105,110,103,84,104,114,101,115,104, 111,108,100,0,109,95,97,110,103,117,108,97,114,83,108,101,101,112,105,110, 103,84,104,114,101,115,104,111,108,100,0,109,95,97,100,100,105,116,105,111, 110,97,108,68,97,109,112,105,110,103,0,109,95,110,117,109,67,111,110,115, 116,114,97,105,110,116,82,111,119,115,0,110,117,98,0,42,109,95,114,98, 65,0,42,109,95,114,98,66,0,109,95,111,98,106,101,99,116,84,121,112, 101,0,109,95,117,115,101,114,67,111,110,115,116,114,97,105,110,116,84,121, 112,101,0,109,95,117,115,101,114,67,111,110,115,116,114,97,105,110,116,73, 100,0,109,95,110,101,101,100,115,70,101,101,100,98,97,99,107,0,109,95, 97,112,112,108,105,101,100,73,109,112,117,108,115,101,0,109,95,100,98,103, 68,114,97,119,83,105,122,101,0,109,95,100,105,115,97,98,108,101,67,111, 108,108,105,115,105,111,110,115,66,101,116,119,101,101,110,76,105,110,107,101, 100,66,111,100,105,101,115,0,109,95,112,97,100,52,91,52,93,0,109,95, 116,121,112,101,67,111,110,115,116,114,97,105,110,116,68,97,116,97,0,109, 95,112,105,118,111,116,73,110,65,0,109,95,112,105,118,111,116,73,110,66, 0,109,95,114,98,65,70,114,97,109,101,0,109,95,114,98,66,70,114,97, 109,101,0,109,95,117,115,101,82,101,102,101,114,101,110,99,101,70,114,97, 109,101,65,0,109,95,97,110,103,117,108,97,114,79,110,108,121,0,109,95, 101,110,97,98,108,101,65,110,103,117,108,97,114,77,111,116,111,114,0,109, 95,109,111,116,111,114,84,97,114,103,101,116,86,101,108,111,99,105,116,121, 0,109,95,109,97,120,77,111,116,111,114,73,109,112,117,108,115,101,0,109, 95,108,111,119,101,114,76,105,109,105,116,0,109,95,117,112,112,101,114,76, 105,109,105,116,0,109,95,108,105,109,105,116,83,111,102,116,110,101,115,115, 0,109,95,98,105,97,115,70,97,99,116,111,114,0,109,95,114,101,108,97, 120,97,116,105,111,110,70,97,99,116,111,114,0,109,95,115,119,105,110,103, 83,112,97,110,49,0,109,95,115,119,105,110,103,83,112,97,110,50,0,109, 95,116,119,105,115,116,83,112,97,110,0,109,95,100,97,109,112,105,110,103, 0,109,95,108,105,110,101,97,114,85,112,112,101,114,76,105,109,105,116,0, 109,95,108,105,110,101,97,114,76,111,119,101,114,76,105,109,105,116,0,109, 95,97,110,103,117,108,97,114,85,112,112,101,114,76,105,109,105,116,0,109, 95,97,110,103,117,108,97,114,76,111,119,101,114,76,105,109,105,116,0,109, 95,117,115,101,76,105,110,101,97,114,82,101,102,101,114,101,110,99,101,70, 114,97,109,101,65,0,109,95,117,115,101,79,102,102,115,101,116,70,111,114, 67,111,110,115,116,114,97,105,110,116,70,114,97,109,101,0,84,89,80,69, 58,0,0,0,99,104,97,114,0,117,99,104,97,114,0,115,104,111,114,116, 0,117,115,104,111,114,116,0,105,110,116,0,108,111,110,103,0,117,108,111, 110,103,0,102,108,111,97,116,0,100,111,117,98,108,101,0,118,111,105,100, 0,80,111,105,110,116,101,114,65,114,114,97,121,0,98,116,80,104,121,115, 105,99,115,83,121,115,116,101,109,0,76,105,115,116,66,97,115,101,0,98, 116,86,101,99,116,111,114,51,70,108,111,97,116,68,97,116,97,0,98,116, 86,101,99,116,111,114,51,68,111,117,98,108,101,68,97,116,97,0,98,116, 77,97,116,114,105,120,51,120,51,70,108,111,97,116,68,97,116,97,0,98, 116,77,97,116,114,105,120,51,120,51,68,111,117,98,108,101,68,97,116,97, 0,98,116,84,114,97,110,115,102,111,114,109,70,108,111,97,116,68,97,116, 97,0,98,116,84,114,97,110,115,102,111,114,109,68,111,117,98,108,101,68, 97,116,97,0,98,116,66,118,104,83,117,98,116,114,101,101,73,110,102,111, 68,97,116,97,0,98,116,79,112,116,105,109,105,122,101,100,66,118,104,78, 111,100,101,70,108,111,97,116,68,97,116,97,0,98,116,79,112,116,105,109, 105,122,101,100,66,118,104,78,111,100,101,68,111,117,98,108,101,68,97,116, 97,0,98,116,81,117,97,110,116,105,122,101,100,66,118,104,78,111,100,101, 68,97,116,97,0,98,116,81,117,97,110,116,105,122,101,100,66,118,104,70, 108,111,97,116,68,97,116,97,0,98,116,81,117,97,110,116,105,122,101,100, 66,118,104,68,111,117,98,108,101,68,97,116,97,0,98,116,67,111,108,108, 105,115,105,111,110,83,104,97,112,101,68,97,116,97,0,98,116,83,116,97, 116,105,99,80,108,97,110,101,83,104,97,112,101,68,97,116,97,0,98,116, 67,111,110,118,101,120,73,110,116,101,114,110,97,108,83,104,97,112,101,68, 97,116,97,0,98,116,80,111,115,105,116,105,111,110,65,110,100,82,97,100, 105,117,115,0,98,116,77,117,108,116,105,83,112,104,101,114,101,83,104,97, 112,101,68,97,116,97,0,98,116,73,110,116,73,110,100,101,120,68,97,116, 97,0,98,116,83,104,111,114,116,73,110,116,73,110,100,101,120,68,97,116, 97,0,98,116,83,104,111,114,116,73,110,116,73,110,100,101,120,84,114,105, 112,108,101,116,68,97,116,97,0,98,116,77,101,115,104,80,97,114,116,68, 97,116,97,0,98,116,83,116,114,105,100,105,110,103,77,101,115,104,73,110, 116,101,114,102,97,99,101,68,97,116,97,0,98,116,84,114,105,97,110,103, 108,101,77,101,115,104,83,104,97,112,101,68,97,116,97,0,98,116,84,114, 105,97,110,103,108,101,73,110,102,111,77,97,112,68,97,116,97,0,98,116, 67,111,109,112,111,117,110,100,83,104,97,112,101,67,104,105,108,100,68,97, 116,97,0,98,116,67,111,109,112,111,117,110,100,83,104,97,112,101,68,97, 116,97,0,98,116,67,121,108,105,110,100,101,114,83,104,97,112,101,68,97, 116,97,0,98,116,67,97,112,115,117,108,101,83,104,97,112,101,68,97,116, 97,0,98,116,84,114,105,97,110,103,108,101,73,110,102,111,68,97,116,97, 0,98,116,71,73,109,112,97,99,116,77,101,115,104,83,104,97,112,101,68, 97,116,97,0,98,116,67,111,110,118,101,120,72,117,108,108,83,104,97,112, 101,68,97,116,97,0,98,116,67,111,108,108,105,115,105,111,110,79,98,106, 101,99,116,68,111,117,98,108,101,68,97,116,97,0,98,116,67,111,108,108, 105,115,105,111,110,79,98,106,101,99,116,70,108,111,97,116,68,97,116,97, 0,98,116,82,105,103,105,100,66,111,100,121,70,108,111,97,116,68,97,116, 97,0,98,116,82,105,103,105,100,66,111,100,121,68,111,117,98,108,101,68, 97,116,97,0,98,116,67,111,110,115,116,114,97,105,110,116,73,110,102,111, 49,0,98,116,84,121,112,101,100,67,111,110,115,116,114,97,105,110,116,68, 97,116,97,0,98,116,82,105,103,105,100,66,111,100,121,68,97,116,97,0, 98,116,80,111,105,110,116,50,80,111,105,110,116,67,111,110,115,116,114,97, 105,110,116,70,108,111,97,116,68,97,116,97,0,98,116,80,111,105,110,116, 50,80,111,105,110,116,67,111,110,115,116,114,97,105,110,116,68,111,117,98, 108,101,68,97,116,97,0,98,116,72,105,110,103,101,67,111,110,115,116,114, 97,105,110,116,68,111,117,98,108,101,68,97,116,97,0,98,116,72,105,110, 103,101,67,111,110,115,116,114,97,105,110,116,70,108,111,97,116,68,97,116, 97,0,98,116,67,111,110,101,84,119,105,115,116,67,111,110,115,116,114,97, 105,110,116,68,97,116,97,0,98,116,71,101,110,101,114,105,99,54,68,111, 102,67,111,110,115,116,114,97,105,110,116,68,97,116,97,0,98,116,83,108, 105,100,101,114,67,111,110,115,116,114,97,105,110,116,68,97,116,97,0,0, 84,76,69,78,1,0,1,0,2,0,2,0,4,0,4,0,4,0,4,0, 8,0,0,0,16,0,48,0,16,0,16,0,32,0,48,0,96,0,64,0, -128,0,20,0,48,0,80,0,16,0,96,0,-112,0,16,0,56,0,56,0, 20,0,72,0,4,0,4,0,8,0,48,0,32,0,80,0,72,0,80,0, 32,0,64,0,64,0,16,0,72,0,80,0,-40,1,8,1,-16,1,-88,3, 8,0,56,0,0,0,88,0,120,0,96,1,-32,0,-40,0,0,1,-48,0, 83,84,82,67,47,0,0,0,10,0,3,0,4,0,0,0,4,0,1,0, 9,0,2,0,11,0,3,0,10,0,3,0,10,0,4,0,10,0,5,0, 12,0,2,0,9,0,6,0,9,0,7,0,13,0,1,0,7,0,8,0, 14,0,1,0,8,0,8,0,15,0,1,0,13,0,9,0,16,0,1,0, 14,0,9,0,17,0,2,0,15,0,10,0,13,0,11,0,18,0,2,0, 16,0,10,0,14,0,11,0,19,0,4,0,4,0,12,0,4,0,13,0, 2,0,14,0,2,0,15,0,20,0,6,0,13,0,16,0,13,0,17,0, 4,0,18,0,4,0,19,0,4,0,20,0,0,0,21,0,21,0,6,0, 14,0,16,0,14,0,17,0,4,0,18,0,4,0,19,0,4,0,20,0, 0,0,21,0,22,0,3,0,2,0,14,0,2,0,15,0,4,0,22,0, 23,0,12,0,13,0,23,0,13,0,24,0,13,0,25,0,4,0,26,0, 4,0,27,0,4,0,28,0,4,0,29,0,20,0,30,0,22,0,31,0, 19,0,32,0,4,0,33,0,4,0,34,0,24,0,12,0,14,0,23,0, 14,0,24,0,14,0,25,0,4,0,26,0,4,0,27,0,4,0,28,0, 4,0,29,0,21,0,30,0,22,0,31,0,4,0,33,0,4,0,34,0, 19,0,32,0,25,0,3,0,0,0,35,0,4,0,36,0,0,0,37,0, 26,0,5,0,25,0,38,0,13,0,39,0,13,0,40,0,7,0,41,0, 0,0,21,0,27,0,5,0,25,0,38,0,13,0,39,0,13,0,42,0, 7,0,43,0,4,0,44,0,28,0,2,0,13,0,45,0,7,0,46,0, 29,0,4,0,27,0,47,0,28,0,48,0,4,0,49,0,0,0,37,0, 30,0,1,0,4,0,50,0,31,0,2,0,2,0,50,0,0,0,51,0, 32,0,2,0,2,0,52,0,0,0,51,0,33,0,7,0,13,0,53,0, 14,0,54,0,30,0,55,0,32,0,56,0,31,0,57,0,4,0,58,0, 4,0,59,0,34,0,4,0,33,0,60,0,13,0,61,0,4,0,62,0, 0,0,37,0,35,0,7,0,25,0,38,0,34,0,63,0,23,0,64,0, 24,0,65,0,36,0,66,0,7,0,43,0,0,0,67,0,37,0,4,0, 17,0,68,0,25,0,69,0,4,0,70,0,7,0,71,0,38,0,4,0, 25,0,38,0,37,0,72,0,4,0,73,0,7,0,43,0,39,0,3,0, 27,0,47,0,4,0,74,0,0,0,37,0,40,0,3,0,27,0,47,0, 4,0,74,0,0,0,37,0,41,0,4,0,4,0,75,0,7,0,76,0, 7,0,77,0,7,0,78,0,36,0,14,0,4,0,79,0,4,0,80,0, 41,0,81,0,4,0,82,0,7,0,83,0,7,0,84,0,7,0,85,0, 7,0,86,0,7,0,87,0,4,0,88,0,4,0,89,0,4,0,90,0, 4,0,91,0,0,0,37,0,42,0,5,0,25,0,38,0,34,0,63,0, 13,0,39,0,7,0,43,0,4,0,92,0,43,0,5,0,27,0,47,0, 13,0,93,0,14,0,94,0,4,0,95,0,0,0,96,0,44,0,24,0, 9,0,97,0,9,0,98,0,25,0,99,0,0,0,35,0,18,0,100,0, 18,0,101,0,14,0,102,0,14,0,103,0,14,0,104,0,8,0,105,0, 8,0,106,0,8,0,107,0,8,0,108,0,8,0,109,0,8,0,110,0, 8,0,111,0,4,0,112,0,4,0,113,0,4,0,114,0,4,0,115,0, 4,0,116,0,4,0,117,0,4,0,118,0,0,0,37,0,45,0,23,0, 9,0,97,0,9,0,98,0,25,0,99,0,0,0,35,0,17,0,100,0, 17,0,101,0,13,0,102,0,13,0,103,0,13,0,104,0,7,0,105,0, 7,0,106,0,7,0,107,0,7,0,108,0,7,0,109,0,7,0,110,0, 7,0,111,0,4,0,112,0,4,0,113,0,4,0,114,0,4,0,115,0, 4,0,116,0,4,0,117,0,4,0,118,0,46,0,21,0,45,0,119,0, 15,0,120,0,13,0,121,0,13,0,122,0,13,0,123,0,13,0,124,0, 13,0,125,0,13,0,126,0,13,0,127,0,13,0,-128,0,13,0,-127,0, 7,0,-126,0,7,0,-125,0,7,0,-124,0,7,0,-123,0,7,0,-122,0, 7,0,-121,0,7,0,-120,0,7,0,-119,0,7,0,-118,0,4,0,-117,0, 47,0,22,0,44,0,119,0,16,0,120,0,14,0,121,0,14,0,122,0, 14,0,123,0,14,0,124,0,14,0,125,0,14,0,126,0,14,0,127,0, 14,0,-128,0,14,0,-127,0,8,0,-126,0,8,0,-125,0,8,0,-124,0, 8,0,-123,0,8,0,-122,0,8,0,-121,0,8,0,-120,0,8,0,-119,0, 8,0,-118,0,4,0,-117,0,0,0,37,0,48,0,2,0,4,0,-116,0, 4,0,-115,0,49,0,11,0,50,0,-114,0,50,0,-113,0,0,0,35,0, 4,0,-112,0,4,0,-111,0,4,0,-110,0,4,0,-109,0,7,0,-108,0, 7,0,-107,0,4,0,-106,0,0,0,-105,0,51,0,3,0,49,0,-104,0, 13,0,-103,0,13,0,-102,0,52,0,3,0,49,0,-104,0,14,0,-103,0, 14,0,-102,0,53,0,13,0,49,0,-104,0,18,0,-101,0,18,0,-100,0, 4,0,-99,0,4,0,-98,0,4,0,-97,0,7,0,-96,0,7,0,-95,0, 7,0,-94,0,7,0,-93,0,7,0,-92,0,7,0,-91,0,7,0,-90,0, 54,0,13,0,49,0,-104,0,17,0,-101,0,17,0,-100,0,4,0,-99,0, 4,0,-98,0,4,0,-97,0,7,0,-96,0,7,0,-95,0,7,0,-94,0, 7,0,-93,0,7,0,-92,0,7,0,-91,0,7,0,-90,0,55,0,11,0, 49,0,-104,0,17,0,-101,0,17,0,-100,0,7,0,-89,0,7,0,-88,0, 7,0,-87,0,7,0,-92,0,7,0,-91,0,7,0,-90,0,7,0,-86,0, 0,0,21,0,56,0,9,0,49,0,-104,0,17,0,-101,0,17,0,-100,0, 13,0,-85,0,13,0,-84,0,13,0,-83,0,13,0,-82,0,4,0,-81,0, 4,0,-80,0,57,0,9,0,49,0,-104,0,17,0,-101,0,17,0,-100,0, 7,0,-85,0,7,0,-84,0,7,0,-83,0,7,0,-82,0,4,0,-81,0, 4,0,-80,0,}; int sBulletDNAlen64= sizeof(sBulletDNAstr64); unsigned char sBulletDNAstr[]= { 83,68,78,65,78,65,77,69,-79,0,0,0,109,95,115,105,122,101,0,109, 95,99,97,112,97,99,105,116,121,0,42,109,95,100,97,116,97,0,109,95, 99,111,108,108,105,115,105,111,110,83,104,97,112,101,115,0,109,95,99,111, 108,108,105,115,105,111,110,79,98,106,101,99,116,115,0,109,95,99,111,110, 115,116,114,97,105,110,116,115,0,42,102,105,114,115,116,0,42,108,97,115, 116,0,109,95,102,108,111,97,116,115,91,52,93,0,109,95,101,108,91,51, 93,0,109,95,98,97,115,105,115,0,109,95,111,114,105,103,105,110,0,109, 95,114,111,111,116,78,111,100,101,73,110,100,101,120,0,109,95,115,117,98, 116,114,101,101,83,105,122,101,0,109,95,113,117,97,110,116,105,122,101,100, 65,97,98,98,77,105,110,91,51,93,0,109,95,113,117,97,110,116,105,122, 101,100,65,97,98,98,77,97,120,91,51,93,0,109,95,97,97,98,98,77, 105,110,79,114,103,0,109,95,97,97,98,98,77,97,120,79,114,103,0,109, 95,101,115,99,97,112,101,73,110,100,101,120,0,109,95,115,117,98,80,97, 114,116,0,109,95,116,114,105,97,110,103,108,101,73,110,100,101,120,0,109, 95,112,97,100,91,52,93,0,109,95,101,115,99,97,112,101,73,110,100,101, 120,79,114,84,114,105,97,110,103,108,101,73,110,100,101,120,0,109,95,98, 118,104,65,97,98,98,77,105,110,0,109,95,98,118,104,65,97,98,98,77, 97,120,0,109,95,98,118,104,81,117,97,110,116,105,122,97,116,105,111,110, 0,109,95,99,117,114,78,111,100,101,73,110,100,101,120,0,109,95,117,115, 101,81,117,97,110,116,105,122,97,116,105,111,110,0,109,95,110,117,109,67, 111,110,116,105,103,117,111,117,115,76,101,97,102,78,111,100,101,115,0,109, 95,110,117,109,81,117,97,110,116,105,122,101,100,67,111,110,116,105,103,117, 111,117,115,78,111,100,101,115,0,42,109,95,99,111,110,116,105,103,117,111, 117,115,78,111,100,101,115,80,116,114,0,42,109,95,113,117,97,110,116,105, 122,101,100,67,111,110,116,105,103,117,111,117,115,78,111,100,101,115,80,116, 114,0,42,109,95,115,117,98,84,114,101,101,73,110,102,111,80,116,114,0, 109,95,116,114,97,118,101,114,115,97,108,77,111,100,101,0,109,95,110,117, 109,83,117,98,116,114,101,101,72,101,97,100,101,114,115,0,42,109,95,110, 97,109,101,0,109,95,115,104,97,112,101,84,121,112,101,0,109,95,112,97, 100,100,105,110,103,91,52,93,0,109,95,99,111,108,108,105,115,105,111,110, 83,104,97,112,101,68,97,116,97,0,109,95,108,111,99,97,108,83,99,97, 108,105,110,103,0,109,95,112,108,97,110,101,78,111,114,109,97,108,0,109, 95,112,108,97,110,101,67,111,110,115,116,97,110,116,0,109,95,105,109,112, 108,105,99,105,116,83,104,97,112,101,68,105,109,101,110,115,105,111,110,115, 0,109,95,99,111,108,108,105,115,105,111,110,77,97,114,103,105,110,0,109, 95,112,97,100,100,105,110,103,0,109,95,112,111,115,0,109,95,114,97,100, 105,117,115,0,109,95,99,111,110,118,101,120,73,110,116,101,114,110,97,108, 83,104,97,112,101,68,97,116,97,0,42,109,95,108,111,99,97,108,80,111, 115,105,116,105,111,110,65,114,114,97,121,80,116,114,0,109,95,108,111,99, 97,108,80,111,115,105,116,105,111,110,65,114,114,97,121,83,105,122,101,0, 109,95,118,97,108,117,101,0,109,95,112,97,100,91,50,93,0,109,95,118, 97,108,117,101,115,91,51,93,0,42,109,95,118,101,114,116,105,99,101,115, 51,102,0,42,109,95,118,101,114,116,105,99,101,115,51,100,0,42,109,95, 105,110,100,105,99,101,115,51,50,0,42,109,95,51,105,110,100,105,99,101, 115,49,54,0,42,109,95,105,110,100,105,99,101,115,49,54,0,109,95,110, 117,109,84,114,105,97,110,103,108,101,115,0,109,95,110,117,109,86,101,114, 116,105,99,101,115,0,42,109,95,109,101,115,104,80,97,114,116,115,80,116, 114,0,109,95,115,99,97,108,105,110,103,0,109,95,110,117,109,77,101,115, 104,80,97,114,116,115,0,109,95,109,101,115,104,73,110,116,101,114,102,97, 99,101,0,42,109,95,113,117,97,110,116,105,122,101,100,70,108,111,97,116, 66,118,104,0,42,109,95,113,117,97,110,116,105,122,101,100,68,111,117,98, 108,101,66,118,104,0,42,109,95,116,114,105,97,110,103,108,101,73,110,102, 111,77,97,112,0,109,95,112,97,100,51,91,52,93,0,109,95,116,114,97, 110,115,102,111,114,109,0,42,109,95,99,104,105,108,100,83,104,97,112,101, 0,109,95,99,104,105,108,100,83,104,97,112,101,84,121,112,101,0,109,95, 99,104,105,108,100,77,97,114,103,105,110,0,42,109,95,99,104,105,108,100, 83,104,97,112,101,80,116,114,0,109,95,110,117,109,67,104,105,108,100,83, 104,97,112,101,115,0,109,95,117,112,65,120,105,115,0,109,95,102,108,97, 103,115,0,109,95,101,100,103,101,86,48,86,49,65,110,103,108,101,0,109, 95,101,100,103,101,86,49,86,50,65,110,103,108,101,0,109,95,101,100,103, 101,86,50,86,48,65,110,103,108,101,0,42,109,95,104,97,115,104,84,97, 98,108,101,80,116,114,0,42,109,95,110,101,120,116,80,116,114,0,42,109, 95,118,97,108,117,101,65,114,114,97,121,80,116,114,0,42,109,95,107,101, 121,65,114,114,97,121,80,116,114,0,109,95,99,111,110,118,101,120,69,112, 115,105,108,111,110,0,109,95,112,108,97,110,97,114,69,112,115,105,108,111, 110,0,109,95,101,113,117,97,108,86,101,114,116,101,120,84,104,114,101,115, 104,111,108,100,0,109,95,101,100,103,101,68,105,115,116,97,110,99,101,84, 104,114,101,115,104,111,108,100,0,109,95,122,101,114,111,65,114,101,97,84, 104,114,101,115,104,111,108,100,0,109,95,110,101,120,116,83,105,122,101,0, 109,95,104,97,115,104,84,97,98,108,101,83,105,122,101,0,109,95,110,117, 109,86,97,108,117,101,115,0,109,95,110,117,109,75,101,121,115,0,109,95, 103,105,109,112,97,99,116,83,117,98,84,121,112,101,0,42,109,95,117,110, 115,99,97,108,101,100,80,111,105,110,116,115,70,108,111,97,116,80,116,114, 0,42,109,95,117,110,115,99,97,108,101,100,80,111,105,110,116,115,68,111, 117,98,108,101,80,116,114,0,109,95,110,117,109,85,110,115,99,97,108,101, 100,80,111,105,110,116,115,0,109,95,112,97,100,100,105,110,103,51,91,52, 93,0,42,109,95,98,114,111,97,100,112,104,97,115,101,72,97,110,100,108, 101,0,42,109,95,99,111,108,108,105,115,105,111,110,83,104,97,112,101,0, 42,109,95,114,111,111,116,67,111,108,108,105,115,105,111,110,83,104,97,112, 101,0,109,95,119,111,114,108,100,84,114,97,110,115,102,111,114,109,0,109, 95,105,110,116,101,114,112,111,108,97,116,105,111,110,87,111,114,108,100,84, 114,97,110,115,102,111,114,109,0,109,95,105,110,116,101,114,112,111,108,97, 116,105,111,110,76,105,110,101,97,114,86,101,108,111,99,105,116,121,0,109, 95,105,110,116,101,114,112,111,108,97,116,105,111,110,65,110,103,117,108,97, 114,86,101,108,111,99,105,116,121,0,109,95,97,110,105,115,111,116,114,111, 112,105,99,70,114,105,99,116,105,111,110,0,109,95,99,111,110,116,97,99, 116,80,114,111,99,101,115,115,105,110,103,84,104,114,101,115,104,111,108,100, 0,109,95,100,101,97,99,116,105,118,97,116,105,111,110,84,105,109,101,0, 109,95,102,114,105,99,116,105,111,110,0,109,95,114,101,115,116,105,116,117, 116,105,111,110,0,109,95,104,105,116,70,114,97,99,116,105,111,110,0,109, 95,99,99,100,83,119,101,112,116,83,112,104,101,114,101,82,97,100,105,117, 115,0,109,95,99,99,100,77,111,116,105,111,110,84,104,114,101,115,104,111, 108,100,0,109,95,104,97,115,65,110,105,115,111,116,114,111,112,105,99,70, 114,105,99,116,105,111,110,0,109,95,99,111,108,108,105,115,105,111,110,70, 108,97,103,115,0,109,95,105,115,108,97,110,100,84,97,103,49,0,109,95, 99,111,109,112,97,110,105,111,110,73,100,0,109,95,97,99,116,105,118,97, 116,105,111,110,83,116,97,116,101,49,0,109,95,105,110,116,101,114,110,97, 108,84,121,112,101,0,109,95,99,104,101,99,107,67,111,108,108,105,100,101, 87,105,116,104,0,109,95,99,111,108,108,105,115,105,111,110,79,98,106,101, 99,116,68,97,116,97,0,109,95,105,110,118,73,110,101,114,116,105,97,84, 101,110,115,111,114,87,111,114,108,100,0,109,95,108,105,110,101,97,114,86, 101,108,111,99,105,116,121,0,109,95,97,110,103,117,108,97,114,86,101,108, 111,99,105,116,121,0,109,95,97,110,103,117,108,97,114,70,97,99,116,111, 114,0,109,95,108,105,110,101,97,114,70,97,99,116,111,114,0,109,95,103, 114,97,118,105,116,121,0,109,95,103,114,97,118,105,116,121,95,97,99,99, 101,108,101,114,97,116,105,111,110,0,109,95,105,110,118,73,110,101,114,116, 105,97,76,111,99,97,108,0,109,95,116,111,116,97,108,70,111,114,99,101, 0,109,95,116,111,116,97,108,84,111,114,113,117,101,0,109,95,105,110,118, 101,114,115,101,77,97,115,115,0,109,95,108,105,110,101,97,114,68,97,109, 112,105,110,103,0,109,95,97,110,103,117,108,97,114,68,97,109,112,105,110, 103,0,109,95,97,100,100,105,116,105,111,110,97,108,68,97,109,112,105,110, 103,70,97,99,116,111,114,0,109,95,97,100,100,105,116,105,111,110,97,108, 76,105,110,101,97,114,68,97,109,112,105,110,103,84,104,114,101,115,104,111, 108,100,83,113,114,0,109,95,97,100,100,105,116,105,111,110,97,108,65,110, 103,117,108,97,114,68,97,109,112,105,110,103,84,104,114,101,115,104,111,108, 100,83,113,114,0,109,95,97,100,100,105,116,105,111,110,97,108,65,110,103, 117,108,97,114,68,97,109,112,105,110,103,70,97,99,116,111,114,0,109,95, 108,105,110,101,97,114,83,108,101,101,112,105,110,103,84,104,114,101,115,104, 111,108,100,0,109,95,97,110,103,117,108,97,114,83,108,101,101,112,105,110, 103,84,104,114,101,115,104,111,108,100,0,109,95,97,100,100,105,116,105,111, 110,97,108,68,97,109,112,105,110,103,0,109,95,110,117,109,67,111,110,115, 116,114,97,105,110,116,82,111,119,115,0,110,117,98,0,42,109,95,114,98, 65,0,42,109,95,114,98,66,0,109,95,111,98,106,101,99,116,84,121,112, 101,0,109,95,117,115,101,114,67,111,110,115,116,114,97,105,110,116,84,121, 112,101,0,109,95,117,115,101,114,67,111,110,115,116,114,97,105,110,116,73, 100,0,109,95,110,101,101,100,115,70,101,101,100,98,97,99,107,0,109,95, 97,112,112,108,105,101,100,73,109,112,117,108,115,101,0,109,95,100,98,103, 68,114,97,119,83,105,122,101,0,109,95,100,105,115,97,98,108,101,67,111, 108,108,105,115,105,111,110,115,66,101,116,119,101,101,110,76,105,110,107,101, 100,66,111,100,105,101,115,0,109,95,112,97,100,52,91,52,93,0,109,95, 116,121,112,101,67,111,110,115,116,114,97,105,110,116,68,97,116,97,0,109, 95,112,105,118,111,116,73,110,65,0,109,95,112,105,118,111,116,73,110,66, 0,109,95,114,98,65,70,114,97,109,101,0,109,95,114,98,66,70,114,97, 109,101,0,109,95,117,115,101,82,101,102,101,114,101,110,99,101,70,114,97, 109,101,65,0,109,95,97,110,103,117,108,97,114,79,110,108,121,0,109,95, 101,110,97,98,108,101,65,110,103,117,108,97,114,77,111,116,111,114,0,109, 95,109,111,116,111,114,84,97,114,103,101,116,86,101,108,111,99,105,116,121, 0,109,95,109,97,120,77,111,116,111,114,73,109,112,117,108,115,101,0,109, 95,108,111,119,101,114,76,105,109,105,116,0,109,95,117,112,112,101,114,76, 105,109,105,116,0,109,95,108,105,109,105,116,83,111,102,116,110,101,115,115, 0,109,95,98,105,97,115,70,97,99,116,111,114,0,109,95,114,101,108,97, 120,97,116,105,111,110,70,97,99,116,111,114,0,109,95,115,119,105,110,103, 83,112,97,110,49,0,109,95,115,119,105,110,103,83,112,97,110,50,0,109, 95,116,119,105,115,116,83,112,97,110,0,109,95,100,97,109,112,105,110,103, 0,109,95,108,105,110,101,97,114,85,112,112,101,114,76,105,109,105,116,0, 109,95,108,105,110,101,97,114,76,111,119,101,114,76,105,109,105,116,0,109, 95,97,110,103,117,108,97,114,85,112,112,101,114,76,105,109,105,116,0,109, 95,97,110,103,117,108,97,114,76,111,119,101,114,76,105,109,105,116,0,109, 95,117,115,101,76,105,110,101,97,114,82,101,102,101,114,101,110,99,101,70, 114,97,109,101,65,0,109,95,117,115,101,79,102,102,115,101,116,70,111,114, 67,111,110,115,116,114,97,105,110,116,70,114,97,109,101,0,84,89,80,69, 58,0,0,0,99,104,97,114,0,117,99,104,97,114,0,115,104,111,114,116, 0,117,115,104,111,114,116,0,105,110,116,0,108,111,110,103,0,117,108,111, 110,103,0,102,108,111,97,116,0,100,111,117,98,108,101,0,118,111,105,100, 0,80,111,105,110,116,101,114,65,114,114,97,121,0,98,116,80,104,121,115, 105,99,115,83,121,115,116,101,109,0,76,105,115,116,66,97,115,101,0,98, 116,86,101,99,116,111,114,51,70,108,111,97,116,68,97,116,97,0,98,116, 86,101,99,116,111,114,51,68,111,117,98,108,101,68,97,116,97,0,98,116, 77,97,116,114,105,120,51,120,51,70,108,111,97,116,68,97,116,97,0,98, 116,77,97,116,114,105,120,51,120,51,68,111,117,98,108,101,68,97,116,97, 0,98,116,84,114,97,110,115,102,111,114,109,70,108,111,97,116,68,97,116, 97,0,98,116,84,114,97,110,115,102,111,114,109,68,111,117,98,108,101,68, 97,116,97,0,98,116,66,118,104,83,117,98,116,114,101,101,73,110,102,111, 68,97,116,97,0,98,116,79,112,116,105,109,105,122,101,100,66,118,104,78, 111,100,101,70,108,111,97,116,68,97,116,97,0,98,116,79,112,116,105,109, 105,122,101,100,66,118,104,78,111,100,101,68,111,117,98,108,101,68,97,116, 97,0,98,116,81,117,97,110,116,105,122,101,100,66,118,104,78,111,100,101, 68,97,116,97,0,98,116,81,117,97,110,116,105,122,101,100,66,118,104,70, 108,111,97,116,68,97,116,97,0,98,116,81,117,97,110,116,105,122,101,100, 66,118,104,68,111,117,98,108,101,68,97,116,97,0,98,116,67,111,108,108, 105,115,105,111,110,83,104,97,112,101,68,97,116,97,0,98,116,83,116,97, 116,105,99,80,108,97,110,101,83,104,97,112,101,68,97,116,97,0,98,116, 67,111,110,118,101,120,73,110,116,101,114,110,97,108,83,104,97,112,101,68, 97,116,97,0,98,116,80,111,115,105,116,105,111,110,65,110,100,82,97,100, 105,117,115,0,98,116,77,117,108,116,105,83,112,104,101,114,101,83,104,97, 112,101,68,97,116,97,0,98,116,73,110,116,73,110,100,101,120,68,97,116, 97,0,98,116,83,104,111,114,116,73,110,116,73,110,100,101,120,68,97,116, 97,0,98,116,83,104,111,114,116,73,110,116,73,110,100,101,120,84,114,105, 112,108,101,116,68,97,116,97,0,98,116,77,101,115,104,80,97,114,116,68, 97,116,97,0,98,116,83,116,114,105,100,105,110,103,77,101,115,104,73,110, 116,101,114,102,97,99,101,68,97,116,97,0,98,116,84,114,105,97,110,103, 108,101,77,101,115,104,83,104,97,112,101,68,97,116,97,0,98,116,84,114, 105,97,110,103,108,101,73,110,102,111,77,97,112,68,97,116,97,0,98,116, 67,111,109,112,111,117,110,100,83,104,97,112,101,67,104,105,108,100,68,97, 116,97,0,98,116,67,111,109,112,111,117,110,100,83,104,97,112,101,68,97, 116,97,0,98,116,67,121,108,105,110,100,101,114,83,104,97,112,101,68,97, 116,97,0,98,116,67,97,112,115,117,108,101,83,104,97,112,101,68,97,116, 97,0,98,116,84,114,105,97,110,103,108,101,73,110,102,111,68,97,116,97, 0,98,116,71,73,109,112,97,99,116,77,101,115,104,83,104,97,112,101,68, 97,116,97,0,98,116,67,111,110,118,101,120,72,117,108,108,83,104,97,112, 101,68,97,116,97,0,98,116,67,111,108,108,105,115,105,111,110,79,98,106, 101,99,116,68,111,117,98,108,101,68,97,116,97,0,98,116,67,111,108,108, 105,115,105,111,110,79,98,106,101,99,116,70,108,111,97,116,68,97,116,97, 0,98,116,82,105,103,105,100,66,111,100,121,70,108,111,97,116,68,97,116, 97,0,98,116,82,105,103,105,100,66,111,100,121,68,111,117,98,108,101,68, 97,116,97,0,98,116,67,111,110,115,116,114,97,105,110,116,73,110,102,111, 49,0,98,116,84,121,112,101,100,67,111,110,115,116,114,97,105,110,116,68, 97,116,97,0,98,116,82,105,103,105,100,66,111,100,121,68,97,116,97,0, 98,116,80,111,105,110,116,50,80,111,105,110,116,67,111,110,115,116,114,97, 105,110,116,70,108,111,97,116,68,97,116,97,0,98,116,80,111,105,110,116, 50,80,111,105,110,116,67,111,110,115,116,114,97,105,110,116,68,111,117,98, 108,101,68,97,116,97,0,98,116,72,105,110,103,101,67,111,110,115,116,114, 97,105,110,116,68,111,117,98,108,101,68,97,116,97,0,98,116,72,105,110, 103,101,67,111,110,115,116,114,97,105,110,116,70,108,111,97,116,68,97,116, 97,0,98,116,67,111,110,101,84,119,105,115,116,67,111,110,115,116,114,97, 105,110,116,68,97,116,97,0,98,116,71,101,110,101,114,105,99,54,68,111, 102,67,111,110,115,116,114,97,105,110,116,68,97,116,97,0,98,116,83,108, 105,100,101,114,67,111,110,115,116,114,97,105,110,116,68,97,116,97,0,0, 84,76,69,78,1,0,1,0,2,0,2,0,4,0,4,0,4,0,4,0, 8,0,0,0,12,0,36,0,8,0,16,0,32,0,48,0,96,0,64,0, -128,0,20,0,48,0,80,0,16,0,84,0,-124,0,12,0,52,0,52,0, 20,0,64,0,4,0,4,0,8,0,28,0,28,0,60,0,56,0,76,0, 24,0,60,0,60,0,16,0,64,0,68,0,-56,1,-8,0,-32,1,-104,3, 8,0,44,0,0,0,76,0,108,0,84,1,-44,0,-52,0,-12,0,-60,0, 83,84,82,67,47,0,0,0,10,0,3,0,4,0,0,0,4,0,1,0, 9,0,2,0,11,0,3,0,10,0,3,0,10,0,4,0,10,0,5,0, 12,0,2,0,9,0,6,0,9,0,7,0,13,0,1,0,7,0,8,0, 14,0,1,0,8,0,8,0,15,0,1,0,13,0,9,0,16,0,1,0, 14,0,9,0,17,0,2,0,15,0,10,0,13,0,11,0,18,0,2,0, 16,0,10,0,14,0,11,0,19,0,4,0,4,0,12,0,4,0,13,0, 2,0,14,0,2,0,15,0,20,0,6,0,13,0,16,0,13,0,17,0, 4,0,18,0,4,0,19,0,4,0,20,0,0,0,21,0,21,0,6,0, 14,0,16,0,14,0,17,0,4,0,18,0,4,0,19,0,4,0,20,0, 0,0,21,0,22,0,3,0,2,0,14,0,2,0,15,0,4,0,22,0, 23,0,12,0,13,0,23,0,13,0,24,0,13,0,25,0,4,0,26,0, 4,0,27,0,4,0,28,0,4,0,29,0,20,0,30,0,22,0,31,0, 19,0,32,0,4,0,33,0,4,0,34,0,24,0,12,0,14,0,23,0, 14,0,24,0,14,0,25,0,4,0,26,0,4,0,27,0,4,0,28,0, 4,0,29,0,21,0,30,0,22,0,31,0,4,0,33,0,4,0,34,0, 19,0,32,0,25,0,3,0,0,0,35,0,4,0,36,0,0,0,37,0, 26,0,5,0,25,0,38,0,13,0,39,0,13,0,40,0,7,0,41,0, 0,0,21,0,27,0,5,0,25,0,38,0,13,0,39,0,13,0,42,0, 7,0,43,0,4,0,44,0,28,0,2,0,13,0,45,0,7,0,46,0, 29,0,4,0,27,0,47,0,28,0,48,0,4,0,49,0,0,0,37,0, 30,0,1,0,4,0,50,0,31,0,2,0,2,0,50,0,0,0,51,0, 32,0,2,0,2,0,52,0,0,0,51,0,33,0,7,0,13,0,53,0, 14,0,54,0,30,0,55,0,32,0,56,0,31,0,57,0,4,0,58,0, 4,0,59,0,34,0,4,0,33,0,60,0,13,0,61,0,4,0,62,0, 0,0,37,0,35,0,7,0,25,0,38,0,34,0,63,0,23,0,64,0, 24,0,65,0,36,0,66,0,7,0,43,0,0,0,67,0,37,0,4,0, 17,0,68,0,25,0,69,0,4,0,70,0,7,0,71,0,38,0,4,0, 25,0,38,0,37,0,72,0,4,0,73,0,7,0,43,0,39,0,3,0, 27,0,47,0,4,0,74,0,0,0,37,0,40,0,3,0,27,0,47,0, 4,0,74,0,0,0,37,0,41,0,4,0,4,0,75,0,7,0,76,0, 7,0,77,0,7,0,78,0,36,0,14,0,4,0,79,0,4,0,80,0, 41,0,81,0,4,0,82,0,7,0,83,0,7,0,84,0,7,0,85,0, 7,0,86,0,7,0,87,0,4,0,88,0,4,0,89,0,4,0,90,0, 4,0,91,0,0,0,37,0,42,0,5,0,25,0,38,0,34,0,63,0, 13,0,39,0,7,0,43,0,4,0,92,0,43,0,5,0,27,0,47,0, 13,0,93,0,14,0,94,0,4,0,95,0,0,0,96,0,44,0,24,0, 9,0,97,0,9,0,98,0,25,0,99,0,0,0,35,0,18,0,100,0, 18,0,101,0,14,0,102,0,14,0,103,0,14,0,104,0,8,0,105,0, 8,0,106,0,8,0,107,0,8,0,108,0,8,0,109,0,8,0,110,0, 8,0,111,0,4,0,112,0,4,0,113,0,4,0,114,0,4,0,115,0, 4,0,116,0,4,0,117,0,4,0,118,0,0,0,37,0,45,0,23,0, 9,0,97,0,9,0,98,0,25,0,99,0,0,0,35,0,17,0,100,0, 17,0,101,0,13,0,102,0,13,0,103,0,13,0,104,0,7,0,105,0, 7,0,106,0,7,0,107,0,7,0,108,0,7,0,109,0,7,0,110,0, 7,0,111,0,4,0,112,0,4,0,113,0,4,0,114,0,4,0,115,0, 4,0,116,0,4,0,117,0,4,0,118,0,46,0,21,0,45,0,119,0, 15,0,120,0,13,0,121,0,13,0,122,0,13,0,123,0,13,0,124,0, 13,0,125,0,13,0,126,0,13,0,127,0,13,0,-128,0,13,0,-127,0, 7,0,-126,0,7,0,-125,0,7,0,-124,0,7,0,-123,0,7,0,-122,0, 7,0,-121,0,7,0,-120,0,7,0,-119,0,7,0,-118,0,4,0,-117,0, 47,0,22,0,44,0,119,0,16,0,120,0,14,0,121,0,14,0,122,0, 14,0,123,0,14,0,124,0,14,0,125,0,14,0,126,0,14,0,127,0, 14,0,-128,0,14,0,-127,0,8,0,-126,0,8,0,-125,0,8,0,-124,0, 8,0,-123,0,8,0,-122,0,8,0,-121,0,8,0,-120,0,8,0,-119,0, 8,0,-118,0,4,0,-117,0,0,0,37,0,48,0,2,0,4,0,-116,0, 4,0,-115,0,49,0,11,0,50,0,-114,0,50,0,-113,0,0,0,35,0, 4,0,-112,0,4,0,-111,0,4,0,-110,0,4,0,-109,0,7,0,-108,0, 7,0,-107,0,4,0,-106,0,0,0,-105,0,51,0,3,0,49,0,-104,0, 13,0,-103,0,13,0,-102,0,52,0,3,0,49,0,-104,0,14,0,-103,0, 14,0,-102,0,53,0,13,0,49,0,-104,0,18,0,-101,0,18,0,-100,0, 4,0,-99,0,4,0,-98,0,4,0,-97,0,7,0,-96,0,7,0,-95,0, 7,0,-94,0,7,0,-93,0,7,0,-92,0,7,0,-91,0,7,0,-90,0, 54,0,13,0,49,0,-104,0,17,0,-101,0,17,0,-100,0,4,0,-99,0, 4,0,-98,0,4,0,-97,0,7,0,-96,0,7,0,-95,0,7,0,-94,0, 7,0,-93,0,7,0,-92,0,7,0,-91,0,7,0,-90,0,55,0,11,0, 49,0,-104,0,17,0,-101,0,17,0,-100,0,7,0,-89,0,7,0,-88,0, 7,0,-87,0,7,0,-92,0,7,0,-91,0,7,0,-90,0,7,0,-86,0, 0,0,21,0,56,0,9,0,49,0,-104,0,17,0,-101,0,17,0,-100,0, 13,0,-85,0,13,0,-84,0,13,0,-83,0,13,0,-82,0,4,0,-81,0, 4,0,-80,0,57,0,9,0,49,0,-104,0,17,0,-101,0,17,0,-100,0, 7,0,-85,0,7,0,-84,0,7,0,-83,0,7,0,-82,0,4,0,-81,0, 4,0,-80,0,}; int sBulletDNAlen= sizeof(sBulletDNAstr); critterding-beta12.1/src/utils/bullet/LinearMath/ibmsdk/0000755000175000017500000000000011347266042022255 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/LinearMath/ibmsdk/Makefile0000644000175000017500000000140611337071441023712 0ustar bobkebobke#### Source code Dirs VPATH = ../ ROOT = ../../.. #### Library LIBRARY_ppu = bulletmath.a #### Compiler flags CPPFLAGS = \ -DUSE_LIBSPE2 \ -I$(ROOT)/src \ -I$(SDKINC) #### Optimization level flags #CC_OPT_LEVEL = $(CC_OPT_LEVEL_DEBUG) CC_OPT_LEVEL = -O3 ##### Objects to be archived in lib OBJS = \ btAlignedAllocator.o \ btGeometryUtil.o \ btQuickprof.o #### Install directories INSTALL_DIR = $(ROOT)/lib/ibmsdk INSTALL_FILES = $(LIBRARY_ppu) IBM_CELLSDK_VERSION := $(shell if [ -d /opt/cell ]; then echo "3.0"; fi) ifeq ("$(IBM_CELLSDK_VERSION)","3.0") CELL_TOP ?= /opt/cell/sdk include $(CELL_TOP)/buildutils/make.footer else CELL_TOP ?= /opt/ibm/cell-sdk/prototype include $(CELL_TOP)/make.footer endif critterding-beta12.1/src/utils/bullet/LinearMath/btTransformUtil.h0000644000175000017500000001611511344267705024324 0ustar bobkebobke/* Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ 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 SIMD_TRANSFORM_UTIL_H #define SIMD_TRANSFORM_UTIL_H #include "btTransform.h" #define ANGULAR_MOTION_THRESHOLD btScalar(0.5)*SIMD_HALF_PI SIMD_FORCE_INLINE btVector3 btAabbSupport(const btVector3& halfExtents,const btVector3& supportDir) { return btVector3(supportDir.x() < btScalar(0.0) ? -halfExtents.x() : halfExtents.x(), supportDir.y() < btScalar(0.0) ? -halfExtents.y() : halfExtents.y(), supportDir.z() < btScalar(0.0) ? -halfExtents.z() : halfExtents.z()); } /// Utils related to temporal transforms class btTransformUtil { public: static void integrateTransform(const btTransform& curTrans,const btVector3& linvel,const btVector3& angvel,btScalar timeStep,btTransform& predictedTransform) { predictedTransform.setOrigin(curTrans.getOrigin() + linvel * timeStep); // #define QUATERNION_DERIVATIVE #ifdef QUATERNION_DERIVATIVE btQuaternion predictedOrn = curTrans.getRotation(); predictedOrn += (angvel * predictedOrn) * (timeStep * btScalar(0.5)); predictedOrn.normalize(); #else //Exponential map //google for "Practical Parameterization of Rotations Using the Exponential Map", F. Sebastian Grassia btVector3 axis; btScalar fAngle = angvel.length(); //limit the angular motion if (fAngle*timeStep > ANGULAR_MOTION_THRESHOLD) { fAngle = ANGULAR_MOTION_THRESHOLD / timeStep; } if ( fAngle < btScalar(0.001) ) { // use Taylor's expansions of sync function axis = angvel*( btScalar(0.5)*timeStep-(timeStep*timeStep*timeStep)*(btScalar(0.020833333333))*fAngle*fAngle ); } else { // sync(fAngle) = sin(c*fAngle)/t axis = angvel*( btSin(btScalar(0.5)*fAngle*timeStep)/fAngle ); } btQuaternion dorn (axis.x(),axis.y(),axis.z(),btCos( fAngle*timeStep*btScalar(0.5) )); btQuaternion orn0 = curTrans.getRotation(); btQuaternion predictedOrn = dorn * orn0; predictedOrn.normalize(); #endif predictedTransform.setRotation(predictedOrn); } static void calculateVelocityQuaternion(const btVector3& pos0,const btVector3& pos1,const btQuaternion& orn0,const btQuaternion& orn1,btScalar timeStep,btVector3& linVel,btVector3& angVel) { linVel = (pos1 - pos0) / timeStep; btVector3 axis; btScalar angle; if (orn0 != orn1) { calculateDiffAxisAngleQuaternion(orn0,orn1,axis,angle); angVel = axis * angle / timeStep; } else { angVel.setValue(0,0,0); } } static void calculateDiffAxisAngleQuaternion(const btQuaternion& orn0,const btQuaternion& orn1a,btVector3& axis,btScalar& angle) { btQuaternion orn1 = orn0.nearest(orn1a); btQuaternion dorn = orn1 * orn0.inverse(); angle = dorn.getAngle(); axis = btVector3(dorn.x(),dorn.y(),dorn.z()); axis[3] = btScalar(0.); //check for axis length btScalar len = axis.length2(); if (len < SIMD_EPSILON*SIMD_EPSILON) axis = btVector3(btScalar(1.),btScalar(0.),btScalar(0.)); else axis /= btSqrt(len); } static void calculateVelocity(const btTransform& transform0,const btTransform& transform1,btScalar timeStep,btVector3& linVel,btVector3& angVel) { linVel = (transform1.getOrigin() - transform0.getOrigin()) / timeStep; btVector3 axis; btScalar angle; calculateDiffAxisAngle(transform0,transform1,axis,angle); angVel = axis * angle / timeStep; } static void calculateDiffAxisAngle(const btTransform& transform0,const btTransform& transform1,btVector3& axis,btScalar& angle) { btMatrix3x3 dmat = transform1.getBasis() * transform0.getBasis().inverse(); btQuaternion dorn; dmat.getRotation(dorn); ///floating point inaccuracy can lead to w component > 1..., which breaks dorn.normalize(); angle = dorn.getAngle(); axis = btVector3(dorn.x(),dorn.y(),dorn.z()); axis[3] = btScalar(0.); //check for axis length btScalar len = axis.length2(); if (len < SIMD_EPSILON*SIMD_EPSILON) axis = btVector3(btScalar(1.),btScalar(0.),btScalar(0.)); else axis /= btSqrt(len); } }; ///The btConvexSeparatingDistanceUtil can help speed up convex collision detection ///by conservatively updating a cached separating distance/vector instead of re-calculating the closest distance class btConvexSeparatingDistanceUtil { btQuaternion m_ornA; btQuaternion m_ornB; btVector3 m_posA; btVector3 m_posB; btVector3 m_separatingNormal; btScalar m_boundingRadiusA; btScalar m_boundingRadiusB; btScalar m_separatingDistance; public: btConvexSeparatingDistanceUtil(btScalar boundingRadiusA,btScalar boundingRadiusB) :m_boundingRadiusA(boundingRadiusA), m_boundingRadiusB(boundingRadiusB), m_separatingDistance(0.f) { } btScalar getConservativeSeparatingDistance() { return m_separatingDistance; } void updateSeparatingDistance(const btTransform& transA,const btTransform& transB) { const btVector3& toPosA = transA.getOrigin(); const btVector3& toPosB = transB.getOrigin(); btQuaternion toOrnA = transA.getRotation(); btQuaternion toOrnB = transB.getRotation(); if (m_separatingDistance>0.f) { btVector3 linVelA,angVelA,linVelB,angVelB; btTransformUtil::calculateVelocityQuaternion(m_posA,toPosA,m_ornA,toOrnA,btScalar(1.),linVelA,angVelA); btTransformUtil::calculateVelocityQuaternion(m_posB,toPosB,m_ornB,toOrnB,btScalar(1.),linVelB,angVelB); btScalar maxAngularProjectedVelocity = angVelA.length() * m_boundingRadiusA + angVelB.length() * m_boundingRadiusB; btVector3 relLinVel = (linVelB-linVelA); btScalar relLinVelocLength = (linVelB-linVelA).dot(m_separatingNormal); if (relLinVelocLength<0.f) { relLinVelocLength = 0.f; } btScalar projectedMotion = maxAngularProjectedVelocity +relLinVelocLength; m_separatingDistance -= projectedMotion; } m_posA = toPosA; m_posB = toPosB; m_ornA = toOrnA; m_ornB = toOrnB; } void initSeparatingDistance(const btVector3& separatingVector,btScalar separatingDistance,const btTransform& transA,const btTransform& transB) { m_separatingDistance = separatingDistance; if (m_separatingDistance>0.f) { m_separatingNormal = separatingVector; const btVector3& toPosA = transA.getOrigin(); const btVector3& toPosB = transB.getOrigin(); btQuaternion toOrnA = transA.getRotation(); btQuaternion toOrnB = transB.getRotation(); m_posA = toPosA; m_posB = toPosB; m_ornA = toOrnA; m_ornB = toOrnB; } } }; #endif //SIMD_TRANSFORM_UTIL_H critterding-beta12.1/src/utils/bullet/LinearMath/CMakeLists.txt0000644000175000017500000000326111344267705023552 0ustar bobkebobke INCLUDE_DIRECTORIES( ${BULLET_PHYSICS_SOURCE_DIR}/src ) SET(LinearMath_SRCS btAlignedAllocator.cpp btConvexHull.cpp btGeometryUtil.cpp btQuickprof.cpp btSerializer.cpp ) SET(LinearMath_HDRS btAabbUtil2.h btAlignedAllocator.h btAlignedObjectArray.h btConvexHull.h btDefaultMotionState.h btGeometryUtil.h btHashMap.h btIDebugDraw.h btList.h btMatrix3x3.h btMinMax.h btMotionState.h btPoolAllocator.h btQuadWord.h btQuaternion.h btQuickprof.h btRandom.h btScalar.h btSerializer.h btStackAlloc.h btTransform.h btTransformUtil.h btVector3.h ) ADD_LIBRARY(LinearMath ${LinearMath_SRCS} ${LinearMath_HDRS}) SET_TARGET_PROPERTIES(LinearMath PROPERTIES VERSION ${BULLET_VERSION}) SET_TARGET_PROPERTIES(LinearMath PROPERTIES SOVERSION ${BULLET_VERSION}) IF (INSTALL_LIBS) IF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) #FILES_MATCHING requires CMake 2.6 IF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) INSTALL(TARGETS LinearMath DESTINATION .) ELSE (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) INSTALL(TARGETS LinearMath DESTINATION lib${LIB_SUFFIX}) INSTALL(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} DESTINATION include FILES_MATCHING PATTERN "*.h") ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) ENDIF (${CMAKE_MAJOR_VERSION}.${CMAKE_MINOR_VERSION} GREATER 2.5) IF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) SET_TARGET_PROPERTIES(LinearMath PROPERTIES FRAMEWORK true) SET_TARGET_PROPERTIES(LinearMath PROPERTIES PUBLIC_HEADER ${LinearMath_HDRS}) ENDIF (APPLE AND BUILD_SHARED_LIBS AND FRAMEWORK) ENDIF (NOT INTERNAL_CREATE_DISTRIBUTABLE_MSVC_PROJECTFILES) ENDIF (INSTALL_LIBS)critterding-beta12.1/src/utils/bullet/LinearMath/btList.h0000644000175000017500000000432611337071441022417 0ustar bobkebobke/* Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ 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 GEN_LIST_H #define GEN_LIST_H class btGEN_Link { public: btGEN_Link() : m_next(0), m_prev(0) {} btGEN_Link(btGEN_Link *next, btGEN_Link *prev) : m_next(next), m_prev(prev) {} btGEN_Link *getNext() const { return m_next; } btGEN_Link *getPrev() const { return m_prev; } bool isHead() const { return m_prev == 0; } bool isTail() const { return m_next == 0; } void insertBefore(btGEN_Link *link) { m_next = link; m_prev = link->m_prev; m_next->m_prev = this; m_prev->m_next = this; } void insertAfter(btGEN_Link *link) { m_next = link->m_next; m_prev = link; m_next->m_prev = this; m_prev->m_next = this; } void remove() { m_next->m_prev = m_prev; m_prev->m_next = m_next; } private: btGEN_Link *m_next; btGEN_Link *m_prev; }; class btGEN_List { public: btGEN_List() : m_head(&m_tail, 0), m_tail(0, &m_head) {} btGEN_Link *getHead() const { return m_head.getNext(); } btGEN_Link *getTail() const { return m_tail.getPrev(); } void addHead(btGEN_Link *link) { link->insertAfter(&m_head); } void addTail(btGEN_Link *link) { link->insertBefore(&m_tail); } private: btGEN_Link m_head; btGEN_Link m_tail; }; #endif critterding-beta12.1/src/utils/bullet/LinearMath/btGeometryUtil.cpp0000644000175000017500000001175611337071441024475 0ustar bobkebobke/* Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ 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 "btGeometryUtil.h" /* Make sure this dummy function never changes so that it can be used by probes that are checking whether the library is actually installed. */ extern "C" { void btBulletMathProbe (); void btBulletMathProbe () {} } bool btGeometryUtil::isPointInsidePlanes(const btAlignedObjectArray& planeEquations, const btVector3& point, btScalar margin) { int numbrushes = planeEquations.size(); for (int i=0;ibtScalar(0.)) { return false; } } return true; } bool btGeometryUtil::areVerticesBehindPlane(const btVector3& planeNormal, const btAlignedObjectArray& vertices, btScalar margin) { int numvertices = vertices.size(); for (int i=0;ibtScalar(0.)) { return false; } } return true; } bool notExist(const btVector3& planeEquation,const btAlignedObjectArray& planeEquations); bool notExist(const btVector3& planeEquation,const btAlignedObjectArray& planeEquations) { int numbrushes = planeEquations.size(); for (int i=0;i btScalar(0.999)) { return false; } } return true; } void btGeometryUtil::getPlaneEquationsFromVertices(btAlignedObjectArray& vertices, btAlignedObjectArray& planeEquationsOut ) { const int numvertices = vertices.size(); // brute force: for (int i=0;i btScalar(0.0001)) { planeEquation.normalize(); if (notExist(planeEquation,planeEquationsOut)) { planeEquation[3] = -planeEquation.dot(N1); //check if inside, and replace supportingVertexOut if needed if (areVerticesBehindPlane(planeEquation,vertices,btScalar(0.01))) { planeEquationsOut.push_back(planeEquation); } } } normalSign = btScalar(-1.); } } } } } void btGeometryUtil::getVerticesFromPlaneEquations(const btAlignedObjectArray& planeEquations , btAlignedObjectArray& verticesOut ) { const int numbrushes = planeEquations.size(); // brute force: for (int i=0;i btScalar(0.0001) ) && ( n3n1.length2() > btScalar(0.0001) ) && ( n1n2.length2() > btScalar(0.0001) ) ) { //point P out of 3 plane equations: // d1 ( N2 * N3 ) + d2 ( N3 * N1 ) + d3 ( N1 * N2 ) //P = ------------------------------------------------------------------------- // N1 . ( N2 * N3 ) btScalar quotient = (N1.dot(n2n3)); if (btFabs(quotient) > btScalar(0.000001)) { quotient = btScalar(-1.) / quotient; n2n3 *= N1[3]; n3n1 *= N2[3]; n1n2 *= N3[3]; btVector3 potentialVertex = n2n3; potentialVertex += n3n1; potentialVertex += n1n2; potentialVertex *= quotient; //check if inside, and replace supportingVertexOut if needed if (isPointInsidePlanes(planeEquations,potentialVertex,btScalar(0.01))) { verticesOut.push_back(potentialVertex); } } } } } } } critterding-beta12.1/src/utils/bullet/LinearMath/btConvexHull.h0000644000175000017500000001641311344267705023603 0ustar bobkebobke /* Stan Melax Convex Hull Computation Copyright (c) 2008 Stan Melax http://www.melax.com/ 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. */ ///includes modifications/improvements by John Ratcliff, see BringOutYourDead below. #ifndef CD_HULL_H #define CD_HULL_H #include "btVector3.h" #include "btAlignedObjectArray.h" typedef btAlignedObjectArray TUIntArray; class HullResult { public: HullResult(void) { mPolygons = true; mNumOutputVertices = 0; mNumFaces = 0; mNumIndices = 0; } bool mPolygons; // true if indices represents polygons, false indices are triangles unsigned int mNumOutputVertices; // number of vertices in the output hull btAlignedObjectArray m_OutputVertices; // array of vertices unsigned int mNumFaces; // the number of faces produced unsigned int mNumIndices; // the total number of indices btAlignedObjectArray m_Indices; // pointer to indices. // If triangles, then indices are array indexes into the vertex list. // If polygons, indices are in the form (number of points in face) (p1, p2, p3, ..) etc.. }; enum HullFlag { QF_TRIANGLES = (1<<0), // report results as triangles, not polygons. QF_REVERSE_ORDER = (1<<1), // reverse order of the triangle indices. QF_DEFAULT = QF_TRIANGLES }; class HullDesc { public: HullDesc(void) { mFlags = QF_DEFAULT; mVcount = 0; mVertices = 0; mVertexStride = sizeof(btVector3); mNormalEpsilon = 0.001f; mMaxVertices = 4096; // maximum number of points to be considered for a convex hull. mMaxFaces = 4096; }; HullDesc(HullFlag flag, unsigned int vcount, const btVector3 *vertices, unsigned int stride = sizeof(btVector3)) { mFlags = flag; mVcount = vcount; mVertices = vertices; mVertexStride = stride; mNormalEpsilon = btScalar(0.001); mMaxVertices = 4096; } bool HasHullFlag(HullFlag flag) const { if ( mFlags & flag ) return true; return false; } void SetHullFlag(HullFlag flag) { mFlags|=flag; } void ClearHullFlag(HullFlag flag) { mFlags&=~flag; } unsigned int mFlags; // flags to use when generating the convex hull. unsigned int mVcount; // number of vertices in the input point cloud const btVector3 *mVertices; // the array of vertices. unsigned int mVertexStride; // the stride of each vertex, in bytes. btScalar mNormalEpsilon; // the epsilon for removing duplicates. This is a normalized value, if normalized bit is on. unsigned int mMaxVertices; // maximum number of vertices to be considered for the hull! unsigned int mMaxFaces; }; enum HullError { QE_OK, // success! QE_FAIL // failed. }; class btPlane { public: btVector3 normal; btScalar dist; // distance below origin - the D from plane equasion Ax+By+Cz+D=0 btPlane(const btVector3 &n,btScalar d):normal(n),dist(d){} btPlane():normal(),dist(0){} }; class ConvexH { public: class HalfEdge { public: short ea; // the other half of the edge (index into edges list) unsigned char v; // the vertex at the start of this edge (index into vertices list) unsigned char p; // the facet on which this edge lies (index into facets list) HalfEdge(){} HalfEdge(short _ea,unsigned char _v, unsigned char _p):ea(_ea),v(_v),p(_p){} }; ConvexH() { } ~ConvexH() { } btAlignedObjectArray vertices; btAlignedObjectArray edges; btAlignedObjectArray facets; ConvexH(int vertices_size,int edges_size,int facets_size); }; class int4 { public: int x,y,z,w; int4(){}; int4(int _x,int _y, int _z,int _w){x=_x;y=_y;z=_z;w=_w;} const int& operator[](int i) const {return (&x)[i];} int& operator[](int i) {return (&x)[i];} }; class PHullResult { public: PHullResult(void) { mVcount = 0; mIndexCount = 0; mFaceCount = 0; mVertices = 0; } unsigned int mVcount; unsigned int mIndexCount; unsigned int mFaceCount; btVector3* mVertices; TUIntArray m_Indices; }; ///The HullLibrary class can create a convex hull from a collection of vertices, using the ComputeHull method. ///The btShapeHull class uses this HullLibrary to create a approximate convex mesh given a general (non-polyhedral) convex shape. class HullLibrary { btAlignedObjectArray m_tris; public: btAlignedObjectArray m_vertexIndexMapping; HullError CreateConvexHull(const HullDesc& desc, // describes the input request HullResult& result); // contains the resulst HullError ReleaseResult(HullResult &result); // release memory allocated for this result, we are done with it. private: bool ComputeHull(unsigned int vcount,const btVector3 *vertices,PHullResult &result,unsigned int vlimit); class btHullTriangle* allocateTriangle(int a,int b,int c); void deAllocateTriangle(btHullTriangle*); void b2bfix(btHullTriangle* s,btHullTriangle*t); void removeb2b(btHullTriangle* s,btHullTriangle*t); void checkit(btHullTriangle *t); btHullTriangle* extrudable(btScalar epsilon); int calchull(btVector3 *verts,int verts_count, TUIntArray& tris_out, int &tris_count,int vlimit); int calchullgen(btVector3 *verts,int verts_count, int vlimit); int4 FindSimplex(btVector3 *verts,int verts_count,btAlignedObjectArray &allow); class ConvexH* ConvexHCrop(ConvexH& convex,const btPlane& slice); void extrude(class btHullTriangle* t0,int v); ConvexH* test_cube(); //BringOutYourDead (John Ratcliff): When you create a convex hull you hand it a large input set of vertices forming a 'point cloud'. //After the hull is generated it give you back a set of polygon faces which index the *original* point cloud. //The thing is, often times, there are many 'dead vertices' in the point cloud that are on longer referenced by the hull. //The routine 'BringOutYourDead' find only the referenced vertices, copies them to an new buffer, and re-indexes the hull so that it is a minimal representation. void BringOutYourDead(const btVector3* verts,unsigned int vcount, btVector3* overts,unsigned int &ocount,unsigned int* indices,unsigned indexcount); bool CleanupVertices(unsigned int svcount, const btVector3* svertices, unsigned int stride, unsigned int &vcount, // output number of vertices btVector3* vertices, // location to store the results. btScalar normalepsilon, btVector3& scale); }; #endif critterding-beta12.1/src/utils/bullet/LinearMath/btIDebugDraw.h0000644000175000017500000002647611344267705023503 0ustar bobkebobke/* Bullet Continuous Collision Detection and Physics Library Copyright (c) 2003-2009 Erwin Coumans http://bulletphysics.org 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 IDEBUG_DRAW__H #define IDEBUG_DRAW__H #include "btVector3.h" #include "btTransform.h" ///The btIDebugDraw interface class allows hooking up a debug renderer to visually debug simulations. ///Typical use case: create a debug drawer object, and assign it to a btCollisionWorld or btDynamicsWorld using setDebugDrawer and call debugDrawWorld. ///A class that implements the btIDebugDraw interface has to implement the drawLine method at a minimum. ///For color arguments the X,Y,Z components refer to Red, Green and Blue each in the range [0..1] class btIDebugDraw { public: enum DebugDrawModes { DBG_NoDebug=0, DBG_DrawWireframe = 1, DBG_DrawAabb=2, DBG_DrawFeaturesText=4, DBG_DrawContactPoints=8, DBG_NoDeactivation=16, DBG_NoHelpText = 32, DBG_DrawText=64, DBG_ProfileTimings = 128, DBG_EnableSatComparison = 256, DBG_DisableBulletLCP = 512, DBG_EnableCCD = 1024, DBG_DrawConstraints = (1 << 11), DBG_DrawConstraintLimits = (1 << 12), DBG_FastWireframe = (1<<13), DBG_MAX_DEBUG_DRAW_MODE }; virtual ~btIDebugDraw() {}; virtual void drawLine(const btVector3& from,const btVector3& to,const btVector3& color)=0; virtual void drawLine(const btVector3& from,const btVector3& to, const btVector3& fromColor, const btVector3& toColor) { (void) toColor; drawLine (from, to, fromColor); } void drawSphere(btScalar radius, const btTransform& transform, const btVector3& color) { btVector3 start = transform.getOrigin(); const btVector3 xoffs = transform.getBasis() * btVector3(radius,0,0); const btVector3 yoffs = transform.getBasis() * btVector3(0,radius,0); const btVector3 zoffs = transform.getBasis() * btVector3(0,0,radius); // XY drawLine(start-xoffs, start+yoffs, color); drawLine(start+yoffs, start+xoffs, color); drawLine(start+xoffs, start-yoffs, color); drawLine(start-yoffs, start-xoffs, color); // XZ drawLine(start-xoffs, start+zoffs, color); drawLine(start+zoffs, start+xoffs, color); drawLine(start+xoffs, start-zoffs, color); drawLine(start-zoffs, start-xoffs, color); // YZ drawLine(start-yoffs, start+zoffs, color); drawLine(start+zoffs, start+yoffs, color); drawLine(start+yoffs, start-zoffs, color); drawLine(start-zoffs, start-yoffs, color); } virtual void drawSphere (const btVector3& p, btScalar radius, const btVector3& color) { btTransform tr; tr.setIdentity(); tr.setOrigin(p); drawSphere(radius,tr,color); } virtual void drawTriangle(const btVector3& v0,const btVector3& v1,const btVector3& v2,const btVector3& /*n0*/,const btVector3& /*n1*/,const btVector3& /*n2*/,const btVector3& color, btScalar alpha) { drawTriangle(v0,v1,v2,color,alpha); } virtual void drawTriangle(const btVector3& v0,const btVector3& v1,const btVector3& v2,const btVector3& color, btScalar /*alpha*/) { drawLine(v0,v1,color); drawLine(v1,v2,color); drawLine(v2,v0,color); } virtual void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color)=0; virtual void reportErrorWarning(const char* warningString) = 0; virtual void draw3dText(const btVector3& location,const char* textString) = 0; virtual void setDebugMode(int debugMode) =0; virtual int getDebugMode() const = 0; virtual void drawAabb(const btVector3& from,const btVector3& to,const btVector3& color) { btVector3 halfExtents = (to-from)* 0.5f; btVector3 center = (to+from) *0.5f; int i,j; btVector3 edgecoord(1.f,1.f,1.f),pa,pb; for (i=0;i<4;i++) { for (j=0;j<3;j++) { pa = btVector3(edgecoord[0]*halfExtents[0], edgecoord[1]*halfExtents[1], edgecoord[2]*halfExtents[2]); pa+=center; int othercoord = j%3; edgecoord[othercoord]*=-1.f; pb = btVector3(edgecoord[0]*halfExtents[0], edgecoord[1]*halfExtents[1], edgecoord[2]*halfExtents[2]); pb+=center; drawLine(pa,pb,color); } edgecoord = btVector3(-1.f,-1.f,-1.f); if (i<3) edgecoord[i]*=-1.f; } } virtual void drawTransform(const btTransform& transform, btScalar orthoLen) { btVector3 start = transform.getOrigin(); drawLine(start, start+transform.getBasis() * btVector3(orthoLen, 0, 0), btVector3(0.7f,0,0)); drawLine(start, start+transform.getBasis() * btVector3(0, orthoLen, 0), btVector3(0,0.7f,0)); drawLine(start, start+transform.getBasis() * btVector3(0, 0, orthoLen), btVector3(0,0,0.7f)); } virtual void drawArc(const btVector3& center, const btVector3& normal, const btVector3& axis, btScalar radiusA, btScalar radiusB, btScalar minAngle, btScalar maxAngle, const btVector3& color, bool drawSect, btScalar stepDegrees = btScalar(10.f)) { const btVector3& vx = axis; btVector3 vy = normal.cross(axis); btScalar step = stepDegrees * SIMD_RADS_PER_DEG; int nSteps = (int)((maxAngle - minAngle) / step); if(!nSteps) nSteps = 1; btVector3 prev = center + radiusA * vx * btCos(minAngle) + radiusB * vy * btSin(minAngle); if(drawSect) { drawLine(center, prev, color); } for(int i = 1; i <= nSteps; i++) { btScalar angle = minAngle + (maxAngle - minAngle) * btScalar(i) / btScalar(nSteps); btVector3 next = center + radiusA * vx * btCos(angle) + radiusB * vy * btSin(angle); drawLine(prev, next, color); prev = next; } if(drawSect) { drawLine(center, prev, color); } } virtual void drawSpherePatch(const btVector3& center, const btVector3& up, const btVector3& axis, btScalar radius, btScalar minTh, btScalar maxTh, btScalar minPs, btScalar maxPs, const btVector3& color, btScalar stepDegrees = btScalar(10.f)) { btVector3 vA[74]; btVector3 vB[74]; btVector3 *pvA = vA, *pvB = vB, *pT; btVector3 npole = center + up * radius; btVector3 spole = center - up * radius; btVector3 arcStart; btScalar step = stepDegrees * SIMD_RADS_PER_DEG; const btVector3& kv = up; const btVector3& iv = axis; btVector3 jv = kv.cross(iv); bool drawN = false; bool drawS = false; if(minTh <= -SIMD_HALF_PI) { minTh = -SIMD_HALF_PI + step; drawN = true; } if(maxTh >= SIMD_HALF_PI) { maxTh = SIMD_HALF_PI - step; drawS = true; } if(minTh > maxTh) { minTh = -SIMD_HALF_PI + step; maxTh = SIMD_HALF_PI - step; drawN = drawS = true; } int n_hor = (int)((maxTh - minTh) / step) + 1; if(n_hor < 2) n_hor = 2; btScalar step_h = (maxTh - minTh) / btScalar(n_hor - 1); bool isClosed = false; if(minPs > maxPs) { minPs = -SIMD_PI + step; maxPs = SIMD_PI; isClosed = true; } else if((maxPs - minPs) >= SIMD_PI * btScalar(2.f)) { isClosed = true; } else { isClosed = false; } int n_vert = (int)((maxPs - minPs) / step) + 1; if(n_vert < 2) n_vert = 2; btScalar step_v = (maxPs - minPs) / btScalar(n_vert - 1); for(int i = 0; i < n_hor; i++) { btScalar th = minTh + btScalar(i) * step_h; btScalar sth = radius * btSin(th); btScalar cth = radius * btCos(th); for(int j = 0; j < n_vert; j++) { btScalar psi = minPs + btScalar(j) * step_v; btScalar sps = btSin(psi); btScalar cps = btCos(psi); pvB[j] = center + cth * cps * iv + cth * sps * jv + sth * kv; if(i) { drawLine(pvA[j], pvB[j], color); } else if(drawS) { drawLine(spole, pvB[j], color); } if(j) { drawLine(pvB[j-1], pvB[j], color); } else { arcStart = pvB[j]; } if((i == (n_hor - 1)) && drawN) { drawLine(npole, pvB[j], color); } if(isClosed) { if(j == (n_vert-1)) { drawLine(arcStart, pvB[j], color); } } else { if(((!i) || (i == (n_hor-1))) && ((!j) || (j == (n_vert-1)))) { drawLine(center, pvB[j], color); } } } pT = pvA; pvA = pvB; pvB = pT; } } virtual void drawBox(const btVector3& bbMin, const btVector3& bbMax, const btVector3& color) { drawLine(btVector3(bbMin[0], bbMin[1], bbMin[2]), btVector3(bbMax[0], bbMin[1], bbMin[2]), color); drawLine(btVector3(bbMax[0], bbMin[1], bbMin[2]), btVector3(bbMax[0], bbMax[1], bbMin[2]), color); drawLine(btVector3(bbMax[0], bbMax[1], bbMin[2]), btVector3(bbMin[0], bbMax[1], bbMin[2]), color); drawLine(btVector3(bbMin[0], bbMax[1], bbMin[2]), btVector3(bbMin[0], bbMin[1], bbMin[2]), color); drawLine(btVector3(bbMin[0], bbMin[1], bbMin[2]), btVector3(bbMin[0], bbMin[1], bbMax[2]), color); drawLine(btVector3(bbMax[0], bbMin[1], bbMin[2]), btVector3(bbMax[0], bbMin[1], bbMax[2]), color); drawLine(btVector3(bbMax[0], bbMax[1], bbMin[2]), btVector3(bbMax[0], bbMax[1], bbMax[2]), color); drawLine(btVector3(bbMin[0], bbMax[1], bbMin[2]), btVector3(bbMin[0], bbMax[1], bbMax[2]), color); drawLine(btVector3(bbMin[0], bbMin[1], bbMax[2]), btVector3(bbMax[0], bbMin[1], bbMax[2]), color); drawLine(btVector3(bbMax[0], bbMin[1], bbMax[2]), btVector3(bbMax[0], bbMax[1], bbMax[2]), color); drawLine(btVector3(bbMax[0], bbMax[1], bbMax[2]), btVector3(bbMin[0], bbMax[1], bbMax[2]), color); drawLine(btVector3(bbMin[0], bbMax[1], bbMax[2]), btVector3(bbMin[0], bbMin[1], bbMax[2]), color); } virtual void drawBox(const btVector3& bbMin, const btVector3& bbMax, const btTransform& trans, const btVector3& color) { drawLine(trans * btVector3(bbMin[0], bbMin[1], bbMin[2]), trans * btVector3(bbMax[0], bbMin[1], bbMin[2]), color); drawLine(trans * btVector3(bbMax[0], bbMin[1], bbMin[2]), trans * btVector3(bbMax[0], bbMax[1], bbMin[2]), color); drawLine(trans * btVector3(bbMax[0], bbMax[1], bbMin[2]), trans * btVector3(bbMin[0], bbMax[1], bbMin[2]), color); drawLine(trans * btVector3(bbMin[0], bbMax[1], bbMin[2]), trans * btVector3(bbMin[0], bbMin[1], bbMin[2]), color); drawLine(trans * btVector3(bbMin[0], bbMin[1], bbMin[2]), trans * btVector3(bbMin[0], bbMin[1], bbMax[2]), color); drawLine(trans * btVector3(bbMax[0], bbMin[1], bbMin[2]), trans * btVector3(bbMax[0], bbMin[1], bbMax[2]), color); drawLine(trans * btVector3(bbMax[0], bbMax[1], bbMin[2]), trans * btVector3(bbMax[0], bbMax[1], bbMax[2]), color); drawLine(trans * btVector3(bbMin[0], bbMax[1], bbMin[2]), trans * btVector3(bbMin[0], bbMax[1], bbMax[2]), color); drawLine(trans * btVector3(bbMin[0], bbMin[1], bbMax[2]), trans * btVector3(bbMax[0], bbMin[1], bbMax[2]), color); drawLine(trans * btVector3(bbMax[0], bbMin[1], bbMax[2]), trans * btVector3(bbMax[0], bbMax[1], bbMax[2]), color); drawLine(trans * btVector3(bbMax[0], bbMax[1], bbMax[2]), trans * btVector3(bbMin[0], bbMax[1], bbMax[2]), color); drawLine(trans * btVector3(bbMin[0], bbMax[1], bbMax[2]), trans * btVector3(bbMin[0], bbMin[1], bbMax[2]), color); } }; #endif //IDEBUG_DRAW__H critterding-beta12.1/src/utils/bullet/LinearMath/btMinMax.h0000644000175000017500000000323311337071441022671 0ustar bobkebobke/* Copyright (c) 2003-2006 Gino van den Bergen / Erwin Coumans http://continuousphysics.com/Bullet/ 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 GEN_MINMAX_H #define GEN_MINMAX_H template SIMD_FORCE_INLINE const T& btMin(const T& a, const T& b) { return a < b ? a : b ; } template SIMD_FORCE_INLINE const T& btMax(const T& a, const T& b) { return a > b ? a : b; } template SIMD_FORCE_INLINE const T& GEN_clamped(const T& a, const T& lb, const T& ub) { return a < lb ? lb : (ub < a ? ub : a); } template SIMD_FORCE_INLINE void btSetMin(T& a, const T& b) { if (b < a) { a = b; } } template SIMD_FORCE_INLINE void btSetMax(T& a, const T& b) { if (a < b) { a = b; } } template SIMD_FORCE_INLINE void GEN_clamp(T& a, const T& lb, const T& ub) { if (a < lb) { a = lb; } else if (ub < a) { a = ub; } } #endif critterding-beta12.1/src/utils/bullet/MiniCL/0000755000175000017500000000000011347266042020073 5ustar bobkebobkecritterding-beta12.1/src/utils/bullet/MiniCL/cl.h0000644000175000017500000012271311337073015020643 0ustar bobkebobke/******************************************************************************* * Copyright (c) 2008-2009 The Khronos Group Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and/or associated documentation files (the * "Materials"), to deal in the Materials without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Materials, and to * permit persons to whom the Materials are 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 Materials. * * THE MATERIALS ARE 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 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. ******************************************************************************/ #ifndef __OPENCL_CL_H #define __OPENCL_CL_H #ifdef __APPLE__ #include #else #include #endif #ifdef __cplusplus extern "C" { #endif /******************************************************************************/ typedef struct _cl_platform_id * cl_platform_id; typedef struct _cl_device_id * cl_device_id; typedef struct _cl_context * cl_context; typedef struct _cl_command_queue * cl_command_queue; typedef struct _cl_mem * cl_mem; typedef struct _cl_program * cl_program; typedef struct _cl_kernel * cl_kernel; typedef struct _cl_event * cl_event; typedef struct _cl_sampler * cl_sampler; typedef cl_uint cl_bool; /* WARNING! Unlike cl_ types in cl_platform.h, cl_bool is not guaranteed to be the same size as the bool in kernels. */ typedef cl_ulong cl_bitfield; typedef cl_bitfield cl_device_type; typedef cl_uint cl_platform_info; typedef cl_uint cl_device_info; typedef cl_bitfield cl_device_address_info; typedef cl_bitfield cl_device_fp_config; typedef cl_uint cl_device_mem_cache_type; typedef cl_uint cl_device_local_mem_type; typedef cl_bitfield cl_device_exec_capabilities; typedef cl_bitfield cl_command_queue_properties; typedef intptr_t cl_context_properties; typedef cl_uint cl_context_info; typedef cl_uint cl_command_queue_info; typedef cl_uint cl_channel_order; typedef cl_uint cl_channel_type; typedef cl_bitfield cl_mem_flags; typedef cl_uint cl_mem_object_type; typedef cl_uint cl_mem_info; typedef cl_uint cl_image_info; typedef cl_uint cl_addressing_mode; typedef cl_uint cl_filter_mode; typedef cl_uint cl_sampler_info; typedef cl_bitfield cl_map_flags; typedef cl_uint cl_program_info; typedef cl_uint cl_program_build_info; typedef cl_int cl_build_status; typedef cl_uint cl_kernel_info; typedef cl_uint cl_kernel_work_group_info; typedef cl_uint cl_event_info; typedef cl_uint cl_command_type; typedef cl_uint cl_profiling_info; typedef struct _cl_image_format { cl_channel_order image_channel_order; cl_channel_type image_channel_data_type; } cl_image_format; /******************************************************************************/ // Error Codes #define CL_SUCCESS 0 #define CL_DEVICE_NOT_FOUND -1 #define CL_DEVICE_NOT_AVAILABLE -2 #define CL_DEVICE_COMPILER_NOT_AVAILABLE -3 #define CL_MEM_OBJECT_ALLOCATION_FAILURE -4 #define CL_OUT_OF_RESOURCES -5 #define CL_OUT_OF_HOST_MEMORY -6 #define CL_PROFILING_INFO_NOT_AVAILABLE -7 #define CL_MEM_COPY_OVERLAP -8 #define CL_IMAGE_FORMAT_MISMATCH -9 #define CL_IMAGE_FORMAT_NOT_SUPPORTED -10 #define CL_BUILD_PROGRAM_FAILURE -11 #define CL_MAP_FAILURE -12 #define CL_INVALID_VALUE -30 #define CL_INVALID_DEVICE_TYPE -31 #define CL_INVALID_PLATFORM -32 #define CL_INVALID_DEVICE -33 #define CL_INVALID_CONTEXT -34 #define CL_INVALID_QUEUE_PROPERTIES -35 #define CL_INVALID_COMMAND_QUEUE -36 #define CL_INVALID_HOST_PTR -37 #define CL_INVALID_MEM_OBJECT -38 #define CL_INVALID_IMAGE_FORMAT_DESCRIPTOR -39 #define CL_INVALID_IMAGE_SIZE -40 #define CL_INVALID_SAMPLER -41 #define CL_INVALID_BINARY -42 #define CL_INVALID_BUILD_OPTIONS -43 #define CL_INVALID_PROGRAM -44 #define CL_INVALID_PROGRAM_EXECUTABLE -45 #define CL_INVALID_KERNEL_NAME -46 #define CL_INVALID_KERNEL_DEFINITION -47 #define CL_INVALID_KERNEL -48 #define CL_INVALID_ARG_INDEX -49 #define CL_INVALID_ARG_VALUE -50 #define CL_INVALID_ARG_SIZE -51 #define CL_INVALID_KERNEL_ARGS -52 #define CL_INVALID_WORK_DIMENSION -53 #define CL_INVALID_WORK_GROUP_SIZE -54 #define CL_INVALID_WORK_ITEM_SIZE -55 #define CL_INVALID_GLOBAL_OFFSET -56 #define CL_INVALID_EVENT_WAIT_LIST -57 #define CL_INVALID_EVENT -58 #define CL_INVALID_OPERATION -59 #define CL_INVALID_GL_OBJECT -60 #define CL_INVALID_BUFFER_SIZE -61 #define CL_INVALID_MIP_LEVEL -62 // OpenCL Version #define CL_VERSION_1_0 1 // cl_bool #define CL_FALSE 0 #define CL_TRUE 1 // cl_platform_info #define CL_PLATFORM_PROFILE 0x0900 #define CL_PLATFORM_VERSION 0x0901 #define CL_PLATFORM_NAME 0x0902 #define CL_PLATFORM_VENDOR 0x0903 #define CL_PLATFORM_EXTENSIONS 0x0904 // cl_device_type - bitfield #define CL_DEVICE_TYPE_DEFAULT (1 << 0) #define CL_DEVICE_TYPE_CPU (1 << 1) #define CL_DEVICE_TYPE_GPU (1 << 2) #define CL_DEVICE_TYPE_ACCELERATOR (1 << 3) #define CL_DEVICE_TYPE_ALL 0xFFFFFFFF // cl_device_info #define CL_DEVICE_TYPE 0x1000 #define CL_DEVICE_VENDOR_ID 0x1001 #define CL_DEVICE_MAX_COMPUTE_UNITS 0x1002 #define CL_DEVICE_MAX_WORK_ITEM_DIMENSIONS 0x1003 #define CL_DEVICE_MAX_WORK_GROUP_SIZE 0x1004 #define CL_DEVICE_MAX_WORK_ITEM_SIZES 0x1005 #define CL_DEVICE_PREFERRED_VECTOR_WIDTH_CHAR 0x1006 #define CL_DEVICE_PREFERRED_VECTOR_WIDTH_SHORT 0x1007 #define CL_DEVICE_PREFERRED_VECTOR_WIDTH_INT 0x1008 #define CL_DEVICE_PREFERRED_VECTOR_WIDTH_LONG 0x1009 #define CL_DEVICE_PREFERRED_VECTOR_WIDTH_FLOAT 0x100A #define CL_DEVICE_PREFERRED_VECTOR_WIDTH_DOUBLE 0x100B #define CL_DEVICE_MAX_CLOCK_FREQUENCY 0x100C #define CL_DEVICE_ADDRESS_BITS 0x100D #define CL_DEVICE_MAX_READ_IMAGE_ARGS 0x100E #define CL_DEVICE_MAX_WRITE_IMAGE_ARGS 0x100F #define CL_DEVICE_MAX_MEM_ALLOC_SIZE 0x1010 #define CL_DEVICE_IMAGE2D_MAX_WIDTH 0x1011 #define CL_DEVICE_IMAGE2D_MAX_HEIGHT 0x1012 #define CL_DEVICE_IMAGE3D_MAX_WIDTH 0x1013 #define CL_DEVICE_IMAGE3D_MAX_HEIGHT 0x1014 #define CL_DEVICE_IMAGE3D_MAX_DEPTH 0x1015 #define CL_DEVICE_IMAGE_SUPPORT 0x1016 #define CL_DEVICE_MAX_PARAMETER_SIZE 0x1017 #define CL_DEVICE_MAX_SAMPLERS 0x1018 #define CL_DEVICE_MEM_BASE_ADDR_ALIGN 0x1019 #define CL_DEVICE_MIN_DATA_TYPE_ALIGN_SIZE 0x101A #define CL_DEVICE_SINGLE_FP_CONFIG 0x101B #define CL_DEVICE_GLOBAL_MEM_CACHE_TYPE 0x101C #define CL_DEVICE_GLOBAL_MEM_CACHELINE_SIZE 0x101D #define CL_DEVICE_GLOBAL_MEM_CACHE_SIZE 0x101E #define CL_DEVICE_GLOBAL_MEM_SIZE 0x101F #define CL_DEVICE_MAX_CONSTANT_BUFFER_SIZE 0x1020 #define CL_DEVICE_MAX_CONSTANT_ARGS 0x1021 #define CL_DEVICE_LOCAL_MEM_TYPE 0x1022 #define CL_DEVICE_LOCAL_MEM_SIZE 0x1023 #define CL_DEVICE_ERROR_CORRECTION_SUPPORT 0x1024 #define CL_DEVICE_PROFILING_TIMER_RESOLUTION 0x1025 #define CL_DEVICE_ENDIAN_LITTLE 0x1026 #define CL_DEVICE_AVAILABLE 0x1027 #define CL_DEVICE_COMPILER_AVAILABLE 0x1028 #define CL_DEVICE_EXECUTION_CAPABILITIES 0x1029 #define CL_DEVICE_QUEUE_PROPERTIES 0x102A #define CL_DEVICE_NAME 0x102B #define CL_DEVICE_VENDOR 0x102C #define CL_DRIVER_VERSION 0x102D #define CL_DEVICE_PROFILE 0x102E #define CL_DEVICE_VERSION 0x102F #define CL_DEVICE_EXTENSIONS 0x1030 #define CL_DEVICE_PLATFORM 0x1031 // cl_device_address_info - bitfield #define CL_DEVICE_ADDRESS_32_BITS (1 << 0) #define CL_DEVICE_ADDRESS_64_BITS (1 << 1) // cl_device_fp_config - bitfield #define CL_FP_DENORM (1 << 0) #define CL_FP_INF_NAN (1 << 1) #define CL_FP_ROUND_TO_NEAREST (1 << 2) #define CL_FP_ROUND_TO_ZERO (1 << 3) #define CL_FP_ROUND_TO_INF (1 << 4) #define CL_FP_FMA (1 << 5) // cl_device_mem_cache_type #define CL_NONE 0x0 #define CL_READ_ONLY_CACHE 0x1 #define CL_READ_WRITE_CACHE 0x2 // cl_device_local_mem_type #define CL_LOCAL 0x1 #define CL_GLOBAL 0x2 // cl_device_exec_capabilities - bitfield #define CL_EXEC_KERNEL (1 << 0) #define CL_EXEC_NATIVE_KERNEL (1 << 1) // cl_command_queue_properties - bitfield #define CL_QUEUE_OUT_OF_ORDER_EXEC_MODE_ENABLE (1 << 0) #define CL_QUEUE_PROFILING_ENABLE (1 << 1) // cl_context_info #define CL_CONTEXT_REFERENCE_COUNT 0x1080 #define CL_CONTEXT_NUM_DEVICES 0x1081 #define CL_CONTEXT_DEVICES 0x1082 #define CL_CONTEXT_PROPERTIES 0x1083 #define CL_CONTEXT_PLATFORM 0x1084 // cl_command_queue_info #define CL_QUEUE_CONTEXT 0x1090 #define CL_QUEUE_DEVICE 0x1091 #define CL_QUEUE_REFERENCE_COUNT 0x1092 #define CL_QUEUE_PROPERTIES 0x1093 // cl_mem_flags - bitfield #define CL_MEM_READ_WRITE (1 << 0) #define CL_MEM_WRITE_ONLY (1 << 1) #define CL_MEM_READ_ONLY (1 << 2) #define CL_MEM_USE_HOST_PTR (1 << 3) #define CL_MEM_ALLOC_HOST_PTR (1 << 4) #define CL_MEM_COPY_HOST_PTR (1 << 5) // cl_channel_order #define CL_R 0x10B0 #define CL_A 0x10B1 #define CL_RG 0x10B2 #define CL_RA 0x10B3 #define CL_RGB 0x10B4 #define CL_RGBA 0x10B5 #define CL_BGRA 0x10B6 #define CL_ARGB 0x10B7 #define CL_INTENSITY 0x10B8 #define CL_LUMINANCE 0x10B9 // cl_channel_type #define CL_SNORM_INT8 0x10D0 #define CL_SNORM_INT16 0x10D1 #define CL_UNORM_INT8 0x10D2 #define CL_UNORM_INT16 0x10D3 #define CL_UNORM_SHORT_565 0x10D4 #define CL_UNORM_SHORT_555 0x10D5 #define CL_UNORM_INT_101010 0x10D6 #define CL_SIGNED_INT8 0x10D7 #define CL_SIGNED_INT16 0x10D8 #define CL_SIGNED_INT32 0x10D9 #define CL_UNSIGNED_INT8 0x10DA #define CL_UNSIGNED_INT16 0x10DB #define CL_UNSIGNED_INT32 0x10DC #define CL_HALF_FLOAT 0x10DD #define CL_FLOAT 0x10DE // cl_mem_object_type #define CL_MEM_OBJECT_BUFFER 0x10F0 #define CL_MEM_OBJECT_IMAGE2D 0x10F1 #define CL_MEM_OBJECT_IMAGE3D 0x10F2 // cl_mem_info #define CL_MEM_TYPE 0x1100 #define CL_MEM_FLAGS 0x1101 #define CL_MEM_SIZE 0x1102 #define CL_MEM_HOST_PTR 0x1103 #define CL_MEM_MAP_COUNT 0x1104 #define CL_MEM_REFERENCE_COUNT 0x1105 #define CL_MEM_CONTEXT 0x1106 // cl_image_info #define CL_IMAGE_FORMAT 0x1110 #define CL_IMAGE_ELEMENT_SIZE 0x1111 #define CL_IMAGE_ROW_PITCH 0x1112 #define CL_IMAGE_SLICE_PITCH 0x1113 #define CL_IMAGE_WIDTH 0x1114 #define CL_IMAGE_HEIGHT 0x1115 #define CL_IMAGE_DEPTH 0x1116 // cl_addressing_mode #define CL_ADDRESS_NONE 0x1130 #define CL_ADDRESS_CLAMP_TO_EDGE 0x1131 #define CL_ADDRESS_CLAMP 0x1132 #define CL_ADDRESS_REPEAT 0x1133 // cl_filter_mode #define CL_FILTER_NEAREST 0x1140 #define CL_FILTER_LINEAR 0x1141 // cl_sampler_info #define CL_SAMPLER_REFERENCE_COUNT 0x1150 #define CL_SAMPLER_CONTEXT 0x1151 #define CL_SAMPLER_NORMALIZED_COORDS 0x1152 #define CL_SAMPLER_ADDRESSING_MODE 0x1153 #define CL_SAMPLER_FILTER_MODE 0x1154 // cl_map_flags - bitfield #define CL_MAP_READ (1 << 0) #define CL_MAP_WRITE (1 << 1) // cl_program_info #define CL_PROGRAM_REFERENCE_COUNT 0x1160 #define CL_PROGRAM_CONTEXT 0x1161 #define CL_PROGRAM_NUM_DEVICES 0x1162 #define CL_PROGRAM_DEVICES 0x1163 #define CL_PROGRAM_SOURCE 0x1164 #define CL_PROGRAM_BINARY_SIZES 0x1165 #define CL_PROGRAM_BINARIES 0x1166 // cl_program_build_info #define CL_PROGRAM_BUILD_STATUS 0x1181 #define CL_PROGRAM_BUILD_OPTIONS 0x1182 #define CL_PROGRAM_BUILD_LOG 0x1183 // cl_build_status #define CL_BUILD_SUCCESS 0 #define CL_BUILD_NONE -1 #define CL_BUILD_ERROR -2 #define CL_BUILD_IN_PROGRESS -3 // cl_kernel_info #define CL_KERNEL_FUNCTION_NAME 0x1190 #define CL_KERNEL_NUM_ARGS 0x1191 #define CL_KERNEL_REFERENCE_COUNT 0x1192 #define CL_KERNEL_CONTEXT 0x1193 #define CL_KERNEL_PROGRAM 0x1194 // cl_kernel_work_group_info #define CL_KERNEL_WORK_GROUP_SIZE 0x11B0 #define CL_KERNEL_COMPILE_WORK_GROUP_SIZE 0x11B1 #define CL_KERNEL_LOCAL_MEM_SIZE 0x11B2 // cl_event_info #define CL_EVENT_COMMAND_QUEUE 0x11D0 #define CL_EVENT_COMMAND_TYPE 0x11D1 #define CL_EVENT_REFERENCE_COUNT 0x11D2 #define CL_EVENT_COMMAND_EXECUTION_STATUS 0x11D3 // cl_command_type #define CL_COMMAND_NDRANGE_KERNEL 0x11F0 #define CL_COMMAND_TASK 0x11F1 #define CL_COMMAND_NATIVE_KERNEL 0x11F2 #define CL_COMMAND_READ_BUFFER 0x11F3 #define CL_COMMAND_WRITE_BUFFER 0x11F4 #define CL_COMMAND_COPY_BUFFER 0x11F5 #define CL_COMMAND_READ_IMAGE 0x11F6 #define CL_COMMAND_WRITE_IMAGE 0x11F7 #define CL_COMMAND_COPY_IMAGE 0x11F8 #define CL_COMMAND_COPY_IMAGE_TO_BUFFER 0x11F9 #define CL_COMMAND_COPY_BUFFER_TO_IMAGE 0x11FA #define CL_COMMAND_MAP_BUFFER 0x11FB #define CL_COMMAND_MAP_IMAGE 0x11FC #define CL_COMMAND_UNMAP_MEM_OBJECT 0x11FD #define CL_COMMAND_MARKER 0x11FE #define CL_COMMAND_WAIT_FOR_EVENTS 0x11FF #define CL_COMMAND_BARRIER 0x1200 #define CL_COMMAND_ACQUIRE_GL_OBJECTS 0x1201 #define CL_COMMAND_RELEASE_GL_OBJECTS 0x1202 // command execution status #define CL_COMPLETE 0x0 #define CL_RUNNING 0x1 #define CL_SUBMITTED 0x2 #define CL_QUEUED 0x3 // cl_profiling_info #define CL_PROFILING_COMMAND_QUEUED 0x1280 #define CL_PROFILING_COMMAND_SUBMIT 0x1281 #define CL_PROFILING_COMMAND_START 0x1282 #define CL_PROFILING_COMMAND_END 0x1283 /********************************************************************************************************/ // Platform API extern CL_API_ENTRY cl_int CL_API_CALL clGetPlatformIDs(cl_uint /* num_entries */, cl_platform_id * /* platforms */, cl_uint * /* num_platforms */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clGetPlatformInfo(cl_platform_id /* platform */, cl_platform_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; // Device APIs extern CL_API_ENTRY cl_int CL_API_CALL clGetDeviceIDs(cl_platform_id /* platform */, cl_device_type /* device_type */, cl_uint /* num_entries */, cl_device_id * /* devices */, cl_uint * /* num_devices */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clGetDeviceInfo(cl_device_id /* device */, cl_device_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; // Context APIs extern CL_API_ENTRY cl_context CL_API_CALL clCreateContext(cl_context_properties * /* properties */, cl_uint /* num_devices */, const cl_device_id * /* devices */, void (*pfn_notify)(const char *, const void *, size_t, void *) /* pfn_notify */, void * /* user_data */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_context CL_API_CALL clCreateContextFromType(cl_context_properties * /* properties */, cl_device_type /* device_type */, void (*pfn_notify)(const char *, const void *, size_t, void *) /* pfn_notify */, void * /* user_data */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clRetainContext(cl_context /* context */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clReleaseContext(cl_context /* context */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clGetContextInfo(cl_context /* context */, cl_context_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; // Command Queue APIs extern CL_API_ENTRY cl_command_queue CL_API_CALL clCreateCommandQueue(cl_context /* context */, cl_device_id /* device */, cl_command_queue_properties /* properties */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clRetainCommandQueue(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clReleaseCommandQueue(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clGetCommandQueueInfo(cl_command_queue /* command_queue */, cl_command_queue_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clSetCommandQueueProperty(cl_command_queue /* command_queue */, cl_command_queue_properties /* properties */, cl_bool /* enable */, cl_command_queue_properties * /* old_properties */) CL_API_SUFFIX__VERSION_1_0; // Memory Object APIs extern CL_API_ENTRY cl_mem CL_API_CALL clCreateBuffer(cl_context /* context */, cl_mem_flags /* flags */, size_t /* size */, void * /* host_ptr */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_mem CL_API_CALL clCreateImage2D(cl_context /* context */, cl_mem_flags /* flags */, const cl_image_format * /* image_format */, size_t /* image_width */, size_t /* image_height */, size_t /* image_row_pitch */, void * /* host_ptr */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_mem CL_API_CALL clCreateImage3D(cl_context /* context */, cl_mem_flags /* flags */, const cl_image_format * /* image_format */, size_t /* image_width */, size_t /* image_height */, size_t /* image_depth */, size_t /* image_row_pitch */, size_t /* image_slice_pitch */, void * /* host_ptr */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clRetainMemObject(cl_mem /* memobj */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clReleaseMemObject(cl_mem /* memobj */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clGetSupportedImageFormats(cl_context /* context */, cl_mem_flags /* flags */, cl_mem_object_type /* image_type */, cl_uint /* num_entries */, cl_image_format * /* image_formats */, cl_uint * /* num_image_formats */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clGetMemObjectInfo(cl_mem /* memobj */, cl_mem_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clGetImageInfo(cl_mem /* image */, cl_image_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; // Sampler APIs extern CL_API_ENTRY cl_sampler CL_API_CALL clCreateSampler(cl_context /* context */, cl_bool /* normalized_coords */, cl_addressing_mode /* addressing_mode */, cl_filter_mode /* filter_mode */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clRetainSampler(cl_sampler /* sampler */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clReleaseSampler(cl_sampler /* sampler */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clGetSamplerInfo(cl_sampler /* sampler */, cl_sampler_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; // Program Object APIs extern CL_API_ENTRY cl_program CL_API_CALL clCreateProgramWithSource(cl_context /* context */, cl_uint /* count */, const char ** /* strings */, const size_t * /* lengths */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_program CL_API_CALL clCreateProgramWithBinary(cl_context /* context */, cl_uint /* num_devices */, const cl_device_id * /* device_list */, const size_t * /* lengths */, const unsigned char ** /* binaries */, cl_int * /* binary_status */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clRetainProgram(cl_program /* program */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clReleaseProgram(cl_program /* program */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clBuildProgram(cl_program /* program */, cl_uint /* num_devices */, const cl_device_id * /* device_list */, const char * /* options */, void (*pfn_notify)(cl_program /* program */, void * /* user_data */), void * /* user_data */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clUnloadCompiler(void) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clGetProgramInfo(cl_program /* program */, cl_program_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clGetProgramBuildInfo(cl_program /* program */, cl_device_id /* device */, cl_program_build_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; // Kernel Object APIs extern CL_API_ENTRY cl_kernel CL_API_CALL clCreateKernel(cl_program /* program */, const char * /* kernel_name */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clCreateKernelsInProgram(cl_program /* program */, cl_uint /* num_kernels */, cl_kernel * /* kernels */, cl_uint * /* num_kernels_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clRetainKernel(cl_kernel /* kernel */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clReleaseKernel(cl_kernel /* kernel */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clSetKernelArg(cl_kernel /* kernel */, cl_uint /* arg_index */, size_t /* arg_size */, const void * /* arg_value */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clGetKernelInfo(cl_kernel /* kernel */, cl_kernel_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clGetKernelWorkGroupInfo(cl_kernel /* kernel */, cl_device_id /* device */, cl_kernel_work_group_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; // Event Object APIs extern CL_API_ENTRY cl_int CL_API_CALL clWaitForEvents(cl_uint /* num_events */, const cl_event * /* event_list */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clGetEventInfo(cl_event /* event */, cl_event_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clRetainEvent(cl_event /* event */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clReleaseEvent(cl_event /* event */) CL_API_SUFFIX__VERSION_1_0; // Profiling APIs extern CL_API_ENTRY cl_int CL_API_CALL clGetEventProfilingInfo(cl_event /* event */, cl_profiling_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; // Flush and Finish APIs extern CL_API_ENTRY cl_int CL_API_CALL clFlush(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clFinish(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; // Enqueued Commands APIs extern CL_API_ENTRY cl_int CL_API_CALL clEnqueueReadBuffer(cl_command_queue /* command_queue */, cl_mem /* buffer */, cl_bool /* blocking_read */, size_t /* offset */, size_t /* cb */, void * /* ptr */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clEnqueueWriteBuffer(cl_command_queue /* command_queue */, cl_mem /* buffer */, cl_bool /* blocking_write */, size_t /* offset */, size_t /* cb */, const void * /* ptr */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clEnqueueCopyBuffer(cl_command_queue /* command_queue */, cl_mem /* src_buffer */, cl_mem /* dst_buffer */, size_t /* src_offset */, size_t /* dst_offset */, size_t /* cb */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clEnqueueReadImage(cl_command_queue /* command_queue */, cl_mem /* image */, cl_bool /* blocking_read */, const size_t * /* origin[3] */, const size_t * /* region[3] */, size_t /* row_pitch */, size_t /* slice_pitch */, void * /* ptr */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clEnqueueWriteImage(cl_command_queue /* command_queue */, cl_mem /* image */, cl_bool /* blocking_write */, const size_t * /* origin[3] */, const size_t * /* region[3] */, size_t /* input_row_pitch */, size_t /* input_slice_pitch */, const void * /* ptr */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clEnqueueCopyImage(cl_command_queue /* command_queue */, cl_mem /* src_image */, cl_mem /* dst_image */, const size_t * /* src_origin[3] */, const size_t * /* dst_origin[3] */, const size_t * /* region[3] */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clEnqueueCopyImageToBuffer(cl_command_queue /* command_queue */, cl_mem /* src_image */, cl_mem /* dst_buffer */, const size_t * /* src_origin[3] */, const size_t * /* region[3] */, size_t /* dst_offset */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clEnqueueCopyBufferToImage(cl_command_queue /* command_queue */, cl_mem /* src_buffer */, cl_mem /* dst_image */, size_t /* src_offset */, const size_t * /* dst_origin[3] */, const size_t * /* region[3] */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY void * CL_API_CALL clEnqueueMapBuffer(cl_command_queue /* command_queue */, cl_mem /* buffer */, cl_bool /* blocking_map */, cl_map_flags /* map_flags */, size_t /* offset */, size_t /* cb */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY void * CL_API_CALL clEnqueueMapImage(cl_command_queue /* command_queue */, cl_mem /* image */, cl_bool /* blocking_map */, cl_map_flags /* map_flags */, const size_t * /* origin[3] */, const size_t * /* region[3] */, size_t * /* image_row_pitch */, size_t * /* image_slice_pitch */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clEnqueueUnmapMemObject(cl_command_queue /* command_queue */, cl_mem /* memobj */, void * /* mapped_ptr */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clEnqueueNDRangeKernel(cl_command_queue /* command_queue */, cl_kernel /* kernel */, cl_uint /* work_dim */, const size_t * /* global_work_offset */, const size_t * /* global_work_size */, const size_t * /* local_work_size */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clEnqueueTask(cl_command_queue /* command_queue */, cl_kernel /* kernel */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clEnqueueNativeKernel(cl_command_queue /* command_queue */, void (*user_func)(void *), void * /* args */, size_t /* cb_args */, cl_uint /* num_mem_objects */, const cl_mem * /* mem_list */, const void ** /* args_mem_loc */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clEnqueueMarker(cl_command_queue /* command_queue */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clEnqueueWaitForEvents(cl_command_queue /* command_queue */, cl_uint /* num_events */, const cl_event * /* event_list */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clEnqueueBarrier(cl_command_queue /* command_queue */) CL_API_SUFFIX__VERSION_1_0; #ifdef __cplusplus } #endif #endif // __OPENCL_CL_H critterding-beta12.1/src/utils/bullet/MiniCL/cl_platform.h0000644000175000017500000002340111337073015022541 0ustar bobkebobke/********************************************************************************** * Copyright (c) 2008-2009 The Khronos Group Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and/or associated documentation files (the * "Materials"), to deal in the Materials without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Materials, and to * permit persons to whom the Materials are 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 Materials. * * THE MATERIALS ARE 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 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. **********************************************************************************/ #ifndef __CL_PLATFORM_H #define __CL_PLATFORM_H #ifdef __APPLE__ /* Contains #defines for AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER below */ #include #endif #ifdef __cplusplus extern "C" { #endif #define CL_API_ENTRY #define CL_API_CALL #ifdef __APPLE__ #define CL_API_SUFFIX__VERSION_1_0 // AVAILABLE_MAC_OS_X_VERSION_10_6_AND_LATER #define CL_EXTENSION_WEAK_LINK __attribute__((weak_import)) #else #define CL_API_SUFFIX__VERSION_1_0 #define CL_EXTENSION_WEAK_LINK #endif #ifdef WIN32 typedef signed __int8 int8_t; typedef unsigned __int8 uint8_t; typedef signed __int16 int16_t; typedef unsigned __int16 uint16_t; typedef signed __int32 int32_t; typedef unsigned __int32 uint32_t; typedef signed __int64 int64_t; typedef unsigned __int64 uint64_t; typedef int8_t cl_char; typedef uint8_t cl_uchar; typedef int16_t cl_short ; typedef uint16_t cl_ushort ; typedef int32_t cl_int ; typedef uint32_t cl_uint ; typedef int64_t cl_long ; typedef uint64_t cl_ulong ; typedef uint16_t cl_half ; typedef float cl_float ; typedef double cl_double ; typedef int8_t cl_char2[2] ; typedef int8_t cl_char4[4] ; typedef int8_t cl_char8[8] ; typedef int8_t cl_char16[16] ; typedef uint8_t cl_uchar2[2] ; typedef uint8_t cl_uchar4[4] ; typedef uint8_t cl_uchar8[8] ; typedef uint8_t cl_uchar16[16] ; typedef int16_t cl_short2[2] ; typedef int16_t cl_short4[4] ; typedef int16_t cl_short8[8] ; typedef int16_t cl_short16[16] ; typedef uint16_t cl_ushort2[2] ; typedef uint16_t cl_ushort4[4] ; typedef uint16_t cl_ushort8[8] ; typedef uint16_t cl_ushort16[16] ; typedef int32_t cl_int2[2] ; typedef int32_t cl_int4[4] ; typedef int32_t cl_int8[8] ; typedef int32_t cl_int16[16] ; typedef uint32_t cl_uint2[2] ; typedef uint32_t cl_uint4[4] ; typedef uint32_t cl_uint8[8] ; typedef uint32_t cl_uint16[16] ; typedef int64_t cl_long2[2] ; typedef int64_t cl_long4[4] ; typedef int64_t cl_long8[8] ; typedef int64_t cl_long16[16] ; typedef uint64_t cl_ulong2[2] ; typedef uint64_t cl_ulong4[4] ; typedef uint64_t cl_ulong8[8] ; typedef uint64_t cl_ulong16[16] ; typedef float cl_float2[2] ; typedef float cl_float4[4] ; typedef float cl_float8[8] ; typedef float cl_float16[16] ; typedef double cl_double2[2] ; typedef double cl_double4[4] ; typedef double cl_double8[8] ; typedef double cl_double16[16] ; #else #include /* scalar types */ typedef int8_t cl_char; typedef uint8_t cl_uchar; typedef int16_t cl_short __attribute__((aligned(2))); typedef uint16_t cl_ushort __attribute__((aligned(2))); typedef int32_t cl_int __attribute__((aligned(4))); typedef uint32_t cl_uint __attribute__((aligned(4))); typedef int64_t cl_long __attribute__((aligned(8))); typedef uint64_t cl_ulong __attribute__((aligned(8))); typedef uint16_t cl_half __attribute__((aligned(2))); typedef float cl_float __attribute__((aligned(4))); typedef double cl_double __attribute__((aligned(8))); /* * Vector types * * Note: OpenCL requires that all types be naturally aligned. * This means that vector types must be naturally aligned. * For example, a vector of four floats must be aligned to * a 16 byte boundary (calculated as 4 * the natural 4-byte * alignment of the float). The alignment qualifiers here * will only function properly if your compiler supports them * and if you don't actively work to defeat them. For example, * in order for a cl_float4 to be 16 byte aligned in a struct, * the start of the struct must itself be 16-byte aligned. * * Maintaining proper alignment is the user's responsibility. */ typedef int8_t cl_char2[2] __attribute__((aligned(2))); typedef int8_t cl_char4[4] __attribute__((aligned(4))); typedef int8_t cl_char8[8] __attribute__((aligned(8))); typedef int8_t cl_char16[16] __attribute__((aligned(16))); typedef uint8_t cl_uchar2[2] __attribute__((aligned(2))); typedef uint8_t cl_uchar4[4] __attribute__((aligned(4))); typedef uint8_t cl_uchar8[8] __attribute__((aligned(8))); typedef uint8_t cl_uchar16[16] __attribute__((aligned(16))); typedef int16_t cl_short2[2] __attribute__((aligned(4))); typedef int16_t cl_short4[4] __attribute__((aligned(8))); typedef int16_t cl_short8[8] __attribute__((aligned(16))); typedef int16_t cl_short16[16] __attribute__((aligned(32))); typedef uint16_t cl_ushort2[2] __attribute__((aligned(4))); typedef uint16_t cl_ushort4[4] __attribute__((aligned(8))); typedef uint16_t cl_ushort8[8] __attribute__((aligned(16))); typedef uint16_t cl_ushort16[16] __attribute__((aligned(32))); typedef int32_t cl_int2[2] __attribute__((aligned(8))); typedef int32_t cl_int4[4] __attribute__((aligned(16))); typedef int32_t cl_int8[8] __attribute__((aligned(32))); typedef int32_t cl_int16[16] __attribute__((aligned(64))); typedef uint32_t cl_uint2[2] __attribute__((aligned(8))); typedef uint32_t cl_uint4[4] __attribute__((aligned(16))); typedef uint32_t cl_uint8[8] __attribute__((aligned(32))); typedef uint32_t cl_uint16[16] __attribute__((aligned(64))); typedef int64_t cl_long2[2] __attribute__((aligned(16))); typedef int64_t cl_long4[4] __attribute__((aligned(32))); typedef int64_t cl_long8[8] __attribute__((aligned(64))); typedef int64_t cl_long16[16] __attribute__((aligned(128))); typedef uint64_t cl_ulong2[2] __attribute__((aligned(16))); typedef uint64_t cl_ulong4[4] __attribute__((aligned(32))); typedef uint64_t cl_ulong8[8] __attribute__((aligned(64))); typedef uint64_t cl_ulong16[16] __attribute__((aligned(128))); typedef float cl_float2[2] __attribute__((aligned(8))); typedef float cl_float4[4] __attribute__((aligned(16))); typedef float cl_float8[8] __attribute__((aligned(32))); typedef float cl_float16[16] __attribute__((aligned(64))); typedef double cl_double2[2] __attribute__((aligned(16))); typedef double cl_double4[4] __attribute__((aligned(32))); typedef double cl_double8[8] __attribute__((aligned(64))); typedef double cl_double16[16] __attribute__((aligned(128))); #endif #include /* and a few goodies to go with them */ #define CL_CHAR_BIT 8 #define CL_SCHAR_MAX 127 #define CL_SCHAR_MIN (-127-1) #define CL_CHAR_MAX CL_SCHAR_MAX #define CL_CHAR_MIN CL_SCHAR_MIN #define CL_UCHAR_MAX 255 #define CL_SHRT_MAX 32767 #define CL_SHRT_MIN (-32767-1) #define CL_USHRT_MAX 65535 #define CL_INT_MAX 2147483647 #define CL_INT_MIN (-2147483647-1) #define CL_UINT_MAX 0xffffffffU #define CL_LONG_MAX ((cl_long) 0x7FFFFFFFFFFFFFFFLL) #define CL_LONG_MIN ((cl_long) -0x7FFFFFFFFFFFFFFFLL - 1LL) #define CL_ULONG_MAX ((cl_ulong) 0xFFFFFFFFFFFFFFFFULL) #define CL_FLT_DIG 6 #define CL_FLT_MANT_DIG 24 #define CL_FLT_MAX_10_EXP +38 #define CL_FLT_MAX_EXP +128 #define CL_FLT_MIN_10_EXP -37 #define CL_FLT_MIN_EXP -125 #define CL_FLT_RADIX 2 #define CL_FLT_MAX 0x1.fffffep127f #define CL_FLT_MIN 0x1.0p-126f #define CL_FLT_EPSILON 0x1.0p-23f #define CL_DBL_DIG 15 #define CL_DBL_MANT_DIG 53 #define CL_DBL_MAX_10_EXP +308 #define CL_DBL_MAX_EXP +1024 #define CL_DBL_MIN_10_EXP -307 #define CL_DBL_MIN_EXP -1021 #define CL_DBL_RADIX 2 #define CL_DBL_MAX 0x1.fffffffffffffp1023 #define CL_DBL_MIN 0x1.0p-1022 #define CL_DBL_EPSILON 0x1.0p-52 /* There are no vector types for half */ #ifdef __cplusplus } #endif #endif // __CL_PLATFORM_H critterding-beta12.1/src/utils/bullet/MiniCL/cl_gl.h0000644000175000017500000001166211337073015021325 0ustar bobkebobke/********************************************************************************** * Copyright (c) 2008-2009 The Khronos Group Inc. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and/or associated documentation files (the * "Materials"), to deal in the Materials without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Materials, and to * permit persons to whom the Materials are 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 Materials. * * THE MATERIALS ARE 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 * MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS. **********************************************************************************/ #ifndef __OPENCL_CL_GL_H #define __OPENCL_CL_GL_H #ifdef __APPLE__ #include #else #include #endif #ifdef __cplusplus extern "C" { #endif // NOTE: Make sure that appropriate GL header file is included separately typedef cl_uint cl_gl_object_type; typedef cl_uint cl_gl_texture_info; typedef cl_uint cl_gl_platform_info; // cl_gl_object_type #define CL_GL_OBJECT_BUFFER 0x2000 #define CL_GL_OBJECT_TEXTURE2D 0x2001 #define CL_GL_OBJECT_TEXTURE3D 0x2002 #define CL_GL_OBJECT_RENDERBUFFER 0x2003 // cl_gl_texture_info #define CL_GL_TEXTURE_TARGET 0x2004 #define CL_GL_MIPMAP_LEVEL 0x2005 extern CL_API_ENTRY cl_mem CL_API_CALL clCreateFromGLBuffer(cl_context /* context */, cl_mem_flags /* flags */, GLuint /* bufobj */, int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_mem CL_API_CALL clCreateFromGLTexture2D(cl_context /* context */, cl_mem_flags /* flags */, GLenum /* target */, GLint /* miplevel */, GLuint /* texture */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_mem CL_API_CALL clCreateFromGLTexture3D(cl_context /* context */, cl_mem_flags /* flags */, GLenum /* target */, GLint /* miplevel */, GLuint /* texture */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_mem CL_API_CALL clCreateFromGLRenderbuffer(cl_context /* context */, cl_mem_flags /* flags */, GLuint /* renderbuffer */, cl_int * /* errcode_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clGetGLObjectInfo(cl_mem /* memobj */, cl_gl_object_type * /* gl_object_type */, GLuint * /* gl_object_name */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clGetGLTextureInfo(cl_mem /* memobj */, cl_gl_texture_info /* param_name */, size_t /* param_value_size */, void * /* param_value */, size_t * /* param_value_size_ret */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clEnqueueAcquireGLObjects(cl_command_queue /* command_queue */, cl_uint /* num_objects */, const cl_mem * /* mem_objects */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; extern CL_API_ENTRY cl_int CL_API_CALL clEnqueueReleaseGLObjects(cl_command_queue /* command_queue */, cl_uint /* num_objects */, const cl_mem * /* mem_objects */, cl_uint /* num_events_in_wait_list */, const cl_event * /* event_wait_list */, cl_event * /* event */) CL_API_SUFFIX__VERSION_1_0; #ifdef __cplusplus } #endif #endif // __OPENCL_CL_GL_H critterding-beta12.1/src/utils/commands.cpp0000644000175000017500000001737011343530351017777 0ustar bobkebobke#include "commands.h" Commands* Commands::Instance () { static Commands t; return &t; } Commands::Commands() { settings = Settings::Instance(); critterselection = Critterselection::Instance(); registerCmd("quit", &Commands::quit); registerCmd("decreaseenergy", &Commands::decreaseenergy); registerCmd("increaseenergy", &Commands::increaseenergy); registerCmd("dec_foodmaxenergy", &Commands::decreasefoodmaxenergy); registerCmd("inc_foodmaxenergy", &Commands::increasefoodmaxenergy); registerCmd("dec_worldsizex", &Commands::dec_worldsizex); registerCmd("inc_worldsizex", &Commands::inc_worldsizex); registerCmd("dec_worldsizey", &Commands::dec_worldsizey); registerCmd("inc_worldsizey", &Commands::inc_worldsizey); registerCmd("loadallcritters", &WorldB::loadAllCritters); registerCmd("saveallcritters", &WorldB::saveAllCritters); registerCmd("insertcritter", &WorldB::insertCritter); registerCmd("killhalfofcritters", &WorldB::killHalfOfCritters); registerCmd("camera_resetposition", &WorldB::resetCamera); registerCmd("camera_moveup", &WorldB::camera_moveup); registerCmd("camera_movedown", &WorldB::camera_movedown); registerCmd("camera_moveforward", &WorldB::camera_moveforward); registerCmd("camera_movebackward", &WorldB::camera_movebackward); registerCmd("camera_moveleft", &WorldB::camera_moveleft); registerCmd("camera_moveright", &WorldB::camera_moveright); registerCmd("camera_lookup", &WorldB::camera_lookup); registerCmd("camera_lookdown", &WorldB::camera_lookdown); registerCmd("camera_lookleft", &WorldB::camera_lookleft); registerCmd("camera_lookright", &WorldB::camera_lookright); registerCmd("camera_rollleft", &WorldB::camera_rollleft); registerCmd("camera_rollright", &WorldB::camera_rollright); registerCmd("gui_togglepanel", &Maincanvas::swapChild); registerCmd("gui_toggle", &Maincanvas::swap); registerCmd("settings_increase", &Settings::increaseCVar); registerCmd("settings_decrease", &Settings::decreaseCVar); registerCmd("cs_unregister", &Critterselection::unregisterCritterVID); registerCmd("cs_select", &Critterselection::selectCritterVID); registerCmd("cs_selectall", &Commands::selectCritterAll); registerCmd("cs_clear", &Critterselection::clear); registerCmd("cs_kill", &WorldB::removeSelectedCritter); registerCmd("cs_killall", &WorldB::removeAllSelectedCritters); registerCmd("cs_duplicate", &WorldB::duplicateSelectedCritter); registerCmd("cs_spawnbrainmutant", &WorldB::spawnBrainMutantSelectedCritter); registerCmd("cs_spawnbodymutant", &WorldB::spawnBodyMutantSelectedCritter); registerCmd("cs_spawnbrainbodymutant", &WorldB::spawnBrainBodyMutantSelectedCritter); registerCmd("cs_duplicateall", &WorldB::duplicateAllSelectedCritters); registerCmd("cs_spawnbrainmutantall", &WorldB::spawnBrainMutantAllSelectedCritters); registerCmd("cs_spawnbodymutantall", &WorldB::spawnBodyMutantAllSelectedCritters); registerCmd("cs_spawnbrainbodymutantall", &WorldB::spawnBrainBodyMutantAllSelectedCritters); registerCmd("cs_feed", &WorldB::feedSelectedCritter); registerCmd("cs_resetage", &WorldB::resetageSelectedCritter); } void Commands::registerCmd(string name, void (Commands::*pt2Func)()) { cmd* c = new cmd(); c->commandtype = T_COMMAND; c->argtype = A_NOARG; c->commandsMember = pt2Func; cmdlist[name] = c; } void Commands::registerCmd(string name, void (WorldB::*pt2Func)()) { cmd* c = new cmd(); c->commandtype = T_WORLD; c->argtype = A_NOARG; c->worldMember = pt2Func; cmdlist[name] = c; } void Commands::registerCmd(string name, void (Maincanvas::*pt2Func)()) { cmd* c = new cmd(); c->commandtype = T_CANVAS; c->argtype = A_NOARG; c->canvasMember = pt2Func; cmdlist[name] = c; } void Commands::registerCmd(string name, void (Maincanvas::*pt2Func)(const string&)) { cmd* c = new cmd(); c->commandtype = T_CANVAS; c->argtype = A_STRING; c->canvasMember_string = pt2Func; cmdlist[name] = c; } void Commands::registerCmd(string name, void (Settings::*pt2Func)(const string&)) { cmd* c = new cmd(); c->commandtype = T_SETTINGS; c->argtype = A_STRING; c->settingsMember_string= pt2Func; cmdlist[name] = c; } void Commands::registerCmd(string name, void (Critterselection::*pt2Func)()) { cmd* c = new cmd(); c->commandtype = T_CS; c->argtype = A_NOARG; c->critterselectionMember = pt2Func; cmdlist[name] = c; } void Commands::registerCmd(string name, void (Critterselection::*pt2Func)(const unsigned int&)) { cmd* c = new cmd(); c->commandtype = T_CS; c->argtype = A_UINT; c->critterselectionMember_uint= pt2Func; cmdlist[name] = c; } // fixme private void Commands::execCmd(const string& name) { if ( cmdlist[name]->commandtype == T_COMMAND ) (this->*cmdlist[name]->commandsMember)(); else if ( cmdlist[name]->commandtype == T_WORLD ) (world->*cmdlist[name]->worldMember)(); else if ( cmdlist[name]->commandtype == T_CS ) (critterselection->*cmdlist[name]->critterselectionMember)(); else if ( cmdlist[name]->commandtype == T_CANVAS ) (canvas->*cmdlist[name]->canvasMember)(); } void Commands::execCmd(const string& name, const string& str) { if ( cmdlist[name]->commandtype == T_CANVAS ) (canvas->*cmdlist[name]->canvasMember_string)(str); else if ( cmdlist[name]->commandtype == T_SETTINGS ) (settings->*cmdlist[name]->settingsMember_string)(str); } void Commands::execCmd(const string& name, const unsigned int& ui) { if ( cmdlist[name]->commandtype == T_CS ) (critterselection->*cmdlist[name]->critterselectionMember_uint)(ui); } // fixme public void Commands::execCmd(const cmdsettings& cmds) { // first check if called function exists if ( cmdlist[cmds.name] ) { // check if expected types match if ( cmdlist[cmds.name]->argtype == cmds.argtype ) { if ( cmds.argtype == A_NOARG ) execCmd(cmds.name); else if ( cmds.argtype == A_STRING ) execCmd(cmds.name, cmds.args); else if ( cmds.argtype == A_UINT ) execCmd(cmds.name, cmds.argui); } else cerr << "command '" << cmds.name << "'s args do not match: got " << cmds.argtype << " but expected " << cmdlist[cmds.name]->argtype << endl; } // else // cerr << "command '" << cmds.name << "' does not exist" << endl; } void Commands::quit() { SDL_Quit(); exit(0); } void Commands::selectCritterAll() { critterselection->clear(); for ( unsigned int i=0; i < world->critters.size(); i++ ) critterselection->registerCritter(world->critters[i]); } void Commands::decreaseenergy() { if ( ( (int)settings->getCVar("energy") - 1 ) >= 0 ) { settings->setCVar("energy", settings->getCVar("energy")-1 ); world->freeEnergy -= settings->getCVar("food_maxenergy"); stringstream buf; buf << "energy: " << settings->getCVar("energy"); Logbuffer::Instance()->add(buf); } } void Commands::increaseenergy() { settings->setCVar("energy", settings->getCVar("energy")+1 ); world->freeEnergy += settings->getCVar("food_maxenergy"); stringstream buf; buf << "energy: " << settings->getCVar("energy"); Logbuffer::Instance()->add(buf); } void Commands::decreasefoodmaxenergy() { if ( ( (int)settings->getCVar("food_maxenergy") - 1 ) >= 0 ) { world->freeEnergy -= settings->getCVar("energy"); settings->setCVar("food_maxenergy", settings->getCVar("food_maxenergy")-1 ); } } void Commands::increasefoodmaxenergy() { world->freeEnergy += settings->getCVar("energy"); settings->setCVar("food_maxenergy", settings->getCVar("food_maxenergy")+1 ); } void Commands::dec_worldsizex() { settings->decreaseCVar("worldsizeX"); world->makeFloor(); } void Commands::inc_worldsizex() { settings->increaseCVar("worldsizeX"); world->makeFloor(); } void Commands::dec_worldsizey() { settings->decreaseCVar("worldsizeY"); world->makeFloor(); } void Commands::inc_worldsizey() { settings->increaseCVar("worldsizeY"); world->makeFloor(); } Commands::~Commands() { for( cmdit = cmdlist.begin(); cmdit != cmdlist.end(); cmdit++ ) delete cmdit->second; } critterding-beta12.1/src/utils/sleeper.h0000644000175000017500000000061411333677463017312 0ustar bobkebobke#ifndef SLEEPER_H #define SLEEPER_H #include "../../utils/settings.h" #include "timer.h" class Sleeper { public: Sleeper(); ~Sleeper(); void mark(); void swap(); bool isRenderTime(); private: Timer *t; bool active; const unsigned int* optimal; unsigned int stepsize; unsigned int sleeptime; float cps; float timeSinceLastRender; Settings* settings; }; #endif critterding-beta12.1/src/utils/color.h0000644000175000017500000000054311342307404016753 0ustar bobkebobke#ifndef COLOR_H #define COLOR_H #include "randgen.h" using namespace std; class Color { public: Color(); ~Color(); float r; float g; float b; float a; Color randomColorRGB(); void normalize(Color* c ); Color& operator=(const Color& other); Color getNormalized(); void normalize(); private: RandGen *randgen; }; #endif critterding-beta12.1/src/utils/dirlayout.h0000644000175000017500000000061211334504050017643 0ustar bobkebobke#ifndef DIRLAYOUT_H #define DIRLAYOUT_H #include "dir.h" #include #include #include using namespace std; class Dirlayout { public: static Dirlayout* Instance(); void createDirs(); string homedir; string progdir; string savedir; string loaddir; protected: Dirlayout(); private: static Dirlayout* _instance; Dir dirH; }; #endif critterding-beta12.1/src/utils/execcmd.cpp0000644000175000017500000000075011277105401017600 0ustar bobkebobke#include "execcmd.h" Execcmd::Execcmd() { } cmdsettings Execcmd::gen(const string& name) { cmdsettings c; c.name = name; c.argtype = A_NOARG; return c; } cmdsettings Execcmd::gen(const string& name, const string& str) { cmdsettings c; c.name = name; c.argtype = A_STRING; c.args = str; return c; } cmdsettings Execcmd::gen(const string& name, const unsigned int& ul) { cmdsettings c; c.name = name; c.argtype = A_UINT; c.argui = ul; return c; } Execcmd::~Execcmd() { } critterding-beta12.1/src/utils/statsbuffer.h0000644000175000017500000000157111340630500020161 0ustar bobkebobke#ifndef STATSBUFFER_H #define STATSBUFFER_H // #include #include // #include "settings.h" #include "../scenes/entities/critterb.h" #include "../scenes/entities/food.h" using namespace std; struct statsSnapshot { unsigned int critters; unsigned int food; unsigned int neurons; unsigned int synapses; unsigned int adamdistance; unsigned int bodyparts; unsigned int weight; }; class Statsbuffer { public: static Statsbuffer* Instance(); // Statsbuffer(); // ~Statsbuffer(); void add( const vector& critters, const vector& food ); vector snapshots; statsSnapshot current; float info_totalWeight; protected: Statsbuffer(); private: static Statsbuffer* _instance; // Settings* settings; unsigned int recordInterval; unsigned int framecounter; unsigned int maxSnapshots; }; #endif critterding-beta12.1/src/utils/events.cpp0000644000175000017500000001117111267452305017502 0ustar bobkebobke#include "events.h" Events* Events::Instance() { static Events t; return &t; } Events::Events() { cmd = Commands::Instance(); } sharedTimer* Events::registerSharedtimer(unsigned int responsetime) { // create a new event and a pointer to it sharedtimers.push_back(sharedTimer()); sharedTimer* t = &sharedtimers[sharedtimers.size() - 1]; t->responsetime = responsetime; t->elapsed = 0; return t; } void Events::registerEvent(SDLKey key, const string& name, const cmdsettings& cmd, sharedTimer* stimer) { // create a new event and a pointer to it events.push_back(event()); event* e = &events[events.size() - 1]; // set up default values of event e->active = false; e->name = name; e->bindkey = key; e->bindbystring = false; e->command = cmd; e->timerisshared = true; e->stimer = stimer; } void Events::registerEvent(SDLKey key, const string& name, const cmdsettings& cmd, unsigned int responsetime, unsigned int minfresponsetime, unsigned int fresponseinterval) { // create a new event and a pointer to it events.push_back(event()); event* e = &events[events.size() - 1]; // set up default values of event e->active = false; e->name = name; e->bindkey = key; e->bindbystring = false; e->command = cmd; e->responsetime = responsetime; e->minfresponsetime = minfresponsetime; e->fresponseinterval = fresponseinterval; e->timerisshared = false; } void Events::registerEvent(const string& name, const cmdsettings& cmd, unsigned int responsetime, unsigned int minfresponsetime, unsigned int fresponseinterval) { // create a new event and a pointer to it events.push_back(event()); event* e = &events[events.size() - 1]; // set up default values of event e->active = false; e->name = name; e->bindstring = name; e->bindbystring = true; e->command = cmd; e->responsetime = responsetime; e->minfresponsetime = minfresponsetime; e->fresponseinterval = fresponseinterval; e->timerisshared = false; } void Events::activateEvent(const long unsigned int key) { for ( unsigned int i=0; i < events.size(); i++ ) { if ( !events[i].bindbystring && events[i].bindkey == key ) { if ( !events[i].timerisshared ) cmd->execCmd( events[i].command ); if ( events[i].responsetime > 0 || events[i].timerisshared ) { events[i].active = true; // events[i].elapsed = events[i].responsetime; events[i].elapsed = 0; events[i].fresponsetime = events[i].responsetime; } // cerr << "activated " << events[i].name << " rt: " << events[i].elapsed << endl; return; } } } void Events::activateEvent(const string& key) { for ( unsigned int i=0; i < events.size(); i++ ) { if ( events[i].bindbystring && events[i].bindstring == key ) { if ( !events[i].timerisshared ) cmd->execCmd( events[i].command ); if ( events[i].responsetime > 0 || events[i].timerisshared ) { events[i].active = true; // events[i].elapsed = events[i].responsetime; events[i].elapsed = 0; events[i].fresponsetime = events[i].responsetime; // cerr << "activated " << events[i].name << " rt: " << events[i].elapsed << endl; } return; } } } void Events::deactivateEvent(const long unsigned int key) { for ( unsigned int i=0; i < events.size(); i++ ) { if ( !events[i].bindbystring && events[i].bindkey == key ) { // cerr << "deactivating " << events[i].name << endl; events[i].active = false; return; } } } void Events::deactivateEvent(const string& key) { for ( unsigned int i=0; i < events.size(); i++ ) { if ( events[i].bindbystring && events[i].bindstring == key ) { // cerr << "deactivating " << events[i].name << endl; events[i].active = false; return; } } } void Events::processSharedTimers() { for ( unsigned int i=0; i < sharedtimers.size(); i++ ) { sharedTimer* t = &sharedtimers[i]; t->elapsed += Timer::Instance()->elapsed; if ( t->elapsed >= t->responsetime ) { t->elapsed = 0; t->active = true; } else t->active = false; } } void Events::handlecommands() { for ( unsigned int i=0; i < events.size(); i++ ) { event* e = &events[i]; if ( e->active ) { // event uses a shared timer if ( e->timerisshared ) { if ( e->stimer->active ) cmd->execCmd( e->command ); } // event has it's own timer else { e->elapsed += Timer::Instance()->elapsed; if ( (int)e->elapsed >= e->fresponsetime ) { if ( e->responsetime > e->minfresponsetime ) { e->fresponsetime -= e->fresponseinterval; if ( e->fresponsetime < (int)e->minfresponsetime ) e->fresponsetime = e->minfresponsetime; } e->elapsed = 0; cmd->execCmd( e->command ); } } } } } Events::~Events() { } critterding-beta12.1/src/utils/execcmd.h0000644000175000017500000000111411277105401017240 0ustar bobkebobke#ifndef EXECCMD_H #define EXECCMD_H #include using namespace std; enum cmdtype { T_COMMAND = 1, T_WORLD, T_CANVAS, T_SETTINGS, T_CS }; enum cmdargtype { A_NOARG = 1, A_INT, A_STRING, A_UINT }; struct cmdsettings { string name; cmdargtype argtype; int argi; unsigned int argui; string args; }; class Execcmd { public: Execcmd(); ~Execcmd(); cmdsettings gen(const string& name); cmdsettings gen(const string& name, const string& str); cmdsettings gen(const string& name, const unsigned int& ul); private: }; #endif critterding-beta12.1/src/utils/headless.cpp0000644000175000017500000000051111301117413017745 0ustar bobkebobke#include "headless.h" Headless::Headless() { } void Headless::create() { w_width = 0; w_height = 0; Settings::Instance()->winWidth = &w_width; Settings::Instance()->winHeight = &w_height; } void Headless::runGLScene(GLScene* glscene) { while(1) glscene->draw(); SDL_Quit(); exit(0); } Headless::~Headless() { } critterding-beta12.1/src/utils/file.h0000644000175000017500000000117111301116254016546 0ustar bobkebobke#ifndef FILE_H #define FILE_H #include #include #include #include #include #include #include #include #include #include using namespace std; class File { public: File(); ~File(); bool exists(string &file); bool exists(const char* file); void save(const string &filename, const string& content); void save(const string &filename, string* content); bool open(const string &filename, string& content); bool open(const char* filename, string &content); void rm(const string &filename); }; #endif critterding-beta12.1/src/utils/statsbuffer.cpp0000644000175000017500000000240611340630500020512 0ustar bobkebobke#include "statsbuffer.h" Statsbuffer* Statsbuffer::Instance () { static Statsbuffer t; return &t; } Statsbuffer::Statsbuffer() { // settings = Settings::Instance(); recordInterval = 100; framecounter = 0; maxSnapshots = 3000; } void Statsbuffer::add( const vector& critters, const vector& food ) { // get stats of this frame current.neurons = 0; current.synapses = 0; current.adamdistance = 0; current.bodyparts = 0; current.weight = 0; CritterB* c; for( unsigned int i=0; i < critters.size(); i++ ) { c = critters[i]; current.neurons += c->brain.totalNeurons; current.synapses += c->brain.totalSynapses; current.adamdistance += c->genotype->adamdist; current.bodyparts += c->body.bodyparts.size(); current.weight += c->body.totalWeight; } current.critters = critters.size(); current.food = food.size(); if ( ++framecounter == recordInterval ) { // remove expired snapshots if ( snapshots.size() == maxSnapshots ) snapshots.erase(snapshots.begin()); // insert the current snapshot snapshots.push_back(current); framecounter = 0; // debug output /* cerr << endl; for ( unsigned int i=0; i < snapshots.size(); i++ ) cerr << "c: " << snapshots[i].critters << ", f: " << snapshots[i].food << endl;*/ } } critterding-beta12.1/src/utils/color.cpp0000644000175000017500000000225711342307404017312 0ustar bobkebobke#include "color.h" Color::Color() { r = 0.0f; g = 0.0f; b = 0.0f; a = 0.0f; } Color Color::randomColorRGB() { Color c; c.r = (float)RandGen::Instance()->get( 1,100 ) / 100.0f; c.g = (float)RandGen::Instance()->get( 1,100 ) / 100.0f; c.b = (float)RandGen::Instance()->get( 1,100 ) / 100.0f; c.a = 0.0f; return c; } void Color::normalize(Color* c) { float highest = c->r; if ( c->g > highest ) highest = c->g; if ( c->b > highest ) highest = c->b; if ( c->a > highest ) highest = c->a; c->r /= highest; c->g /= highest; c->b /= highest; c->a /= highest; } Color Color::getNormalized() { float highest = r; if ( g > highest ) highest = g; if ( b > highest ) highest = b; if ( a > highest ) highest = a; Color c; c.r = r/highest; c.g = g/highest; c.b = b/highest; c.a = a/highest; return c; } void Color::normalize() { float highest = r; if ( g > highest ) highest = g; if ( b > highest ) highest = b; if ( a > highest ) highest = a; r /= highest; g /= highest; b /= highest; a /= highest; } Color& Color::operator=(const Color& other) { r = other.r; g = other.g; b = other.b; a = other.a; return (*this); } Color::~Color() { } critterding-beta12.1/src/utils/logbuffer.cpp0000644000175000017500000000214511342625205020145 0ustar bobkebobke#include "logbuffer.h" Logbuffer* Logbuffer::Instance () { static Logbuffer t; return &t; // _instance isn't needed in this case } Logbuffer::Logbuffer() { maxMessages = 5; msgLifetime = 3000; } void Logbuffer::add(const stringstream& streamptr) { msg *Msg = new msg; Msg->str = streamptr.str(); Msg->appeartime = Timer::Instance()->sdl_lasttime; Msg->len = Textprinter::Instance()->getWidth(Msg->str); messages.push_back(Msg); // to prevent overfilling: deleteExpiredMsg(); getLongest(); } void Logbuffer::deleteExpiredMsg() { if ( !messages.empty() ) { if ( messages.size() > maxMessages || ( msgLifetime > 0.0f && (Timer::Instance()->sdl_lasttime - messages[0]->appeartime) > msgLifetime ) // || ( msgLifetime > 0.0f && Timer::Instance()->timediff( Timer::Instance()->lasttime, messages[0]->appeartime ) > msgLifetime ) ) { delete messages[0]; messages.erase(messages.begin()+0); } } } void Logbuffer::getLongest() { longestLength = 0; for ( unsigned int i=0; i < messages.size(); i++ ) { if ( messages[i]->len > longestLength ) longestLength = messages[i]->len; } } critterding-beta12.1/src/utils/events.h0000644000175000017500000000321611266416045017150 0ustar bobkebobke#ifndef EVENTS_H #define EVENTS_H #include #include #include #include #include #include "timer.h" #include "commands.h" #include "execcmd.h" using namespace std; struct sharedTimer { bool active; unsigned int responsetime; unsigned int elapsed; }; struct event { string name; bool active; bool bindbystring; long unsigned int bindkey; string bindstring; cmdsettings command; // private timer unsigned int responsetime; int fresponsetime; unsigned int minfresponsetime; unsigned int fresponseinterval; // degredation interval unsigned int elapsed; // shared timer bool timerisshared; sharedTimer* stimer; }; class Events { public: static Events* Instance(); ~Events(); void registerEvent(SDLKey key, const string& name, const cmdsettings& cmd, sharedTimer* stimer); void registerEvent(SDLKey key, const string& name, const cmdsettings& cmd, unsigned int responsetime, unsigned int minfresponsetime, unsigned int fresponseinterval); void registerEvent(const string& name, const cmdsettings& cmd, unsigned int responsetime, unsigned int minfresponsetime, unsigned int fresponseinterval); void activateEvent(const long unsigned int key); void activateEvent(const string& key); void deactivateEvent(const long unsigned int key); void deactivateEvent(const string& key); sharedTimer* registerSharedtimer(unsigned int responsetime); void processSharedTimers(); void handlecommands(); protected: Events(); private: static Events* _instance; Commands* cmd; vector events; vector sharedtimers; }; #endif critterding-beta12.1/src/utils/raycast.h0000644000175000017500000000064711276347255017326 0ustar bobkebobke#ifndef RAYCAST_H #define RAYCAST_H #include "btBulletDynamicsCommon.h" #include using namespace std; struct castResult { bool hit; btCollisionObject* hitBody; btVector3 hitPosition; }; class Raycast { public: Raycast(btDynamicsWorld* btWorld); ~Raycast(); castResult cast(const btVector3& rayFrom, const btVector3& rayTo); private: btDynamicsWorld* btDynWorld; castResult result; }; #endif critterding-beta12.1/src/utils/mousepicker.h0000644000175000017500000000126111247060346020166 0ustar bobkebobke#ifndef MOUSEPICKER_H #define MOUSEPICKER_H #include "btBulletDynamicsCommon.h" #include using namespace std; class Mousepicker { public: Mousepicker(btDynamicsWorld* btWorld); ~Mousepicker(); void attach( btRigidBody* pickBody, const btVector3& attachPosition, const btVector3& rayFrom, const btVector3& rayTo ); void detach(); void moveTo( const btVector3& origin, const btVector3& newdirection ); void moveFrom( const btVector3& origin ); bool* pickedBool; bool active; private: btDynamicsWorld* btDynWorld; btVector3 direction; btPoint2PointConstraint* constraint; btRigidBody* pickedBody; float oldPickingDist; }; #endif critterding-beta12.1/src/utils/mousepicker.cpp0000644000175000017500000000307311277553273020535 0ustar bobkebobke#include "mousepicker.h" Mousepicker::Mousepicker(btDynamicsWorld* btWorld) { btDynWorld = btWorld; active = false; } void Mousepicker::attach( btRigidBody* pickBody, const btVector3& attachPosition, const btVector3& rayFrom, const btVector3& rayTo ) { active = true; pickedBody = pickBody; pickedBody->setActivationState(DISABLE_DEACTIVATION); btVector3 localPivot = pickedBody->getCenterOfMassTransform().inverse() * attachPosition; // create constraint and add it to bulletworld constraint = new btPoint2PointConstraint(*pickedBody,localPivot); constraint->m_setting.m_impulseClamp = 30.f; constraint->m_setting.m_tau = 0.1f; btDynWorld->addConstraint(constraint); oldPickingDist = (attachPosition - rayFrom).length(); } void Mousepicker::detach() { if ( active ) { active = false; btDynWorld->removeConstraint(constraint); delete constraint; pickedBody->forceActivationState(ACTIVE_TAG); pickedBody->setDeactivationTime( 0.001 ); // set the object that was picked back to false *pickedBool = false; } } void Mousepicker::moveTo( const btVector3& origin, const btVector3& newdirection ) { direction = newdirection; btVector3 oldPivotInB = constraint->getPivotInB(); btVector3 dir = ( origin + direction ); dir.normalize(); constraint->setPivotB( (dir * oldPickingDist) + origin); } void Mousepicker::moveFrom( const btVector3& origin ) { btVector3 oldPivotInB = constraint->getPivotInB(); btVector3 dir = ( origin + direction ); dir.normalize(); constraint->setPivotB( (dir * oldPickingDist) + origin); } Mousepicker::~Mousepicker() { } critterding-beta12.1/src/utils/settings.cpp0000644000175000017500000004713411347254352020047 0ustar bobkebobke#include "settings.h" Settings* Settings::Instance () { static Settings t; return &t; } Settings::Settings() { profileName = "default"; registerCVar("fullscreen", 0, 0, 1, true, "enable fullscreen mode"); registerCVar("threads", 1, 1, 16, false, "threads to use"); registerCVar("headless", 0, 0, 1, true, "do not open gl context"); registerCVar("drawscene", 1, 0, 1, true, "draw the scene"); registerCVar("fsX", 800, 1, 1000000, false, "fullscreen resolution X"); registerCVar("fsY", 600, 1, 1000000, false, "fullscreen resolution Y"); registerCVar("startseed", 0, 0, 4000000000, true, "enable fullscreen mode"); registerCVar("benchmark", 0, 0, 1, true, "run the critterding benchmark"); registerCVar("race", 0, 0, 1, false, "enable race simulation"); registerCVar("roundworld", 0, 0, 1, false, "enable round planet"); registerCVar("testworld", 0, 0, 1, false, "a world for test purposes"); registerCVar("worldsizeX", 23, 1, 5000, false, "size of the world along axis X"); registerCVar("worldsizeY", 13, 1, 5000, false, "size of the world along axis Y"); registerCVar("worldwalls", 1, 0, 1, false, "enable walls around the world"); registerCVar("killhalf_decrenergypct", 1, 0, 100, false, "decrease energy by n percent when killhalfat triggers"); registerCVar("killhalf_incrworldsizeX", 0, 0, 100, false, "increase worldsizeX by n when killhalfat triggers"); registerCVar("killhalf_incrworldsizeY", 0, 0, 100, false, "increase worldsizeY by n when killhalfat triggers"); registerCVar("killhalf_decrmaxlifetimepct", 0, 0, 100, false, "decrease critter_maxlifetime by n when killhalfat triggers"); registerCVar("energy", 400, 0, 1000000, false, "energy in the system by number of food cubes"); registerCVar("mincritters", 10, 0, 1000, false, "minimum number of critters"); registerCVar("retinasperrow", 20, 1, 1000, false, "number of vision retinas to stack per row onscreen"); registerCVar("camerasensitivity", 20, 1, 1000, false, "sensitivity of the camera"); registerCVar("colormode", 0, 0, 1, true, "colors genetically exact critters identically"); registerCVar("exit_if_empty", 0, 0, 1, true, "exit simulation if there are no critters"); registerCVar("autoload", 0, 0, 1, true, "autoload critters from ~/.critterding/load"); registerCVar("autoloadlastsaved", 0, 0, 1, true, "autoload critters from ~/.critterding/lastsaved"); registerCVar("fpslimit", 30, 1, 1000, false, "frames per second for the fps limiter"); registerCVar("critter_insertevery", 0, 0, 1000000, false, "inserts a random critter every n frames"); registerCVar("critter_maxlifetime", 40000, 1, 1000000, false, "maximum number of frames a critter lives"); registerCVar("critter_maxenergy", 5000, 1, 1000000, false, "maximum amount of energy a critter has"); registerCVar("critter_startenergy", 3000, 1, 1000000, false, "energy a new critter (adam) starts with"); registerCVar("critter_procinterval", 20, 1, 1000000, false, "minimum frames between procreations"); registerCVar("critter_minenergyproc", 3000, 1, 1000000, false, "energy a critters needs to procreate"); registerCVar("critter_sightrange", 70, 1, 1000000, false, "distance a critter can see (10 = 1 worldsize)"); registerCVar("critter_retinasize", 8, 1, 1000, false, "size of a critters eye retina"); registerCVar("critter_autosaveinterval", 0, 0, 1000000, false, "save critters every n seconds"); registerCVar("critter_autoexchangeinterval", 0, 0, 1000000, false, "save critters every n seconds"); registerCVar("critter_killhalfat", 120, 2, 1000000, false, "kill 50% of critters if population reaches n"); registerCVar("critter_enableomnivores", 1, 0, 1, true, "enables critters to eat each other"); registerCVar("critter_raycastvision", 0, 0, 1, true, "use raycast vision instead of opengl"); registerCVar("food_maxlifetime", 40000, 1, 1000000, false, "maximum number of frames a food unit exists"); registerCVar("food_maxenergy", 1500, 1, 1000000, false, "maximum amount of energy a food unit has"); registerCVar("food_size", 200, 1, 1000000, false, "size of a food unit"); registerCVar("body_maxmutations", 3, 1, 1000000, false, "maximum mutations on a body mutant"); registerCVar("body_mutationrate", 10, 0, 100, false, "percentage of newborns that mutate bodies"); registerCVar("body_maxbodyparts", 30, 0, 1000000, false, "maximum body parts per critter"); registerCVar("body_maxbodypartsatbuildtime", 6, 1, 1000000, false, "maximum body parts for a new critter"); registerCVar("body_minbodypartsize", 20, 1, 1000000, false, "minimum size of a critters body part"); registerCVar("body_maxbodypartsize", 200, 1, 1000000, false, "maximum size of a critters body part"); registerCVar("body_minheadsize", 30, 1, 1000000, false, "minimum size of a critters head"); registerCVar("body_maxheadsize", 80, 1, 1000000, false, "maximum size of a critters head"); registerCVar("body_percentmutateeffectchangecolor", 1, 0, 100, false, "chance of changing body color"); registerCVar("body_percentmutateeffectchangecolor_slightly", 5, 0, 100, false, "chance of changing body color"); registerCVar("body_percentmutateeffectaddbodypart", 1, 0, 100, false, "chance of adding a body part"); registerCVar("body_percentmutateeffectremovebodypart", 1, 0, 100, false, "chance of removing a body part"); registerCVar("body_percentmutateeffectresizebodypart", 1, 0, 100, false, "chance of resizing a body part"); registerCVar("body_percentmutateeffectresizebodypart_slightly", 5, 0, 100, false, "chance of slightly resizing a body part"); registerCVar("body_percentmutateeffectchangeconstraintlimits", 1, 0, 100, false, "chance of changing a joints motion limits"); registerCVar("body_percentmutateeffectchangeconstraintlimits_slightly", 5, 0, 100, false, "chance of slightly changing a joints motion limits"); registerCVar("body_percentmutateeffectchangeconstraintangles", 1, 0, 100, false, "chance of changing a joints position angles"); registerCVar("body_percentmutateeffectchangeconstraintangles_slightly", 5, 0, 100, false, "chance of changing a joints position angles"); registerCVar("body_percentmutateeffectchangeconstraintposition", 1, 0, 100, false, "chance of changing a joints position"); registerCVar("body_percentmutateeffectchangeconstraintposition_slightly", 5, 0, 100, false, "chance of slightly changing a joints position"); registerCVar("body_percentmutateeffectresizehead", 1, 0, 100, false, "chance of resizing a head"); registerCVar("body_percentmutateeffectresizehead_slightly", 5, 0, 100, false, "chance of slightly resizing a head"); registerCVar("body_percentmutateeffectrepositionhead", 5, 0, 100, false, "chance of repositioning head"); registerCVar("brain_maxmutations", 10, 1, 1000000, false, "maximum mutations on a brain mutant"); registerCVar("brain_mutationrate", 10, 0, 100, false, "percentage of newborns that mutate brains"); registerCVar("brain_maxneurons", 1000, 1, 1000000, false, "maximum neurons per critter"); registerCVar("brain_minsynapses", 1, 1, 1000000, false, "minimum synapses per neuron"); registerCVar("brain_maxsynapses", 100, 1, 1000000, false, "maximum synapses per neuron"); registerCVar("brain_minneuronsatbuildtime", 50, 1, 1000000, false, "minimum neurons for a new critter"); registerCVar("brain_maxneuronsatbuildtime", 200, 1, 1000000, false, "maximum neurons for a new critter"); registerCVar("brain_minsynapsesatbuildtime", 1, 1, 1000000, false, "minimum synapses for a new neuron"); registerCVar("brain_maxsynapsesatbuildtime", 40, 1, 1000000, false, "maximum synapses for a new neuron of a new critter"); registerCVar("brain_percentchanceinhibitoryneuron", 50, 0, 100, false, "percent chance a neuron is inhibotory"); registerCVar("brain_mutate_percentchanceinhibitoryneuron", 0, 0, 1, true, "mutate this value"); registerCVar("brain_percentchancemotorneuron", 50, 0, 100, false, "percent chance a neuron is a motor neuron"); registerCVar("brain_mutate_percentchancemotorneuron", 0, 0, 1, true, "mutate this value"); registerCVar("brain_percentchanceplasticneuron", 20, 0, 100, false, "percent chance a neuron has plastic synapses"); registerCVar("brain_mutate_percentchanceplasticneuron", 0, 0, 1, true, "mutate this value"); registerCVar("brain_minplasticitystrengthen", 100, 1, 1000000, false, "minimum weight by which plastic synapses strengthen"); registerCVar("brain_maxplasticitystrengthen", 1000, 1, 1000000, false, "maximum weight by which plastic synapses strengthen"); registerCVar("brain_minplasticityweaken", 1000, 1, 1000000, false, "minimum weight by which plastic synapses weaken"); registerCVar("brain_maxplasticityweaken", 10000, 1, 1000000, false, "maximum weight by which plastic synapses weaken"); registerCVar("brain_mutate_plasticityfactors", 0, 0, 1, true, "mutate min/max plasticity values"); registerCVar("brain_minfiringthreshold", 2, 1, 1000000, false, "minimum firingthreshold of a neuron"); registerCVar("brain_mutate_minfiringthreshold", 0, 0, 1, true, "mutate this value"); registerCVar("brain_maxfiringthreshold", 10, 1, 1000000, false, "maximum firingthreshold of a neuron"); registerCVar("brain_mutate_maxfiringthreshold", 0, 0, 1, true, "mutate this value"); registerCVar("brain_maxdendridicbranches", 3, 1, 1000000, false, "maximum number of dendrites per neuron"); registerCVar("brain_mutate_maxdendridicbranches", 0, 0, 1, true, "mutate this value"); registerCVar("brain_percentchanceconsistentsynapses", 0, 0, 100, false, "percent chance a neurons synapses are all inhibitory or excitatory"); registerCVar("brain_mutate_percentchanceconsistentsynapses", 0, 0, 1, true, "mutate this value"); registerCVar("brain_percentchanceinhibitorysynapses", 50, 0, 100, false, "percent chance a synapse is inhibitory"); registerCVar("brain_mutate_percentchanceinhibitorysynapses", 0, 0, 1, true, "mutate this value"); registerCVar("brain_percentchancesensorysynapse", 20, 0, 100, false, "percent change a synapse connects to an input"); registerCVar("brain_mutate_percentchancesensorysynapse", 0, 0, 1, true, "mutate this value"); registerCVar("brain_percentmutateeffectaddneuron", 1, 0, 100, false, "chance of adding a neuron"); registerCVar("brain_percentmutateeffectremoveneuron", 1, 0, 100, false, "chance of removing a neuron"); registerCVar("brain_percentmutateeffectalterneuron", 2, 0, 100, false, "chance of altering a neuron"); registerCVar("brain_percentmutateeffectaddsynapse", 5, 0, 100, false, "chance of adding a synapse"); registerCVar("brain_percentmutateeffectremovesynapse", 5, 0, 100, false, "chance of removing a synapse"); registerCVar("brain_mutate_mutateeffects", 0, 0, 1, true, "mutate mutation effects"); registerCVar("brain_percentmutateeffectaltermutable", 1, 0, 100, false,"mutate value of a mutatable option"); registerCVar("brain_costhavingneuron", 50, 0, 1000000, false, "cost of having a neuron (1/100000 energy)"); registerCVar("brain_costfiringneuron", 10, 0, 1000000, false, "cost of firing a neuron"); registerCVar("brain_costfiringmotorneuron", 100, 0, 1000000, false, "cost of firing a motor neuron"); registerCVar("brain_costhavingsynapse", 1, 0, 1000000, false, "cost of having a synapse"); dirlayout = Dirlayout::Instance(); createHelpInfo(); } void Settings::registerCVar(const string& name, const unsigned int& defaultvalue, const unsigned int& min_val, const unsigned int& max_val, const string& comment) { registerCVar( name, defaultvalue, min_val, max_val, false, comment ); } void Settings::registerCVar(const string& name, const unsigned int& defaultvalue, const unsigned int& min_val, const unsigned int& max_val, bool loop, const string& comment) { cvar* v = new cvar(); v->int_val = defaultvalue; v->int_min = min_val; v->int_max = max_val; v->loop = loop; v->comment = comment; unregisterCVar(name); cvarlist[name] = v; // cvarlist[name]->loop = true; } void Settings::registerLocalCVar(const string& name, const unsigned int& defaultvalue, const unsigned int& min_val, const unsigned int& max_val, bool loop, const string& comment) { cvar* v = new cvar(); v->int_val = defaultvalue; v->int_min = min_val; v->int_max = max_val; v->loop = loop; v->local = true; v->comment = comment; unregisterCVar(name); cvarlist[name] = v; // cvarlist[name]->loop = true; } unsigned int Settings::getCVar(const string& name) { // cerr << "asking for " << name << endl; // the fast"er" way // return cvarlist[name]->int_val; // the slow way cvarit = cvarlist.find(name); if ( cvarit != cvarlist.end() ) return cvarit->second->int_val; else cerr << "getCVar: no such key: " << name << endl; return 0; } const unsigned int* Settings::getCVarPtr(const string& name) { return &cvarlist[name]->int_val; } bool Settings::setCVar(const string& name, const unsigned int& value) { if ( value >= cvarlist[name]->int_min && value <= cvarlist[name]->int_max ) { cvarlist[name]->int_val = value; return true; } else { cerr << name << " expects a value that is >=" << cvarlist[name]->int_min << " and <=" << cvarlist[name]->int_max << endl; return false; } } // FIXME private void Settings::increaseCVar(const string& name, const unsigned int& value) { unsigned int diff = cvarlist[name]->int_val + value; if ( diff >= cvarlist[name]->int_min && diff <= cvarlist[name]->int_max ) cvarlist[name]->int_val += value; else if ( cvarlist[name]->loop ) { cvarlist[name]->int_val = cvarlist[name]->int_min; } } // FIXME private void Settings::decreaseCVar(const string& name, const unsigned int& value) { unsigned int diff = cvarlist[name]->int_val - value; if ( diff >= cvarlist[name]->int_min && diff <= cvarlist[name]->int_max ) cvarlist[name]->int_val -= value; } void Settings::increaseCVar(const string& name) { unsigned int diff = cvarlist[name]->int_val + 1; if ( diff >= cvarlist[name]->int_min && diff <= cvarlist[name]->int_max ) cvarlist[name]->int_val = diff; else if ( cvarlist[name]->loop ) { cvarlist[name]->int_val = cvarlist[name]->int_min; } stringstream buf; buf << name << ": " << getCVar(name); Logbuffer::Instance()->add(buf); } void Settings::decreaseCVar(const string& name) { int diff = -1 + cvarlist[name]->int_val; if ( diff >= (int)cvarlist[name]->int_min && diff <= (int)cvarlist[name]->int_max ) cvarlist[name]->int_val = (unsigned int)diff; stringstream buf; buf << name << ": " << getCVar(name); Logbuffer::Instance()->add(buf); } void Settings::unregisterCVar(const string& name) { cvarit = cvarlist.find(name); if ( cvarit != cvarlist.end() ) { delete cvarit->second; cvarlist.erase(cvarit->first); } } bool Settings::isCVar(const string& name) { cvarit = cvarlist.find(name); if ( cvarit != cvarlist.end() ) return true; return false; } void Settings::createHelpInfo() { // helpinfo << "STARTUP OPTIONS" << endl << endl; // helpinfo << " Global Settings" << endl; helpinfo << endl << " option [default] [range] [comment]" << endl << endl; for( cvarit = cvarlist.begin(); cvarit != cvarlist.end(); cvarit++ ) { stringstream buf(""); buf << " --" << cvarit->first; // buf << " " << buf.str().size(); for ( unsigned int i=buf.str().size(); i < 62; i++ ) buf << " "; buf << cvarit->second->int_val; for ( unsigned int i=buf.str().size(); i < 72; i++ ) buf << " "; buf << cvarit->second->int_min << "-" << cvarit->second->int_max; for ( unsigned int i=buf.str().size(); i < 85; i++ ) buf << " "; buf << cvarit->second->comment; helpinfo << buf.str() << endl; } helpinfo << endl << " To save the default settings to a profile, press \"s\" in the simulation. \n It will be saved to ./default and can be loaded by using \"--profile ./default\"" << endl ; helpinfo << endl << " Use F1 in the simulation for more information about keys." << endl; } void Settings::loadProfile(char* filename) { cerr << "loading settins from '" << filename << "'" << endl; // nasty code for stripping dir names from the given profile name profileName = filename; string dirs(""); parseH->Instance()->beginMatchesStrip( "/", profileName ); dirs = parseH->Instance()->returnUntillStrip( "/", profileName ); while ( !dirs.empty() ) { dirs=""; dirs = parseH->Instance()->returnUntillStrip( "/", profileName ); } profileName = parseH->Instance()->returnUntillStrip( ".pro", profileName ); string content; if ( fileH.open( filename, content ) ) { content.append("\n"); string line = parseH->Instance()->returnUntillStrip( "\n", content ); while ( !content.empty() ) { // trim spaces while ( parseH->Instance()->beginMatchesStrip( " ", line ) ) {}; // remove comment lines if ( parseH->Instance()->beginMatchesStrip( "#", line ) ) line.clear(); if ( !line.empty() ) { string sw = parseH->Instance()->returnUntillStrip( " ", line ); if ( !sw.empty() ) { if ( isCVar(sw) ) { while ( parseH->Instance()->beginMatchesStrip( " ", line ) ) {}; if ( !line.empty() ) { unsigned int value = atoi( line.c_str() ); line.clear(); if ( !setCVar(sw, value) ) exit(1); } else { cerr << "Option expects an argument: " << sw << endl; exit(1); } } else { cerr << "Unknown option in profile: " << sw << endl; // exit(1); } } else { cerr << "Option without an argument: " << line << endl; exit(1); } } line = parseH->Instance()->returnUntillStrip( "\n", content ); } } else { cerr << "cannot open profile '" << filename << "'" << endl; exit(1); } } void Settings::saveProfile() { string fulldir; fulldir = dirlayout->savedir; fulldir.append("/"); fulldir.append(profileName); if ( !dirH.exists(fulldir) ) dirH.make(fulldir); stringstream filename; filename << fulldir << "/" << profileName << ".pro"; stringstream buf; for( cvarit = cvarlist.begin(); cvarit != cvarlist.end(); cvarit++ ) { if ( !cvarit->second->local ) buf << cvarit->first << " " << cvarit->second->int_val << endl; } fileH.save(filename.str(), buf.str()); } void Settings::doCommandLineOptions(int argc, char *argv[]) { // parse argv[0] for binary path string path; path.append(argv[0]); size_t pos = path.find_last_of("/", path.size()); if ( pos != string::npos ) binarypath = path.substr( 0, pos+1 ); // check if --help occurs, overrides the rest for (int i=1; i < argc; i++ ) { string sw = argv[i]; if ( sw == "--help" ) { cout << helpinfo.str() << endl; exit(1); } } // decode arguments int optind=1; while ((optind < argc) && (argv[optind][0]=='-')) { string sw = argv[optind]; if ( sw=="--profile" ) { if ( argv[++optind] ) { loadProfile(argv[optind]); } else { cerr << "--profile expects a filename" << endl; exit(1); } } else if ( parseH->Instance()->beginMatchesStrip( "--", sw ) ) { if ( isCVar(sw) ) { if ( argv[++optind] ) { if ( !setCVar(sw, atoi( argv[optind] )) ) exit(1); } else { cerr << "--" << sw << " expects an argument" << endl; exit(1); } } else { cerr << "Unknown commandline option: --" << sw << endl; // cerr << "use --help for more information" << endl; // exit(1); } } optind++; } if (optindsecond; } critterding-beta12.1/src/utils/timer.cpp0000644000175000017500000000177011344543245017322 0ustar bobkebobke#ifdef _WIN32 #include #endif #include "timer.h" Timer* Timer::Instance () { static Timer t; return &t; // _instance isn't needed in this case } Timer::Timer() { // calc lasttime for first time // gettimeofday(&lasttime, &timer_tz); sdl_lasttime = SDL_GetTicks(); sdl_firsttime = sdl_lasttime; } void Timer::mark() { // get now // gettimeofday(&lasttime, &timer_tz); sdl_now = SDL_GetTicks(); // cerr << SDL_GetTicks() << endl; // calc diff between now and lasttime elapsed = sdl_now - sdl_lasttime; // while ( elapsed == 0) // { // usleep(100); // sdl_now = SDL_GetTicks(); // elapsed = sdl_now - sdl_lasttime; // // cerr << sdl_now << " frame missed" << endl; // } if ( elapsed > 0 ) bullet_ms = 1000.f / elapsed; else bullet_ms = 0; sdl_lasttime = sdl_now; } // float Timer::timediff(const struct timeval& now, const struct timeval& lasttime) // { // return ( (float)((now.tv_sec - lasttime.tv_sec) * 1000000 + (now.tv_usec - lasttime.tv_usec)) / 1000000); // } critterding-beta12.1/src/utils/fps.cpp0000644000175000017500000000061211346046106016760 0ustar bobkebobke#include "fps.h" Fps::Fps() { t = Timer::Instance(); dispcounter = 0; dispevery = 25; dispsum = 0.0f; currentfps = 0.0f; } void Fps::mark() { if ( t->elapsed > 0.0f ) { dispsum += t->bullet_ms; if ( ++dispcounter == dispevery ) { currentfps = dispsum/dispevery; /* cerr << "FPS: " << currentfps << endl;*/ dispcounter = 0; dispsum = 0.0f; } } } Fps::~Fps() { } critterding-beta12.1/src/critterding.cpp0000644000175000017500000000116111344065077017354 0ustar bobkebobke#include "gl/glwindow.h" #include "utils/headless.h" #include "scenes/evolution.h" #include "utils/settings.h" using namespace std; int main(int argc, char* argv[]) { Settings *settings = Settings::Instance(); settings->doCommandLineOptions(argc,argv); if ( settings->getCVar("headless") ) { Headless headless; headless.create(); Evolution* mainscene = new Evolution(); headless.runGLScene(mainscene); delete mainscene; } else { GLWindow glwindow; glwindow.create("Critterding beta12", 800, 600); Evolution* mainscene = new Evolution(); glwindow.runGLScene(mainscene); delete mainscene; } } critterding-beta12.1/src/gl/0000755000175000017500000000000011347266042014733 5ustar bobkebobkecritterding-beta12.1/src/gl/glscene.h0000644000175000017500000000161311256242330016516 0ustar bobkebobke#ifndef GLSCENE_H #define GLSCENE_H // Standard OpenGL/GLX header files #include #include /* Headers needed for keys used in the program */ #include // #include // #include // FIXME GET RID OF KEYSIM AND XLIB class GLScene { public: GLScene(); virtual ~GLScene(); virtual void init(); // This is the drawing function. Whatever needs to be drawn, goes in this function virtual void draw(); // glwindow passes events to the scene virtual void handlekeyPressed(const SDLKey& key); virtual void handlekeyReleased(const SDLKey& key); virtual void handlemousebuttonPressed(int x, int y, const int&); virtual void handlemousebuttonReleased(int x, int y, const int&); virtual void handleMouseMotionRel(int x, int y); virtual void handleMouseMotionAbs(int x, int y); virtual void clean(); }; #endif // GLSCENE_H critterding-beta12.1/src/gl/Makefile.am0000644000175000017500000000037711336076205016774 0ustar bobkebobkeINCLUDES = $(all_includes) -I../utils/bullet METASOURCES = AUTO libgl_la_LDFLAGS = -avoid-version -no-undefined noinst_LTLIBRARIES = libgl.la noinst_HEADERS = glwindow.h glscene.h libgl_la_SOURCES = glwindow.cpp glscene.cpp libgl_la_LIBADD = -L/usr/lib critterding-beta12.1/src/gl/gldebugdrawer.h0000644000175000017500000000220011242036113017700 0ustar bobkebobke#ifndef GLDEBUGDRAWER_H #define GLDEBUGDRAWER_H #include "LinearMath/btIDebugDraw.h" #include "GL/gl.h" class GLDebugDrawer : public btIDebugDraw { int m_debugMode; public: GLDebugDrawer(); virtual void drawLine(const btVector3& from,const btVector3& to,const btVector3& fromColor, const btVector3& toColor); virtual void drawLine(const btVector3& from,const btVector3& to,const btVector3& color); virtual void drawSphere (const btVector3& p, btScalar radius, const btVector3& color); virtual void drawBox (const btVector3& boxMin, const btVector3& boxMax, const btVector3& color, btScalar alpha); virtual void drawTriangle(const btVector3& a,const btVector3& b,const btVector3& c,const btVector3& color,btScalar alpha); virtual void drawContactPoint(const btVector3& PointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color); virtual void reportErrorWarning(const char* warningString); virtual void draw3dText(const btVector3& location,const char* textString); virtual void setDebugMode(int debugMode); virtual int getDebugMode() const { return m_debugMode;} }; #endif//GL_DEBUG_DRAWER_H critterding-beta12.1/src/gl/gldebugdrawer.cpp0000644000175000017500000000747611242036113020257 0ustar bobkebobke #include "gldebugdrawer.h" // #include "GLDebugFont.h" // #include "GlutStuff.h" #include //printf debugging GLDebugDrawer::GLDebugDrawer() :m_debugMode(0) { } void GLDebugDrawer::drawLine(const btVector3& from,const btVector3& to,const btVector3& fromColor, const btVector3& toColor) { glBegin(GL_LINES); glColor3f(fromColor.getX(), fromColor.getY(), fromColor.getZ()); glVertex3d(from.getX(), from.getY(), from.getZ()); glColor3f(toColor.getX(), toColor.getY(), toColor.getZ()); glVertex3d(to.getX(), to.getY(), to.getZ()); glEnd(); } void GLDebugDrawer::drawLine(const btVector3& from,const btVector3& to,const btVector3& color) { // if (m_debugMode > 0) { glBegin(GL_LINES); glColor4f(color.getX(), color.getY(), color.getZ(),1.f); glVertex3d(from.getX(), from.getY(), from.getZ()); glVertex3d(to.getX(), to.getY(), to.getZ()); glEnd(); } } void GLDebugDrawer::drawSphere (const btVector3& p, btScalar radius, const btVector3& color) { glColor4f (color.getX(), color.getY(), color.getZ(), btScalar(1.0f)); glPushMatrix (); glTranslatef (p.getX(), p.getY(), p.getZ()); int lats = 5; int longs = 5; int i, j; for(i = 0; i <= lats; i++) { btScalar lat0 = SIMD_PI * (-btScalar(0.5) + (btScalar) (i - 1) / lats); btScalar z0 = radius*sin(lat0); btScalar zr0 = radius*cos(lat0); btScalar lat1 = SIMD_PI * (-btScalar(0.5) + (btScalar) i / lats); btScalar z1 = radius*sin(lat1); btScalar zr1 = radius*cos(lat1); glBegin(GL_QUAD_STRIP); for(j = 0; j <= longs; j++) { btScalar lng = 2 * SIMD_PI * (btScalar) (j - 1) / longs; btScalar x = cos(lng); btScalar y = sin(lng); glNormal3f(x * zr0, y * zr0, z0); glVertex3f(x * zr0, y * zr0, z0); glNormal3f(x * zr1, y * zr1, z1); glVertex3f(x * zr1, y * zr1, z1); } glEnd(); } glPopMatrix(); } void GLDebugDrawer::drawBox (const btVector3& boxMin, const btVector3& boxMax, const btVector3& color, btScalar alpha) { btVector3 halfExtent = (boxMax - boxMin) * btScalar(0.5f); btVector3 center = (boxMax + boxMin) * btScalar(0.5f); //glEnable(GL_BLEND); // Turn blending On //glBlendFunc(GL_SRC_ALPHA, GL_ONE); glColor4f (color.getX(), color.getY(), color.getZ(), alpha); glPushMatrix (); glTranslatef (center.getX(), center.getY(), center.getZ()); glScaled(2*halfExtent[0], 2*halfExtent[1], 2*halfExtent[2]); // glutSolidCube(1.0); glPopMatrix (); //glDisable(GL_BLEND); } void GLDebugDrawer::drawTriangle(const btVector3& a,const btVector3& b,const btVector3& c,const btVector3& color,btScalar alpha) { // if (m_debugMode > 0) { const btVector3 n=btCross(b-a,c-a).normalized(); glBegin(GL_TRIANGLES); glColor4f(color.getX(), color.getY(), color.getZ(),alpha); glNormal3d(n.getX(),n.getY(),n.getZ()); glVertex3d(a.getX(),a.getY(),a.getZ()); glVertex3d(b.getX(),b.getY(),b.getZ()); glVertex3d(c.getX(),c.getY(),c.getZ()); glEnd(); } } void GLDebugDrawer::setDebugMode(int debugMode) { m_debugMode = debugMode; } void GLDebugDrawer::draw3dText(const btVector3& location,const char* textString) { glRasterPos3f(location.x(), location.y(), location.z()); //BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),textString); } void GLDebugDrawer::reportErrorWarning(const char* warningString) { printf(warningString); } void GLDebugDrawer::drawContactPoint(const btVector3& pointOnB,const btVector3& normalOnB,btScalar distance,int lifeTime,const btVector3& color) { { btVector3 to=pointOnB+normalOnB*distance; const btVector3&from = pointOnB; glColor4f(color.getX(), color.getY(), color.getZ(),1.f); //glColor4f(0,0,0,1.f); glBegin(GL_LINES); glVertex3d(from.getX(), from.getY(), from.getZ()); glVertex3d(to.getX(), to.getY(), to.getZ()); glEnd(); glRasterPos3f(from.x(), from.y(), from.z()); char buf[12]; sprintf(buf," %d",lifeTime); //BMF_DrawString(BMF_GetFont(BMF_kHelvetica10),buf); } } critterding-beta12.1/src/gl/glscene.cpp0000644000175000017500000000077611256242330017062 0ustar bobkebobke #include "glscene.h" GLScene::GLScene() { } void GLScene::init() { } void GLScene::draw() { } void GLScene::handlekeyPressed(const SDLKey& key) { } void GLScene::handlekeyReleased(const SDLKey& key) { } void GLScene::handlemousebuttonPressed(int x, int y, const int&) { } void GLScene::handlemousebuttonReleased(int x, int y, const int&) { } void GLScene::handleMouseMotionRel(int x, int y) { } void GLScene::handleMouseMotionAbs(int x, int y) { } void GLScene::clean() { } GLScene::~GLScene() { } critterding-beta12.1/src/gl/glwindow.h0000644000175000017500000000167711301116254016736 0ustar bobkebobke#ifndef GLWINDOW_H #define GLWINDOW_H #include // #include // #include #include "../gui/textprinter.h" #include "../utils/displaylists.h" #include "../utils/settings.h" #include "glscene.h" class GLWindow { public: GLWindow(); ~GLWindow(); // create the XFree86 window, with a GLX context. void create(const char* title, int width, int height); // Destroy window and OpenGL Context, close the Display // void destroy(); // Main loop for the program. void runGLScene(GLScene* glscene); private: // Resize Window void resize(); void toggleFs(); unsigned int w_bpp; // Bits Per Pixel. With XFree86, highest = 24 int w_width; int w_height; int n_width; int n_height; unsigned int fs; SDL_Surface* surface; const SDL_VideoInfo* vidInfo; int vidFlags; bool hwaccel; const unsigned int* settingsfs; int mousex; int mousey; SDL_Event event; }; #endif // GLWINDOW_H critterding-beta12.1/src/gl/glwindow.cpp0000644000175000017500000001042511344065077017275 0ustar bobkebobke#include "glwindow.h" GLWindow::GLWindow() { } void GLWindow::create(const char* title, int width, int height) { if( SDL_Init(SDL_INIT_VIDEO) < 0 ) { cerr << "Video initialization failed: " << SDL_GetError() << endl; exit(1); } vidInfo = SDL_GetVideoInfo(); w_bpp = vidInfo->vfmt->BitsPerPixel; if ( !vidInfo ) { cerr << "Cannot get video information: " << SDL_GetError() << endl; exit(1); } vidFlags = SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_HWPALETTE; hwaccel = false; if( vidInfo->hw_available ) { hwaccel = true; vidFlags |= SDL_HWSURFACE; } else vidFlags |= SDL_SWSURFACE; if( vidInfo->blit_hw != 0 ) vidFlags |= SDL_HWACCEL; SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 4); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 4); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 4); SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 4); // SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_WM_SetCaption(title, 0); // SDL_WM_SetIcon(SDL_LoadBMP("other files/critterding icon.png"), 0); // SDL_WM_SetIcon(SDL_LoadBMP("other files/cd.bmp"), 0); string pixmappath = Settings::Instance()->binarypath; pixmappath.append( "../share/critterding/pixmaps/cd.bmp" ); SDL_WM_SetIcon(SDL_LoadBMP(pixmappath.c_str()), 0); // SDL_WM_SetIcon(SDL_LoadBMP("/projects/lessons/lesson20/data/image2.bmp"), 0); w_width = width; w_height = height; n_width = width; n_height = height; Settings::Instance()->winWidth = &w_width; Settings::Instance()->winHeight = &w_height; settingsfs = Settings::Instance()->getCVarPtr("fullscreen"); fs = *settingsfs; if ( fs == 1 ) surface = SDL_SetVideoMode( w_width, w_height, w_bpp, vidFlags | SDL_FULLSCREEN ); else surface = SDL_SetVideoMode( w_width, w_height, w_bpp, vidFlags | SDL_RESIZABLE ); cerr << "SDL: subsystem initialized\n"; // cerr << "Video " << front.width() << "x" << front.height() << "x" << int(front.getSurface()->format->BitsPerPixel) << "\n"; // cerr << "Render Mode: " << ((hwaccel) ? "Direct Rendering" : "Software Rendering") << "\n"; // cerr << "Hardware Blit Acceleration: " << ((vidInfo->blit_hw) ? "Yes": "No") << "\n"; } void GLWindow::resize() { if ( w_height == 0 ) w_height = 1; if ( w_width == 0 ) w_width = 1; #ifndef _WIN32 SDL_FreeSurface(surface); surface = SDL_SetVideoMode( w_width, w_height, w_bpp, vidFlags | SDL_RESIZABLE ); #endif } void GLWindow::toggleFs() { if ( fs ) { if ( w_height == 0 ) w_height = 1; if ( w_width == 0 ) w_width = 1; SDL_FreeSurface(surface); n_width = w_width; n_height = w_height; w_width = Settings::Instance()->getCVar("fsX"); w_height = Settings::Instance()->getCVar("fsY"); surface = SDL_SetVideoMode( w_width, w_height, w_bpp, vidFlags | SDL_FULLSCREEN ); Displaylists::Instance()->generateList(); Textprinter::Instance()->setUpFonts(); } else { SDL_FreeSurface(surface); w_width = n_width; w_height = n_height; surface = SDL_SetVideoMode( w_width, w_height, w_bpp, vidFlags | SDL_RESIZABLE ); Displaylists::Instance()->generateList(); Textprinter::Instance()->setUpFonts(); } } void GLWindow::runGLScene(GLScene* glscene) { bool stop = false; while(!stop) { if ( fs != *settingsfs ) { fs = *settingsfs; toggleFs(); } while(SDL_PollEvent(&event)) { if(event.type == SDL_VIDEORESIZE) { w_width = event.resize.w; w_height = event.resize.h; resize(); } else if(event.type == SDL_QUIT) stop = true; else if(event.type == SDL_KEYDOWN) glscene->handlekeyPressed( event.key.keysym.sym ); else if(event.type == SDL_KEYUP) glscene->handlekeyReleased( event.key.keysym.sym ); else if (event.type == SDL_MOUSEBUTTONDOWN) { SDL_GetMouseState(&mousex, &mousex); glscene->handlemousebuttonPressed( mousex, mousex, event.button.button ); } else if (event.type == SDL_MOUSEBUTTONUP) { SDL_GetMouseState(&mousex, &mousex); glscene->handlemousebuttonReleased( mousex, mousex, event.button.button ); } else if(event.type == SDL_MOUSEMOTION) { glscene->handleMouseMotionRel( event.motion.xrel, event.motion.yrel ); glscene->handleMouseMotionAbs( event.motion.x, event.motion.y ); } } glscene->draw(); } SDL_Quit(); exit(0); } GLWindow::~GLWindow() { } critterding-beta12.1/src/brainz/0000755000175000017500000000000011347266042015616 5ustar bobkebobkecritterding-beta12.1/src/brainz/Makefile.am0000644000175000017500000000067411337071441017655 0ustar bobkebobkeINCLUDES = $(all_includes) METASOURCES = AUTO noinst_LTLIBRARIES = libbrainz.la libbrainz_la_LDFLAGS = -avoid-version -no-undefined noinst_HEADERS = archneuronz.h \ archsynapse.h \ brainzarch.h \ brainz.h \ neuroninterz.h \ synapse.h libbrainz_la_SOURCES = archneuronz.cpp \ archsynapse.cpp \ brainzarch.cpp \ brainz.cpp \ neuroninterz.cpp \ synapse.cpp libbrainz_la_LIBADD = $(top_builddir)/src/utils/libutils.la critterding-beta12.1/src/brainz/brainz.h0000644000175000017500000000231511337071441017251 0ustar bobkebobke#ifndef BRAINZ_H #define BRAINZ_H // internal includes #include "brainzarch.h" #include "neuroninterz.h" // external includes #include #include #include using namespace std; struct motorNeuron { bool* output; unsigned int id; }; struct sensorNeuron { float output; unsigned int id; }; class Brainz { public: Brainz(); ~Brainz(); // input / output accessor/mutators vector Inputs; vector Outputs; // vectors vector Neurons; // BUILD TIME // fixed numbers of inputs/outputs unsigned int numberOfInputs; unsigned int numberOfOutputs; // INFO // total neuron & connection keepers unsigned int totalNeurons; unsigned int totalSynapses; // after every time instance, this will contain how many neurons where fired in that instant (energy usage help) unsigned int neuronsFired; unsigned int motorneuronsFired; // build void registerOutput(bool* var, unsigned int id); void registerInput(unsigned int id); void wireArch(BrainzArch* brainzArch); // RUN TIME // functions void clearInputs(); void process(); void processTillAnswer(); private: }; #endif critterding-beta12.1/src/brainz/synapse.cpp0000644000175000017500000000011111016665070017772 0ustar bobkebobke#include "synapse.h" Synapse::Synapse() { } Synapse::~Synapse() { } critterding-beta12.1/src/brainz/synapse.h0000644000175000017500000000045611075474420017455 0ustar bobkebobke#ifndef SYNAPSE_H #define SYNAPSE_H class Synapse { public: Synapse(); ~Synapse(); // InputNeuron's Output Pointer //int *ref; float *ref; // dendridic branch synapse is located on float dendriteBranch; // it's synaptic weight -1.0f <-> +1.0f float weight; private: }; #endif critterding-beta12.1/src/brainz/archneuronz.cpp0000644000175000017500000000052411240127074020652 0ustar bobkebobke#include "archneuronz.h" ArchNeuronz::ArchNeuronz() { isInhibitory = false; hasConsistentSynapses = false; hasInhibitorySynapses = false; firingThreshold = 100; dendridicBranches = 10; isMotor = false; motorID = 0; isPlastic = false; plasticityStrengthen = 1; plasticityWeaken = 1; } ArchNeuronz::~ArchNeuronz() { } critterding-beta12.1/src/brainz/brainzarch.cpp0000644000175000017500000014246511340355604020455 0ustar bobkebobke#include "brainzarch.h" #include BrainzArch::BrainzArch() { neuronsFired = 0; // build time defaults maxNeurons = 150; minSynapses = 1; maxSynapses = 150; totalNeurons = 0; totalSynapses = 0; numberOfInputs = 0; numberOfOutputs = 0; minNeuronsAtBuildtime = 10; maxNeuronsAtBuildtime = 150; // mutatables minSynapsesAtBuildtime = 1; maxSynapsesAtBuildtime = 50; percentChanceInhibitoryNeuron = 50; mutate_percentChanceInhibitoryNeuron = false; percentChanceConsistentSynapses = 50; mutate_percentChanceConsistentSynapses = false; percentChanceInhibitorySynapses = 50; mutate_percentChanceInhibitorySynapses = false; percentChanceMotorNeuron = 50; mutate_percentChanceMotorNeuron = false; percentChancePlasticNeuron = 50; mutate_percentChancePlasticNeuron = false; minPlasticityStrengthen = 100; maxPlasticityStrengthen = 1000; minPlasticityWeaken = 1000; maxPlasticityWeaken = 10000; mutate_PlasticityFactors = false; percentChanceSensorySynapse = 50; mutate_percentChanceSensorySynapse = false; minFiringThreshold = 10; mutate_minFiringThreshold = false; maxFiringThreshold = 100; mutate_maxFiringThreshold = false; maxDendridicBranches = 20; mutate_maxDendridicBranches = false; percentMutation = 1; mutate_percentMutation = false; // 90 % > 10 for mutatables percentMutateEffectAddNeuron = 5; percentMutateEffectRemoveNeuron = 5; percentMutateEffectAlterNeuron = 5; percentMutateEffectAddSynapse = 40; percentMutateEffectRemoveSynapse = 40; percentMutateEffectAlterMutable = 5; mutate_MutateEffects = false; } // BUILD TIME void BrainzArch::registerInput(unsigned int id) { /* Inputs.push_back( sensorNeuron() ); Inputs[numberOfInputs].id = id;*/ InputIDs.push_back(id); numberOfInputs++; } void BrainzArch::registerOutput(unsigned int id) { // Outputs.push_back( motorNeuron() ); // Outputs[numberOfOutputs].output = var; // Outputs[numberOfOutputs].id = id; OutputIDs.push_back(id); numberOfOutputs++; } void BrainzArch::removeObsoleteMotorsAndSensors() { // cerr << endl << "removing obsolete brainstuff" << endl; for ( int i = 0; i < (int)ArchNeurons.size(); i++ ) { ArchNeuronz* an = &ArchNeurons[i]; // disable motor neurons if ( an->isMotor ) { if ( findMotorNeuron( an->motorID ) == -1 ) { an->isMotor = false; } } // disable sensor inputs for ( int j = 0; j < (int)an->ArchSynapses.size(); j++ ) { ArchSynapse* as = &an->ArchSynapses[j]; if ( as->isSensorNeuron ) { if ( findSensorNeuron( as->neuronID ) == -1 ) { an->ArchSynapses.erase( an->ArchSynapses.begin()+j ); j--; } } } } // cerr << "done removing obsolete brainstuff" << endl << endl; } void BrainzArch::buildArch() { // clear architecture by removing all architectural neurons ArchNeurons.clear(); // determine number of neurons this brain will start with unsigned int NeuronAmount = randgen->Instance()->get( minNeuronsAtBuildtime, maxNeuronsAtBuildtime ); // create the architectural neurons for ( unsigned i = 0; i < NeuronAmount; i++ ) addRandomArchNeuron(); // create architectural synapses for ( unsigned neuronID = 0; neuronID < NeuronAmount; neuronID++ ) { // determine amount of synapses this neuron will start with unsigned int SynapseAmount = randgen->Instance()->get( minSynapsesAtBuildtime, maxSynapsesAtBuildtime ); // create the architectural neurons for ( unsigned j = 0; j < SynapseAmount; j++ ) addRandomArchSynapse(neuronID); } } void BrainzArch::addRandomArchNeuron() { // new architectural neuron ArchNeuronz an; // is it inhibitory ? if ( randgen->Instance()->get(1,100) <= percentChanceInhibitoryNeuron ) an.isInhibitory = true; // if not, is it motor ? // if 1 or 2nd archneuron, pic eat & procreate specifically else if ( randgen->Instance()->get(1,100) <= percentChanceMotorNeuron || ArchNeurons.size() < 3 ) { unsigned int motorID; if ( ArchNeurons.size() == 0 ) motorID = OutputIDs[ numberOfOutputs-2 ]; else if ( ArchNeurons.size() == 1 ) motorID = OutputIDs[ numberOfOutputs-1 ]; else motorID = OutputIDs[ randgen->Instance()->get( 0, numberOfOutputs-1 ) ]; // check if motor already used bool proceed = true; for ( unsigned int i=0; i < ArchNeurons.size() && proceed; i++ ) if ( ArchNeurons[i].isMotor && ArchNeurons[i].motorID == motorID ) proceed = false; if ( proceed ) { an.isMotor = true; an.motorID = motorID; } } // does it have synaptic plasticity ? if ( randgen->Instance()->get(1,100) <= percentChancePlasticNeuron ) { an.isPlastic = true; an.plasticityStrengthen = randgen->Instance()->get( minPlasticityStrengthen, maxPlasticityStrengthen ); an.plasticityWeaken = randgen->Instance()->get( minPlasticityWeaken, maxPlasticityWeaken ); } // does it have consistent synapses ? if ( randgen->Instance()->get(1,100) <= percentChanceConsistentSynapses ) { an.hasConsistentSynapses = true; // if so, does it have inhibitory synapses ? if ( randgen->Instance()->get(1,100) <= percentChanceInhibitorySynapses ) an.hasInhibitorySynapses = true; } // determine firing threshold if ( an.isMotor ) an.firingThreshold = maxFiringThreshold; else an.firingThreshold = randgen->Instance()->get( minFiringThreshold, maxFiringThreshold ); // determine dendritic branches if ( an.isMotor ) an.dendridicBranches = maxDendridicBranches; else an.dendridicBranches = randgen->Instance()->get( 1, maxDendridicBranches ); // push it on the vector ArchNeurons.push_back( an ); } unsigned int BrainzArch::addRandomArchSynapse(unsigned int parentneuron) { // new architectural synapse ArchSynapse as; // is it connected to a sensor neuron ? // < 2 because if only 1 archneuron, it can't connect to other one if ( randgen->Instance()->get( 1, 100 ) <= percentChanceSensorySynapse || ArchNeurons.size() < 2 ) { as.isSensorNeuron = true; // sensor neuron id synapse is connected to as.neuronID = InputIDs[ randgen->Instance()->get( 0, numberOfInputs-1 ) ]; } // if not determine inter neuron id else { // as in real life, neurons can connect to themselves as.neuronID = randgen->Instance()->get( 0, ArchNeurons.size()-1 ); } // dendrite branch number as.dendriteBranch = randgen->Instance()->get( 1, ArchNeurons[parentneuron].dendridicBranches ); // synaptic weight if ( ArchNeurons[parentneuron].hasConsistentSynapses ) { if ( ArchNeurons[parentneuron].hasInhibitorySynapses ) as.weight =-1.0f; else as.weight =1.0f; } else { if ( randgen->Instance()->get(1,100) <= percentChanceInhibitorySynapses ) as.weight =-1.0f; else as.weight =1.0f; } // push it on the vector ArchNeurons[parentneuron].ArchSynapses.push_back( as ); // return it's id return (ArchNeurons[parentneuron].ArchSynapses.size()-1); } int BrainzArch::findSensorNeuron( unsigned int id ) { for ( unsigned int i=0; i < numberOfInputs; i++ ) if ( InputIDs[i] == id ) return i; // cerr << "brain findSensorNeuron error for id: " << id << endl; return -1; } int BrainzArch::findMotorNeuron( unsigned int id ) { for ( unsigned int i=0; i < numberOfOutputs; i++ ) if ( OutputIDs[i] == id ) return i; // cerr << "brain findMotorNeuron error for id: " << id << endl; return -1; } void BrainzArch::mutate(unsigned int runs) { // have to do count cuz wireArch not done yet totalNeurons = ArchNeurons.size(); totalSynapses = 0; for ( unsigned int i = 0; i < totalNeurons; i++ ) totalSynapses += ArchNeurons[i].ArchSynapses.size(); if ( runs == 0 ) { runs = randgen->Instance()->get(1, (int)(totalSynapses/(100/percentMutation))); } for ( unsigned int i=0; i < runs; i++ ) { unsigned int tsum = percentMutateEffectAddNeuron + percentMutateEffectRemoveNeuron + percentMutateEffectAlterNeuron + percentMutateEffectAddSynapse + percentMutateEffectRemoveSynapse + percentMutateEffectAlterMutable ; unsigned int mode = randgen->Instance()->get(1,tsum); // add a new neuron unsigned int modesum = percentMutateEffectAddNeuron; if ( mode <= modesum ) { if ( ArchNeurons.size() < maxNeurons ) { addRandomArchNeuron(); unsigned int nid = ArchNeurons.size()-1; //cerr << "\t+N " << nid << endl; // random amount of connections, at mutation time we take the average syns / neuron *2 as a maximum unsigned int tNeurons = totalNeurons; if ( tNeurons == 0 ) tNeurons = 1; int maxSynapsesAtMutation = (2*(totalSynapses/tNeurons)) + 1; unsigned int cAmount = randgen->Instance()->get( minSynapsesAtBuildtime, maxSynapsesAtMutation ); for ( unsigned j = 0; j < cAmount; j++ ) addRandomArchSynapse(nid); } else runs++; continue; } // remove a neuron modesum += percentMutateEffectRemoveNeuron; if ( mode <= modesum ) { if ( ArchNeurons.size() > 0 ) { // pick a random neuron unsigned int nid = randgen->Instance()->get( 0, ArchNeurons.size()-1 ); //cerr << "\t-N " << nid << endl; // first remove all connections to this neuron for ( unsigned int i=0; i < ArchNeurons.size(); i++ ) { for ( unsigned int j=0; j < ArchNeurons[i].ArchSynapses.size(); j++ ) { if ( !ArchNeurons[i].ArchSynapses[j].isSensorNeuron ) { if ( ArchNeurons[i].ArchSynapses[j].neuronID == nid ) { //delete ArchNeurons[i].ArchSynapses[j]; ArchNeurons[i].ArchSynapses.erase(ArchNeurons[i].ArchSynapses.begin()+j); j--; } // if higher id drop one else if ( ArchNeurons[i].ArchSynapses[j].neuronID > nid ) { ArchNeurons[i].ArchSynapses[j].neuronID--; } } } } ArchNeurons.erase(ArchNeurons.begin()+nid); } // make sure we mutate else runs++; continue; } // alter a neuron modesum += percentMutateEffectAlterNeuron; if ( mode <= modesum ) { if ( ArchNeurons.size() > 0 ) { // pick a random neuron unsigned int nid = randgen->Instance()->get( 0, ArchNeurons.size()-1 ); // decide what to alter unsigned int jmode = randgen->Instance()->get(1,6); // inhibitory function if ( jmode == 1 ) { // backup old bool old = ArchNeurons[nid].isInhibitory; // reset ArchNeurons[nid].isInhibitory = false; // redetermine if ( randgen->Instance()->get(1,100) <= percentChanceInhibitoryNeuron ) ArchNeurons[nid].isInhibitory = true; // make sure we mutate if ( old == ArchNeurons[nid].isInhibitory ) runs++; } // motor neuron else if ( jmode == 2 ) { // backup old bool old = ArchNeurons[nid].isMotor; unsigned int oldfunc = ArchNeurons[nid].motorID; // reset ArchNeurons[nid].isMotor = false; ArchNeurons[nid].motorID = 0; // redetermine if ( !ArchNeurons[nid].isInhibitory && randgen->Instance()->get(1,100) <= percentChanceMotorNeuron ) { unsigned int motorID = OutputIDs[ randgen->Instance()->get( 0, numberOfOutputs-1 ) ]; bool proceed = true; for ( unsigned int i=0; i < ArchNeurons.size() && proceed; i++ ) if ( ArchNeurons[i].isMotor && ArchNeurons[i].motorID == motorID ) proceed = false; if ( proceed ) { ArchNeurons[nid].isMotor = true; ArchNeurons[nid].motorID = motorID; } } // make sure we mutate if ( old == ArchNeurons[nid].isMotor && oldfunc == ArchNeurons[nid].motorID ) runs++; } // synaptic plasticity else if ( jmode == 3 ) { // backup old bool old = ArchNeurons[nid].isPlastic; unsigned int olds = ArchNeurons[nid].plasticityStrengthen; unsigned int oldw = ArchNeurons[nid].plasticityWeaken; // reset ArchNeurons[nid].isPlastic = false; ArchNeurons[nid].plasticityStrengthen = 1; ArchNeurons[nid].plasticityWeaken = 1; // redetermine if ( randgen->Instance()->get(1,100) <= percentChancePlasticNeuron ) { ArchNeurons[nid].isPlastic = true; ArchNeurons[nid].plasticityStrengthen = randgen->Instance()->get( minPlasticityStrengthen, maxPlasticityStrengthen ); ArchNeurons[nid].plasticityWeaken = randgen->Instance()->get( minPlasticityWeaken, maxPlasticityWeaken ); } // make sure we mutate if ( old == ArchNeurons[nid].isPlastic && olds == ArchNeurons[nid].plasticityStrengthen && oldw == ArchNeurons[nid].plasticityWeaken ) runs++; } // consistent synapses else if ( jmode == 4 ) { // backup old bool old = ArchNeurons[nid].hasConsistentSynapses; bool oldi = ArchNeurons[nid].hasInhibitorySynapses; // reset ArchNeurons[nid].hasConsistentSynapses = false; // redetermine if ( randgen->Instance()->get(1,100) <= percentChanceConsistentSynapses ) { ArchNeurons[nid].hasConsistentSynapses = true; // if so, does it have inhibitory synapses ? if ( randgen->Instance()->get(1,100) <= percentChanceInhibitorySynapses ) ArchNeurons[nid].hasInhibitorySynapses = true; } // make sure we mutate if ( old == ArchNeurons[nid].hasConsistentSynapses && oldi == ArchNeurons[nid].hasInhibitorySynapses ) runs++; } // firing threshold else if ( jmode == 5 ) { // backup old unsigned int old = ArchNeurons[nid].firingThreshold; ArchNeurons[nid].firingThreshold = randgen->Instance()->get( minFiringThreshold, maxFiringThreshold ); // make sure we mutate if ( old == ArchNeurons[nid].firingThreshold ) runs++; } // dendritic branches else if ( jmode == 6 ) { // backup old unsigned int old = ArchNeurons[nid].dendridicBranches; ArchNeurons[nid].dendridicBranches = randgen->Instance()->get( 1, maxDendridicBranches ); // make sure we mutate if ( old == ArchNeurons[nid].dendridicBranches ) runs++; } } else runs++; continue; } // add a new synapse modesum += percentMutateEffectAddSynapse; if ( mode <= modesum ) { if ( ArchNeurons.size() > 0 ) { // pick a random neuron unsigned int nid = randgen->Instance()->get( 0, ArchNeurons.size()-1 ); // don't go over maximum connections if ( ArchNeurons[nid].ArchSynapses.size() < maxSynapses ) { //cerr << "\t+C " << nid << endl; addRandomArchSynapse(nid); } else runs++; } else runs++; continue; } // remove a synapse modesum += percentMutateEffectRemoveSynapse; if ( mode <= modesum ) { if ( ArchNeurons.size() > 0 ) { // pick a random neuron unsigned int nid = randgen->Instance()->get( 0, ArchNeurons.size()-1 ); // don't go under minimum connections if ( ArchNeurons[nid].ArchSynapses.size() > minSynapses ) { //cerr << "\t-C " << nid << endl; unsigned int sID = randgen->Instance()->get(0, ArchNeurons[nid].ArchSynapses.size()-1); //delete ArchNeurons[nid].ArchSynapses[connid]; ArchNeurons[nid].ArchSynapses.erase(ArchNeurons[nid].ArchSynapses.begin()+sID); } else runs++; } else runs++; continue; } // change a mutatable modesum += percentMutateEffectAlterMutable; if ( mode <= modesum ) { unsigned int imode = randgen->Instance()->get(1,12); if ( imode == 1 && mutate_percentChanceInhibitoryNeuron ) { unsigned int jmode = randgen->Instance()->get(1,2); unsigned int factor = randgen->Instance()->get(1,5); if ( jmode == 1 && percentChanceInhibitoryNeuron < 100-factor ) percentChanceInhibitoryNeuron+=factor; else if ( percentChanceInhibitoryNeuron > 0+factor ) percentChanceInhibitoryNeuron-=factor; } else if ( imode == 2 && mutate_percentChanceConsistentSynapses ) { unsigned int jmode = randgen->Instance()->get(1,2); unsigned int factor = randgen->Instance()->get(1,5); if ( jmode == 1 && percentChanceConsistentSynapses < 100-factor ) percentChanceConsistentSynapses+=factor; else if ( percentChanceConsistentSynapses > 0+factor ) percentChanceConsistentSynapses-=factor; } else if ( imode == 3 && mutate_percentChanceInhibitorySynapses ) { unsigned int jmode = randgen->Instance()->get(1,2); unsigned int factor = randgen->Instance()->get(1,5); if ( jmode == 1 && percentChanceInhibitorySynapses < 100-factor ) percentChanceInhibitorySynapses+=factor; else if ( percentChanceInhibitorySynapses > 0+factor ) percentChanceInhibitorySynapses-=factor; } else if ( imode == 4 && mutate_percentChanceMotorNeuron ) { unsigned int jmode = randgen->Instance()->get(1,2); unsigned int factor = randgen->Instance()->get(1,5); if ( jmode == 1 && percentChanceMotorNeuron < 100-factor ) percentChanceMotorNeuron+=factor; else if ( percentChanceMotorNeuron > 0+factor ) percentChanceMotorNeuron-=factor; // !!! > 1 } else if ( imode == 5 && mutate_percentChancePlasticNeuron ) { unsigned int jmode = randgen->Instance()->get(1,2); unsigned int factor = randgen->Instance()->get(1,5); if ( jmode == 1 && percentChancePlasticNeuron < 100-factor ) percentChancePlasticNeuron+=factor; else if ( percentChancePlasticNeuron > 0+factor ) percentChancePlasticNeuron-=factor; } else if ( imode == 6 && mutate_percentChanceSensorySynapse ) { unsigned int jmode = randgen->Instance()->get(1,2); unsigned int factor = randgen->Instance()->get(1,5); if ( jmode == 1 && percentChanceSensorySynapse < 100-factor ) percentChanceSensorySynapse+=factor; else if ( percentChanceSensorySynapse > minSynapses+factor ) percentChanceSensorySynapse-=factor; } else if ( imode == 7 && mutate_minFiringThreshold ) { unsigned int jmode = randgen->Instance()->get(1,2); unsigned int factor = randgen->Instance()->get(1,5); if ( jmode == 1 && minFiringThreshold < maxFiringThreshold-factor ) minFiringThreshold+=factor; // watch out idd else if ( minFiringThreshold > 1+factor ) minFiringThreshold-=factor; // !!! > 1 } else if ( imode == 8 && mutate_maxFiringThreshold ) { unsigned int jmode = randgen->Instance()->get(1,2); unsigned int factor = randgen->Instance()->get(1,5); if ( jmode == 1 && maxFiringThreshold < 1000-factor ) maxFiringThreshold+=factor; else if ( maxFiringThreshold > minFiringThreshold+factor ) maxFiringThreshold-=factor; // !!! > minFiringThreshold } else if ( imode == 9 && mutate_maxDendridicBranches ) { unsigned int jmode = randgen->Instance()->get(1,2); unsigned int factor = randgen->Instance()->get(1,5); if ( jmode == 1 && maxDendridicBranches < 100-factor ) maxDendridicBranches+=factor; else if ( maxDendridicBranches > 1+factor ) maxDendridicBranches-=factor; // !!! > 1 } else if ( imode == 10 && mutate_percentMutation ) { unsigned int jmode = randgen->Instance()->get(1,2); unsigned int factor = randgen->Instance()->get(1,5); if ( jmode == 1 && percentMutation < 100-factor ) percentMutation+=factor; else if ( percentMutation > 1+factor ) percentMutation-=factor; // !!! > 1 or no more mutation at all } else if ( imode == 11 && mutate_MutateEffects ) { // up or down unsigned int jmode = randgen->Instance()->get(1,2); // which of 5 unsigned int kmode = randgen->Instance()->get(1,6); if ( jmode == 1 && percentMutateEffectAddNeuron + percentMutateEffectRemoveNeuron + percentMutateEffectAlterNeuron + percentMutateEffectAddSynapse + percentMutateEffectRemoveSynapse + percentMutateEffectAlterMutable <= 100 ) { if ( kmode == 1 ) percentMutateEffectAddNeuron++; else if ( kmode == 2 ) percentMutateEffectRemoveNeuron++; else if ( kmode == 3 ) percentMutateEffectAlterNeuron++; else if ( kmode == 4 ) percentMutateEffectAddSynapse++; else if ( kmode == 5 ) percentMutateEffectRemoveSynapse++; else if ( kmode == 6 ) percentMutateEffectAlterMutable++; } else if ( jmode == 2 ) { if ( kmode == 1 && percentMutateEffectAddNeuron > 0 ) percentMutateEffectAddNeuron--; else if ( kmode == 2 && percentMutateEffectRemoveNeuron > 0 ) percentMutateEffectRemoveNeuron--; else if ( kmode == 3 && percentMutateEffectAlterNeuron > 0 ) percentMutateEffectAlterNeuron--; else if ( kmode == 4 && percentMutateEffectAddSynapse > 0 ) percentMutateEffectAddSynapse--; else if ( kmode == 5 && percentMutateEffectRemoveSynapse > 0 ) percentMutateEffectRemoveSynapse--; else if ( kmode == 6 && percentMutateEffectAlterMutable > 0 ) percentMutateEffectAlterMutable--; } } else if ( imode == 12 && mutate_PlasticityFactors ) { // up or down unsigned int jmode = randgen->Instance()->get(1,2); // which of 4 unsigned int kmode = randgen->Instance()->get(1,4); // factor unsigned int factor = randgen->Instance()->get(10,1000); if ( jmode == 1 ) { if ( kmode == 1 && minPlasticityStrengthen+factor < maxPlasticityStrengthen ) minPlasticityStrengthen+=factor; else if ( kmode == 2 && maxPlasticityStrengthen+factor < 1000000 ) maxPlasticityStrengthen+=factor; else if ( kmode == 3 && minPlasticityWeaken+factor < maxPlasticityWeaken ) minPlasticityWeaken+=factor; else if ( kmode == 4 && maxPlasticityWeaken+factor < 1000000 ) maxPlasticityWeaken+=factor; } else { if ( kmode == 1 && minPlasticityStrengthen > 10+factor ) minPlasticityStrengthen-=factor; else if ( kmode == 2 && maxPlasticityStrengthen > minPlasticityStrengthen+factor ) maxPlasticityStrengthen-=factor; else if ( kmode == 3 && minPlasticityWeaken > 100+factor ) minPlasticityWeaken-=factor; else if ( kmode == 4 && maxPlasticityWeaken > minPlasticityWeaken+factor ) maxPlasticityWeaken-=factor; } } else runs++; } else runs++; continue; } } // RUN TIME void BrainzArch::copyFrom(const BrainzArch* otherBrain) { maxNeurons = otherBrain->maxNeurons; minSynapses = otherBrain->minSynapses; maxSynapses = otherBrain->maxSynapses; percentChanceInhibitoryNeuron = otherBrain->percentChanceInhibitoryNeuron; mutate_percentChanceInhibitoryNeuron = otherBrain->mutate_percentChanceInhibitoryNeuron; percentChanceMotorNeuron = otherBrain->percentChanceMotorNeuron; mutate_percentChanceMotorNeuron = otherBrain->mutate_percentChanceMotorNeuron; percentChancePlasticNeuron = otherBrain->percentChancePlasticNeuron; mutate_percentChancePlasticNeuron = otherBrain->mutate_percentChancePlasticNeuron; minPlasticityStrengthen = otherBrain->minPlasticityStrengthen; maxPlasticityStrengthen = otherBrain->maxPlasticityStrengthen; minPlasticityWeaken = otherBrain->minPlasticityWeaken; maxPlasticityWeaken = otherBrain->maxPlasticityWeaken; mutate_PlasticityFactors = otherBrain->mutate_PlasticityFactors; minFiringThreshold = otherBrain->minFiringThreshold; mutate_minFiringThreshold = otherBrain->mutate_minFiringThreshold; maxFiringThreshold = otherBrain->maxFiringThreshold; mutate_maxFiringThreshold = otherBrain->mutate_maxFiringThreshold; maxDendridicBranches = otherBrain->maxDendridicBranches; mutate_maxDendridicBranches = otherBrain->mutate_maxDendridicBranches; percentChanceConsistentSynapses = otherBrain->percentChanceConsistentSynapses; mutate_percentChanceConsistentSynapses = otherBrain->mutate_percentChanceConsistentSynapses; percentChanceInhibitorySynapses = otherBrain->percentChanceInhibitorySynapses; mutate_percentChanceInhibitorySynapses = otherBrain->mutate_percentChanceInhibitorySynapses; percentChanceSensorySynapse = otherBrain->percentChanceSensorySynapse; mutate_percentChanceSensorySynapse = otherBrain->mutate_percentChanceSensorySynapse; percentMutateEffectAddNeuron = otherBrain->percentMutateEffectAddNeuron; percentMutateEffectRemoveNeuron = otherBrain->percentMutateEffectRemoveNeuron; percentMutateEffectAlterNeuron = otherBrain->percentMutateEffectAlterNeuron; percentMutateEffectAddSynapse = otherBrain->percentMutateEffectAddSynapse; percentMutateEffectRemoveSynapse = otherBrain->percentMutateEffectRemoveSynapse; percentMutateEffectAlterMutable = otherBrain->percentMutateEffectAlterMutable; mutate_MutateEffects = otherBrain->mutate_MutateEffects; for ( unsigned int i = 0; i < otherBrain->ArchNeurons.size(); i++ ) { ArchNeuronz an; const ArchNeuronz *oan = &otherBrain->ArchNeurons[i]; an.isInhibitory = oan->isInhibitory; an.hasConsistentSynapses = oan->hasConsistentSynapses; an.hasInhibitorySynapses = oan->hasInhibitorySynapses; an.firingThreshold = oan->firingThreshold; an.dendridicBranches = oan->dendridicBranches; an.isMotor = oan->isMotor; an.motorID = oan->motorID; an.isPlastic = oan->isPlastic; an.isPlastic = oan->isPlastic; an.plasticityStrengthen = oan->plasticityStrengthen; an.plasticityWeaken = oan->plasticityWeaken; // inputs for ( unsigned int j = 0; j < oan->ArchSynapses.size(); j++ ) { ArchSynapse as; const ArchSynapse *oas = &oan->ArchSynapses[j]; as.isSensorNeuron = oas->isSensorNeuron; as.neuronID = oas->neuronID; as.dendriteBranch = oas->dendriteBranch; as.weight = oas->weight; an.ArchSynapses.push_back( as ); } ArchNeurons.push_back( an ); } } void BrainzArch::mergeFrom(const BrainzArch* otherBrain1, const BrainzArch* otherBrain2) { maxNeurons = otherBrain1->maxNeurons; minSynapses = otherBrain1->minSynapses; maxSynapses = otherBrain1->maxSynapses; percentChanceInhibitoryNeuron = otherBrain1->percentChanceInhibitoryNeuron; mutate_percentChanceInhibitoryNeuron = otherBrain1->mutate_percentChanceInhibitoryNeuron; percentChanceMotorNeuron = otherBrain1->percentChanceMotorNeuron; mutate_percentChanceMotorNeuron = otherBrain1->mutate_percentChanceMotorNeuron; percentChancePlasticNeuron = otherBrain1->percentChancePlasticNeuron; mutate_percentChancePlasticNeuron = otherBrain1->mutate_percentChancePlasticNeuron; minPlasticityStrengthen = otherBrain1->minPlasticityStrengthen; maxPlasticityStrengthen = otherBrain1->maxPlasticityStrengthen; minPlasticityWeaken = otherBrain1->minPlasticityWeaken; maxPlasticityWeaken = otherBrain1->maxPlasticityWeaken; mutate_PlasticityFactors = otherBrain1->mutate_PlasticityFactors; minFiringThreshold = otherBrain1->minFiringThreshold; mutate_minFiringThreshold = otherBrain1->mutate_minFiringThreshold; maxFiringThreshold = otherBrain1->maxFiringThreshold; mutate_maxFiringThreshold = otherBrain1->mutate_maxFiringThreshold; maxDendridicBranches = otherBrain1->maxDendridicBranches; mutate_maxDendridicBranches = otherBrain1->mutate_maxDendridicBranches; percentChanceConsistentSynapses = otherBrain1->percentChanceConsistentSynapses; mutate_percentChanceConsistentSynapses = otherBrain1->mutate_percentChanceConsistentSynapses; percentChanceInhibitorySynapses = otherBrain1->percentChanceInhibitorySynapses; mutate_percentChanceInhibitorySynapses = otherBrain1->mutate_percentChanceInhibitorySynapses; percentChanceSensorySynapse = otherBrain1->percentChanceSensorySynapse; mutate_percentChanceSensorySynapse = otherBrain1->mutate_percentChanceSensorySynapse; percentMutateEffectAddNeuron = otherBrain1->percentMutateEffectAddNeuron; percentMutateEffectRemoveNeuron = otherBrain1->percentMutateEffectRemoveNeuron; percentMutateEffectAlterNeuron = otherBrain1->percentMutateEffectAlterNeuron; percentMutateEffectAddSynapse = otherBrain1->percentMutateEffectAddSynapse; percentMutateEffectRemoveSynapse = otherBrain1->percentMutateEffectRemoveSynapse; percentMutateEffectAlterMutable = otherBrain1->percentMutateEffectAlterMutable; mutate_MutateEffects = otherBrain1->mutate_MutateEffects; // take biggest unsigned int loops = otherBrain1->ArchNeurons.size(); if ( otherBrain2->ArchNeurons.size() < loops ) loops = otherBrain2->ArchNeurons.size(); bool even = false; for ( unsigned int i = 0; i < loops; i++ ) { even = !even; ArchNeuronz an; const ArchNeuronz *oan; if ( i < otherBrain1->ArchNeurons.size() && even ) oan = &otherBrain1->ArchNeurons[i]; else //if ( i < otherBrain2.ArchNeurons.size() && !even ) oan = &otherBrain2->ArchNeurons[i]; an.isInhibitory = oan->isInhibitory; an.hasConsistentSynapses = oan->hasConsistentSynapses; an.hasInhibitorySynapses = oan->hasInhibitorySynapses; an.firingThreshold = oan->firingThreshold; an.dendridicBranches = oan->dendridicBranches; an.isMotor = oan->isMotor; an.motorID = oan->motorID; an.isPlastic = oan->isPlastic; an.isPlastic = oan->isPlastic; an.plasticityStrengthen = oan->plasticityStrengthen; an.plasticityWeaken = oan->plasticityWeaken; // inputs for ( unsigned int j = 0; j < oan->ArchSynapses.size(); j++ ) { ArchSynapse as; const ArchSynapse *oas = &oan->ArchSynapses[j]; as.isSensorNeuron = oas->isSensorNeuron; as.neuronID = oas->neuronID; as.dendriteBranch = oas->dendriteBranch; as.weight = oas->weight; an.ArchSynapses.push_back( as ); } ArchNeurons.push_back( an ); } } // SERIALIZE FUNC void BrainzArch::setArch(string* content) { string contentCopy = *content; string line = parseH->Instance()->returnUntillStrip( "\n", contentCopy ); while ( !line.empty() ) { // neuron(ft=24|iwr=20|mtr=4|inputs(|s,78,6|s,186,-12|s,123,10|n,19,5|n,3,3|n,11,-19)); if ( parseH->Instance()->beginMatchesStrip( "n(", line ) ) { ArchNeuronz an; // unsigned int nid = (ArchNeurons.size()-1); if ( parseH->Instance()->beginMatchesStrip( "i=", line ) ) { string II = parseH->Instance()->returnUntillStrip( "|", line ); //cerr << "II: " << II << endl; int isIt; if(EOF == sscanf(II.c_str(), "%d", &isIt)) cerr << "ERROR INSERTING CRITTER" << endl; if ( isIt == 1 ) an.isInhibitory = true; } if ( parseH->Instance()->beginMatchesStrip( "cs=", line ) ) { string CS = parseH->Instance()->returnUntillStrip( "|", line ); //cerr << "II: " << II << endl; int isItC; if(EOF == sscanf(CS.c_str(), "%d", &isItC)) cerr << "ERROR INSERTING CRITTER" << endl; if ( isItC == 1 ) an.hasConsistentSynapses = true; if ( parseH->Instance()->beginMatchesStrip( "is=", line ) ) { string IS = parseH->Instance()->returnUntillStrip( "|", line ); //cerr << "II: " << II << endl; int isIt; if(EOF == sscanf(IS.c_str(), "%d", &isIt)) cerr << "ERROR INSERTING CRITTER" << endl; if ( isIt == 1 ) an.hasInhibitorySynapses = true; } } if ( parseH->Instance()->beginMatchesStrip( "f=", line ) ) { string FT = parseH->Instance()->returnUntillStrip( "|", line ); //cerr << "FT: " << FT << endl; if(EOF == sscanf(FT.c_str(), "%d", &an.firingThreshold)) cerr << "ERROR INSERTING CRITTER" << endl; } if ( parseH->Instance()->beginMatchesStrip( "d=", line ) ) { string DB = parseH->Instance()->returnUntillStrip( "|", line ); //cerr << "IWR: " << IWR << endl; if(EOF == sscanf(DB.c_str(), "%d", &an.dendridicBranches)) cerr << "ERROR INSERTING CRITTER" << endl; } if ( parseH->Instance()->beginMatchesStrip( "m=", line ) ) { string MTR = parseH->Instance()->returnUntillStrip( "|", line ); //cerr << "MTR: " << MTR << endl; if(EOF == sscanf(MTR.c_str(), "%d", &an.motorID)) cerr << "ERROR INSERTING CRITTER" << endl; an.isMotor = true; } if ( parseH->Instance()->beginMatchesStrip( "p=", line ) ) { string PLAS = parseH->Instance()->returnUntillStrip( ",", line ); string PLAW = parseH->Instance()->returnUntillStrip( "|", line ); if(EOF == sscanf(PLAS.c_str(), "%d", &an.plasticityStrengthen)) cerr << "ERROR INSERTING CRITTER" << endl; if(EOF == sscanf(PLAW.c_str(), "%d", &an.plasticityWeaken)) cerr << "ERROR INSERTING CRITTER" << endl; an.isPlastic = true; } while ( parseH->Instance()->beginMatchesStrip( "s=", line ) ) { ArchSynapse as; string SY = parseH->Instance()->returnUntillStrip( "|", line ); string isSensorNeuron = parseH->Instance()->returnUntillStrip( ",", SY ); string neuronID = parseH->Instance()->returnUntillStrip( ",", SY ); string dendriteBranch = parseH->Instance()->returnUntillStrip( ",", SY ); string weight = SY; int isIt; if(EOF == sscanf(isSensorNeuron.c_str(), "%d", &isIt)) cerr << "ERROR INSERTING CRITTER" << endl; if ( isIt == 1 ) as.isSensorNeuron = true; if(EOF == sscanf(neuronID.c_str(), "%d", &as.neuronID)) cerr << "ERROR INSERTING CRITTER" << endl; if(EOF == sscanf(dendriteBranch.c_str(), "%d", &as.dendriteBranch)) cerr << "ERROR INSERTING CRITTER" << endl; if(EOF == sscanf(weight.c_str(), "%f", &as.weight)) cerr << "ERROR INSERTING CRITTER" << endl; an.ArchSynapses.push_back( as ); } ArchNeurons.push_back( an ); } // else if ( parseH->Instance()->beginMatchesStrip( "numberOfInputs=", line ) ) // { // string Holder = parseH->Instance()->returnUntillStrip( ";", line ); // if(EOF == sscanf(Holder.c_str(), "%d", &numberOfInputs)) cerr << "ERROR INSERTING CRITTER" << endl; // } // else if ( parseH->Instance()->beginMatchesStrip( "numberOfOutputs=", line ) ) // { // string Holder = parseH->Instance()->returnUntillStrip( ";", line ); // if(EOF == sscanf(Holder.c_str(), "%d", &numberOfOutputs)) cerr << "ERROR INSERTING CRITTER" << endl; // } else if ( parseH->Instance()->beginMatchesStrip( "maxNeurons=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &maxNeurons)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "minSynapses=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &minSynapses)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "maxSynapses=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &maxSynapses)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "percentChanceInhibitoryNeuron=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &percentChanceInhibitoryNeuron)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "mutate_percentChanceInhibitoryNeuron=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); int result; if(EOF == sscanf(Holder.c_str(), "%d", &result)) cerr << "ERROR INSERTING CRITTER" << endl; if ( result == 1 ) mutate_percentChanceInhibitoryNeuron = true; else mutate_percentChanceInhibitoryNeuron = false; } else if ( parseH->Instance()->beginMatchesStrip( "percentChanceConsistentSynapses=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &percentChanceConsistentSynapses)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "mutate_percentChanceConsistentSynapses=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); int result; if(EOF == sscanf(Holder.c_str(), "%d", &result)) cerr << "ERROR INSERTING CRITTER" << endl; if ( result == 1 ) mutate_percentChanceConsistentSynapses = true; else mutate_percentChanceConsistentSynapses = false; } else if ( parseH->Instance()->beginMatchesStrip( "percentChanceInhibitorySynapses=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &percentChanceInhibitorySynapses)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "mutate_percentChanceInhibitorySynapses=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); int result; if(EOF == sscanf(Holder.c_str(), "%d", &result)) cerr << "ERROR INSERTING CRITTER" << endl; if ( result == 1 ) mutate_percentChanceInhibitorySynapses = true; else mutate_percentChanceInhibitorySynapses = false; } else if ( parseH->Instance()->beginMatchesStrip( "percentChanceMotorNeuron=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &percentChanceMotorNeuron)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "mutate_percentChanceMotorNeuron=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); int result; if(EOF == sscanf(Holder.c_str(), "%d", &result)) cerr << "ERROR INSERTING CRITTER" << endl; if ( result == 1 ) mutate_percentChanceMotorNeuron = true; else mutate_percentChanceMotorNeuron = false; } else if ( parseH->Instance()->beginMatchesStrip( "percentChancePlasticNeuron=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &percentChancePlasticNeuron)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "mutate_percentChancePlasticNeuron=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); int result; if(EOF == sscanf(Holder.c_str(), "%d", &result)) cerr << "ERROR INSERTING CRITTER" << endl; if ( result == 1 ) mutate_percentChancePlasticNeuron = true; else mutate_percentChancePlasticNeuron = false; } else if ( parseH->Instance()->beginMatchesStrip( "percentChanceSensorySynapse=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &percentChanceSensorySynapse)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "mutate_percentChanceSensorySynapse=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); int result; if(EOF == sscanf(Holder.c_str(), "%d", &result)) cerr << "ERROR INSERTING CRITTER" << endl; if ( result == 1 ) mutate_percentChanceSensorySynapse = true; else mutate_percentChanceSensorySynapse = false; } else if ( parseH->Instance()->beginMatchesStrip( "minFiringThreshold=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &minFiringThreshold)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "mutate_minFiringThreshold=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); int result; if(EOF == sscanf(Holder.c_str(), "%d", &result)) cerr << "ERROR INSERTING CRITTER" << endl; if ( result == 1 ) mutate_minFiringThreshold = true; else mutate_minFiringThreshold = false; } else if ( parseH->Instance()->beginMatchesStrip( "maxFiringThreshold=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &maxFiringThreshold)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "mutate_maxFiringThreshold=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); int result; if(EOF == sscanf(Holder.c_str(), "%d", &result)) cerr << "ERROR INSERTING CRITTER" << endl; if ( result == 1 ) mutate_maxFiringThreshold = true; else mutate_maxFiringThreshold = false; } else if ( parseH->Instance()->beginMatchesStrip( "maxDendridicBranches=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &maxDendridicBranches)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "mutate_maxDendridicBranches=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); int result; if(EOF == sscanf(Holder.c_str(), "%d", &result)) cerr << "ERROR INSERTING CRITTER" << endl; if ( result == 1 ) mutate_maxDendridicBranches = true; else mutate_maxDendridicBranches = false; } // else if ( parseH->Instance()->beginMatchesStrip( "percentMutation=", line ) ) // { // string Holder = parseH->Instance()->returnUntillStrip( ";", line ); // if(EOF == sscanf(Holder.c_str(), "%d", &percentMutation)) cerr << "ERROR INSERTING CRITTER" << endl; // } // else if ( parseH->Instance()->beginMatchesStrip( "mutate_percentMutation=", line ) ) // { // string Holder = parseH->Instance()->returnUntillStrip( ";", line ); // int result; // if(EOF == sscanf(Holder.c_str(), "%d", &result)) cerr << "ERROR INSERTING CRITTER" << endl; // if ( result == 1 ) mutate_percentMutation = true; // else mutate_percentMutation = false; // } else if ( parseH->Instance()->beginMatchesStrip( "percentMutateEffectAddNeuron=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &percentMutateEffectAddNeuron)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "percentMutateEffectRemoveNeuron=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &percentMutateEffectRemoveNeuron)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "percentMutateEffectAlterNeuron=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &percentMutateEffectAlterNeuron)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "percentMutateEffectAddSynapse=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &percentMutateEffectAddSynapse)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "percentMutateEffectRemoveSynapse=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &percentMutateEffectRemoveSynapse)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "percentMutateEffectAlterMutable=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &percentMutateEffectAlterMutable)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "mutate_MutateEffects=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); int result; if(EOF == sscanf(Holder.c_str(), "%d", &result)) cerr << "ERROR INSERTING CRITTER" << endl; if ( result == 1 ) mutate_MutateEffects = true; else mutate_MutateEffects = false; } else if ( parseH->Instance()->beginMatchesStrip( "minPlasticityStrengthen=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &minPlasticityStrengthen)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "maxPlasticityStrengthen=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &maxPlasticityStrengthen)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "minPlasticityWeaken=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &minPlasticityWeaken)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "maxPlasticityWeaken=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); if(EOF == sscanf(Holder.c_str(), "%d", &maxPlasticityWeaken)) cerr << "ERROR INSERTING CRITTER" << endl; } else if ( parseH->Instance()->beginMatchesStrip( "mutate_PlasticityFactors=", line ) ) { string Holder = parseH->Instance()->returnUntillStrip( ";", line ); int result; if(EOF == sscanf(Holder.c_str(), "%d", &result)) cerr << "ERROR INSERTING CRITTER" << endl; if ( result == 1 ) mutate_PlasticityFactors = true; else mutate_PlasticityFactors = false; } line = parseH->Instance()->returnUntillStrip( "\n", contentCopy ); } } string* BrainzArch::getArch() { stringstream buf; buf << "maxNeurons=" << maxNeurons << ";" << endl; buf << "minSynapses=" << minSynapses << ";" << endl; buf << "maxSynapses=" << maxSynapses << ";" << endl; buf << "percentChanceInhibitoryNeuron=" << percentChanceInhibitoryNeuron << ";" << endl; buf << "mutate_percentChanceInhibitoryNeuron=" << mutate_percentChanceInhibitoryNeuron << ";" << endl; buf << "percentChanceMotorNeuron=" << percentChanceMotorNeuron << ";" << endl; buf << "mutate_percentChanceMotorNeuron=" << mutate_percentChanceMotorNeuron << ";" << endl; buf << "percentChancePlasticNeuron=" << percentChancePlasticNeuron << ";" << endl; buf << "mutate_percentChancePlasticNeuron=" << mutate_percentChancePlasticNeuron << ";" << endl; buf << "minPlasticityStrengthen=" << minPlasticityStrengthen << ";" << endl; buf << "maxPlasticityStrengthen=" << maxPlasticityStrengthen << ";" << endl; buf << "minPlasticityWeaken=" << minPlasticityWeaken << ";" << endl; buf << "maxPlasticityWeaken=" << maxPlasticityWeaken << ";" << endl; buf << "mutate_PlasticityFactors=" << mutate_PlasticityFactors << ";" << endl; buf << "minFiringThreshold=" << minFiringThreshold << ";" << endl; buf << "mutate_minFiringThreshold=" << mutate_minFiringThreshold << ";" << endl; buf << "maxFiringThreshold=" << maxFiringThreshold << ";" << endl; buf << "mutate_maxFiringThreshold=" << mutate_maxFiringThreshold << ";" << endl; buf << "maxDendridicBranches=" << maxDendridicBranches << ";" << endl; buf << "mutate_maxDendridicBranches=" << mutate_maxDendridicBranches << ";" << endl; buf << "percentChanceConsistentSynapses=" << percentChanceConsistentSynapses << ";" << endl; buf << "mutate_percentChanceConsistentSynapses="<< mutate_percentChanceConsistentSynapses << ";" << endl; buf << "percentChanceInhibitorySynapses=" << percentChanceInhibitorySynapses << ";" << endl; buf << "mutate_percentChanceInhibitorySynapses="<< mutate_percentChanceInhibitorySynapses << ";" << endl; buf << "percentChanceSensorySynapse=" << percentChanceSensorySynapse << ";" << endl; buf << "mutate_percentChanceSensorySynapse=" << mutate_percentChanceSensorySynapse << ";" << endl; buf << "percentMutateEffectAddNeuron=" << percentMutateEffectAddNeuron << ";" << endl; buf << "percentMutateEffectRemoveNeuron=" << percentMutateEffectRemoveNeuron << ";" << endl; buf << "percentMutateEffectAlterNeuron=" << percentMutateEffectAlterNeuron << ";" << endl; buf << "percentMutateEffectAddSynapse=" << percentMutateEffectAddSynapse << ";" << endl; buf << "percentMutateEffectRemoveSynapse=" << percentMutateEffectRemoveSynapse << ";" << endl; buf << "percentMutateEffectAlterMutable=" << percentMutateEffectAlterMutable << ";" << endl; buf << "mutate_MutateEffects=" << mutate_MutateEffects << ";" << endl; // neuronal arch & connections for ( unsigned int i = 0; i < ArchNeurons.size(); i++ ) { // neuron info buf << "n("; if ( ArchNeurons[i].isInhibitory ) buf << "i=1|"; else buf << "i=0|"; if ( ArchNeurons[i].hasConsistentSynapses ) { buf << "cs=1|"; if ( ArchNeurons[i].hasInhibitorySynapses ) buf << "is=1|"; else buf << "is=0|"; } else buf << "cs=0|"; buf << "f=" << ArchNeurons[i].firingThreshold << "|"; buf << "d=" << ArchNeurons[i].dendridicBranches << "|"; if ( ArchNeurons[i].isMotor ) buf << "m=" << ArchNeurons[i].motorID << "|"; if ( ArchNeurons[i].isPlastic ) buf << "p=" << ArchNeurons[i].plasticityStrengthen << "," << ArchNeurons[i].plasticityWeaken << "|"; // inputs for ( unsigned int j = 0; j < ArchNeurons[i].ArchSynapses.size(); j++ ) { buf << "s="; // sensor or inter neuron if ( ArchNeurons[i].ArchSynapses[j].isSensorNeuron ) buf << "1"; else buf << "0"; buf << "," << ArchNeurons[i].ArchSynapses[j].neuronID; buf << "," << ArchNeurons[i].ArchSynapses[j].dendriteBranch; buf << "," << ArchNeurons[i].ArchSynapses[j].weight; buf << "|"; } buf << ");\n"; } archBuffer = buf.str(); return &archBuffer; } BrainzArch::~BrainzArch() { } critterding-beta12.1/src/brainz/neuroninterz.cpp0000644000175000017500000000735411331362115021064 0ustar bobkebobke#include "neuroninterz.h" NeuronInterz::NeuronInterz() { isInhibitory = false; // input weight range, 5 = -5 <-> +5 -> 10 in total because 0 will be excluded // dendridicBranches = 10; // processing potential = 0.0f; potentialDecay = 0.95f; // output output = 0.0f; waitoutput = 0.0f; // plasticity up & down isPlastic = false; // optional reference that makes this a MOTOR neuron, but it depends on not being defined isMotor = false; motorFunc = 0; } void NeuronInterz::process() { // potential decay potential = potential * potentialDecay; // make every connection do it's influence on the neuron's total potential unsigned int ssize = Synapses.size(); for ( unsigned int i=0; i < ssize; i++ ) { // lower synaptic weights if (isPlastic) Synapses[i].weight = Synapses[i].weight * plasticityWeaken; if ( *Synapses[i].ref != 0 ) potential += (Synapses[i].weight * Synapses[i].dendriteBranch * *Synapses[i].ref); } if ( isInhibitory ) { // do we spike/fire if ( potential <= -1.0f * firingThreshold ) { // reset neural potential potential = 0.0f; // fire the neuron waitoutput = -1; // PLASTICITY: if neuron & synapse fire together, the synapse strenghtens if (isPlastic) { for ( unsigned int i=0; i < ssize; i++ ) { // if synapse fired, strenghten the weight if ( (*Synapses[i].ref < 0.0f && Synapses[i].weight > 0.0f) || (*Synapses[i].ref > 0.0f && Synapses[i].weight < 0.0f) ) { // cerr << endl << "Inhibitory firing" << endl << "synref: " << *Synapses[i].ref << endl << "pre weight: " << Synapses[i].weight << endl; Synapses[i].weight = Synapses[i].weight * plasticityStrengthen; // cerr << "post weight: " << Synapses[i].weight << endl; } // if weight > max back to max if ( Synapses[i].weight > 5.0f ) Synapses[i].weight = 5.0f; else if ( Synapses[i].weight <-5.0f ) Synapses[i].weight =-5.0f; } } } // don't fire the neuron else { waitoutput = 0; // reset potential if < 0 if ( potential > 0.0f ) potential = 0.0f; } } else { // do we spike/fire if ( potential >= firingThreshold ) { // reset neural potential potential = 0.0f; // fire the neuron waitoutput = 1; // PLASTICITY: if neuron & synapse fire together, the synapse strenghtens if (isPlastic) { for ( unsigned int i=0; i < ssize; i++ ) { // if synapse fired, strenghten the weight if ( (*Synapses[i].ref > 0.0f && Synapses[i].weight > 0.0f) || (*Synapses[i].ref < 0.0f && Synapses[i].weight < 0.0f) ) { // cerr << endl << "Excititory firing" << endl << "synref: " << *Synapses[i].ref << endl << "pre weight: " << Synapses[i].weight << endl; Synapses[i].weight = Synapses[i].weight * plasticityStrengthen; // cerr << "post weight: " << Synapses[i].weight << endl; } // if weight > max back to max if ( Synapses[i].weight > 5.0f ) Synapses[i].weight = 5.0f; else if ( Synapses[i].weight <-5.0f ) Synapses[i].weight =-5.0f; } } } // don't fire the neuron else { waitoutput = 0; // reset potential if < 0 if ( potential < 0.0f ) potential = 0.0f; } } } void NeuronInterz::connec( float *output, unsigned int dendriteBranch, float synapticWeight ) //void NeuronInterz::connec( int *output, unsigned int dendriteBranch, float synapticWeight ) { Synapse s; s.ref = output; s.dendriteBranch = dendriteBranch; s.weight = synapticWeight; Synapses.push_back( s ); // cerr << "I: " << Synapses.size()-1 << "=" << *Synapses[Synapses.size()-1].ref << "(" << Synapses[Synapses.size()-1].ref << ")"; // cerr << *Synapses[0].ref << endl; } NeuronInterz::~NeuronInterz() { // for ( unsigned int i=0; i < inputs.size(); i++ ) delete inputs[i]; } critterding-beta12.1/src/brainz/LICENSE0000644000175000017500000010451311054613550016622 0ustar bobkebobke GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The GNU General Public License is a free, copyleft license for software and other kinds of works. The licenses for most software and other practical works are designed to take away your freedom to share and change the works. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change all versions of a program--to make sure it remains free software for all its users. We, the Free Software Foundation, use the GNU General Public License for most of our software; it applies also to any other work released this way by its authors. You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for them if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs, and that you know you can do these things. To protect your rights, we need to prevent others from denying you these rights or asking you to surrender the rights. Therefore, you have certain responsibilities if you distribute copies of the software, or if you modify it: responsibilities to respect the freedom of others. For example, if you distribute copies of such a program, whether gratis or for a fee, you must pass on to the recipients the same freedoms that you received. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. Developers that use the GNU GPL protect your rights with two steps: (1) assert copyright on the software, and (2) offer you this License giving you legal permission to copy, distribute and/or modify it. For the developers' and authors' protection, the GPL clearly explains that there is no warranty for this free software. For both users' and authors' sake, the GPL requires that modified versions be marked as changed, so that their problems will not be attributed erroneously to authors of previous versions. Some devices are designed to deny users access to install or run modified versions of the software inside them, although the manufacturer can do so. This is fundamentally incompatible with the aim of protecting users' freedom to change the software. The systematic pattern of such abuse occurs in the area of products for individuals to use, which is precisely where it is most unacceptable. Therefore, we have designed this version of the GPL to prohibit the practice for those products. If such problems arise substantially in other domains, we stand ready to extend this provision to those domains in future versions of the GPL, as needed to protect the freedom of users. Finally, every program is threatened constantly by software patents. States should not allow patents to restrict development and use of software on general-purpose computers, but in those that do, we wish to avoid the special danger that patents applied to a free program could make it effectively proprietary. To prevent this, the GPL assures that patents cannot be used to render the program non-free. The precise terms and conditions for copying, distribution and modification follow. TERMS AND CONDITIONS 0. Definitions. "This License" refers to version 3 of the GNU General Public License. "Copyright" also means copyright-like laws that apply to other kinds of works, such as semiconductor masks. "The Program" refers to any copyrightable work licensed under this License. Each licensee is addressed as "you". "Licensees" and "recipients" may be individuals or organizations. To "modify" a work means to copy from or adapt all or part of the work in a fashion requiring copyright permission, other than the making of an exact copy. The resulting work is called a "modified version" of the earlier work or a work "based on" the earlier work. A "covered work" means either the unmodified Program or a work based on the Program. To "propagate" a work means to do anything with it that, without permission, would make you directly or secondarily liable for infringement under applicable copyright law, except executing it on a computer or modifying a private copy. Propagation includes copying, distribution (with or without modification), making available to the public, and in some countries other activities as well. To "convey" a work means any kind of propagation that enables other parties to make or receive copies. Mere interaction with a user through a computer network, with no transfer of a copy, is not conveying. An interactive user interface displays "Appropriate Legal Notices" to the extent that it includes a convenient and prominently visible feature that (1) displays an appropriate copyright notice, and (2) tells the user that there is no warranty for the work (except to the extent that warranties are provided), that licensees may convey the work under this License, and how to view a copy of this License. If the interface presents a list of user commands or options, such as a menu, a prominent item in the list meets this criterion. 1. Source Code. The "source code" for a work means the preferred form of the work for making modifications to it. "Object code" means any non-source form of a work. A "Standard Interface" means an interface that either is an official standard defined by a recognized standards body, or, in the case of interfaces specified for a particular programming language, one that is widely used among developers working in that language. The "System Libraries" of an executable work include anything, other than the work as a whole, that (a) is included in the normal form of packaging a Major Component, but which is not part of that Major Component, and (b) serves only to enable use of the work with that Major Component, or to implement a Standard Interface for which an implementation is available to the public in source code form. A "Major Component", in this context, means a major essential component (kernel, window system, and so on) of the specific operating system (if any) on which the executable work runs, or a compiler used to produce the work, or an object code interpreter used to run it. The "Corresponding Source" for a work in object code form means all the source code needed to generate, install, and (for an executable work) run the object code and to modify the work, including scripts to control those activities. However, it does not include the work's System Libraries, or general-purpose tools or generally available free programs which are used unmodified in performing those activities but which are not part of the work. For example, Corresponding Source includes interface definition files associated with source files for the work, and the source code for shared libraries and dynamically linked subprograms that the work is specifically designed to require, such as by intimate data communication or control flow between those subprograms and other parts of the work. The Corresponding Source need not include anything that users can regenerate automatically from other parts of the Corresponding Source. The Corresponding Source for a work in source code form is that same work. 2. Basic Permissions. All rights granted under this License are granted for the term of copyright on the Program, and are irrevocable provided the stated conditions are met. This License explicitly affirms your unlimited permission to run the unmodified Program. The output from running a covered work is covered by this License only if the output, given its content, constitutes a covered work. This License acknowledges your rights of fair use or other equivalent, as provided by copyright law. You may make, run and propagate covered works that you do not convey, without conditions so long as your license otherwise remains in force. You may convey covered works to others for the sole purpose of having them make modifications exclusively for you, or provide you with facilities for running those works, provided that you comply with the terms of this License in conveying all material for which you do not control copyright. Those thus making or running the covered works for you must do so exclusively on your behalf, under your direction and control, on terms that prohibit them from making any copies of your copyrighted material outside their relationship with you. Conveying under any other circumstances is permitted solely under the conditions stated below. Sublicensing is not allowed; section 10 makes it unnecessary. 3. Protecting Users' Legal Rights From Anti-Circumvention Law. No covered work shall be deemed part of an effective technological measure under any applicable law fulfilling obligations under article 11 of the WIPO copyright treaty adopted on 20 December 1996, or similar laws prohibiting or restricting circumvention of such measures. When you convey a covered work, you waive any legal power to forbid circumvention of technological measures to the extent such circumvention is effected by exercising rights under this License with respect to the covered work, and you disclaim any intention to limit operation or modification of the work as a means of enforcing, against the work's users, your or third parties' legal rights to forbid circumvention of technological measures. 4. Conveying Verbatim Copies. You may convey verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice; keep intact all notices stating that this License and any non-permissive terms added in accord with section 7 apply to the code; keep intact all notices of the absence of any warranty; and give all recipients a copy of this License along with the Program. You may charge any price or no price for each copy that you convey, and you may offer support or warranty protection for a fee. 5. Conveying Modified Source Versions. You may convey a work based on the Program, or the modifications to produce it from the Program, in the form of source code under the terms of section 4, provided that you also meet all of these conditions: a) The work must carry prominent notices stating that you modified it, and giving a relevant date. b) The work must carry prominent notices stating that it is released under this License and any conditions added under section 7. This requirement modifies the requirement in section 4 to "keep intact all notices". c) You must license the entire work, as a whole, under this License to anyone who comes into possession of a copy. This License will therefore apply, along with any applicable section 7 additional terms, to the whole of the work, and all its parts, regardless of how they are packaged. This License gives no permission to license the work in any other way, but it does not invalidate such permission if you have separately received it. d) If the work has interactive user interfaces, each must display Appropriate Legal Notices; however, if the Program has interactive interfaces that do not display Appropriate Legal Notices, your work need not make them do so. A compilation of a covered work with other separate and independent works, which are not by their nature extensions of the covered work, and which are not combined with it such as to form a larger program, in or on a volume of a storage or distribution medium, is called an "aggregate" if the compilation and its resulting copyright are not used to limit the access or legal rights of the compilation's users beyond what the individual works permit. Inclusion of a covered work in an aggregate does not cause this License to apply to the other parts of the aggregate. 6. Conveying Non-Source Forms. You may convey a covered work in object code form under the terms of sections 4 and 5, provided that you also convey the machine-readable Corresponding Source under the terms of this License, in one of these ways: a) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by the Corresponding Source fixed on a durable physical medium customarily used for software interchange. b) Convey the object code in, or embodied in, a physical product (including a physical distribution medium), accompanied by a written offer, valid for at least three years and valid for as long as you offer spare parts or customer support for that product model, to give anyone who possesses the object code either (1) a copy of the Corresponding Source for all the software in the product that is covered by this License, on a durable physical medium customarily used for software interchange, for a price no more than your reasonable cost of physically performing this conveying of source, or (2) access to copy the Corresponding Source from a network server at no charge. c) Convey individual copies of the object code with a copy of the written offer to provide the Corresponding Source. This alternative is allowed only occasionally and noncommercially, and only if you received the object code with such an offer, in accord with subsection 6b. d) Convey the object code by offering access from a designated place (gratis or for a charge), and offer equivalent access to the Corresponding Source in the same way through the same place at no further charge. You need not require recipients to copy the Corresponding Source along with the object code. If the place to copy the object code is a network server, the Corresponding Source may be on a different server (operated by you or a third party) that supports equivalent copying facilities, provided you maintain clear directions next to the object code saying where to find the Corresponding Source. Regardless of what server hosts the Corresponding Source, you remain obligated to ensure that it is available for as long as needed to satisfy these requirements. e) Convey the object code using peer-to-peer transmission, provided you inform other peers where the object code and Corresponding Source of the work are being offered to the general public at no charge under subsection 6d. A separable portion of the object code, whose source code is excluded from the Corresponding Source as a System Library, need not be included in conveying the object code work. A "User Product" is either (1) a "consumer product", which means any tangible personal property which is normally used for personal, family, or household purposes, or (2) anything designed or sold for incorporation into a dwelling. In determining whether a product is a consumer product, doubtful cases shall be resolved in favor of coverage. For a particular product received by a particular user, "normally used" refers to a typical or common use of that class of product, regardless of the status of the particular user or of the way in which the particular user actually uses, or expects or is expected to use, the product. A product is a consumer product regardless of whether the product has substantial commercial, industrial or non-consumer uses, unless such uses represent the only significant mode of use of the product. "Installation Information" for a User Product means any methods, procedures, authorization keys, or other information required to install and execute modified versions of a covered work in that User Product from a modified version of its Corresponding Source. The information must suffice to ensure that the continued functioning of the modified object code is in no case prevented or interfered with solely because modification has been made. If you convey an object code work under this section in, or with, or specifically for use in, a User Product, and the conveying occurs as part of a transaction in which the right of possession and use of the User Product is transferred to the recipient in perpetuity or for a fixed term (regardless of how the transaction is characterized), the Corresponding Source conveyed under this section must be accompanied by the Installation Information. But this requirement does not apply if neither you nor any third party retains the ability to install modified object code on the User Product (for example, the work has been installed in ROM). The requirement to provide Installation Information does not include a requirement to continue to provide support service, warranty, or updates for a work that has been modified or installed by the recipient, or for the User Product in which it has been modified or installed. Access to a network may be denied when the modification itself materially and adversely affects the operation of the network or violates the rules and protocols for communication across the network. Corresponding Source conveyed, and Installation Information provided, in accord with this section must be in a format that is publicly documented (and with an implementation available to the public in source code form), and must require no special password or key for unpacking, reading or copying. 7. Additional Terms. "Additional permissions" are terms that supplement the terms of this License by making exceptions from one or more of its conditions. Additional permissions that are applicable to the entire Program shall be treated as though they were included in this License, to the extent that they are valid under applicable law. If additional permissions apply only to part of the Program, that part may be used separately under those permissions, but the entire Program remains governed by this License without regard to the additional permissions. When you convey a copy of a covered work, you may at your option remove any additional permissions from that copy, or from any part of it. (Additional permissions may be written to require their own removal in certain cases when you modify the work.) You may place additional permissions on material, added by you to a covered work, for which you have or can give appropriate copyright permission. Notwithstanding any other provision of this License, for material you add to a covered work, you may (if authorized by the copyright holders of that material) supplement the terms of this License with terms: a) Disclaiming warranty or limiting liability differently from the terms of sections 15 and 16 of this License; or b) Requiring preservation of specified reasonable legal notices or author attributions in that material or in the Appropriate Legal Notices displayed by works containing it; or c) Prohibiting misrepresentation of the origin of that material, or requiring that modified versions of such material be marked in reasonable ways as different from the original version; or d) Limiting the use for publicity purposes of names of licensors or authors of the material; or e) Declining to grant rights under trademark law for use of some trade names, trademarks, or service marks; or f) Requiring indemnification of licensors and authors of that material by anyone who conveys the material (or modified versions of it) with contractual assumptions of liability to the recipient, for any liability that these contractual assumptions directly impose on those licensors and authors. All other non-permissive additional terms are considered "further restrictions" within the meaning of section 10. If the Program as you received it, or any part of it, contains a notice stating that it is governed by this License along with a term that is a further restriction, you may remove that term. If a license document contains a further restriction but permits relicensing or conveying under this License, you may add to a covered work material governed by the terms of that license document, provided that the further restriction does not survive such relicensing or conveying. If you add terms to a covered work in accord with this section, you must place, in the relevant source files, a statement of the additional terms that apply to those files, or a notice indicating where to find the applicable terms. Additional terms, permissive or non-permissive, may be stated in the form of a separately written license, or stated as exceptions; the above requirements apply either way. 8. Termination. You may not propagate or modify a covered work except as expressly provided under this License. Any attempt otherwise to propagate or modify it is void, and will automatically terminate your rights under this License (including any patent licenses granted under the third paragraph of section 11). However, if you cease all violation of this License, then your license from a particular copyright holder is reinstated (a) provisionally, unless and until the copyright holder explicitly and finally terminates your license, and (b) permanently, if the copyright holder fails to notify you of the violation by some reasonable means prior to 60 days after the cessation. Moreover, your license from a particular copyright holder is reinstated permanently if the copyright holder notifies you of the violation by some reasonable means, this is the first time you have received notice of violation of this License (for any work) from that copyright holder, and you cure the violation prior to 30 days after your receipt of the notice. Termination of your rights under this section does not terminate the licenses of parties who have received copies or rights from you under this License. If your rights have been terminated and not permanently reinstated, you do not qualify to receive new licenses for the same material under section 10. 9. Acceptance Not Required for Having Copies. You are not required to accept this License in order to receive or run a copy of the Program. Ancillary propagation of a covered work occurring solely as a consequence of using peer-to-peer transmission to receive a copy likewise does not require acceptance. However, nothing other than this License grants you permission to propagate or modify any covered work. These actions infringe copyright if you do not accept this License. Therefore, by modifying or propagating a covered work, you indicate your acceptance of this License to do so. 10. Automatic Licensing of Downstream Recipients. Each time you convey a covered work, the recipient automatically receives a license from the original licensors, to run, modify and propagate that work, subject to this License. You are not responsible for enforcing compliance by third parties with this License. An "entity transaction" is a transaction transferring control of an organization, or substantially all assets of one, or subdividing an organization, or merging organizations. If propagation of a covered work results from an entity transaction, each party to that transaction who receives a copy of the work also receives whatever licenses to the work the party's predecessor in interest had or could give under the previous paragraph, plus a right to possession of the Corresponding Source of the work from the predecessor in interest, if the predecessor has it or can get it with reasonable efforts. You may not impose any further restrictions on the exercise of the rights granted or affirmed under this License. For example, you may not impose a license fee, royalty, or other charge for exercise of rights granted under this License, and you may not initiate litigation (including a cross-claim or counterclaim in a lawsuit) alleging that any patent claim is infringed by making, using, selling, offering for sale, or importing the Program or any portion of it. 11. Patents. A "contributor" is a copyright holder who authorizes use under this License of the Program or a work on which the Program is based. The work thus licensed is called the contributor's "contributor version". A contributor's "essential patent claims" are all patent claims owned or controlled by the contributor, whether already acquired or hereafter acquired, that would be infringed by some manner, permitted by this License, of making, using, or selling its contributor version, but do not include claims that would be infringed only as a consequence of further modification of the contributor version. For purposes of this definition, "control" includes the right to grant patent sublicenses in a manner consistent with the requirements of this License. Each contributor grants you a non-exclusive, worldwide, royalty-free patent license under the contributor's essential patent claims, to make, use, sell, offer for sale, import and otherwise run, modify and propagate the contents of its contributor version. In the following three paragraphs, a "patent license" is any express agreement or commitment, however denominated, not to enforce a patent (such as an express permission to practice a patent or covenant not to sue for patent infringement). To "grant" such a patent license to a party means to make such an agreement or commitment not to enforce a patent against the party. If you convey a covered work, knowingly relying on a patent license, and the Corresponding Source of the work is not available for anyone to copy, free of charge and under the terms of this License, through a publicly available network server or other readily accessible means, then you must either (1) cause the Corresponding Source to be so available, or (2) arrange to deprive yourself of the benefit of the patent license for this particular work, or (3) arrange, in a manner consistent with the requirements of this License, to extend the patent license to downstream recipients. "Knowingly relying" means you have actual knowledge that, but for the patent license, your conveying the covered work in a country, or your recipient's use of the covered work in a country, would infringe one or more identifiable patents in that country that you have reason to believe are valid. If, pursuant to or in connection with a single transaction or arrangement, you convey, or propagate by procuring conveyance of, a covered work, and grant a patent license to some of the parties receiving the covered work authorizing them to use, propagate, modify or convey a specific copy of the covered work, then the patent license you grant is automatically extended to all recipients of the covered work and works based on it. A patent license is "discriminatory" if it does not include within the scope of its coverage, prohibits the exercise of, or is conditioned on the non-exercise of one or more of the rights that are specifically granted under this License. You may not convey a covered work if you are a party to an arrangement with a third party that is in the business of distributing software, under which you make payment to the third party based on the extent of your activity of conveying the work, and under which the third party grants, to any of the parties who would receive the covered work from you, a discriminatory patent license (a) in connection with copies of the covered work conveyed by you (or copies made from those copies), or (b) primarily for and in connection with specific products or compilations that contain the covered work, unless you entered into that arrangement, or that patent license was granted, prior to 28 March 2007. Nothing in this License shall be construed as excluding or limiting any implied license or other defenses to infringement that may otherwise be available to you under applicable patent law. 12. No Surrender of Others' Freedom. If conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot convey a covered work so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not convey it at all. For example, if you agree to terms that obligate you to collect a royalty for further conveying from those to whom you convey the Program, the only way you could satisfy both those terms and this License would be to refrain entirely from conveying the Program. 13. Use with the GNU Affero General Public License. Notwithstanding any other provision of this License, you have permission to link or combine any covered work with a work licensed under version 3 of the GNU Affero General Public License into a single combined work, and to convey the resulting work. The terms of this License will continue to apply to the part which is the covered work, but the special requirements of the GNU Affero General Public License, section 13, concerning interaction through a network will apply to the combination as such. 14. Revised Versions of this License. The Free Software Foundation may publish revised and/or new versions of the GNU General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies that a certain numbered version of the GNU General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that numbered version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the GNU General Public License, you may choose any version ever published by the Free Software Foundation. If the Program specifies that a proxy can decide which future versions of the GNU General Public License can be used, that proxy's public statement of acceptance of a version permanently authorizes you to choose that version for the Program. Later license versions may give you additional or different permissions. However, no additional obligations are imposed on any author or copyright holder as a result of your choosing to follow a later version. 15. Disclaimer of Warranty. THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. Limitation of Liability. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. 17. Interpretation of Sections 15 and 16. If the disclaimer of warranty and limitation of liability provided above cannot be given local legal effect according to their terms, reviewing courts shall apply local law that most closely approximates an absolute waiver of all civil liability in connection with the Program, unless a warranty or assumption of liability accompanies a copy of the Program in return for a fee. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively state the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program. If not, see . Also add information on how to contact you by electronic and paper mail. If the program does terminal interaction, make it output a short notice like this when it starts in an interactive mode: Copyright (C) This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, your program's commands might be different; for a GUI interface, you would use an "about box". You should also get your employer (if you work as a programmer) or school, if any, to sign a "copyright disclaimer" for the program, if necessary. For more information on this, and how to apply and follow the GNU GPL, see . The GNU General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. But first, please read . critterding-beta12.1/src/brainz/brainzarch.h0000644000175000017500000001061411337071441020110 0ustar bobkebobke#ifndef BRAINZARCH_H #define BRAINZARCH_H // internal includes #include "../utils/randgen.h" #include "../utils/parser.h" #include "archneuronz.h" #include "neuroninterz.h" // external includes #include #include #include using namespace std; class BrainzArch { public: BrainzArch(); ~BrainzArch(); // input / output accessor/mutators vector InputIDs; vector OutputIDs; // vectors vector ArchNeurons; // BUILD TIME // min/max neurons at build time unsigned int minNeuronsAtBuildtime; unsigned int maxNeuronsAtBuildtime; // fixed numbers of inputs/outputs unsigned int numberOfInputs; unsigned int numberOfOutputs; // absolute max neurons (mutation bounding) unsigned int maxNeurons; unsigned int percentMutateEffectAddNeuron; unsigned int percentMutateEffectRemoveNeuron; unsigned int percentMutateEffectAlterNeuron; unsigned int percentMutateEffectAddSynapse; unsigned int percentMutateEffectRemoveSynapse; unsigned int percentMutateEffectAlterMutable; bool mutate_MutateEffects; // percent chance that when adding a new random neuron, it's inhibitory unsigned int percentChanceInhibitoryNeuron; bool mutate_percentChanceInhibitoryNeuron; // synaptic consistancy, meaning all synapses of a neuron will be OR I OR E // if set to 0, neurons will have mixed I and E synapses unsigned int percentChanceConsistentSynapses; bool mutate_percentChanceConsistentSynapses; // percent chance that when adding a new random neuron, it has inhibitory synapses unsigned int percentChanceInhibitorySynapses; bool mutate_percentChanceInhibitorySynapses; // percent chance that when adding a new random neuron, it has a motor function unsigned int percentChanceMotorNeuron; bool mutate_percentChanceMotorNeuron; // percent chance that when adding a new random neuron, it is has synaptic plasticity unsigned int percentChancePlasticNeuron; bool mutate_percentChancePlasticNeuron; // min/max synaptic plasticity strengthening factor unsigned int minPlasticityStrengthen; unsigned int maxPlasticityStrengthen; // min/max synaptic plasticity weakening factor unsigned int minPlasticityWeaken; unsigned int maxPlasticityWeaken; // flag if we'll mutate these bool mutate_PlasticityFactors; // min/max firing threshold unsigned int minFiringThreshold; bool mutate_minFiringThreshold; unsigned int maxFiringThreshold; bool mutate_maxFiringThreshold; // max dendritic branches in a new neuron unsigned int maxDendridicBranches; bool mutate_maxDendridicBranches; // percent chance that a new synapse is connected to a sensor neuron unsigned int percentChanceSensorySynapse; bool mutate_percentChanceSensorySynapse; // min/max synapses at build time unsigned int minSynapsesAtBuildtime; unsigned int maxSynapsesAtBuildtime; // absolute min/max synapses (mutation/plastic bounding) unsigned int minSynapses; unsigned int maxSynapses; // brain architecture mutation factor @ mutation time (%) unsigned int percentMutation; bool mutate_percentMutation; // INFO // total neuron & connection keepers unsigned int totalNeurons; unsigned int totalSynapses; // after every time instance, this will contain how many neurons where fired in that instant (energy usage help) unsigned int neuronsFired; unsigned int motorneuronsFired; // build commands // functions void copyFrom(const BrainzArch* otherBrain); void mergeFrom(const BrainzArch* otherBrain1, const BrainzArch* otherBrain2); void registerOutput(unsigned int id); void registerInput(unsigned int id); void removeObsoleteMotorsAndSensors(); void buildArch(); void mutate(unsigned int runs); void wireArch(); // load save architecture (serialize) void setArch(string* content); string* getArch(); // RUN TIME // functions int findSensorNeuron( unsigned int id ); int findMotorNeuron( unsigned int id ); private: // utilities Parser *parseH; RandGen *randgen; // a buffer for reading architecture string archBuffer; // int findSensorNeuron( unsigned int id ); // build time functions void addRandomArchNeuron(); unsigned int addRandomArchSynapse(unsigned int parentneuron); }; #endif critterding-beta12.1/src/brainz/archsynapse.cpp0000644000175000017500000000030711161311005020622 0ustar bobkebobke#include "archsynapse.h" ArchSynapse::ArchSynapse() { isSensorNeuron = false; neuronID = 0; neurontargetlayer = 0; dendriteBranch = 1; weight = 0.0f; } ArchSynapse::~ArchSynapse() { } critterding-beta12.1/src/brainz/archsynapse.h0000644000175000017500000000073011302100702020264 0ustar bobkebobke#ifndef ARCHSYNAPSE_H #define ARCHSYNAPSE_H class ArchSynapse { public: ArchSynapse(); ~ArchSynapse(); // determines if id referes to an interneuron or sensorneuron bool isSensorNeuron; // id of neuron which axon connects to this synapse unsigned int neuronID; unsigned int realneuronID; unsigned int neurontargetlayer; // dendridic weight according unsigned int dendriteBranch; // it's "weight" float weight; private: }; #endif critterding-beta12.1/src/brainz/brainz.cpp0000644000175000017500000001126511340053306017602 0ustar bobkebobke#include "brainz.h" #include Brainz::Brainz() { neuronsFired = 0; // build time defaults numberOfInputs = 0; numberOfOutputs = 0; } // BUILD TIME void Brainz::registerInput(unsigned int id) { Inputs.push_back( sensorNeuron() ); Inputs[numberOfInputs].id = id; numberOfInputs++; } void Brainz::registerOutput(bool* var, unsigned int id) { Outputs.push_back( motorNeuron() ); Outputs[numberOfOutputs].output = var; Outputs[numberOfOutputs].id = id; numberOfOutputs++; } void Brainz::wireArch(BrainzArch* brainzArch) { // clear everything Neurons.clear(); Inputs.clear(); Outputs.clear(); // we know the amount of neurons already, reset totalsynapses for the count later totalNeurons = brainzArch->ArchNeurons.size(); totalSynapses = 0; // create all runtime neurons for ( unsigned int i=0; i < totalNeurons; i++ ) { NeuronInterz ni; ni.isInhibitory = brainzArch->ArchNeurons[i].isInhibitory; ni.firingThreshold = brainzArch->ArchNeurons[i].firingThreshold; ni.isMotor = brainzArch->ArchNeurons[i].isMotor; if (ni.isMotor) ni.motorFunc = brainzArch->findMotorNeuron(brainzArch->ArchNeurons[i].motorID); ni.isPlastic = brainzArch->ArchNeurons[i].isPlastic; ni.plasticityStrengthen = 1.0f+(1.0f/brainzArch->ArchNeurons[i].plasticityStrengthen); ni.plasticityWeaken = 1.0f-(1.0f/brainzArch->ArchNeurons[i].plasticityWeaken); Neurons.push_back( ni ); } // create their synapses & link them to their inputneurons for ( unsigned int i=0; i < totalNeurons; i++ ) { // count connections totalSynapses += brainzArch->ArchNeurons[i].ArchSynapses.size(); for ( unsigned int j=0; j < brainzArch->ArchNeurons[i].ArchSynapses.size(); j++ ) { if ( brainzArch->ArchNeurons[i].ArchSynapses[j].isSensorNeuron ) { brainzArch->ArchNeurons[i].ArchSynapses[j].realneuronID = brainzArch->findSensorNeuron(brainzArch->ArchNeurons[i].ArchSynapses[j].neuronID); Neurons[i].connec( &Inputs[ brainzArch->ArchNeurons[i].ArchSynapses[j].realneuronID ].output, brainzArch->ArchNeurons[i].ArchSynapses[j].dendriteBranch, brainzArch->ArchNeurons[i].ArchSynapses[j].weight ); } else Neurons[i].connec( &Neurons[ brainzArch->ArchNeurons[i].ArchSynapses[j].neuronID ].output, brainzArch->ArchNeurons[i].ArchSynapses[j].dendriteBranch, brainzArch->ArchNeurons[i].ArchSynapses[j].weight ); } } //cerr << "total neurons: " << totalNeurons << "total synapses: " << totalSynapses << endl; } // RUN TIME void Brainz::clearInputs() { for ( unsigned int i=0; i < numberOfInputs; i++ ) { Inputs[i].output = 0; } } void Brainz::process() { // reset fired neurons counter neuronsFired = 0; motorneuronsFired = 0; // clear Motor Outputs for ( unsigned int i=0; i < numberOfOutputs; i++ ) { *Outputs[i].output = false; } int i; NeuronInterz* n; //#pragma omp parallel for shared(totalNeurons, Neurons) private(i, n, neuronsFired, motorsFired) for ( i=0; i < totalNeurons; i++ ) { n = &Neurons[i]; n->process(); // if neuron fires if ( n->waitoutput != 0 ) { neuronsFired++; //cerr << "neuron " << i << " fired " << n->waitoutput << endl; // motor neuron check & exec if ( n->isMotor ) { motorneuronsFired++; *Outputs[n->motorFunc].output = true; //cerr << "neuron " << i << " fired, motor is " << Neurons[i]->MotorFunc << " total now " << Outputs[Neurons[i]->MotorFunc]->output << endl; } } } // commit outputs at the end for ( unsigned int i=0; i < totalNeurons; i++ ) Neurons[i].output = Neurons[i].waitoutput; } void Brainz::processTillAnswer() { // neuronsFired = 0; // clear Motor Outputs for ( unsigned int i=0; i < numberOfOutputs; i++ ) Outputs[i].output = false; // clear Neurons for ( unsigned int i=0; i < totalNeurons; i++ ) { Neurons[i].output = 0; Neurons[i].potential = 0.0f; } unsigned int counter = 0; bool motorFired = false; while ( counter < 1000 && !motorFired ) { for ( unsigned int i=0; i < totalNeurons; i++ ) { NeuronInterz* n = &Neurons[i]; n->process(); // if neuron fires if ( n->waitoutput != 0 ) { neuronsFired++; // motor neuron check & exec if ( n->isMotor ) { motorFired = true; *Outputs[n->motorFunc].output = true; //cerr << "neuron " << i << " fired, motor is " << Neurons[i]->MotorFunc << " total now " << Outputs[Neurons[i]->MotorFunc]->output << endl; } } } // commit outputs at the end for ( unsigned int i=0; i < totalNeurons; i++ ) Neurons[i].output = Neurons[i].waitoutput; counter++; } } Brainz::~Brainz() { } critterding-beta12.1/src/brainz/archneuronz.h0000644000175000017500000000157011240127074020321 0ustar bobkebobke#ifndef ARCHNEURONZ_H #define ARCHNEURONZ_H // interneal includes #include "archsynapse.h" // external includes #include using namespace std; class ArchNeuronz { public: ArchNeuronz(); ~ArchNeuronz(); // inhibitory neuron by flag bool isInhibitory; // Consistent Synapses flag bool hasConsistentSynapses; // inhibitory synapses flag bool hasInhibitorySynapses; // neuron firing potential unsigned int firingThreshold; // dendridic branches unsigned int dendridicBranches; // motor neuron ability (excititatory only) // flag bool isMotor; // function unsigned int motorID; // synaptic plasticity by flag bool isPlastic; // factors unsigned int plasticityStrengthen; unsigned int plasticityWeaken; // vector of synapses vector ArchSynapses; private: }; #endif critterding-beta12.1/src/brainz/neuroninterz.h0000644000175000017500000000127111331362115020521 0ustar bobkebobke#ifndef NEURONINTERZ_H #define NEURONINTERZ_H // internal includes #include "synapse.h" // external includes #include #include #include using namespace std; class NeuronInterz { public: NeuronInterz(); ~NeuronInterz(); float output; float waitoutput; bool isInhibitory; unsigned int firingThreshold; bool isMotor; unsigned int motorFunc; void process(); void connec( float *output, unsigned int dendriteBranch, float synapticWeight ); vector Synapses; float potential; float potentialDecay; bool isPlastic; float plasticityStrengthen; float plasticityWeaken; private: }; #endif critterding-beta12.1/src/gui/0000755000175000017500000000000011347266042015115 5ustar bobkebobkecritterding-beta12.1/src/gui/container.h0000644000175000017500000000262511347254352017256 0ustar bobkebobke#ifndef CONTAINER_H #define CONTAINER_H #include "../utils/execcmd.h" #include "widget.h" using namespace std; class Container : public Widget { public: Container(); ~Container(); void draw(); // children map, publically accessible map children; bool mouseOverChild( Widget** fWidget, int x, int y ); Execcmd cmd; Widget* addWidgetPanel( const string& name, Widget* nwidget ); protected: void drawChildren(); Widget* addWidgetText( const string& name, unsigned int posx, unsigned int posy, const string& textstring ); Widget* addWidgetText( const string& name, const string& textstring ); Widget* addWidgetText( const string& name, unsigned int posx, unsigned int posy, const unsigned int* uintp ); Widget* addWidgetButton( const string& name, const Vector2i& pos, const Vector2i& dimensions, const string& textstring, const Vector2i& textpos, const cmdsettings& cmds, unsigned int responsetime, unsigned int minfresponsetime, unsigned int fresponseinterval ); Widget* addWidgetButton( const string& name, const Vector2i& pos, const Vector2i& dimensions, const string& textstring, const cmdsettings& cmds, unsigned int responsetime, unsigned int minfresponsetime, unsigned int fresponseinterval ); void updateAbsPosition(); // children map iterator typedef map ::const_iterator children_iterator; children_iterator childit; private: }; #endif critterding-beta12.1/src/gui/Makefile.am0000644000175000017500000000076011336076205017152 0ustar bobkebobkeINCLUDES = $(all_includes) -I../utils/bullet METASOURCES = AUTO noinst_LTLIBRARIES = libgui.la noinst_HEADERS = widget.h \ container.h \ text.h \ text_uintp.h \ panel.h \ settingspanel.h \ button.h \ textprinter.h libgui_la_SOURCES = widget.cpp \ container.cpp \ text.cpp \ text_uintp.cpp \ panel.cpp \ settingspanel.cpp \ button.cpp \ textprinter.cpp libgui_la_LIBADD = $(top_builddir)/src/utils/libutils.la \ $(top_builddir)/src/math/libmath.la critterding-beta12.1/src/gui/textprinter.h0000644000175000017500000000235411340334147017655 0ustar bobkebobke#ifndef TEXTPRINTER_H #define TEXTPRINTER_H #include #include #include "../utils/settings.h" #include "../utils/file.h" #include "../math/vector2i.h" // #define FTGL_TEXTURE 5 #include #include "../utils/ftgl/FTGL/ftgl.h" using namespace std; class Textprinter { public: static Textprinter* Instance(); void printTextprinter(); // get bounding boxes // FTPoint getBBox(const string& str); // FTPoint getBBox(const char *fmt, ...); unsigned int getWidth(const char *fmt, ...); unsigned int getWidth(const string& str); unsigned int getWidth(const int& number); Vector2i getDimensions(const string& str); string getFormattedString(const char *fmt, ...); // print left aligned void print(int x, int y, const char *fmt, ...); void print(int x, int y, const string& str); void print(int x, int y, const long unsigned int& longuint); void print(const Vector2i& pos, const string& str); void print(const Vector2i& pos, const unsigned int* num); // print right aligned void printR(float x, float y, const char *fmt, ...); void setUpFonts(); protected: Textprinter(); private: FTFont** fonts; File file; va_list ap; /* our argument pointer */ char text[256]; }; #endif critterding-beta12.1/src/gui/textprinter.cpp0000644000175000017500000001164511344301105020203 0ustar bobkebobke#include "textprinter.h" Textprinter* Textprinter::Instance () { static Textprinter t; return &t; } Textprinter::Textprinter() { // settings = Settings::Instance(); if ( Settings::Instance()->getCVar("headless") == 0 ) setUpFonts(); } void Textprinter::print(int x, int y, const char *fmt, ...) { glPushMatrix(); glTranslatef(x, y, 0); // glRotatef(180, 1.0f, 0.0f, 0.0f); glScalef(1,-1,1); va_list ap; /* our argument pointer */ char text[256]; if (fmt == NULL) return; va_start(ap, fmt); /* make ap point to first unnamed arg */ /* FIXME: we *should* do boundschecking or something to prevent buffer * overflows/segmentations faults */ vsprintf(text, fmt, ap); fonts[0]->Render(text); glPopMatrix(); } string Textprinter::getFormattedString(const char *fmt, ...) { va_list ap; /* our argument pointer */ char text[256]; va_start(ap, fmt); /* make ap point to first unnamed arg */ /* FIXME: we *should* do boundschecking or something to prevent buffer * overflows/segmentations faults */ vsprintf(text, fmt, ap); string a(text); return a; } unsigned int Textprinter::getWidth(const char *fmt, ...) { va_list ap; /* our argument pointer */ char text[256]; va_start(ap, fmt); /* make ap point to first unnamed arg */ /* FIXME: we *should* do boundschecking or something to prevent buffer * overflows/segmentations faults */ vsprintf(text, fmt, ap); FTBBox test = fonts[0]->BBox(text); return test.Upper().X(); } unsigned int Textprinter::getWidth(const string& str) { const char *text = str.c_str(); FTBBox test = fonts[0]->BBox(text); return test.Upper().X(); } unsigned int Textprinter::getWidth(const int& number) { stringstream sstream; sstream << number; const char *text = sstream.str().c_str(); FTBBox test = fonts[0]->BBox(text); return test.Upper().X(); } Vector2i Textprinter::getDimensions(const string& str) { const char *text = str.c_str(); FTBBox test = fonts[0]->BBox(text); Vector2i v(test.Upper().X(), test.Upper().Y()); return v; } // FTPoint Textprinter::getBBox(const char *fmt, ...) // { // va_list ap; /* our argument pointer */ // char text[256]; // va_start(ap, fmt); /* make ap point to first unnamed arg */ // /* FIXME: we *should* do boundschecking or something to prevent buffer // * overflows/segmentations faults // */ // vsprintf(text, fmt, ap); // // FTBBox test = fonts[0]->BBox(text); // return test.Upper(); // } // // FIXME if we get rid of this ftbbox shit here, we can cleanup the makefile // FTPoint Textprinter::getBBox(const string& str) // { // const char *text = str.c_str(); // // FTBBox test = fonts[0]->BBox(text); // return test.Upper(); // } // FIXME get rid of this void Textprinter::print(int x, int y, const string& str) { glPushMatrix(); glTranslatef(x, y, 0); glScalef(1,-1,1); const char *text = str.c_str(); fonts[0]->Render(text); glPopMatrix(); } void Textprinter::print(int x, int y, const long unsigned int& longuint) { stringstream sstream; sstream << longuint; print(x, y, sstream.str()); } void Textprinter::print(const Vector2i& pos, const string& str) { glPushMatrix(); glTranslatef(pos.x, pos.y, 0); glScalef(1,-1,1); // glRotatef(180, 1.0f, 0.0f, 0.0f); const char *text = str.c_str(); fonts[0]->Render(text); glPopMatrix(); } void Textprinter::print(const Vector2i& pos, const unsigned int* num) { glPushMatrix(); glTranslatef(pos.x, pos.y, 0); glScalef(1,-1,1); // glRotatef(180, 1.0f, 0.0f, 0.0f); stringstream str; str << *num; fonts[0]->Render(str.str().c_str()); glPopMatrix(); } void Textprinter::printR(float x, float y, const char *fmt, ...) { va_start(ap, fmt); vsprintf(text, fmt, ap); string str(text); print(x - getWidth(str), y, str); } void Textprinter::setUpFonts() { // clear if exists if ( fonts ) { delete fonts[0]; delete fonts; } // Allocate an array to hold all fonts fonts = new FTFont *[1]; char const *fontFilePath; string fontpath = Settings::Instance()->binarypath; string defaultf = "../share/critterding/font.ttf"; string systemf = "/usr/share/fonts/TTF/DejaVuSans.ttf"; string usepath = fontpath; usepath.append(defaultf); if ( !file.exists(usepath.c_str()) ) { usepath = systemf; if ( !file.exists(usepath.c_str()) ) { cerr << "Count not find font " << usepath << endl; exit(1); } } // fontFilePath = "fonts/DejaVuSans.ttf"; // if ( !file.exists(fontFilePath) ) // { // fontFilePath = "../fonts/DejaVuSans.ttf"; // if ( !file.exists(fontFilePath) ) // { // fontFilePath = "/usr/share/fonts/TTF/DejaVuSans.ttf"; // if ( !file.exists(fontFilePath) ) // { // cerr << "Count not find font " << fontFilePath << endl; // exit(1); // } // } // } fonts[0] = new FTTextureFont(usepath.c_str()); fonts[0]->UseDisplayList(true); if(!fonts[0]->FaceSize(11)) { cerr << "Failed to set size" << endl; exit(1); } // fonts[0]->Depth(32); fonts[0]->CharMap(ft_encoding_unicode); } critterding-beta12.1/src/gui/text.h0000644000175000017500000000040611301116254016237 0ustar bobkebobke#ifndef TEXT_H #define TEXT_H #include "widget.h" using namespace std; class Text : public Widget { public: Text(); ~Text(); void set(const string& n_string); void draw(); string v_string; Vector2i dimensions; protected: private: }; #endif critterding-beta12.1/src/gui/button.h0000644000175000017500000000134011277151350016574 0ustar bobkebobke#ifndef BUTTON_H #define BUTTON_H #include "panel.h" #include "../utils/events.h" // #include "../utils/commands.h" using namespace std; class Button : public Panel { public: Button(); ~Button(); void draw(); void click(const int& button); void release(const int& button); void genEvent( const int& button, const string& name, const cmdsettings& cmds, unsigned int responsetime, unsigned int minfresponsetime, unsigned int fresponseinterval ); // cmdsettings command; private: // Commands* cmd; // vector eventnames; map buttonlist; // typedef map ::const_iterator cmdlist_iterator; // cmdlist_iterator cmdit; Events *events; string eventname; }; #endif critterding-beta12.1/src/gui/settingspanel.cpp0000644000175000017500000000306011331352461020472 0ustar bobkebobke#include "settingspanel.h" Settingspanel::Settingspanel() { // isTouchable = true; // isTransparant = true; // zaxis = 0; mutatorcol1 = 10; mutatorcol2 = 200; mutatorcol3 = 280; } void Settingspanel::addMutator( const string& name, const cmdsettings& cmd1, const cmdsettings& cmd2, unsigned int posx, unsigned int posy ) { string str(name); string strval = str; string strdec = str; string strinc = str; strval.append("val"); strdec.append("dec"); strinc.append("inc"); addWidgetText( str, posx+mutatorcol1, posy+9, name ); addWidgetText( strval, posx+mutatorcol2, posy+9, settings->getCVarPtr(name) ); addWidgetButton( strdec, Vector2i(posx+mutatorcol3, posy), Vector2i(11, 10), "-", Vector2i(3, 8), cmd1, 150, 0, 2 ); addWidgetButton( strinc, Vector2i(posx+mutatorcol3+18, posy), Vector2i(11, 10), "+", Vector2i(1, 8), cmd2, 150, 0, 2 ); } void Settingspanel::addSettingmutator( const string& name, unsigned int posx, unsigned int posy ) { string str(name); string strval = str; string strdec = str; string strinc = str; strval.append("val"); strdec.append("dec"); strinc.append("inc"); addWidgetText( str, posx+mutatorcol1, posy+9, name ); addWidgetText( strval, posx+mutatorcol2, posy+9, settings->getCVarPtr(name) ); addWidgetButton( strdec, Vector2i(posx+mutatorcol3, posy), Vector2i(11, 10), "-", Vector2i(3, 8), cmd.gen("settings_decrease", name), 150, 0, 2 ); addWidgetButton( strinc, Vector2i(posx+mutatorcol3+18, posy), Vector2i(11, 10), "+", Vector2i(1, 8), cmd.gen("settings_increase", name), 150, 0, 2 ); } Settingspanel::~Settingspanel() { } critterding-beta12.1/src/gui/panel.h0000644000175000017500000000043011302776100016352 0ustar bobkebobke#ifndef PANEL_H #define PANEL_H #include "container.h" using namespace std; class Panel : public Container { public: Panel(); ~Panel(); void draw(); unsigned int zaxis; protected: virtual void drawBackground(); virtual void drawBorders(); private: }; #endif critterding-beta12.1/src/gui/container.cpp0000644000175000017500000000730411301116254017574 0ustar bobkebobke#include "text.h" #include "text_uintp.h" #include "button.h" #include "container.h" Container::Container() { isContainer = true; } void Container::draw() { if ( active ) drawChildren(); } void Container::drawChildren() { for( childit = children.begin(); childit != children.end(); childit++ ) childit->second->draw(); } Widget* Container::addWidgetPanel( const string& name, Widget* nwidget ) { children[name] = nwidget; children[name]->parent = this; children[name]->translate(0, 0); return children[name]; } Widget* Container::addWidgetText( const string& name, unsigned int posx, unsigned int posy, const string& textstring ) { Text* t = new Text(); t->parent = this; t->translate(posx, posy); t->set(textstring); t->active = true; children[name] = t; return children[name]; } Widget* Container::addWidgetText( const string& name, const string& textstring ) { Text* t = new Text(); t->parent = this; // t->translate(posx, posy); t->hcenter = true; t->vcenter = true; t->set(textstring); t->active = true; children[name] = t; return children[name]; } Widget* Container::addWidgetText( const string& name, unsigned int posx, unsigned int posy, const unsigned int* uintp ) { Text_uintp* t = new Text_uintp(); t->parent = this; t->translate(posx, posy); t->content = uintp; t->active = true; children[name] = t; return children[name]; } Widget* Container::addWidgetButton( const string& name, const Vector2i& pos, const Vector2i& dimensions, const string& textstring, const Vector2i& textpos, const cmdsettings& cmds, unsigned int responsetime, unsigned int minfresponsetime, unsigned int fresponseinterval ) { Button* t = new Button(); t->parent = this; t->translate(pos.x, pos.y); t->v_width = dimensions.x; t->v_height = dimensions.y; t->addWidgetText( "btext", textpos.x, textpos.y, textstring ); t->genEvent(1, name, cmds, responsetime, minfresponsetime, fresponseinterval); t->active = true; children[name] = t; return children[name]; } Widget* Container::addWidgetButton( const string& name, const Vector2i& pos, const Vector2i& dimensions, const string& textstring, const cmdsettings& cmds, unsigned int responsetime, unsigned int minfresponsetime, unsigned int fresponseinterval ) { Button* t = new Button(); t->parent = this; t->translate(pos.x, pos.y); t->v_width = dimensions.x; t->v_height = dimensions.y; t->addWidgetText( "btext", textstring ); t->genEvent(1, name, cmds, responsetime, minfresponsetime, fresponseinterval); t->active = true; children[name] = t; return children[name]; } bool Container::mouseOverChild(Widget** fWidget, int x, int y) { for( childit = children.begin(); childit != children.end(); childit++ ) { if ( (childit->second->isTouchable && childit->second->active && childit->second->mouseOver(x, y)) || !childit->second->isTouchable ) { // RECURSIVE INTO CONTAINERS if ( childit->second->isContainer ) { Container* c = static_cast(childit->second); if ( c->mouseOverChild( fWidget, x, y ) ) { return true; } else if ( childit->second->isTouchable ) { *fWidget = childit->second; return true; } } else if ( childit->second->isTouchable ) { *fWidget = childit->second; return true; } } } return false; } void Container::updateAbsPosition() { absPosition.x = position.x; absPosition.y = position.y; if ( parent ) { absPosition.x += parent->absPosition.x; absPosition.y += parent->absPosition.y; } // adjust children aswell for( childit = children.begin(); childit != children.end(); childit++ ) childit->second->updateAbsPosition(); } Container::~Container() { for( childit = children.begin(); childit != children.end(); childit++ ) delete childit->second; } critterding-beta12.1/src/gui/text_uintp.h0000644000175000017500000000036311264467233017476 0ustar bobkebobke#ifndef TEXT_UINTP_H #define TEXT_UINTP_H #include "widget.h" using namespace std; class Text_uintp : public Widget { public: Text_uintp(); ~Text_uintp(); void draw(); const unsigned int* content; protected: private: }; #endif critterding-beta12.1/src/gui/text_uintp.cpp0000644000175000017500000000031311264472777020035 0ustar bobkebobke#include "text_uintp.h" Text_uintp::Text_uintp() { content = 0; } void Text_uintp::draw() { glColor3f(1.0f, 1.0f, 1.0f); textprinter->print( absPosition, content ); } Text_uintp::~Text_uintp() { } critterding-beta12.1/src/gui/widget.cpp0000644000175000017500000000217511302776100017101 0ustar bobkebobke#include "widget.h" Widget::Widget() { settings = Settings::Instance(); textprinter = Textprinter::Instance(); v_widthP = &v_width; v_heightP = &v_height; hcenter = false; vcenter = false; isMovable = false; isTouchable = false; isContainer = false; isTransparant = false; active = false; } void Widget::draw() {} void Widget::click(const int& button) {} void Widget::release(const int& button) {} bool Widget::mouseOver(int x, int y) { if ( active && x > absPosition.x && x < absPosition.x+(int)*v_widthP && y > absPosition.y && y < absPosition.y+(int)*v_heightP ) return true; return false; } void Widget::translate(int x, int y) { position.x += x; position.y += y; updateAbsPosition(); } void Widget::updateAbsPosition() { absPosition.x = position.x; absPosition.y = position.y; if ( parent ) { absPosition.x += parent->absPosition.x; absPosition.y += parent->absPosition.y; } } void Widget::swap() { active = !active; } unsigned int Widget::height() { if ( active ) return *v_heightP; return 0; } unsigned int Widget::width() { if ( active ) return *v_widthP; return 0; } Widget::~Widget() { } critterding-beta12.1/src/gui/panel.cpp0000644000175000017500000000232311331157113016707 0ustar bobkebobke#include "panel.h" Panel::Panel() { isTouchable = true; isTransparant = true; zaxis = 0; } void Panel::draw() { if (active) { drawBackground(); drawBorders(); drawChildren(); } } void Panel::drawBackground() { if (isTransparant) { glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); glEnable(GL_BLEND); } glColor4f(0.05f, 0.05f, 0.05f, 0.75f); glBegin(GL_QUADS); glVertex2f(absPosition.x, absPosition.y+v_height); glVertex2f(absPosition.x, absPosition.y); glVertex2f(absPosition.x+v_width, absPosition.y); glVertex2f(absPosition.x+v_width, absPosition.y+v_height); glEnd(); if (isTransparant) glDisable(GL_BLEND); } void Panel::drawBorders() { glColor3f(0.5f, 0.5f, 0.5f); glBegin(GL_LINES); glVertex2f(absPosition.x, absPosition.y+v_height); glVertex2f(absPosition.x, absPosition.y); glVertex2f(absPosition.x, absPosition.y); glVertex2f(absPosition.x+v_width, absPosition.y); glVertex2f(absPosition.x+v_width, absPosition.y); glVertex2f(absPosition.x+v_width, absPosition.y+v_height); glVertex2f(absPosition.x+v_width, absPosition.y+v_height); glVertex2f(absPosition.x, absPosition.y+v_height); glEnd(); } Panel::~Panel() { } critterding-beta12.1/src/gui/settingspanel.h0000644000175000017500000000102011331352461020131 0ustar bobkebobke#ifndef SETTINGSPANEL_H #define SETTINGSPANEL_H #include "panel.h" using namespace std; class Settingspanel : public Panel { public: Settingspanel(); ~Settingspanel(); protected: unsigned int mutatorcol1; unsigned int mutatorcol2; unsigned int mutatorcol3; virtual void addMutator( const string& name, const cmdsettings& cmd1, const cmdsettings& cmd2, unsigned int posx, unsigned int posy ); virtual void addSettingmutator( const string& name, unsigned int posx, unsigned int posy ); private: }; #endif critterding-beta12.1/src/gui/text.cpp0000644000175000017500000000104511301116254016572 0ustar bobkebobke#include "text.h" Text::Text() { v_string = ""; } void Text::draw() { glColor3f(1.0f, 1.0f, 1.0f); if ( hcenter ) { absPosition.x = parent->absPosition.x + (*parent->v_widthP/2) - (dimensions.x/2); absPosition.y = parent->absPosition.y + (*parent->v_heightP/2) - (dimensions.y/2) + dimensions.y; textprinter->print( absPosition, v_string ); } else textprinter->print( absPosition, v_string ); } void Text::set(const string& n_string) { v_string = n_string; dimensions = textprinter->getDimensions(v_string); } Text::~Text() { } critterding-beta12.1/src/gui/button.cpp0000644000175000017500000000152411302776100017126 0ustar bobkebobke#include "button.h" Button::Button() { isTransparant = false; // cmd = Commands::Instance(); events = Events::Instance(); v_width = 60; v_height = 40; } void Button::draw() { if (active) { drawBackground(); drawBorders(); drawChildren(); } } void Button::genEvent(const int& button, const string& name, const cmdsettings& cmds, unsigned int responsetime, unsigned int minfresponsetime, unsigned int fresponseinterval ) { eventname = name; buttonlist[button] = eventname; events->registerEvent(eventname, cmds, responsetime, minfresponsetime, fresponseinterval ); } void Button::click(const int& button) { // cerr << "activating event with button" << button << endl; events->activateEvent( buttonlist[button] ); } void Button::release(const int& button) { events->deactivateEvent( buttonlist[button] ); } Button::~Button() { } critterding-beta12.1/src/gui/widget.h0000644000175000017500000000214611324453044016547 0ustar bobkebobke#ifndef WIDGET_H #define WIDGET_H #include #include #include "textprinter.h" #include "../math/vector2i.h" #include using namespace std; class Widget { public: Widget(); ~Widget(); Vector2i position; virtual void draw(); virtual void click(const int& button); virtual void release(const int& button); void swap(); bool active; // movable (pickable) object bool isMovable; // touchable object (allows ignoring containers as clickable) bool isTouchable; // types bool isContainer; // drawing bool isTransparant; // width/height accessors unsigned int height(); unsigned int width(); Vector2i absPosition; // pointer to parent Widget* parent; // is mouse over widget bool mouseOver( int x, int y ); // widget ops virtual void translate( int x, int y ); int* v_heightP; int* v_widthP; bool hcenter; bool vcenter; virtual void updateAbsPosition(); protected: Settings* settings; Textprinter* textprinter; // width and height int v_height; int v_width; private: }; #endif critterding-beta12.1/profiles/0000755000175000017500000000000011347266042015365 5ustar bobkebobkecritterding-beta12.1/profiles/race0000644000175000017500000000026611320212237016212 0ustar bobkebobkerace 1 mincritters 33 worldsizeX 130 worldsizeY 15 food_maxenergy 3000 food_size 500 critter_maxlifetime 3000 critter_maxenergy 50000 brain_mutationrate 15 body_mutationrate 15 critterding-beta12.1/INSTALL0000644000175000017500000000063411344074465014601 0ustar bobkebobkeRequirements ============ gcc 4.2+ libtool freetype2 SDL Basic Installation ================== > autoreconf -fi > ./configure > make > (make install) start an ecosim > ./src/critterding or if you did 'make install' > critterding start a race > ./src/critterding --profile profiles/race or if you did 'make install' > critterding --profile profiles/race Problems ======== IRC: #critterding@irc.freenode.orgcritterding-beta12.1/share/0000755000175000017500000000000011347266042014644 5ustar bobkebobkecritterding-beta12.1/share/critterding/0000755000175000017500000000000011347266042017162 5ustar bobkebobkecritterding-beta12.1/share/critterding/font.ttf0000644000175000017500000227731011344065077020665 0ustar bobkebobke0FFTMSH<GDEF]XXGPOS/GSUBN֘LOS/2!r Vcmap .cvt i9<fpgmq4vj<gasp glyfCĀhead)t6hhea $hmtxv~Uhkernk/6i8<~locaJfUlmaxpqj$ namehMjD=postL3Lprep; y`heƼHƼH$W           "##$HIIJLMQRpq|}     "#     ; < < = I J P Q Q R U V W X o p q r   ~!"qr|}2334Y \DFLTzarabarmnbraicanschercyrlgeorgrekhanihebrkana*lao 6latnFmathnko ogamrunrtfngthaiKUR SND URD MKD SRB 4ISM 4KSM 4LSM 4MOL 4NSM 4ROM 4SKS 4SSM 4 kern8kern>markFmarkTmark\markdmkmkjmkmkrmkmkx    "*2:BLT\dlt|x8  8 >/024<7j7:I`j0&:  sv{sv{ &,28>DJPV\bhntz::::r 4 4 `Iqrtuwxyz|Iqrtuwxyz|JPV\bhntz$ l N>X  &,lwlwlwfn " &,28l`l~l~l`l~l`Z& #HNTZ`flrx~tt;888  !"    ! "(.4:@FB :v| $*06<BHNTZ`flrx~hhh=DhhhDhh=DDnnnnhh   !# J P)rr0tt1v|2339  J P%r|,3378 $*06<BHNTZ`flrx~ &,{{{{{{{{{{{{{{{{{{{{{{{{{{{{{{ $6HZl~ cj cj cj cj c c cj cj#sv{>DJPV\bhntz*  &,28>DJPV\bhntz "(.4:@FLRX^djpv| $*06<BHNTZ`flrx~ &,28>DJPV\bhntz "(.4:@FLRX^djpv|     $ * 0 6 < B H N T Z ` f l r x ~      & , 2 8 > D J P V \ b h n t z     " ( . 4 : @ F L R X ^ d j p v |     $ * 0 6 < B H N T Z ` f l r x ~      & , 2 8 > D J P V \ b h n t z  "(.4:@FLRX^djpv| $*06<BHNTZ`flrx~{U:t!N8'Qn ppjjj,v,,vjj  XXXXD[j[j, 8 8>>j pjjj^jj,,,,,,,     8 8 8 j j>>, ppjI^`k/#eYYYcP`{U:tii!NQnU!Q{++++++jj++jj++jj++ 8 8jj 8 8jj,,X X ,,XX,,X X ,,X X      j j,j,j j j,j,j>  ++pp++,,,, ,,,,,,,,,,2  pp++pp++jjjj++jj++,,XX,,XX,,XXjjjj    XXjjXXjjXX&j&jXX&j&j[j[jSjSj[j[jSjSjXX 8 8jjjj 8 8,j,j>>SS&j&j>++jjj  pp++j++ 8jjjj++^++j++,XX,XX,XX,X X   >SSp++ jIII^^^```kkk///###eeeYYYYYYYYY$AMpBDcs~2#sv{BHNTZ`flrx~F 'PV\bhntz "(.4U0+0008q00800i00E0 0100000P=i0v00v00d000UU8000U $*,022 45 78:> "0 $6HZl~ cr cr cr cr cr cr cr crIqrtuwxyz|RX^djpv|``& b lrx~ &,28>DJPV\bhntz "(.4:@FLRX^djpv| $*06<BHNTZ`flrx~ &,28>DJPV\bhntz "(.4:@FLRX^djpv|     $ * 0 6 < B H N T Z ` f l r x ~      & , 2 8 > D J P V \ b h n t z     " ( . 4 : @ F L R X ^ d j p v |     $ * 0 6 < B H N T Z ` f l r x ~      & , 2 8 > D J P V \ b h n t z R``S`4rrLRLX X X X [r[r~x,LLRLLRLxLLLxx4RI^`n#YYY`R``S`++++++LL++LL++++LL@LL@XXXXXXXXxxxxxx++XV++,,,:,,,,:,:,,,,,:,:LrrX+F+Frr++L&LRR++LL++XXXXX~X~X X X X RRX X & & X X &&[r[rSrSr[r[rSrSr~~x~x~LLFLRFSrSrR&R&R++R&RL XVX++++LLRL++R++++XXXxXxXxXxX~X~4S4S4++&RIII^^^```nnn###YYYYYYYYY%%//88Mp')Hfghij4?QZ2[Iqrtuwxyz|rx~`{{{{{{{{` <BHNTZ`flrx~]xx@[")@>E"~~x2x::-."> @FLRX^djpv|]kxyyyxyz[f"w)h>yEy`P["~[~t`zxy2{`uxJJ::++-.   !" 28>DJPV\bhnttbbbbt`~~`~` Z R   !"# $*06<BHNTZ Y &,28>DJPV\bhntz "(.4:@FLRX^djpv| $=D]468QT9Zd=grHw{T D6L  $Js}- {{8> 7pv| $*06<BHNTZ`flrx~L/'s.}////////s}/////s{y5D;/}R7$&(,268DFHLRVX-* [\]^klz?   $*06<BHNTZ`flrx~ &,28>DJPV\bhntz "(.4:@FLRX^djpv| $*06<BHNTZ`flrx~ &,28>DJPV\bhntz "(.4:@FLRX^djpv|     $ * 0 6 < B H N T Z ` f l r x ~      & , 2 8 > D J P V \ b h n t z     " ( . 4 : @ F L R X ^ d j p v | L\/.Rs''}srJf;RRsRR%}^Gb`R////}}J////Rs}f7R/'z`RR///.RR'}r`RTTRTcRRJ@@RjRjRbRb}RRRRRRRR}R555RRaRt;Q'RRRRRRR}}^G^dRRR::R'aHRR_R:RGR R~RJ}'/'}'}^TTT@X}Tg^GX^//LBRRf,4$R'_zRf4L}`ReT'sR^G^5s/RRwRRJV1vvvR;nR RRL5s/<\R&Rx9\wR}RO$= D]$>BCHIJKRT  UV--WEEXNNYTTZYY[aa\ll]vv^{{_`bf iJqLmFFIILL""3366|}346;>FJNRW S S [ ^ ` b e e h m t t x x | }      ~ ~ "36QT7VW;Yd=grIw{UZ&&m((n]foy{|}??~   !"# $*06<BHNTZn 6ntz "(.4:@FNT\bjpv| $*06<BHNTZ`flrx~ &,28>DJPV\bhntz &,28>DJPV\bhntz     " ( . 4 : @ F L R X ^ d j p v |      & , 2 8 > D J P V \ b h n t z     " ( . 4 : @ F L R X ^ d j p v |     $ * 0 6 < B H N T Z ` f l r x ~      & , 2 8 > D J P V \ b h n t z  "*06<BHNTZ`fntz "(.4:@FLRX^djpv|  &,28>DJPV\bhntz &,28>DJPV\bhntzL\/.*s''}srJ{#{{;j{//{{s{ {o{{'{}{^{G{b{`{{'{{}}{Q{{{{}{\LX;\//''{ssr`{{{'{{{./'}{r`{{T{{{{c{R{R{J|@{@{{{jj{{b{b{}{/{{{{{{{{}{{{3{33{^{a{p{{;{Q{'{{{}{}{^{G{^d{{{{{::'a{H{{/{{j:{G{ J{~^{}J|E{}{{{{E}{p{{t{}{j{{{b{{^{~~{}{t{^{{{{/'{{{H/rtOs}s'LsoqGGYNsT{a{E{{{{@{{t{{{{}{{{{T{`{kb{{K{{{{{{{{t{{'{///{{4{^{c{s{"{O{,s{O{%'}{{{O{t{t{e{sK{{{{'}{E{b{{{{^{{{T{{TT{{@{{{{{}{{{{{{{{{T{g{b{^{G{{{{^{{LBRf,4${' _zf4DL}1{`{e**}T{{'s^{G{^{{{3s{{/ {0{{{{'l{n{T{T{wJ{{{1{{v{vqv{*\;{n{{{L5s/<\&Rx9{\{w{{{{{}{m$= D]$>?ABCDFG  HI55JBBKEELHIMNNOPPPRVQXYV[]X__[aa\ff]ij^lp`txe{{jkl pJxLmE]deiikkmmooww.DL ["#a*+c.6e@@nMMoXXp^^qbbr|}suvxyz3;{>GJNQW[[ S S [ ^ ` b e e h m t t x x | }      ~ ~$'*02588::QTVWYdgrw{ && ((!]f",/0124??5  "#( J P.r|533@A$*06>FLRX`flrx~ &,28>FNTZ`flrx~{{{{{{{{{{{{{{{{{{orr{r{{{{{{{{{{{{{{A{{{{{{{{{{{{{{ {{{{{{{{{{{{{{&!0#5PKr9KD &&K9a}au9aauaau/&DaDDkkDDDDkDD)ak}/DDa9}D}&&9}k}k}&D aDY}aaauNaaau}}k}ka aakkAk&k}}DHVaD)kkDN9a}au9aau/9a}au9aau/9a}au9aau/&kD&9a}au9aau/9a}a9aa/D?}DVD aDKr9KD &&Kk}k&/<&O$$%%&&''))**++-- .. // 22 33 445566778899::;;<<==HHIINNQQRRUUYYZZ[[ \\!mm"}}#$%&%'( )*+!!,,-((. /  0  ""&&100::?? 2 3 4$$%%&&''))** ++-- ./22 3344 5566 778899::;;<<==DDFFGGHHIIJKLLOOPPQQRRTTUUVV WW!XX"YY#ZZ$[[%\\&mm'}}()* ++,,-../"/&&010101234352678888393:;;  3<3<=<;    !! "" ## $$>%%5&&''!((?++@--@//@0011"33@55@66A77B88C99D::??4EFEF G43H4IJ H HA I IK J JL K KB L LA M MB C D M N O^$%&')*+-./23456789:;<=HINQRUYZ[\m}  "&0:? `$XAYAEGKMQ SW .DFLTzarabarmnbraicanschercyrlgeorgrek"hani2hebr>kanaPlao \latnhmathnko ogamrunrtfng thaiKUR SND (URD (  MKD SRB  4ISM FKSM FLSM FMOL ZNSM FROM ZSKS FSSM F    aaltaaltaaltccmpccmpccmpccmpdligdligdligfinafinahlighliginitinit ligaligalocl locl&locl,medi2medi8rlig>rligHsaltPsaltVsalt\     'PX`h "*2:BJRZbjrzJ\ nvX               p   *  H   R !$% B6##66>9LM *_ J K L M i$=EEGGIIKKLMNOWW      ""$$&&((**,,..0022446688:;==??AAHHRRTTVV  **__  J M &   &$$4F!!$$4F""$$4F##$$4F$$$$4F%%(0AD&.6EEGI&.6JKMN&.6OQSS&(0TW&v6Pblv",6PZd        $%&'()*,-./024578:;<=>A B  !$'*-0D$&(*,0268<@DHLNPRTX\`dhlptx|Megp#%B  "%(+.1l3.4:>BFJVZ^bfjnrvz~ QQSSUY^egmop)1B  #&),/2l3-39=AEIUY]aeimquy} QQSSUY^egmop)12  ww vssvw~&8Jlww zw zw utrq utqrtuwz 00> $*&$*&$J 8 "(IOILOLI OLIRl$*06< xwvutsrqP{NzMy &,!xwvutqOzQzRfnp0$B 8  WVWA(:FPZfr "   " $; <V p0 q(/ QF WX VR")567DF o ogfhdeji#9?FLTZgfhdeji#9?FLTZ,-DO *"&?,-DO\  X6 usvtyzr3{w|x  ! LM *_ YYYYY33f . `)PfEd@ m`,$, x~OSXZbw~%V_  :UZot?5JR>PjGv#.[jx{EMWY[]} ' d q ! !I!K!N!###!#(#,#u#z#}######$#$i&&'' '''K'M'R'V'^''''''()) )A))))***/***++$+T,o,w,}-e-o..%..MGMQWn+?KO6<>ADO#t QWZ\pz 1Ya  !@Z`ty? 7LT@RtFn&0]w{ HPY[]_ * j t !! !K!N!S!###$#+#s#z#}######$"$`%&''' ')'M'O'V'X'a'''''')) )@))))** */*}**+++S,`,q,y-0-o.."..MDLPTb&0FN8>@CFR pv^\TO>=<4/,+&" mljiga`_^][ZYWVUSQ~}|zyqpofbY+)320/." zvsoQPOMI>8642\ ?><;:96530/) A,gb^0%$#qhkkkkkkkk5k1k+k'k!kjjj|"|snmlkjig_W ~bOQSWXZZ\bpwz~"#7 %1VY_a "$?D  F  HIJK!:L@UfZZ|`o}tty??#-/U 57JLRT:e>@PRjt  FG nv 3#H&.V0[_]jwx{{ d   E HM PW YY [[ ]] _}  2 g v    ' * d j q t  / 4 J L N P!! Q! !I [!K!K !N!N !S! !# ## P##! R#$#( X#+#, ]#s#u _#z#z b#}#} c## d## e## f## z## |## }$"$# ~$`$i %& &&'''@'' D' ''H')'Kd'M'M'O'R'V'V'X'^'a''''''''''''())) )  )@)A )) ))))))*** **/*/.*}*/**S**`++b++$}+S+T,`,o,q,w,y,}-0-e-o-o...".%....MMDGLM"PQ$TW&bn*7;=L&+Q0?WFKgNOmosw|~68<>>@ACDFOR #ptvV89;>@DFFJPRkՠ)]   !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`a rdei xpk rvj \s gw @ O MT il|=cn XT Dm} b T: @  y qz5fqu-J3T99NR7s`s3VV9s3D{o{RoHT3fs +b-{T#\q#H99`#fy```{w``b{{Rffw;{J/}oo5jo{-{T7fD)fs, %Id@QX Y!-,%Id@QX Y!-,  P y PXY%%# P y PXY%-,KPX EDY!-,%E`D-,KSX%%EDY!!-,ED-,%%I%%I` ch #:e:-ff@ /10!%!!fsr)5 5@ K TX8Y<2991/0 P ]%3#3#5qeB@KTKT[X8Y1<20@0 @ P ` p ]#!#o$++`@1      91/<<<<<<<2220@   ]!! !3!!!!#!#!5!!5!T%Dh$ig8R>hggh`TifaabbNm!(/@U" '&( /)/))/B" ) *!#*- ) " & 0K TX8YK TKT[KT[X@8Y<<<1/299990KSX99Y"#.'5.546753.'>54&dijfod]SS\dtzq{---@A$*.U# jXV`OnZXhq) #'3@6$%&%&'$'B .$ &($4'!%   ! + 1 4K TK T[K T[KT[KT[K T[X18Y9912<0KSXY""32654&'2#"&546"32654&%3#2#"&546WccWUccUVcbWWcd1Zܻۻa ۻۼ 0@      !         B  (('+'$ .  .'.'!!199999991/9990KSX99999999Y"2]@ " ) **&:4D ^YZ UZZY0g{ "-  ' (   2'') #**(/2; 49?2J LKFO2VZ Y UY\_2j i`2uy z 2229]]3267 >73#'#"5467.54632.#"[UԠ_I{;B h]hΆ02޸SUWDi;#QX?@Yr~YW׀c?}<$$/1oX3go7@ KTKT[X8Y10@ @P`p]#o+{ 7@  KTX 8YKTX @8Y29910#&547{>;o @ <99103#654<:=JN@,       <2<2991<22990 %#'-73%g:r:g:PrPbybcy #@   <<1/<<0!!#!5!-Ө-Ӫ--@ 1073#ӤR@d10!!d1/073#B-@B/9910KSXY"3#m #@  10"32'2#"  P3343ssyzZ @@B  KTX@8Y1/20KSXY"]7!5%3!!JeJsHHժJ@'B   KTKT[KT[X8Y91/20KSX9Y"@2UVVzzvtvust]]%!!567>54&#"5>32Ls3aM_xzXE[w:mIwBC12\ps(p@.    #)&  )KTKT[X 8Y99190@ daa d!]!"&'532654&+532654&#"5>32?^jTmǹSrsY %Đ%%12wps{$& Ѳ|d @   B    K TK T[X 8Y<291/<290KSXY"@* *HYiw+&+6NO O Vfuz ]] !33##!55^%3`d^@#    KTKT[X8YKTX@8Y190!!>32!"&'532654&#",X,$^hZkʭQTժ 10$& $X@$  "% " !%190@]]"32654&.#">32# !2 LL;kPL;y$&W]ybhc@B991/0KSXY"KTX@878Y@X9Hg]]!#!3V+ #/C@% '-'0 $*$ !0991990"32654&%.54$32#"$54632654&#"HŚV г "Əُattt$X@# %!"" %190@]]7532#"543 !"&2654&#"LK:lL>$& V\s[#@<21/073#3### %@  <2103#3#ӤR#٬@^M@*B$#29190KSXY" 5Ѧ`@ #<210!!!!^O@+B$#<9190KSXY"55//m$e@+$     &%K TX8Y99991/9990y z z ]%3##546?>54&#"5>32ſ8ZZ93lOa^gHZX/'eVY5^1YnFC98ŸLVV/5<4q L@2  L4307$7CM34( (+(I+*(I,=M<9912990K TK T[KT[KT[KT[XMMM@878Y@ NN/N?N]32654&#"#"&5463253>54&'&$#"3267#"$'&5476$32|{zy!orqp ˘s'6@   0210].# !267# !2'ffjzSb_^^_HHghG.@   2 99991/0`]3 !%! )5BhPa/w.,~ .@   21/0 ]!!!!!!9>ժF# )@ 21/0 ]!!!!#ZpPժH7s9@ 43 1990%!5!# !2.# !26uu^opkSUmnHF_`%; ,@ 8  221/<20P ]3!3#!#"d+9.KTX@8Y1/0@ 0@P`]3#+f B@  9 KTX@8Y991990@ 0 @ P ` ]3+53265M?nj @(B  291/<290KSXY"]@ ((764GFCUgvw    (+*66650 A@E@@@ b`hgwp  ,]q]q3! !#3wH1j%@ :1/0@ 0P]3!!_ժ @4  B    >  91/<290KSXY"p]@V   && & 45 i|{y   #,'( 4<VY ej vy ]]! !###-}-+3 y@B6 991/<2990KSXY" ]@068HGif FIWXeiy ]]!3!#j+s #@  310"32' ! ':xyLHH[[bb:@   ? 291/0@ ?_]32654&#%!2+#8/ϒs R@*  B     39991990KSX9Y""32#'# ! '? !#y;:xLHHab[T@5  B    ?  299991/<9990KSX9Y"@]@Bz%%%&'&&& 66FFhuuw]]#.+#! 32654&#A{>ٿJx~hb؍O'~@<    B %( "-"(9999190KSX99Y")])/)O)].#"!"&'532654&/.54$32Hs_wzj{r{i76vce+ٶ0/EF~n|-&J@@@1/20K TX@878Y@  @ p ]!!#!ժ+)@@   8AKTX8Y1299990]332653! ˮ®u\*$h@'B91/290KSXY"P]@b*GGZ} *&&))% 833<<7HEEIIGYVfiizvvyyu)]]!3 3J+D {@I      B     91/<2290KSXY"]@  ($ >>4 0 LMB @ Yjkg ` {|      !   # $ %  <:5306 9 ? 0FFJ@E@BBB@@ D M @@XVY Pfgab```d d d wv{xwtyywpx   []]3 3 3# #D:9:9+=; f@  1 ]@ /<20KBPX@   @    Y3 3 # #su \Y+3{@(B@@ 91/290KSXY" ]@<5000F@@@QQQe &)78@ ghxp ]]3 3#f9\ @BB K TK T[X8Y991/0KSXY"@@ )&8HGH    / 59? GJO UYfio wx ]]!!!5!sP=g՚oX;@CK TX@8YKTKT[X8Y210!#3!XB-@B/9910KSXY"#mo0@CKTKT[X@8Y<10!53#5oXޏ@ 91290 # #HHu-10!5f1@ D10K TKT[X@878Y #ofv{-{ %@'   #   E&22991/9990@n0000 0!0"?'@@@@ @!@"PPPP P!P"P'p' !"'''000 0!@@@ @!PPP P!``` `!ppp p! !]]"326=7#5#"&5463!54&#"5>32߬o?`TeZ3f{bsٴ)Lfa..'' 8@  G F221/0`]4&#"326>32#"&'#3姒:{{:/Rdaadq{?@  HE210@ ].#"3267#"!2NPƳPNM]-U5++++$$>:#qZ8@G E221/0`]3#5#"3232654&#":||ǧ^daDDaq{p@$   KE9190@)?p?????,// , ooooo ]q]!3267# 32.#" ͷjbck)^Z44*,8 Cė/Y@     LK TX @8YKTX 8Y<<991/22990@P]#"!!##535463cM/ѹPhc/яNqVZ{ (J@#  &#' & G E)221/990`***]4&#"326!"&'5326=#"3253aQQR9||9=,*[cb::bcd4@  N  F21/<90`]#4&#"#3>32d||Bu\edy+@F<21/0@  @ P ` p ]3#3#`Vy D@   O  F<2991990@ @P`p]3+532653#F1iL`a( @)B F 291/<90KSXY" ]@_ ')+Vfgsw    ('(++@ h` ]q]33 ##%kǹi#y"F1/0@ @P`p]3#{"Z@&   PPF#291/<<<290@0$P$p$$$$$$$ ]>32#4&#"#4&#"#3>32)Erurw?yz|v\`gb|d{6@  N  F21/<90`]#4&#"#3>32d||Bu\`edqu{ J@  QE10@#?{{   {  {]"32654&'2#"s98V{>@ GF2210@ `]%#3>32#"&4&#"326s:{{8 daaqVZ{ >@   GE2210@ `]32654&#"#"3253#/s:||:/daDDadJ{0@    F21/90P].#"#3>32JI,:.˾`fco{'@<  S  SB %( R"E(9999190KSX99Y"']@m   . , , , ; ; ; ; $( ( *//*(() )!$'      '/)?)_))))))]]q.#"#"&'532654&/.54632NZb?ĥZlfae@f?((TT@I!*##55YQKP%$78@  F<<2991/<2990]!!;#"&5#53w{KsբN`>X{;@    NF921/290o]332653#5#"&||Cua{fc=`@'BK TX@8YKTKT[X8Y91/290KSXY"@Hj{  &&)) 55::0FFIIFH@VVYYPffiigh`ut{{uz>]]3 3#=^^\`TV5` @IU U U U   B     K TKT[KT[KT[K T[X@8YK TK T[KT[X8Y91/<2290KSXY"@" 5 IIF @ [[U P nnf yy          %%#'!%""%' $ ! # 9669 0FHF@B@@@D D D @@VVVPQRRPS T U cdejejjjn a g ouuy}x}zzxy  { v } @/   y]]333# #V`jjj;y` C@F      B   K TKT[KT[KT[X@8YKTX8Y91/<290KSXY"@   & =1 UWX f vzvt        )&% * :9746 9 0 IFE J @ YVYYWVYVV Y P o x  /]] # # 3 dkr))`HJq=V`@C        B     K TKT[X @8YKTX 8Y9129990KSX2Y"@     # 5 I O N Z Z j        '$$  )( % $ $ ' ** 755008 6 6 8 990A@@@@@@@@B E G II@TQQUPPVUVW W U U YYPffh ii`{xx   e]]+5326?3 3N|lLT3!;^^hzHTNlX` @B K TK T[X8YKTX@8Y2991/0KSXY"@B&GI  + 690 @@E@@CWY_ ``f``b ]]!!!5!qjL}e`ۓ%$w@4 %   !  % $  C %K TX@8Y<<29999999199999990&]#"&=4&+5326=46;#"3>l==k>DV[noZVtsݓXX10#$@6%   #%#C %K TX8YKTX@8Y<2<9999999199999990&]326=467.=4&+532;#"+FUZooZUF?l>>l?VWstݔ1#@  1990#"'&'&'&#"5>32326ian ^Xbian ^V1OD;>MSOE<>L5 b@ <2991/0K TX @ 878YKTKT[KT[X  @878Y P ]#53#3+e#!Q@+     "  "<<<221<9990%.'>7#&73JDFHAMf fIX⸹)**'# 32!b`@!    <<1/2<2990K TX@878Y66].#"!!!!53#535632NL=ty-=))׏/я^R#/@I -'! - -'!0 *$0* $ $(st*(s099999999919999999907'#"&''7.5467'7>324&#"326{r%$&(r;t=:x=q%%&&s7t@?s9q(&%%s>v:@t8s'%$|pprR@F  B     fe f e<2299991/2<2<290KSXY"K TX@878Y@(' ' ')((79  ]]!#!5!5'!5!3 3!!!c`Tþ{yT9{3{JD{3@ <210##  \= >@54&.#"#"&'532654/.5467.54632{?>?>S8alӃ\]>9̭IXW:fqր][;;ȦI.Z.L-[.K''PGZsweZ54m@''TLf{xf[1,pEF)@dd1<20K TK T[X@878YK TK T[KT[KT[X@878YKTKT[X@878Y@````pppp]3#%3#^y/IC@&=>:A$104G$ 7aD=0^* D^ J21/02#"$'&5476$"3267>54&'..#"3267#"&54632mmllmmmmllmm^^``^^⃄^]]^\^BB@zBCFInmmmmnnmmmmng^^^傁^^__^]⃅]^^! "s;)_@3(%%  * "(kl"k *22999199990!!#5#"&546;54&#"5>32"326=P,]uu>DIE~bRhP{@p?Dq[[""CO@Mr%# @I    B   o o n<2991<2990KSXY" 5 5%-+#-+#RR^@ 10!#!^d10!!d/8L`@6EBC?2H09JC 9 $HE301B54&'.'2#"$'&5476$#32654&'2#'.+#^^``^^⃄^]]^\^ㄘmmllmmmmllmm}{{nWXfi`C.;I6Bf^^^傁^^__^]⃅]^^gnmmmmnnmmmmnb>KL?gwyVpMI`3Db+/10K TKT[X@878Y!!Vu=  @  Z[Z10"32654&'2#"&546PnnPPnoO@v+..ooPOmmOOp1.-rB .@     <2<21/<<0!!#!5!!!-Ө-}}^J@$}}B ~9190KSX2Y"!!56754&#"5>32 "?XhU4zHM98rn81^BQ##{l0b(H@'    #)~&~ )999190#"&'532654&+532654&#"5>32 \e9}F4wCmxolV^^ad_(fQI7Z`mR|yOFJLl?<:=svcE`sRf1@ D10K TKT[X@878Y3#fV` M@%  !   NF!2912<990"`""]3326533267#"&'#"&'#% )I#ER2bf*V H<9 NPOONN;9 %@]] 91290!###.54$yfNݸHF103#F#u@  ' 1/90!#"&'532654&'T76xv.W+"J/;<+->i0Y[ 0.W= ,@   |]|| 12035733! c)t'+n`d.@  klk 9910!!2#"&546"32654&PXγгi~hi}|P{ݿܾsH# @I  B   o op<<991<2990KSXY"5 %5 +-+-#^R^  ^R^  &{' d 5?&{'td 5b&u' d 5 $@/  !# #%" " "!& %999919990KTKT[KT[X%%%@878Y@ ttttv]33267#"&546?>7>5#537ZZ:3mN`^gIYX0&DeWX5^1YnFC98ŸLVV/5<6hk&$uuhk&$suhm&$vu  +@ ]1h^&$tu #+@ @O# /#]1hN&$ru  +@ 0?  ]1hm !@T   !!  ! !!!B     !  VV!"2299999991/<9990KSXY" #]@  s P#f iu {yyv v!# ]]4&#"326!.54632#!#TY?@WX??Y!X=>sr?<҈_Z?YWA?XXN)sIsrFv)H@9  B     <291/<0KSXY"]@gww  ]!!!!!!#!59=qժF՞su'&&z-k&(uuk&(sum&(vu@@ ]1N&(ru @@ @]1;k&,u/uk&,s/u`m&,v/u +1XN&,r/u +1  g@    2  y<291/220@(   ]]! )#53!!3 !iP`P5~.,3^&1tu"+@ 0?""]1sk&2u'usk&2s'usm&2v'u+@]1s^&2t'u!0 +@ 0!?0 !/0!0]1sN&2r'u +@ @O]1? @M    B   <291<290KSXY"  ' 7 7w55v8vL57y5yy5f +@< +,  )&  *&& &,+,* # )#3,99999999199999990@*WZWU!je!{vu! FYVjddj(|svz( ]] 324&'.#"&5!27!"&''3>_'y=_''NOy;WfNPƀ[gX@CHp@CpDfbMKYg[KKX)k&8uu)k&8su)m&8vu +@ / ]1)N&8ru +@P_@O /]1k&<ssu =@   ? 2291/0@ ?_]332+#32654&#'ђ/@0-'!  **.  !' $'$-F099991/990@@'(     ! "&  : :!MM I!I"jj  ]]4632#"&'532654&/.5467.#"#:A9`@IPAtx;e\`Wqqs`/Q*%jd_[?T>7;[gp{-f&DCR @?&/&&]1{-f&DvR @?&/&&]1{-f&DR (,+1{-7&DR.< +@ ./<.<]1{-&DjR -( +@(o(P-_(@-O(0-?(-( ]1{-&DR%@&,,& 2882 ++1@ ?5?/5/]0{o{3>@C'-%= 4%:.-*1 %?47&%7& =&-7"E?<9999912<<29990@0+0,0-0.0/00@+@,@-@.@/@0P+P,P-P.P/P0+0@@@@@@@@@??? ??0,0-0.0/@,@-@.@/P,P-P.P/ooo oo`,`-`.`/p,p-p.p/,-./]q].#">32!3267#"&'#"&5463!54&#"5>32"326=DJԄ ̷hddjMI؏`TeZ߬o0Z^Z55*,ywxx..''`f{bsٴ)qu{&Fzqf&HCqf&Hvqf&H"+1q&Hj@@ ]1f'Cof'v\f& +1F&j +1qu('@^%{&%#${##{#({'(#&'('%$%(('"#" ! B('&%"! ## #)&' ! (%#" QE)999999919990KSXY"?*]@v%+("/#/$)%-&-'*(6%F%X X!` `!f"u u!u"%#%$&&&''(6$6%F$E%Z Z!b b!z{     {zzv v!x"**']].#"32654&#"432''%'3%F2X)6 ~r4*!M!ü޼z&77kc\̑oabd7&Qquf&RCsquf&Rvsquf&Rs+1qu7&Rs .+@ /. .]1qu&Rjs +@ @O0?]1o )@ r <<103#3#!!oAH +@<+,&  )&  *&& &,+,* # #Q)E,22999999199999990@p(?-YVUV jf!{    { z{ {!"#$%{&%--&YVUZ(ifej(ztvz($$]] 32654&'.#".5327#"&'')gA\*g>}66]C_56`?`!*(Ou))Hn.Mw834OMx43NXf&XC{Xf&Xv{Xf&X{ +1X&Xj{ +@ @O0?]1=Vf&\v^V>@ GF2210@ `]%#3>32#"&4&#"326s:{{8daa=V&\j^+@ 0? /]1h1'q;$ +@@O]1{-&qJD+@o]1h'J$+1@oo]0{-&OD"+1u&${u{&Ds'k&&s-uqf&Fvs'm'vLu& <=/1qf&Fs'P&&zLuq&Fs'm&&w-u@]1qf&F&'wq&Gq @_?]1 q$J@$ "    GE%<<1/<20`&&&]!5!533##5#"3232654&#"F:||ǧN}}daDDa3&(q=q'qH@p]1m'yu(@@]1qH'H@p]1P&(zuq&Hu&(qu{&Hxg&(wo@@ ]1qa&H!+@!]1sm'v\u* <=/1qVZf&hJ  <=/1sm&*yuqVZH&JsP'z\u*@?]0qVZ&hJs'^*qVZ4' J;m'vu+ +@ / ]1dm'vuK*+1KQX88Y@ @@]:@    8 22221/<2222203!533##!##53!5qʨ"ʨ9Qx>@!   N  2221/<2290#4&#"##5353!!>32||}}`Bu\zzedx^'t.u, +1g7'+1Y1'q.;,+1H'q+1gm'y.u,+1VH'+1u%'d,u 'JLP&,z/u<<1??]0y{,@ F91/0@4D@P`p]3#\`{f'-\,@1V'M8L@F1f_m'v.u-+1V\f'+1j' .' N` @(B F 291/<290KSXY" ]@_ ')+Vfgsw    ('(++@ h` ]q]33 ##%kǹ`!jl'snv/Jl'sZvO<1KQX@8Y@O]0j' /' O@@]1j'q/'q9O @]1j'y1w/'ysOK QKSKQZ[X@8Y1u ?@   : y<<991/900P]3%!!'79Pw^Mo;jnH ^@  z z <<991/90KTX @ 878Y@ @ P ` sz p ]37#'7Ǹ}Lɸ{JZjXj3l'sv1@O]1dm&vBQ @?O]13' 1d{' Q3_&1wg +@ /  ]1df&Q +@]1'QU~V;@  AKTX8Y21@ /0!"#367632+53265PͳNijQRW1fOCCoa`ZVd{;@  NF 21/90`!!]+5327654&#"#367632dRQi&&||BYZuccH``01`e22wxs1'q';2 +@]1qu&qsR+1sm'y'u2+@]1quH&sR#+1sk'{'u2quf'Rs ;@   299991/220!!!!! !# !39OAg@AժF|pm|q{'3@1 . ("%4"1 K1 Q+E499912<2290@%?5_5p55555????? ooooo ]q].#"!3267#"&'#"32>32%"32654& H ̷jbdjQGьBN5Z44*,nmnm98olkp݇Tl'sv5m&vBUT' 5J{' UT_&5w}g@_]0Zf&U +@]1l'sv6om&vBVm'vu6  ))Ic:1of&%V  ))Ic:1u&6zou{&Vzm&6wu + ""Ic:1of&V + ""Ic:1u&zP77u&zW_&7wsg +1@_]07&Wq7p@]1F@   @ @ <<1/2<20@@p ]!!!!#!5!!  ժA@7C@  F<<2<<2991/<<<20]!!3#;#"'&=#535#53w{%&sQQ''PO>)^'tu8 '+@ ]1X7'X&+1)1'q;8 +@ / ]1X'qX+1)m'yu8+@]1XH'X+1)o&8iX&X| @@@!]1)k'{u8^f'Xe)&8u{&X'Dt'v|:+1V5m'EZ+1t'vr|< +1=Vm&^\+1N&<rsu +1\l'sv=Xm&vB]\N'zs=X&]\m&=wuXf&] +@ ]1/#@  L<1/0!##53546;#"c'&яN()g ,D@% ")%,$'".EG* ,(%#'F-<2221/<204'&#"327667632#"'&'##5353!!STTSSTTS:YX{{XY:E/tssttsstRd0110d}}P)C@#   . *29991/90"]!2654&#!2654&#%!2#!"#546D+ |v݇f>orqp ˘0_i1F&8@# (EGF'221/067632#"'&'#!%4'&#"3276s:YX{{XY:NkrSTTSSTTSd0110dtssttsst 3@  . /21@  / 9/04'&#!!276!2#!#ONDNO|N8DCDCD>@  G /221@  /ij9/0>32#"&'##34&#"326s:{{:"QrdaadDs'0@  0 <10>3 !"&'53 !"shSzjffbGGaaHH_^9'(9^_sZd$D@"! %  %  0%210&&].# !267# !2676;#"'ffjzS` SfM?nb_^^_HHgh$bzq"N@$ ## HE#210@ $$$$$].#"3267#"!2546;#"NPƳPNM]-GFE0iL~++++$$>: a .@   2 99991/0`]3 !%! )"#5465BhPav/w.,~0_i1F.@  .21@   /0)!"!!"$54$3!!@DNN|#+qZ?@G E221/0` ]5!#5#"3232654&#" M:||:ndaDDadqVtc'T@ )E Q E(]99@   (99@%S 910%!"'53254%&'&326&#">kGxfu'~@3cnBOFFu\0%p9 *E +@    21@ /0!5!!5!!5E>9+uD@& 39190!!"56$3 ! 7327upo^   2`_FHg[{(@@$ )) #)* &)190.54$32.#";#"3267# $546؃ YsrSǾmTj^У%!| &${spw21%%ݐf#A@  2991990 ]!!!!+53265ZpPM?nժHVe@#   LK TX@8YKTX8Y<<9912299990@P]#"!!+53265#535463cM/ѮcMPhc뻫Ph*Nsd&I@43! F'1@'$$'990%!5!# !246;#".# !26uu^[DM?npkSUmnꪖ_`%Rv%@ 'P $&]ĵ 91@ %$&222990@ #%$$<<$#$%#@$"! #9927654'&'3#"'&5476736,3,,3,6hC.KddK.Ch B9Iy\\yI9B z^ȮwBAWWABw1G*O@, *&NF+291@ '&&  #/<<9990%27654'&'5+"&54&#"#3>323LTWJ>ymoF||BuLibep_!edg .@  KTX@8Y991/9903;#"&n?M-– R E@   >f3@)B 6  999991/299990KSXY" ]@068HGif FIWXeiy]]!3!+53265jG?n+Vd{Ks 1@ 3221@   0! ! "!&32sy:;x Vb[[z=g&24v'X Rs3@ !  <1/0!4&#! !2!2"327&nzy;pa'Xܯ–bb-LgFqVY{!:@ """# E"9104'&##"3232"327&&&idRصRQ@TVt1098``:6:@   ? 291/0@ ?_]32654&#%!2+#"#5468ʄv/ϒ0_i1FV$O@$#% %G  F%22991990@ `&&&&]%#46;#">32#"&4&#"326siL:{{8(adaaTV@  ?  2299991@  /9990@ @u|]#.+#33 326&#A{>ٿJx~hb؍Oђ r!d@ -" "99991@B!  "90KSX@ Y6 327# '&546?6764'& {璑z<;YZL-|숋_ppٶ+23@@md{'@  !! RE(99991@ '$$(90@S !S BKSX99Y"]@/)?)_))))))]@% '$&((*//*( ( ))$]@.,,,;;;; q>323267#"&546?>54&#"Lf@eaflZ?bZN?$%PKQY55##*!I@TT((7V6@   O 221@   <20;#"&5# 54!23%&'&#"3wMc/R5!n|wj=hP`@o,0A37V?@ F<<291@/<2990!!;+53276="&5#53w{KsF0j&&էN01`>X@ @  991/2990K TX@878Y@@p ]!!##"#546;^vժ+Zi1F7I@  F<<2291@  /<299990]!!;#"&5#53546;#"w{KsբcMcN`NQfT@ @@ 120K TX@878Y@@p ]!!;#"&!n?Nժ=–_&84i' XN:@!3   1@   <2220!! 47!5!3254'5!X ƱXw>*a"Lav-@   /<91@ 0%254'&'5!'&'&33cAnMagn"ʦmWDtz–d@  @ @99/1@  /9990@        BKSXY""#3 632#54&9%NZUUIG9\[ny6P=V{j@  K TKT[X @8YKTX 8Y9991@:        B    9990KSX2Y"@      '$$  )( % $ $ ' 755008 6 6 8 A@@@@@@@@B E G TQQUPPVUVW W U U ffh { F]@%     # 5 I O N Z Z j ]+5326?3 67632#54&#"N|lLT3!;^0XQ99) hzHTN43`rr:T*\@5    B  B K TK T[X 8Y9991/<20KSX<<<323#L:s_%'ST_ijxzX"Jh0@umHLIwKK!!C12\RI`1]5@ F1@  0 4&#!!!%$ $5& )sQ;-%,%hV)$yhL?`3@  F1@ 203 4&#!!!32!"'hi;-ԧc%,&cV)$yJX$!"'&'5327674'&+#5333!plnUQQLITNPc9:V>}ws}#(rAbLrV{@@  F221@ B 0KSXY#36763254'&#"s4QҸMNr98xܭz BR1pqWBAV&@ F10@ @P`p]3#V''V:@    <<2<<219/<2<203!!!!#!5!5!5!s____,Ԫ m'?' f'@'qf'@Gf$'-/V'Me/V'MvOf'-_1V'M>1V'MeQhm&$wu<1{-f&DZ +'+1`m&,w/u  Ic:1^f&  Ic:1sm&2w'uquf&Rv <1)m&8wu<1Xf&Xv  Ic:1)3&08X1'q{;)Z&86X"&X)Z&80X"&X)`&80X"&Xq{h3&${-1&qR;h3&${-&DH4'q>{o'qs%T@!$"43 &<1@"#%&99ܰ KTX"@8Y<203## !2.# !2675#535!5yyuu^opkC XSUmnHF_`%'XqV{ 4X@"2% G,E5221@ #% ) 2/3 &)/99<20`666]4&#"3263#!"&'532767!5!6=#"3253:aQQRZ9||9=nXF]@,*_EG^[cb::bcsm&*wJu!<@!T!$!]1qVZc&JJjm'wu.m&Nwu* +1KQX88Y@ @@]se'42qeu{'Rse1'q';qeu&qsm'wuyXL/f&TVdf'%  Ic:1 '=' ']'q']Gsl'sv*qVZc&Jv-5@8221@ /203!327653! '&5!#>=B>d`gd"dPNOKZ߀xxv 9V@@  221@ B 0KSXY%#3676324'&#"8WST=<HW5xz7 GF3k'uu1dd&QChs&s\}{s&s}Hl's\v{oc&vefl'svHc&vhp&$|z{-d'Dh6&$x>{-H'eDp&(|zqc'H6&(x>qH'Hsp&,|Yzc'fw6&,x>>UH'$sp&2|Azqud'Rs6&2x>quH'RTp&5|yzJc'%UT6&5x>^H'-U)p&8|zXd'X)6&8x>XH'X'v6o{',V'S77'WRs. 56$>54&#"57>54.#"5632?4o1\}p_s54&#"57>54.#"5$32Fp>!BlJc(v];?"AW?-1CA#E ptgDZX%KlaF='.`[b[3XpVU 2#PQ̝qpD(4%3254'"632!"'#67&5#"'&76323 76'& %44nI5"C0:XY|ˀ|YX:ST$TTTTT- H:E<$d0110d^jtssttssq% ;W@$3=E (B!8;7B/E<̲ ;]91@$3< ;<,<990" 7654&327654'&'52 '&54767&'&5476!˸jkkjpkk_;̨_`Lm䖋_``aCUtMMMMMN'|OEH-AA+Mdha "ccttttُcc"FYXSJqq 4C@6E B42()+&BE5221@4)".559920" 7654'& '&5467&'&5473327654'qSRRS SSSR:4HRQ;4?+IHIJ,MMMMMNMMJ@b@Y "ccttttُ"#VKYIAAAAAtw>\V@ B  K TK T[X 8Y991@ B  /0KSX@ Y@@ )&8HGH  /59?GJOUYfiowx]]+53276=!5!5!!Hri&&gPP%01oXV`@   K TK T[X 8YKTX @8YĴ@`]99Դ@`]1@ B  /0KSX@ Y@2&GI + 690EIWY_fh]]+53276=!5!5!!۞Hri&&5ejLP%01%hP&$@{-&D_u&(zqu{&Hz{s3&2bqu1&qs;s3&2iqu&RsO'z't2qu&sRs3&2jqu1&qs;1'qr;<=V&q^\p\%3254'"632!"'#67&73%44nI5"C1- H:EVy` 8@   OF 991990@  @ P ` p ]3+53265F1iL`aq #/A@1E%G +G!E0<<<<1@( . /22220 6& 23632#"'#5#"'&76'&  7/ST$Trrrrˀ]STTSST$Tjtss ^ŨŢtsstjtssqV{ %/D@1E$G+G'E0<<<<1@ *.! 02<220'&  7"'##"'&763253632 6& STTSST$TrrˀrrST$TdtsstjtssRŢŪjtss|3 #!#'#7'7 3!Jafp|҈2F;R/o]jY'FF8O ",'&76!27&'!2767# '#&# rfuSv=:efc.1 tsfjwv9tFXh$xYv+!f //_H$$\/ح ]"+'7&576!27&'32767#"'&#"i`UUQ.-Y_vcPNONMRS]7GGcc^N lOU ^q+$Vqrg j ;@   : <<1/<20@ 0P]33#!!#53ʿ_w1##'!5!7 !4" gZ8f,i> XRBY bo{=4'&/&'&54632.#"3#"'&/&'&'&'53276 23@LLfLNZDE11?PS{W*L'TrGY$alfccaFF'K((%$JK((**T@%$!,KL[@~$=&[#5-,X3`!;#"'&/&+=!qjN\1*LlTrGY=Z^e`1~$=&[? %P6@ 9991@  /0##32654&+"56;2'񍚚EOZ*,FP{7@   991@  /032654'&#"5632##/dLUIVVN}AH+Fnt  (\@ #  . &%)<229991@(% #/99/<20*]!!!2654&#!2654&#%!2#!#53[D+ |迿ɐʇf>orqp ˘p _@ 8AKTX8Y<2<21@   29/<<2299990]3!33#! 5#53!3265˥ߦ®j*$}h0B33#!!!!#7#!#!AX .AA<VF㪾FqB&-1&'&'!3267#"'#&'&3273&#"#So+Jajbck{cPm!)81G\9/Zo Z 6Z44*,!  C "2JcfRY@    9 KTX@8Y<2991<2990@ 0@P`]#+53265#5333RM?nʿwHVS@$   OF<<22991<2990@ @P`p]33#+53265#533#F1iL`(aؤsf$C@$  %" %  %2299199053;#"&5# !232#"nEMMT–\\xEEqV@{$H@"%"%G E%229910`&&&]#"&=#"3253;32654&#"@F:||:Li1戮VּdaDDada= T @  ?  !<299991@!  B  /<229990KSX9Y"@"]@Bz%%%&'&&& "66FFhuuw]]#.+##53! 32654&#A{>ٿJxʿ~hbw؍OJ{=@ F<<<1@  /<20P]###533>32.#":.I,h<ĤfcΡ3!733!#!53!ٗ ٗwјv9 V`+5326?!533!33!+N|lLT3!øLùmhzHT33`{ ,@ .% F-22991@-&%"*-%  9990@1?$?%?&?'O$O%O&O'_$_%_&_'o$o%o&o'$%&'$%&']@+?#?$?%?&?'?(?)O#O$O%O&O'O(O)_#_$_%_&_'_(_)]2654'&#"367632#!3267#"&߬A@o\]?^^fe~ST`Te__Z+f{b:9ml)Lf01a```FE..'qZ{8@G E221/0`]53#5#"3232654&#":||ǧdaDDa{ 8@  G F221/0`]4&#"326>32#"&'#3姒:||:/Rdaad` $C@  !G! F%22991/0`&&&]4&#"326>32#"&'#46;#"姒:{{:Z[/Rdaad~Ӝ}}{ 0@ ! !"EH!<106763 #"'&'5327654'&#"LQQU]SRMNONPccccPNON5#$+qrrq+qs{'/O@( ,,H"E02991@.*%00@ 11111].#"67632#"'#47&'&!23254#"NPc'>IjJ?_SPI 9/-U:Me5++rQ,3H=Y}/)9DhQ#3 :#:9KqV@$K@$%"%OG E%221990`]#"&=#"323;32654&#"@F:||:Li1戮VּdaDDad^ؙa=q$=@" %%  GE%2210`]546;#"#5#"3232654&#"iL:||ǧadaDDaq{"r@ KE#91@  #90@)?$p$$$$?????,//,ooooo ]q]47632!"&'532767!7&'&#"qkcbdcjfg ]\RS^,*4cdWWZZq{A@$  KE91905!.#"5>3 #"73267qN ͷjbck 9Z44*,#ė|{ 4w@6.('4 KE5<Ķ&  91@/.'""5 5@  &"90@ 4 &'<<<<<%6'6'32#"'&'&'&5>3 73;#"'&5Nf  R`\Lladbck $˸&&i+@WR֊>8E#Z`vg'#d4*,#)u10`Z|I|*|>i@@603273;#"'&5|PUTZGUU]UTNHtCDFEwGQPabLq_&&i+@WR@\l%88ZX83,-F@.. NBj10`ZȦFq|/;@ 1 &,E01@00)0#90"327654'&+5327654'&'2# 76`cchҗUTNHtCDFEhqr<V`K@   OF<<22991<2990@ @P`p]33#+53265#53F1iL`(aؤqV 0U@)  &#-* *-+& G E122991/990`222]4&#"326!"&'5326=#"32546;#"aQQR9||9iL=,*[cb::bcaqVZ` #C@ # GE$21/990`%%%]!"326!"&'5326=#"43!aQQR9|=ͻ,*[cb:*qO{8@4 E1990%#5!#"!2.#"326Ae{-h]_cƳO|$$>:77>>`Rd`#y@ %  $ĵ 91@  $222  990<<<<< 3#"&54767327654'&'bB_j&;;&j_BC(::(xܱSccS$-EIdccdIE-`d`#y@ %  $ĵ 91@  $222  990<<<<< 3#"&54767327654'&'b)rG,EE,Gr)C'88'bLx>>xLb-!@2FF2@!-VX`9@     NF21290`]332653##"&||Cua{VfcdC@!   N  F2991/<9990`]#4&#"#46;#">32d||iMBu\~aedVd!J@%  " NF"2991/9990`#]+53265#"#46;#"632diLiMHa=~a >@    F<<<2221/<20@ @P`p]33###533#¸`<Ĥn`Mt` '@   221@   /2205!#3!53t褤K#<@ % V V$<<1@#! !//2<903327673#"'#&'&#"#67632= &}33[ &}33[ %$RIJ %$RIJMT5@  <2<1@ /9/<2033##4'# 7632&#"3=5*7M\TK9V_ (@  F 1@   990;#"&5y=x1F|t(L6$@#&#" F%<̲#91@B""  " /9/ 990@$#@  **8;ILT[q ]@$$%$$5$7E$FT$\ ]@    ]2!"'&'5327654'&+5!#3!CicUQ^cdjTmcd\[je8+lh%12KKKJ3Lb&^@PP F'<91@  #''<<<290@0(P(p((((((( ]%#"&5332765332653#5#"'&Cb`ruSSrw=ZXyzVUy=<b`^zbze32>>Vb&a@PP F'<91@  #''<<<290@0(P(p((((((( ]%#"&5332765332653##"'&Cb`ruSSrw=ZXyzVUy=<b`^zbzZe32>>V{0c@PP)%'F1291@ %*!*-(&/<<290@02P2p2222222 ]>32+5327654&#"#4'&#"#3>32)E__RQi&&ru99wSS?yzUV|v{zH``01NM_``gb>>Vk{Q@N O F2991@ /9@   990`]#4&#"+532653>32k||F1iLBu\satedVJ{;@ N  F21@   /  90&54&#"#3>32;#"R||Bu&&i1F``edH10d` y@BNF 991/<2990KSXY" ]@068HGif FIWXeiy ]]!3!##`ylqu{ ,@  Q E2210"!.265!2#"qt蔔98q$`I@  E2ij 991@   /<<@ 9/0!!!!! '&76!#";:E*%xxxx%`ݛlklm>|$2@ &E E%1@ #%<202765 26= "&'"&H`k&InI&k`B"F:.aע ģ0[1[0T\l6puypVi`/@   /2991@  /90%!"/32653#r%832JI,:.˾ fcVJ{:@  F2190P].#";#"&53>32JI,Li:.˾atfc~{%@ 21@  /29903!5346;#"iLAat~{%@ 1@  /29903!534&+532ʴLiAa`@4  B      F299991/<9990KSX9Y"@]@Bz%%%&'&&& 66FFhuuw]]#.+#!232654&#0s2âJ{Qpwu t]:'`iVNM``E@  F299991@  /29990332673#!32654&#Q{Jî2s0jp|Ɓuw`':]t i`MNVoV{0@C  S('  S'('B1 '(!.1' ($R$+E19999190KSX99Y"0].#"#"/;#"&=32654&/.54632NZb?ĥdXLie@f?((TT@I!* ajYQKP%$V4@ O F<22991@  99046;#"+5326cMF1iK»Ph)aV O@ !O F!<<229921@! ! !99<20546;#"3#+53265#53#5cMF1iK`NPh(aؤi7V5e"O 1@ 04&+532;#"&McKi1F(hPaV2@   O 221@  /<20!3## 54!346;#"#"3276w5RcMów|n!o@`Ph3A07^3@   /<<2991@  /<2990]!5!4&+5323#{Ksբ>`N7V=@   F<<2991<2990]!!;#"&5#53w{Liൣa>`C@     NF2221/222220` ]3!33##5#"&=#5!326:CuȮ||h=$#^lfk`8@   91/20@ 3 3#f%.]`8XV`@"B  OK TK T[X8YKTX@8Y2991/0KSXY"@B&GI + 690@@E@@CWY_``f``b]]!!;#"&=!5!qjLLi/F7e`ۧa%X`!@  "KTK T[X8YKTX@8Y299<21@  /<0@ BKSXY"@:&GI #+ #690#@@ECWY_#``fb###]]!367632+#47!5!3254qjL"TA`:&>R~ie8FX`ۢG7W9W`/=3<;4%6]XL/` @ "!̲91@B!  !9/ 990@ @  **8;ILT[q ]@  %$ 5 7E FT \ ]@    ]2!"'&'5327654'&+5!5!`q|/=@1 %,%E01@0 0"0( 90";#"327654'&% !"$5467&'&5476EwEFDCtHNTUhcc`a|p<:!a>>`V.9@ F<<991@   /<203#33## 54!3#"32767Ku_+xG`͋BA0 L` ## 33R9L T#`@ F1/03!!`3qV $C@  #%% "GE%2210@ `&&&&]32654&#"#"32546;#"#/s:||:iM/daDDadaX$L@ & %<<ij#1@  $! /<2KPXY032765&'&#"56763 3###53T?V:9cPONNLQQUmlprLbAr+#}swԤX$M@ &"#E%<<ij "#1@ $!# ##/<2KPXY0535&'&5476!2&'&#";3##plnUQQLNONPc9:V>ws}#+rAbLrq &) 76'& %3!!!+5#"'&7632/ST$TTTTT iL:XY|ˀ|YXjtssttssH^Lۓd0110MqL4@#5#"'&76323!2!"'&'5327654'&+5 76'& Z:XY|ˀ|YX:jejbVQ^cdjTmcd\]:ST$TTTTT3d0110d^L$8*mh%12KKKJjtssttssq 3: 76'& %%!332!##47!#5#"'&763233254#/ST$TTTTTghL<):XY|ˀ|YX:FXjtssttss_ 3<;4d0110d^6[7@F.#"#"'&'#"'&5#533!!;5327654'&/&'&54632NZED11?QR|{Za]gQQ{%&sfccaFF3,@LLf?((**T@%$!,KL[[!&PO`>''M5-,QK($)$JK7V&/!05476;#"+53276=#"'&5#53!3wxWQîc&'QRF1i&&QQ3%&sN[V((h)``01PO`>''7p-9D!6!2&'&#"63 #"'47!"'&5#533276'&#"&57!3w{UQQLNONPcccO+eKTIQQ;BS_r(ր%&sz#+qrfr v)2LOAPO`> 'KV ''/Vo5+5327654&#"#!##535476;#"!;67632oRQi&&||ӹWWc'&-BYZuccH``01/яNUV((hce22wx#5.#"#"'&'#34632327654'&/&'&NZDE11?PS{|Zb]hf8b_caFF2-@LL?((**T@%$!,KL[[!&2-,QK($)$JK @   F<2991@ B /0KSX@  Y@B &GI   + 09 @@@@@C EWY `````b f]]3!!!+iLLۓ6 333# #333# #6ttttU=63@    <2<21@  220!#!#!#!#6kkUXrXJ3@ NF 21@ 0%#"&54&+53232653#׃Li1FęaBþyVv!:@ #NF "21@" ""0%#"&54&+53232653;#"&'׃Li1FPh2FęaBþyfu0@ 32tNN^luu)qJy}wYYk\g88u:KSX@ 32tNN^lugrB0)qJy}wYYk\xkW6Vr88 #@<<1@03+5327653#zt43r,Bttx66XVru@ 1@ /0.#"#3>32.biuu$uT  qksa97H <1 /032653#5#"&'H.bitt$uT  qkJa97Hu' <1@  /<032653;#"&=#"&'H.bit0B,rg$uT  qkJ V6Xlx a97 !+33276?3327654'&+CFCDtk=%%(f{n!!"}K'))'K}N;[--s?5/.6 333# #6tt&+53276?331/.N]D0 {{bp"#WK/itftf&t  @ 10#5Rڬ@u1 ܴ? O ]ܶ ]<1ܲ]90526544u@XX@sPOOP{X@?X{POPPu1 @    ]<1 Բ]90"'&4763"3sPOOPs@XX@PPOP{X?@Xu+@ 91@   032765&'&#"567632#'y7$#?q22110335WDDFk[@*7K$@ ` XFh_@Cu-@ 91@   0#&'&547632&'&#"3kGDEW53301212q>$%6y[AmC@_hFX ` @$K7*@ 2% % g 25-5g'|?f=u912]90K TKT[X@878Y3# #fg|?fLu91<Բ]90K TKT[X@878Y@ 5:5:3]]33|g?f7@ u91290K TKT[X@878Y3#'#f?f7@ u91<90K TKT[X@878Y373x^@1@/0#^+b+qsRf3#ff #ofv^@1@/0%#^++Tq^#onvsR3#lo#E@ j,5!##–,dU 533##5#5Dud&u!5!&>ߖ)9H W@ VV1<0K TX@878YKTKT[KT[X@878Y332673#"&v aWV` v HKKJLDfN@ d10K TK T[X@878Y KTKT[X@878Y3#  @ V xV104&#"3267#"&54632X@AWWA@Xzssss?XW@AWX@sssLu @   '1/90!33267#"&546w-+76 >&Dzs5=X.. W]0iJ7c@$   VwVv99991<<99990K TK T[X@878Y'.#"#>3232673#"&9! &$}f[&@%9! &$}f[&@Z7IR!7IRfB@991<20K TKT[X@878Y3#3#߉fx%3;#"'&5&&i+@WRd10`ZȢf '#7'373\\]]\aa``u # 5473733254/MMz /1/03#zttu/2&'&#"#"'&'532654'&/&'&547632j1549W++](}24NM9>=D@?>=RX o(l00GF@99 a /$*+MW33 k2-*)*IX01 u! #'#37 ͉H+uX@ 1/0!!5!AGЈX'@??//21/]0!!5!3A4X@ 21/0!!5!3AhhX'@pp0021/]0!!5!3A4X@ 1/0%3!5?p+v'qqm 93vJ!_@ Vw V v"99991@   "<<99990K TX@878Y'&'&#"#67632327673#"&9 &}33[&@%9 &}33[&@7 %$RIJ!7 %$RIJ{f6@ D910K TKT[X@878Y # mXfvq{Pf6@ D910K TKT[X@878Y3#fs{?f<@u991290K TKT[X@878Y3#'#?fsH7b/q|  )1H{d%@ 910@4D]3#h{)I@ dd 91<20@#4D`````````ppppp]3#%3#^y)7{"@ V@ V /1@@ /0632#546?654&#"7pihX,#w3-.>GZdH3UC=A   (6%""($4f{Cf<@u991<90K TKT[X@878Y373NxsD/1/0#DD'4]fB@991<20K TKT[X@878Y#!#͇fxx)1')1H VV/1 /<0#.#"#> v aWV` v ")KKJLD( @0#3Ӥ?#55#53pp{53#7"op{y3#@uUCqPUv$<#5353#ĠxxxF33##xx2xU?p!5!#Ik{1@V/K TK T[KT[X@8Y21@ /0532654&'3#"&=X.. W]0iw-+76 >&Dzs5V @  V21@ /0"&5463"3VZ||Z(55(}ZY|x5'(5 M3!5353D M#5!##걈ň$ #53533##Ġxxxx 5! zV '+53276=0RQi&&``01wV %3;#"'&5w&&iQR10``fSC'SjC( @V xV1@ /04&#"3267#"&54632[6'(55('6y|ZZ||ZZ|&65'(56&Z}}ZY||jT @03#Ӥ#uzLuD/1/0#D`tP#5!#fJc9X#"4533273273" v aWV` v "6KKJL9HS/TB  #"'&'.#"5>32326SKOZq Mg3OINS5dJ t]F ;73 !;?<6 7=xh!5xhh5!Ĥh'`_^NO'ygfFXY @  V21@ /02#52654&#Z||Z(55(B}ZY|x5'(5[3!53[J!!5#>J*>c9X632#&#"#&'"#72;tv gfv ifvtR+ '7'77}`}}`}}`}}`p}`}}`}}`}}` .54675>54'&'C!RI 7!RI 0PQn +0PQn : '  fCqPfvH7FbV+I#5!#!Ֆ֖V,2!5!5!5!>>2xx3#3#@`tt!#!–*>,Jf'73327673#"'&'#7&'&#"#67632Bmk  &}33[& !Bnk  &}33[& g  $%RJI g $%RJI J!%'.#"#4632326=3#"&3#3#9 $(}gV$=09" (}gT";薖Җh! 2-ev 3)dw.CJ"ttc( 7!#'73!'3p~(͛3#557'2d͛~~x&'&4767@*,,*@rNPPNr*,@A++{OPPN`1'+!x050567654'&xrNPPNr@*,,*{NPPO{++A@,*.Do2>&"762"'"&46264&" 5O57O5>||=>||66O5555M75m?|}A@}|6M65O5p pk Ppk!!p kpT!!p ଔ* '#'&'&#"#67632327673#"'&O,$e5Fqp[?9ZO,$a9Gqp[?9J7  $0GJI "7  $,KJI pn w(5!'3#7ws~~d͛q` !#!#!#Sb+e !#####b+tf@103AntVH@10%#AnH3y`V #"'&=3; #V!. {q{'yOF{'y#sRf1@ D10K TKT[X@878Y3#fFR&jl@_]@_q0hf'&HFyuf't*f',}f'z.f'4(f'n9f'h=6'.Mh$%j@ 1/03!!)ժh=@ B1/0KSX@Y !3f5:9+(\=;+s!2@"" "#3"10!!"3276'&' ! '&76>b܁܁:xżp[bb,j.h<@ B1/<0KSX@Y3#3#:9&+031b *@    <<1/0!!!!!!29iggqs2;3 F@B   <<1/220KSX@   Y%!!5 5!!>!8ߪp7<s'<@) !%(<<<<1@' %'/<<<<0367654'&'&'&76753#–bbʖbbWssWWssW=;;s.@ <<1/22<20!6'"'&336763#ּՂnʊnhg椌gHN&3@ &("3'1/<2220%!567654'&#"!5!&'&576! cccd?IH1/GGaʦa>”XN'r/u. +1N'rqu9 +1qf&Enf&PIVdf'Kf&MF*&Yqy *@ ,%E+99@ ?/]q@ ) !/99@<<10@  ]@IIIJN LNIK ]@:9:88? <>]@ + +*))]@  ]@++]'&#"3273;#"'&'#"'&763 N,-=MKLyHc( #) Xn^T).^,ru7 nik%1)0T*XoW)&V!7@E F21@  90%#! !"3 5 4# yYo 0kEdZ&J:@ V`@@ 1@ /<20@ 993#&+532i^;,_1FLdVD~qu-T@(/E( Q!E. ]99@%%.99@S910&#"#"'&4767&5!232654'&'&fu5KxD7VUV[a~@Fu\0%p̥@$OF(Iqrs`g |2=@" 33'(#,34 '0E310&'&547632&'&#";#"32767#"'&546p<@ KQX@8Y1@ 20%#457654'&# !5!ʄOTJPE* :;f,KOxsPWKL,#%5,*3Y'iVd{1@  FN  F21/0@]#4&#"#367632d||BYZuccH`e22wxqu$!O@ """#E QE"2]21@?]0@ w##]!3276'&#"2#"'&76EVSI 6VQ@=񈉉d~uvn` @ F1@ /0;#"'&5c"$lYoRR`+.0`b` I@   F 21@ /<20@    <<33 ##Gb`/ZFB?= F@ 1@ /<0@  # #'&+5z~J/k`ue<2~V`wJ`B@1@ /20@ 99!367676'&'31!xdLjE.*{`T|p5dwY|rNįtkR&@@ (" %'1@ '#"'<90%#457654'&# %$47#5! $ڄOTJPE* :MKOxsPWKL,#%5,*,X$Rݿ qu{RJ`/@  1@ /220!#3267#"&5!##J117,#J%x\c`PH? XV{1@ EQ F]1067632#"&'#44&#"326=;{:+fZ#adqR{$6@ !& HE%1@% %0 !2.#"32#457654'&-ULNPƯPTJPE* >:##++LOxsPWKL,#%5,*q` 1@  QE]1@ 0"32654'&'!##"'&76sRVVOcm񈉉qnsȷzn휝dm`#@  1@ /20%;#"'&5!5!!$lYoRR\ W0`b*`+@ E F@?? ?]1@ /<0327676'&'31'"'&5R27ki;jF-*eb`+@EvfwZ{sxvpVh )=@+E(#E*<<1@ *'*<2<20"27654'&'2##"'&7673=A__UVF6˷džfB:VVMpˑRh]p[nmNssg.;Uda@    <<91@  <<90%KSX@   99  9 9Y#&+53;'$ܕ11FA3N11F~0)~pV`6@   <<1@  <2<<0&'&53367653#EkUJ|CUvܷ%aw~LB,BTxnc#n'`8@E  E1@  /<2<0 433233243! &aƏ˪ޏƛa!)R@O@+}&Mj.*&jYquf&}S*f&"Y'f&]YVj 3! # # wHV1M$ 'G@)E& F(2Բ?]1@ ("((Զ?]990267656#" '&76#327>&iPDyz]6;~oxҤ]Y:PWp=l޺lǧ_ը,嶖ꀰ-ўqu$ 7@ !EE <1@  04'&#" '&4632  1BSxyJ̃Я#/p~ZZ7Ai6deBWQ I@ "!9Ĵ?@]1@ /<99@ o]0#4''&"562%62#"FR**RMw(oUCHk&_*SKHv H# 0r{C @[)/Bf'nfPWQN'rufpV'A@)   $E(<<<<1@ (  (<<<<02##"'&76327676'&#"DžǷdžǷqMTVMqqLWULc휙owgsugHgusgAm`E@ EE91@ <22205!#%$! 47)323764A,Ma")aM:GϤ*RѧOp[g9&'&47#"54654'&#"563277632327"'532! `7"7$>9[@[`7"7>9[&F]_I I5l|"O z:6hl0'[Ml |"Oz:6hlf$11sXD@!  ܶ0]9ܶ0]1@   <0#&'&76!   76';:{HpҳI椤qVu{ <@!E E ܲ0]9991@   <0"32654'&#&'&7632sVVUVVV9kjstntstu n}{R$.@ & #%1@ %"%0 32#457654'&# '&76)F`{[mzYTJPE* :xe+wTOxsPWKL,#%5,*eNqRQ` 4@ " E!IJ]1@ ! !0")!"32#457654'&g-[oPTJPE* >LOxsPWKL,#%5,*#)@VF'6  (<1@ ( $(0347632&'&#"!!#"'&'53276`1213$)),x:KAb933.1220W@Rd >Qoɏ?s K_7"'&76'&526n 'BQ_'BQ_[~,`*l#FR`*l#FRB@ 91B/0KSX@Y #!3&pM]rV`!#56! #'#64?!"QhRR_@0:IKiXL}/M4!wx#&'#&' #'nd2Fb.-t`4#M!P^sK=W@< 9:?5 +,">99KSX +9> &1>29<90'6767&'&'#"'&46733276=332764''3=D۴vayͤgDd''dey{d;]TCHI}rHGFFtAGCT_8d榈d*0QA^^^Fkmihhimw'AFU'`%S@!'E  E&99KSX"Pe^Ґ8*7D ! ! 12԰.#AL.#^Yq4+& "H4B;;=/?"+VhPOV !! 7654'&#"#676! 3 7llc^#,V)ۄe]6?fضdVj{ # 7654'&#"#67632327\B\\TP%I/yYk}oSKu,2R¤ຐs5%! &'&#"567632 67632'&#" ;!53276n"?E! rK,/ 4'Kr !D<&tEGGH h=" C(FK#C "&E !!6{5%! &'&#"56763267632'&#";!53276[96:@%((%@:6-:IkI:8=3553gs%+$67632! '&76!2767&#"327*W8QU{2Τ|sK^lȺhiieb-sJV"1Pһ '$Astxssq[/&67632#"'&76!27674'&#"3276I,)e[xtgO_\SG]EZSTVXXTRS7xJF61𢢜Pһ ''rsstxsst,V4@  <<1@   <220#5!#!#!3`d`du7U3@  <<1@   <220#5####!3_pzpppg3#"54654'&#"563277632327#"'$47(`7"7$>9[@[`7"7>9[@[|"O z:6hl0%[Ml |"Oz:6hl0%?[MV{$:@&E QF% ]1@%" %04767632#"'&')! $'&  7Z6;x[Y: +STTSST$T%Уb^#10dX4tsstjtssq{FVyMsaq{!&'&#"!!32?# '&76!2%%cjf_[_fMJOhk en(' c\\c( +{!56763 !"/532767!5!&'&#"'(ne khOJMf_[_fjc% ؜c\\c Vs'& @  >  91@ B  /<290KSX@  Yp]@ 6II YY @  &)5:EJ ]]! !###-}-!+V` O@ F  1@ B   /290KSX@   Y!!###`{`UV{'4767632#"'&'!!#5#5'&  7Z=;{XY:eSTTSST$TfZ#10dȪpptsstjtsss'Hs'&y3s''yk&uuN&ruBBBB|#I#IabhFaF`C`#BC`CUXC`C85YBB#Ih;5#I@PX@855Yf4@  <1@/20%+532654&#!#!5!!!2L>o||Rh"9+Fjk&sus'N@  2<1@  IIPX@8Y0! ! &! !!! 'zOFӐhgս6,XNf-T/3@   <1@  /<20!565!32#!% 4&+pٕxL@+8/Xڦ5@ 2<21@   /<2<20!!#3!332#4&+326 z6࡟9d݇,@   <1@    /<202#4&#!#!5!!||Rqf9+Fk&su3k&uu#m'yru; )@   1  /<20)3!3!#++h$.@  . 21@  /04&#!!26!!2)DlN݇@%j@ 1/03!!)ժe4@ <1@  /2220%!!67!3#!#p&axު D+?x4&A((v@   <2991@B   /<<2290KSX@    <<Y@ I:I:I:I:I:I:@  <<<<33 # # # 3DDxM(?@ * %)21@  %&" )02#"$'532654&+532654&#"5>I8z,|йԳƆ\qѲ|!ĐBY+wps{M("3 y@ B  6 991/<2990KSXY" ]@068HGif  FI WX ei y   ]]#!33j+3m&yu# + KT KT[KT[X@ 88Y1 Y@   2991@ B  /<290KSX@    <<Y3! # #_yT:%@   1@  /<035675!#!T>Wxfb/X++0;+s2;@ 1/<0#!#;"++3s'&7#> 1B /20KSX@   Y%+53276?3 3 OM?w.-!suٵ2&]*jklyj =@!   <<<<1@ /<2<203>54&'$%53# W==U+  -=;; )@  <1@ /2<0)3!33#;ʪ+$@  21 /20!!"&533!3_||xdv+ *@    1@ /2<<0%!3!3!3OOʪ+++o2@  <1@   /22<<0)3!3!33#OOʪ++< *@  21/0!!5!!2#4'&#!!276GN6ONDPO+DCDCF&, $@   21/04'&#!!2763!2#!ONDNONDCDCo#N@ <21@   IIPX@8Y0! 7!5!&! 56! ! 'oOzFՎaa0&8@''!&$#(  !%$'2<1/0"3276'&76! ! '&!#3~܂܀s;:ŴL椤kj@@  21@ B  /<0KSX  Y3!!" &$54$)#!:ƒdv'V+w{-{Dp7):@+E'Q! E*21@*$ *9902#"'&5476$%676"32654&}:[;z631-~LӔ{0w)v ,u8w>` /@ " F!21@  /0!2654&#32654&#%!2#!r~~hhVlj9_ZZ^SJJOgyr`F1/03!!`3k`4@  <1@  /2220%!!6765!3#!#}v[(bt:d6(U3Rq{HF`@   <2991@B   /<<2290KSX@    <<Y@ I:I:I:I:I:I:@  <<<<33 ##'# 3?nn`QO6m|(N@ &* )1@ #)) ) KQXY KQXY0#"&'532654&+532654&#"5>32|PZG]twGabLx\l%%pZXkYF@\]y` ?@B  F F 991/<2990KSX@  Y##3y`}`y&# +KTKT[KT[X@ 88Y1` Y@  F 2991@ B  /<290KSX@    <<Y33 ##Tsŷ`OQ5Ls`$@ F  1  /<0356765!#!L8D{X^~ŷoPO` M@B   F F 1/<290KSX@   Y! !### >? ˸ʹ`'P` '@  F F 221/<203!3#!#U`7qu{R`@ FF1/<0#!#`3`V{Sq{F<m` 1/20!!#!<1BB`3=V`\pVg (3B@5E)! '.E4<<<<1@,41$ 4<2<20327&#"#"323>32#"&'4&#"326/{brrb{9SS99SS9{brrb{/Ǩ<9^N5=L^^LN^Ǩ;y`[` (@ F <1 /2<0)3!33#9U`33R`;@ F21/2#I #IRX 8Y0!!"'&533!3Hf\45h)_Vu;;` )@ F  F 1 /2<<0%!3!3!3ڹ"ٹ`3+`2@  F<1@   /22<<0)3!3!33#"ٹڹ`333R>.` ,@ E  21@   /02#!!5!!!2654&q8$~͓7_ZZ^{'">`%@ E  F21 /04&#!!263!2#!z~~@9LZ^_n7q{M@ H<21@   IIPX@8Y073267!5!.#"563 !"'q2 ǚ-VړiVFHL{ :@ E  F2<1@/0"32654&632#"'##3Jq и¾.`At"`<@  21@ B  /<0KSX  Y;#" .5463!##zwwVtS^a\'qk&CZq&jBBBB|#I##Iabh#FaF`C`#BC`CUXC`C85YBB##Ih;#5##I@PX#@8#55Y/V?@N F <221@ /<20#533!!>325654&#"#߰Bvz||яLmedY).ПĞm&vq{N@ HE221@  I IPX @8Y02&#"!!327# ǟ 2ғ-{FViګVH>=o{VyLFVyML`6@!E  <1@ /<0356765!32#!!%2654&+L8DثX^x~~~ŷ7oPv_ZZ^`8@E   F2<21@    /<2<2032#!!#3!2654&+N޹"\~~`7`73_ZZ^/:@N F<221@ /<<20#533!!>32#4&#"#߰Buʸ||яLmed*m&voyk&C]=V&^` )@ F F 1  /<20)3!3!#TfUf`3s48@$%6 )  51@ $-/<2<0"'&46733276=332764''3#"'&':y{d;]TCHI}rHGFFtAGCT_8d{{ђed''deFkmihhimw'AFf^^^^'`]:@  <<<1@    /<20!2#!!5!53!4'&#!!276XNpqONDNOQQfDCDC:@E  <<<1@    /<20$4&#!!2!5!3!!!2##~~EW^͓Lʣ+#3376!2&'&# !!!2767# '&SvwhfstgFtsfjwvú 9$#G_//wƪ//_H$$O{#2&#"!!327# '&'##33676>\" , Ux{ z{FVAW^3VH`3ʀ !#!#!#3 73` !#####3 Ñkk`_ !#!#!#!#3!3  o_<9d7`!#####!#3!3 kÑkk`_s@   9ܴO]9ܶ@@]9991@B  /<<9<20KSX@  Y@]##767!#'&'!ʓdսxQPtՀ`>YY~b҆12z(k{`~@   9ܲ]9ܲ0]9991@B  /<<9<20KSX@Yp]! #4'&'##767E]kKV:VS8V‰Jl&VtO\KtU'4! !#'&'##767!#3!PtՀ`ʓdսUn>qd2z Y~b_49n(.`! !#4'&'##767!#3!7kKV:VS8V‰]w&VtO\Kt`?sVszS#"&#"3276&#"#"'&54763!27654'4327654!"567376767632'&#"ssD#`At bTDt;<}J5?u_hFAXVRuťޠsj#B#' "2ZbrRUgr %',azQ^XRj7&6J- @' WoWdE\`[tO#"&#"32632&#"#"'&53!2654'&'"#5223 54'&#"5673767632&#"vmDPb!',-cX;b12i?,ZnN .rr. >._- > ^ >‘  tӪ ҫ q{&P%327654'&+"&'&'#";67>2# '&5476!36767623 !#"'&'&r-HVV?- ,4, -GVUH- ,4 .xt. 4 .wt. 4 `ta  _tp_   颈   袉   vt&"'0'&#'s3'<cS'&<sV'9@  0Դ/?]1@   /0]!# '&76!2&'&# 3!#SvwhfstkSh$#G_//ӂqV{9@  HE1@ /0@ ]! '&576!2&'&#";#UQQLNONPccccɖ#+qr͹rq;'''7'77'77did}}didii}}}d}}}}dBz/!"'&'&'&547676763!476767623 8  8 g    ) M #&#"56763 v][Jw}$)/K'*Ca"53#7 a#55#53g M 365%$# ʭf'rQ q\t{F` &3@MZg#.#"#> #.#"#> #.#"#> #.#"#> #.#"#> #.#"#> #.#"#> #.#"#> v aWV` v "8v aWV` v "v aWV` v "fv aWV` v "v aWV` v "v aWV` v " v aWV` v "v aWV` v "AKKJLQKKJLKKJLKKJLKKJL)KKJLKKJLKKJLX- #)/'7'7'7%'%53-#%5#53 3#kyo\wyo\zV\Ly[`@¬@_ӤRӤRZy\yW\zn[wyo\ԤRԤR߬@¬@Vm&=yuV8&>!:@  <<<1@    /<20!2#!#535334'&#!!276N訨ʨONDNOQQfDCDC&E 9@ E <<<1@  /<204'&#!!276!2#!#5333>CB>ytts9L^*..+URRRя>'+#!2'674&+327'7Uj~ rGj#u~{Sqrے-,9/~V{)%'7654'& 32'#"'&'#367632*nOSTTSSTFoWl{XY::YX{ ]ststsjts].01d d01j@ 1/03!3!)2$ F1/03!3!`:33G )@  <<1/<20!!5!!!!!N)#l8U` +@  <<1@  /<20!!5!!!!!?`۪ f3@  <1@/0#!!!2+5327654&#)qmL>87||9ժFwrKK"V `3@  F<1@/0#!!3 +5327654'&#rFRRQn!&&1`GQ``07 )(33 3## # # 3׈)D"AMF`33 3###'# 3?nfz!n`QL6mu&z9u|&z3! 3## #E#A`33 3###Tw8sŷ`OL5373! ###ʭd_dTy%u`37533 ##5#`eBTse``avFOQ5a!33#! # ##53ʨ_ʨye=3!!3 ###53dTsŷ}}z}5OQ5}2 _@   2991@B   /<290KSX@    <<Y!! # #!2_=y+*` _@   2991@B   /<290KSX@    <<Y!3 ##!*8Tsŷ`OQ56@    8 22<1/<20P]3!33##!#"dA9@`1@  F   F2<21/<203!33##!#W`39L -@   8 221/<203!!!#!#)"d9` +@    F221/<203!!!#!#W`3ͪJft8@<1@ /<0#!#!!2+5327654&#;"rqmL>87||9+wrKK"V!`3@!F <1@  /<0#!#!3 +5327654'&FRRQn!&&1:`GQ``07&.sAY%.54>323267#".'#"$&54>73267>54.#"+9lR2*DaSN}aF-?jQ&h;>e3.x=&QUW+Byc[sp8<{R?S0 $0>&1H3!(BT1kBtW22Tp{:SJ#&4t}f|}ާbm:E/fcYC(+G[`_&bnqxz?P4>73267.54>3232>7#"&'#".>54.#"qKц][-2`X'V$?/(PtMBpP-\_#D-)*%-8%7CFIGԑLV"- !(,!(؜XFrXbr> %gx@]sA9hY^    , Tָ&^dc+KiB&HiCsu''z-qu{'z ,@ @ @ <1@  /20%3##!5!!A+<m` (@   <1@ /20%3##!5!!B1BL<=V`o@  K TKT[X @8YKTX 8YI:9120@BKSXY"%#3 3;^^DNl!#!5!53 3!ssf=V` !!#5!5!53 F;^^`XXNl=;%3## # 3 3p\Y/su A{+3;y`%3## # 3 3q!r))kLHJqG5@ @ @ <1@    /2<20%!33#!!5!!+A+B`3@  <1@    /2<20%!33#!!5!!xZ9B1B9L|.@   <221@  /20%3##!"'&533!3_qm||x˪Awr7ٟd`F@ F  <221@  /2#I#IRX8Y0%3##!"'&=33!3f\45h)L _Vu;;#"'&53;333###;qm||֐wr7ٟ9d+`5333###5#"'&=3f\4+ _Vu;0$@  21 /<0!2#4&#!#z||f9dK"*I@#$ $3 +291@ $ (+<2076! !!267# '&'&=3%!&'& ":Cppoż vzKB@bHam `_F$$UgkL>A9||f{%.i@.&&K /2@ p000]91@& &"*"/o]2</]90"'&=33676!2!32767# '&&'&#"XY`09Jt⃄ fgjdcbhcneNRS]\RZF1!&łZdc4,ZZWW-!&'& 76! !!267#$'&'&=3bHa":Cppomw vzKBm|| `_F$c TgkL>A9f{1&'&#""'&=33676!2!32767#&'&RS]\ƐY`09Jt⃄ fgjdcbhcOJ{ZZWWRZF1!&łZdc4,3{,(vm'y[uFH'f532+5327654&#!#3!qmL>87||qwrKK"9wV`3 +5327654'&#!#33^HRRQn!&&,%wGQ``07$)`6V!#!567!3#:bCux+8.%5ժV.V+`%3##!56765!s{{v^̳;bVdžf;1@ 82<1@  /20%!#3!3+53276q"L>87h_9dKKV`/@ F F2<1@  /<0!#3!3+53276WRQn!&`3``07V!#!#3!33#;"9dժVV@`!#!#3!33#W{`39V/@ 221@  /20%!"'&533!3##_qm||xɪwr7ٟd+`G@ F221@  /2#I #IRX 8Y0%!"'&=33!3##Hf\45h)p_Vu;;V%3####! !+-}-VV`%3####! !H{˸ʲ>?V'P`yOh'J+1@oo]0{-&O"+1hN&ru  +@ 0?  ]1{-&jR -( +@(o(P-_(@-O(0-?(-( ]1H{o{m'yu@@]1qH'@p]1uQq{uN'r ulq&jTm(vN'rQuF'jN'ru&j:yXL/`T31'q;y'q3N'ruy'jsN&r'u +@ @O]1qu&js +@ @O0?]1saqu{7sN&|r'uqu&}jso#N'rguq&j#1'qr;=V&q^#N'rru=V&j^#k'{ru=Vf&^N'ru&j^j #@   <1/03!!3#)ժA` #@  F <1/03!!3#`LFN&ru&jGV9@  <<<1@ /<20!!5!!!!!!+53265N)#iGRiL`na8VU`;@  <<1@ /<<0!!5!!!!!!+53265?`nFRjK۪`na=f*%+532767 # 3 3*SfL>7( ^Y/su bzK5sx+3;Vd` +527>5 # 3 dkkCQO5r))`&9as mHJq=;3 3!!# #!5!suNt\Y+wD{;y` 3 3!!# #!5)) ~q4H &@  21@   /03!!"!"$54$3!fONDNONNCD#CD+fq` %@ F E21  /03!!"!"'&763!5>BC>9sttyLZ+.i.*RRPRUC 09@2&)  1291@"-(1220!"32765#"'&54$3!3327653#"'&NOO_KV! 3j^nN?4pi;?nhf1CDP_m}`61f[JJOZxx9qs` 08@2F&) E1291@" 1-(1220!"32765#"'&54763!3327653#"'&=C>A@j\-1C]^fety>dhd.*^\:9m4l01a`RUaPOORAsxx%7@@9., ,#81@'2-28904'&+5327654'&#"567632327653#"'&'&\]OOQRSrsdeY憆GGRQ?4pi;?nhf0!JK;$& hi|UV!bb[JJOZxx8PaF|5G@7., ,#61@66'2,6 KQXY04'&+5327654'&#"5>32327653#"'&NHtCDFEwGQPabLqr<=ih<>dhpb8f83,-F@.. NO]@AHOHXDEORAsxueV<):@  '+%*1@!'(/90!#4'&+5327654'&#"5676323#s\]OOQRSrsdeY憆GGRQJK;$& hi|UV!baV|)?@ !+) *1@ / KQXY0%3##4'&+5327654'&#"5>32ȻNHtCDFEwGQPabLqr<dhpb{v^̳;b`WORAsxue{-`6@F  F221@  /20327653#"'&=!#3!zgh<>dhpbW`WORAsxue{`3s0@  1@ 0# '&76! &! !2653d-|e'%{9!Ҏ׿qF{0@ E E1@ 076!2&#"3253# '&q кĽbZZb/n||r|r|>禞f/@  @@1@  20327653#"'&5!5!?4oi;?nhin+[JJOZxx}q`2@  1@  2 ]0327653#"'&5!5!x>=ih<>dhpbB1VFEORAsxue{~{R|ITf:/@ 1@ 20356765!+532765!T:WxM?77fb0dKLøLVs`/@ F1@ 20356765!+532765!L3DF1a.&{X^}з0)oPT 35675! 3 # # !T>Wysu \Yfb/X+3{L` # # !56765! k0X^̶8D')`HJoP~ŷt32654&#!##!23 #h /ϒ0*3V{ ##"&'#3>32&  k\{::{T%+ܧ$`tad dakj3&$54$)!!!!!!3!!"d;>v78ȒFwtw{&/!3267# '&'##.5463!632.#"%;#"w ͷjbckVteVgKww^Z44*,'ėS^a\s4qVZ{TD:V5`ZTfs%9@' !&<1@!/<035675!!2+5327654&#!#!T>WxqmL>87||fb/XwrKK"9+LV `'9@)"#(<1@#!/<0356765!3 +5327654'&#!#!L8DFRRQn!&&,{X^~ŷGQa`07$)oPft!?@ #8"2<21@ /<2<203!3!2+5327654&#!#!#qmL>87||"dwrKK"99V`#@@ % !F$2<21@!#/<203!33 +5327654'&#!#!#UFRRQn!&&,`7GQa`07$) !!#!3#q"r+A9` 3##!#`9L3` F@   8A!p] 991@  /2  9033265332#54&+! '&ˮ® ,gQ]*-呐u\GCF1l[R.$)K@  8Ap]2<991@  /Ĵ`]0 ]376! #54&#"!2#54&#!$ˮîXgQ$9 𝶫F1l[%D@   8!&p]<2991@    /<<0O']32#54&+#!"'&54! 4&#"3)GgQG*ɟn(!ˮî5ZrF1l[=ó|#ӢI|H@   8Ap] 91@   /90O ]32#54&+#4&#"#576! YgQGˮîːZ`F1l[O 9$\)$30!2#54'&#!3276=3! '&X_`07QWWWWˑ呐1[[F1l*1jiij 9㒕$2%!67#"'&543 2#54'&#!3 7654'& f<0I|q4_`07Q5˧OPPOOPP'.ƪV][[F1l*1LL]]]^^]])D@8 :  2]99991@  /0%!2#54&#!3!2#54&#!}gQXgQF1l[F1l[)@@  8Ap]<991@  /0]376! #54&#"!2#54&#(ˮìXgQ$9 $F1l[-:#'&'&763!&'&#"#76! 32#54'&!#"327654:gimINK(*WWWː\!%_`05л9:E5:. rs TfLQR2jjiu$[[[F1j,1i--Q@+#! '&4763!332#54'&)"32765pG혐nG_`07TZ5WWWWܕ.|n[[F1l*1}Hijji):@ 8Ap]21@ /09]363 #54&#"#ˠ(ˮ;dK2V 3@ : ]991@ /0@0P]!2#54&#!}gQڶF1l[327653#"'&!#3|%3x*%qXdq`>WWK7}bbpiOA$3! '&7#'&=33!2#54'&#%" 76'&ɼżg``07Q_`07Q|y&bc\[F1l*1[[F1l*1 椤)!## '&33276=3)ˠ혐WWYWd+&jiih) !2#54'&#!5 uw _`07Q1k,[[F1l*1f'1?%#"'&543267#"'&543 327%&#"32 7654'& oUIeβr0I|q9I9~dX/? 9.YOPPOOPP@$2iw'.ƪdkWM( ]]]^^]]?@  8Ap]1@    /90O]%32#54&#!4&#"#576! )GgQìː!F1l[ 9$\,3276=4'&#!#5354763!!"!2#5# '&WWYW07Q `_# Q70X_`ˠ璐ijjgl*1[[1*k[[Fd%!! '&332765!2#54'&#)呐WWWW_`07Q& ܕ$ujiij[[F1l*1S" $53 6&#!5!2654& #4$ 5JRS覥A ++.WHNMItYa[J\n@@  81@   9/0326=3! #"&=33®ìGœgQm 9-!F2lZ) 3276=3! '&576%7%5zZ[WWˑz=s9W/hiik 9ψ&dAU)7@  8Ap]1@   /<90]376! #4&#"!ˮî$\uB)4'&#"#576! %5%$76aZ[îː 1y=\gW/ίgj 92dAU##576! #4'&ˈKuˮ9)uBGlP| 9\̍P0%&'&43 2#54'&#!3!767654'&'& Eq4_`07Q5e, 7OOPܪƪV][[F1l*1L,@B@^^]t~H@   8Ap] 91@   /<90O ]32#54&+#4&#"#76! YgQGˮîːZ`F1l[Ou$\)8!!# '&5332765332#54'&#^혐WWYWG_`07Qd)jiih [[F1l*16).@  8Ap]1@ /0]376! #54&#"(ˮî$9 uS0@ '&53 7654'&#""#6767&'&5476! "327654'&RQJRSSSSRefg#RHJIIPacIJIJcaW"ccttstNMMNMMM *c" Y[`XX^[Y01YtAAAAtY10 =@ 8  Ap]21@  /0 9]54&#"#363 3^ˠu2;dss:\,<47632#"'!2#54'&#!##"'&=337654'&В􄑑I_`07Q _`07Q*]WW]_WW_rsppzzpS[[F1l*1=[[F1l*1A>T]=BD=[V>Cs2167654'&4'"!"'&'5&'&547632qG^CC95+<&0kljxw{vEB[eK[ 4D~n>=>@%c3A +mlpp/E# ,,W`aru~^#33vx%"#476327653[RBhj[RBhjTDDjlTDDjl}fC^7#47! !"33254'&'#" q3U7a\ "9S A5z\&NZ%03!Z}4b`&^@PP F'<91@  #/<<<290@0(P(p((((((( ]%#"&5332765332653#5#"'&E``ruSSrw?XXyzVU|:<b`^zbzh02>>Vd{?@    N  F22<1/90`]54&#"!!#3>32||Buܟ6V edqV{ <@" GE!<221@  !032654&#"##"3253!!/+:||:Z/\RdaDDadOV{=@ N  F2<1@   /<  90!#4&#"#3>32!d||BuZVH`ed X?@ NF2<21/90`]3!!3276=3#5#"'&>>|TVCuddZL PO_bvfcxxqV/{<@ G E221@ 03!#"325332654&#"Zs:||:էRdaDDad,@ F<1@  /0)3!!32#54'&S[zM`01LI[F1i&&Vd{>@   N  F2<1/90`]!4&#"!!3>32||VBu ed\V6{ )u@ +G  F*2ij$!!$ISX $<323#'&5476#"3276#§:{5`4xBdBJ4/' daZ+h|{Nvqq<q/ 4@ ! GE <21@  <<0!"32765#"4763!33ƈbOMSK}<zaksC+D߫LVd5@  N  F21/90`]#4&#"#3>32d||Bu\edV` @F1@0!!3y^ VI@  NF221@  /< 90@]32653#5#"&5!#3||Cu`a{fcLq0\@ 2 $G,E1Ĵ,1@ 011(1<<0!""<<!<<#"327676''&5476;#&!!'&'&4763[AS].SD81N/Vɮ!qZsIR\++(VL-%)$?뮘VX:@     NF2190`]332653##"&||CuZ{VfcdKqZ 4e@ GE5<@ (''*%%*39/ 91@. '/ 90@ `6666]32654&#"#5#"325&+"'&5473;2/nD:|WCv>!%7)/kPըdaDE<6pG5P0,!K7V9{;@ N  F21@   /  90!4&#"#3>329s||BuH`edTX-b@ (N  F.<<2 -9   /1@%/<<! (90#5#"'&=47#5367$732%326=4'&#XCubdzzp>BiO>AycW fcx{Iʪ`&$%8vJMO;) +?@-% $NF,21@ &$&)$/90332654'&/&7676;#"#5#"&|| M.=<(`Cua p0.- */(fcVy`2Z#G@%  N!$21@  !   /<90;32653#5#"&5#"'&5476;#"||Cu;^PZl}YYa{fc^PzKWV{!<@ #E F"<2<1@ ""0!  3!!"'&547654'&#"#4632/Q@'$C#@l;qsDE E+G56dZY0Y^cԫeed{QFV;`%X@##'  &9/1@#&&990%   ! 3!!"'&547676/&5476;#&(3W:'$F[L2se`6g+! E/>A/(32||BuƯ`ed X{XV-=@    NF21@   903326533!#"&||sCua/Vfc{%i@  PPF&<<1@ "  /<<9  90@0'P'p''''''' ]3>32#4&#"#5#"&533276BYƸ||zUVCdȸ||XW{ed\_`fca_\Vd{7@  N  F21/90`]#4&#"#3>32d||Bu\ edqVZ{J`@F1@/0%!!3y&"`V%k@  PPF&<<1@ "  /9  90@0'P'p''''''' ]3>32#4&#"##"&533276BYƸ||vYVCdȸ||XW/ed\_\Vfca_\V{$U@&E  G/<2221@"%%<<IPX32#"&'!!#54&#"326չ:{{:+Īdaad)qu{RzV*"-6u@83 .# *E7<<<<<1@&7/  "7<2#99#93.  90#,<<. #"'&'53&'&547632##4#"27654'&,Dd%Kcfep_{5S#al~EU@<%I]7_E8BQ-a`ta2N-bliZn!vFDs:#+IJ>8@    NF21@   /90332653!!5#"&||^CuZ{OfcR@<21@//073#3#R` 27#"'&'3U oo,rrONcAUUWDC <21I:03#3#D-dC'KRX@8<1YC %  <<1@  <5G.i=dB]Gg`":T)yX`!  1  /204&#!5!23!5!&nZͦy–1CZ`G 1B /<0KSX@      Y4&+532##n̒[^ޕ<S"Xh`$1/20@]1#!5!t/яd`4@ FN F<1 /<0@ @P`p]!#3#4&#!5!2snvy–t`FF1/0]!#3t`X` #  1/20@ ]5!"#7XNrXGяy Kd` (@ F N F1 /<0@]!#4&#!#!2dny–/``*@ E F1@  <0332654&+532! w`ҏ/t`FF10]#3tXV` , FN 1 0@  ]#4&#!5!2nV#–X` @ EN <1 /035!26&#!5! #Xt뒦X&@ F N1 /04=!3!#T[CLzld` )@ F N F1 /0@]3!2%!4&#!6n`–X`^@ F E991@  /<990BKSX@     99Y"#673632!5!4&WWHFdaxѧȠ˨Vt`FF10]#3tV X` %F  1 /0@]4&+532!5!ny–X(` *@ E 1@  20#5! !"264&+" я0D_ЍNO`U@ F 991B/2990KSX@  9999Y%67676535673VGu",:pΈLƒ4U}*p>1=!"$Vd`1@ FN F1@ 0@]#4&#!;#"&5!2dn\pTQV#–U;zdd`,@ E N F<1@  /0! )5!2676&+;#"&5*4{\Lwuq`U;zCVp`D@ F  91@ B 290KSX@  Y#3>=3#q_V`}՛C!`J@ F  991B /<0KSX@      <=3!5!CcMgXC"`ԛ:V`,@F F<1 /0!#76654&#!5!2#3l)WzB'*˺u,/HVv.4X` ) FN 1/0@  ]!#4&#!5!2ny–`/@F F21@   /<<033$763 76763) :0nLaT`Sl+7`+@ F 1@  /<20!#4&#!+53265#5!2ndDrL~y–a; `')) `')- `'--`@ D103#`n`@DD1<203#3#`|"%0#4'&'37676537653#"'% '##5 rb{ .q & q-aT !}Bs12j{@E#$]} q!<"ibP-F`)*5"2767#"'&54767&'&5&76 '##5M@V:118UF%/>7P6.N@?^G?D)7-#F}Bs)^ &# \*$@.") n F>]KH*!#TH#bP-F`z %3#%3#3#%3#ƴ>^< %3#%3#%3#3#%3#>>^!#53ӤR@ 327654'&+5336767N5G4pQf$h?FA@6b ! eI(R[2* #53 3#ӤR%@-$%#5754&'./.54632.#"'/XZH߸g^aOl39ZZ8{4<5/VVL89CFnY1^5YVeU"756767&'&54767632&767/SD435gcbnZdF31`9:H:ZU!LOTAKv?=0ps2#nl '{R'z>oy3#&}9&m~ &~& (f&X} (f$3  !27# '&5767"$JKԖ^`e~h'?6`vc–e4- (&X}?}R%67654'&'3#"'532# b&\}q  ?%#&'$473327676'&/3327653323#"'&'TPxmil_Qb_y^@@$;sR,%@n\Kf% I01_2F,k>GHܳ&%0l}=J"5^.327654'&'&#"&#4763&547632#bzL,5;(.;Dn2KxAZM\MObxX'*9:X DD(NOf7*(?$S-8APH&}? "327654'&'2#"'&5476B!799[]KB{ƶ`Q%T*WE{R,,9.UMAx|KU#JN @ &"34'&!5 767"'&'&547632?,3/V%._]g>v-(tYhYH9!$3/,;̠X*VL_ !"bWg3ZfJ6%#"'$47376767654'&'&'&'4762#&'&'&VfxH?Ba=~T;~BrC:@_` B(EN><}9M I&huqc- !P85J.39sJ%*==!'&"7*S@UYD J&o~ $5%5%HHnnnn$&567&'&54763233"/#"'&5332767654&#" %!lE?I(7 /4KU^r8Z #08 " -d$* 9^W4'6O'&n=NV)qaK" %$5%%5%HHnnnnn$5%Hnn$-&'&5476323"'&'#5276767654&#") lE?I(7$# +EȓV " - 8_W4'6O -n=*{nmp" %$5%Hnn8(#"'&54737676533254'3'&!9EO)"a 2=`YG g -SGL(E?4mmb}8T"RY$6îs9It6Y ! 4&#"32>"&462X@AWWA@Xz柟?XW@AWX栠h732767#"'&'gC*6:)kXZZC5"LMD6{S )L}@FOwO  4373ËF3# !#'3%1yI !nR#'337673#" %1BR{6)coajr!nUPymL%#'37676537653#"' %1/(/H/; 'G 44.5WY9!nr|> @2%,*;l>3  *"2767#"'&54767&'&'&76#zf\MOYp0;JcX~VI|eepdkAXH,7p 4C@#90L@rRiUZhsBBsǮuu5aU#'#"'532N%bU`DK*22<!&'3673b~ĚZ00ZĥxU:Ũ ;6I<3#&'#6̴UxĚZ00Z~bI6; :d#"'&'&547632#54'&#"=:i_{\ %Z[,,G\O98<SGU37e{a}UwnWl42@B^!x$%-`+-!d! M fM&I&9 &9 &'~& && & (&Xz8 (&X? (f&X~ (f&X (&X (f&X (f&X /'I>\ r'|>\ &'|\ &\ :654'&32! '$&73! 76767#"'&54767632)B,4((7(*Hnق@AZAd#?zKbNLZB`.+M;3*)3P&ڴF=)d \^tL"9;l&NKCW4,E$2Hf6&x~&xx)-%2767654'&54767#"'$473$62 #dGf>5?AhXPA7.EB|=Q#!w*6(  %{{qeVUI&b \^~B")+&&j|H#"'$47332767654'3HdnaPm/1]]LGL"fh8D%jdQ45b`ޜ ('&X}? @r'|>nJor&o|>m}~RLR%'&547632&767#"'#'3X\lTX\D8/0E= %1Bx:=$!"4'Qjr!n8j$(327654'&#"327#"'&5732#"-2!WZWXZV%2-Z(.5__52ZJkV0B7,g`p5oU%mao3/AbM3))I<<d (@  1@  0"32$  h P3343ssyzZ (@  1@  /20%!5!3%=Je+HH=  21 /203!#3ulh=   221 /0)5!!5!3=lȪ=   21/0%!!!3!l =21 /0!#3!=l*=1/0!#!3!=lcr8A'91/0#3ASuNA (  < /<10%!3!#N{ 2@ EEܲ@]91@   /<02>4."#&'.4>329[ZZ_PGr䆇䄄rEMp`77`p_88 1ŧbbŧ1 y@ 1/03#+q!/@ E  EԶ 0 ]1@  0 6&    z>z='+@  2291@ /2903#36Q*=q33# =qCq @ 1/<0)3!39Uq"q @ <1/0!5!!59qKqO!>@#E E"ܲ@]ܲ@]1@  /2<0%!!5!&'.4> 2>4.":RJr 惃sKRQ[ZZ{ 1ũbbŨ1 p`88`p`88 %@    21 /03"3#!5!p9 fq2@ E<21@  /<20!#!##"&6 54'&"3qvCf^]8mr^:<UfɃ]8ƃD '@   <<1@  /0#!!!y5!Փ/= '@   <<1@  /03!!!}5!Փ/ %@ <1 /0!!27654'&'2#!3,R4,,=iXXXlι]Oz}I__ҭ$;@   ܲ_]9@   /999@ 10#4'&'5!4B 5McAq_9V= 491@ /̲]촍]0 53#T9+!-@ #"1@  !/203432>324&#"!4&#"!}x5%^ZHZlK--Xh&|ŕnc= &@   <<1  /<<0!5!3!!#KK?=9@  <<<<1@    /<<<<<<0!!5!3!3!!#!KøL=??q!@ 1/0!!9UqqK==1B/0KSX@Y! #tFC00B~+n 4@ <<1@    /<20327654'&+!!2/!!m]%i ;@ED\TqQE=4."XErrJSRJrCEoJ[ZZO{ 2Ʀ1 { 1SV/p_88_p`88} @ 1/0#!#}+B} #@   <1/0#!#3}Om +@   <<1@   /0!%!!5!!z;  TKѓ+qO $=@&E "E%ܲ@]<<ܲ@]1@  "#/<<02>4."%#&'.4767673 [ZZTXErrJSRJrCEoJR"p_88_p`88 2Ʀ1 { 1SV/ qO(#&'.4767675!5!!2>4."XErrJSRJrCEoJRNQ[ZZP 2Ʀ1 { 1SV/ p_88_p`88b/1/0!!VBf#"&/#332?E=9Qct2 %xf" %/x $Dp/1/03#=f7u91290K TKT[X@878Y3#'#f[fE9190@ Ueu@ )9IUe]]!5'3{Bf3326?3#'#"&'Bx% 2tcQ9=Ef$ /% "[fC9190@Ueu&6FZj]]5%3%[{fS/1/03#̭F'/1/<<03#%3#\yu  <1/0#527#53gu  <1/03"3#  gd 1/03#!!Mdd '@  <<1@ /03#3#!!Mޒ1/0'!! '(033!!3'#67654'&67654&udruxtNMddx>DD>xIIv! RTxXY`aw,0dc1-!:;z{t{*L@$% E+<<<<@!#91@$+<@ (+0%"3254"3254#"54!#"543263 #4#"h??AA??A'+,LW@@@@@@@@pطQQ9/@@1(. #E0<<1@!0%* 00"3254"54$3  !2632&#"# 54-654!"`@@@CvBըiUv˫:knL?o@@@@N;Ejfae:.88U8327&'"254"%47&5476! #4'&# 63 #"'632# i60IKhh*)7!o^RX;*:9u`/'"6OfqAtqLI $\9.ȶmQ!6@   E"1@"  "0463 #"&'7325#'&&7'6met "xCBCquЍ h! ACBB )2@  #&E*<1@  *%/0"32654& 4''&5432#5476$ % U%|{e6Lj` %"%:yx~)RhKK>  65@$- 3 (E7<<<1@ 5/7&7"32654&4763  !27632! 54-654!"#"`$ % 琺By#xJi:OknLIo %"%0yKpjNdfDQcwiC|85ss *;@&%   E+<1@")+&+02654&'&47&7'73%$$!% l݁6ZA| $! $Vm-G4 p?{1@ F1@ <@0%"32544!  #"54$32@@@)@@@@Pvv .<@- " 'E/<1@ $/-)/<20%"32654&672#4#"#"'&#" #"53232l$ % L 7*>(z*M#6&8"$ %"%3|0ۯqiPWu{+?@-$'+ ,<1@ )!,&,<0%"3254"3254 #"5#&767663 #4!" @@@@@@!Ӣ7y-^@@@@@@@@edm%W ,9@. $  )E-<1@ '-+"<0"32654&4323254#4#"%$7"@$ % 쐋'(uj %"%@կ̰Xsgh\_"9@ $ E#1@# #<0254#"53265$54767653!"'#W@@>z]U]iTrs@@@@pegu/ssIs|2@  E<1@  0"325447&763! 3%$5@@@ԶMg@@@@R&Ѩ'LBIs2@  E<1@  0"325447&76! 3%$5@@@ԶMg@@@@<%Ҩ'hBY E"32654&!"32654&&''"&5623253765$7465&'7$ % $ % Kfg饤IJ %"% %"%IKbv4ˋ42@7-]fn9h%A@'$ F&1@&<<@" &0!"'# 432!32533253"3254hfg襤>@@@ JJ=|\@@@@@h} -?@, (,$ E.<1@"&. .<<0"32654&2533253!"'# 47&5432d$ % AfgB %"%4˩/JJ=%܉Mh -?@, (,$ E.<1@"&. .<<0"32654&2533253!"'# 47&5432d$ % AfgB %"%4˩JJ=%܋L@`$@1@  <<03!23! '#"543225O)3Ɯ)`,88{s *;@&%   E+<1@")+&+02654&'&47&7'73%$$!% l݁6ZA| $! $Vm-G4 p& ,7@  '#E-<1@+.%.0"32654&4! ! &# ! ! '&54323 c$ $ 6buUKX $ $8${nE{N%O 0@@2, %&E1<1@%/1!*<0%"32654&&'&'&5! 765! '676%&4% $  ,D )@ ' 1#-E5<<1@ )6/%!60"32654& 4%$54!232#"'&#"! '&5432h$ % ${ajjh@MqKy)LJm_ %"%1EYl0xP^b8Rsu_|]F'"2''&'$!32'&547"32?6AS2;9’hhNU~ +;9jq!Bao' u ` +@   /991@ /0! &7623$'4'74"Y#!A[VB8?<kP$U.FM?>={{+@  E1@   <0 ##"2#"53254#"n=;C>@{jVR777r&" @ji  /1  /<20! ! !5 74! %&?%~?>~@i$@  /1 /<220! ! 3!5 76! %&>%~?>wJ~~@ji*@   /1@   /<20! ! !5 74! #5%&?%~?>~N@i.@  /1@  /<220! ! 3!5 76! #5%&>%~?>wJ~~T3"36654'#"5432AA\(DeN[̼o[$N[u%@ /1@ /0"3254"547&54323253r>Juum@s> [yu?{EBXF` '656%"'&76! 4"3YVA!. {x9322674&#"CCjFPH OQ$!%!p'(FnJv-O!3] $ $z{&00, ("32654&&3 #"4/&5432N$ % s $ˌeqɘzm %"%82y,v\#"6@ E#@! 1@ ##04$54%&&5! $#"57"3254ix@@@X4|`Pٳ ?@@@@ ""32654&5&'7!$#"47#$ % dt.; %"%Ȉ_p 8>u%t/;4#"#"'&#"$#&532327632! '&57"32654&"3C2z7J,"/IN\=0BWTO3H$ % Xt\DD\t] 5<\UCfwpv  gH %"%V@/1/03#V '@ /1@  /<0'6"%)56574 65+*+UGm++),}݅.p\(>.4"!27676327673!#5654#"'&'&#";&543.%2~*&IHHܝBOg(LBC]i%>e>.`h>3A?~= h\$kb8:;-F_Zkf2)N !@ /<<1@ /<<053533##5N؎؎؎ P>r@ /1@ /0432#"73254#"ЄLTPPHHH` " 7654&' ! '&476^L:NbX1coqoh`WĒcg&24764'&#"676'&'&5476  pHgc/5pIu upHECle\gUܚsuϨcy\$24"27#&5432# '&5?$5+r%3]f́|pHFPfouTapH/%24'$5432327#"'&#"%$'#"54322533]L/|tkZ1AQf(3Ɯ)DjR:jTh8KOpt$68{cW%24"$'&5?$532&'&32!r|T9lc ~x?LvTamY<KcW-224"7&5&326532&'&32$'&324!B}b$|T9lc ~xr=Ch(筭 ?fXmY<KLvttY4@'&''"&54323253765'$543227#"$#""32654&fg饤u ^|uISL\>$ % ,IKbv4ˋjEaTW8ҋ %"%{ &%"324"324#"54!#"543263 #4#"h??AA??A'+,LWpطQQ%Rpt MU"32654&254"#&76767%4#"#"'&#"$#&3232763276'767$ % nnvp+-"2D2z7J,"0IN\=0J%.3?5xv'Q %"%933hk//3wt\DD\t 5<\UCrTF-2bG;"b,i $5354#" #"524"m~ŶejsX\|9 LX"327$"3273253!"''&76324%$7&76%$5#0#&76262654&'&A?A?fxԅ$8$+Rb,7Hu Ӣ5r$!% @@@@@@@mӔJce$3- /ԋu cd $! $ I"327$"3273653%"'%5254%$7&76%$5#0#&7626A?A? Tcb*@RX6&$Hu Ӣ5r@@@@@@@mo6J,/7'- /ԋu cdPi.".54>7!5!!"32>54&'7i7eȬd7&KlGqǔVXxyӚYlūc66clJ7^sz֟\[{6yEr2b\TZ@#!#".54>7332>53!w!KNM#hN&?Q*nq-Nj=8kT3$ KfWxc*s@nQ/+Lk?Z 5!4.#".54>2!/A%'B/+(=B=if:y'D33D( R0oCEOc88cO'MP.4.#"32>7#".54>7!5!!"@YmEgLLfjJkoX؁q؝XGxdI(YjiMKkii۫uuZ8!4.#".54>32i+Kg<>lP-7:p0M6NifL>@kK*0Rp?>?1ill3eMF}gZ,#!#4.#".54>32!|/@%&@0&%BE;hRPg;(C03F(#P/MCOe96`PFZ(4.#"32>7".5!5!>32&/Oj=kOOδMEHHjMoP.)NpF@pR00RfLLfan0/IP- %#"3!!"$&546$3!!J׉@@ט`a( ]wxԟ\Fww2P:G!!3!n!.x1Z+(4.#"32>#".53>32`+Li=?jM*,Ni=>hL+iJEMfLK{W06\xCKxT.4XwA_bKr62NpZ+4.#"32>#".5##!>32*+Lk?AlM+/Pj<@jM*KihNIHk?pR0,PpEBnO--OnβKKgcBvj12KZ+"32>5!#".54>3!!5!!Q@lO--Ol@>iL+MghONiL.QoA@nQ//Qn@/eMMehJ{PS$!4.#"#4>3!!"632,Mh<>e-PKhr>iM,fL?nR0*'R} gM1Tr@aKfPc K4.#"32>2>73#".5#".54>2*LjOwϙYVz|՚X0/':Yr?DsU0 E nǬc67dȭe7><qU'!RkL)[z{֝[W.>#K]59_|D 6clkǬd77dk{Z'kE"1%P#".5!5!2>53KeiL*-Nj|fH'eMOfXAqT12Vq>P&!#"&'.5467!5!32>534JEp=AB7D4+! )#$+e;:iP/05IGHeLJ )RpEn),/,Nj=Z""!#".54672>53!`NgiMNL6--Nk|jN,+eMKgV[@n6@nQ//Qn@]S#".5332>54&'7SLfiJ,Mi>=iL+>5{-H3eMKg@nQ//Qn@6|>/dfdS 4.#!!2>7##!!!2/Oj;;jO/JGHܓ.gM@qR0,Nl?dEHCMPbF4.#"32>5>54.#"#".4>32YywКYXxԗR6aO"?/$/ .@KZj>mȬd78ekoɭc5[])D0z֞[[z{֞[WwAoV5'//!6cǫc66clv?GOPb 14.+32>#";+##".4>3!2>mTEETmFUl>>lUFk\܀EFޥ^^ހWܢ\YqA@n@oWVn?~ٟ[][ڟ[]F!#!3!3!3FS!4.#"#4>32/Oj;53`EIgJ,Mg<:iO/02Kf>mQ0,Mi=nB-#".'332>=#".533267653BLi`R0Lc8;jO/FIiJ,Ni=:c'YgKSkFzZ40Sm>1/Jg@mQ.+(P|S!4.#"#3632+Kh<7g4QɑeL|?nR0++N|uaKfPk*!5#".54>32.#"32673YUlǬd77dlps[.\YS$wЛYXy^Pr2@6clkƫc6JH,Z՞Z;;xXZ)"32>5!#".54>3!3!Q@mO--Om@>iL+MgiNNi.QoA@nQ//Qn@/eMMehJ35S !4.#!!2>7#!!#!#!2 )4)2VsA4(AsV2*=&$;,S~U+ 9/XZ.?#".'332>54.'.'.54>32#6.#".KfbT1Ng:jN-VU^]4R8eMRlHzY3/Qn@72*63UeMTkH|Z4/Rn@)D BFRZS#"'!!332>53SLf,Ni=53 KihN/Pj732>54.'.54>32#.#"]~|ۤ_-H3K7>kTSj==jS8mV4/Rn@8gQ6';#w٥aL~מY[{:omn:vQNVl=53 ,T,Pf:l #D;%?.a=4.#"32>7+!!#".4>;5!5!54>2-  -)//?%&@.%?/:fPW2WvCDwX22XwDp=  @xY9lY|PW!%! %674#"&5! % %1,lշ._z+,S.+RLo ۤTn8d`'675$!2363 ! ##&!"#"32CxuM6sc*rE) PlaؕyZeY!&732#"&5 ][*8F e]N/I3^@[7rr2eY'!&732=6+537#&5! nN ggGVzkB3L.ķ@JKW~Xq\,d!$75&7! &324'"6Z^,CH!IJ:QU,X\$d56#"! !2363#"32UTcD>0R^<]te'6#"$! +.!TueudY! 473254+5365!5 Wb 퇇2mNEIJ(bC+d`3675$%2363363 565&#'#"#'#&#4%"fDjPQUOR Tg@! 5y<O-6d! !234#"#!#"2mLC{%  }>e~! )!363#"7Y`PlB   ry_d56#"#'#"$!2363 H LDVza!t#rd!! 4732+53274'$53X`4"gzҶ/c7Qib6ȕ!6G))=HdY2! 3325 '%5%Uc| CGko 4Y_nd9$5$#"#'#"$%7367 > B)oQT7-ngDP5kn1w5! 3324&547cTɜW\wؠ?c-'9dY: %3! ! %#d6*Q&q)QGFޕd$! %35#$ 3#3%#" 5;54 X`dHrrr44OfkQؔcdX1&!"'#!525#"3$%2363 #"321ZG\KVOvBppdY_!! %$54#"'! ! 4'7_GD `U6I@bYsrg8A:ԃM){6\lY(3324'7%#"'#723! ߫fB߻cV̿0?7YpeW $!6=3! 47$$5! eڞòkHuLL8TWJ&)*dr54&#"'675&%'%"t_CCt?h]|KytJfqI8=ۣ&*2 5#5#5#d 2"4;%"4#"32;ѹF|pux$LRQ´h=@ B1/0KSX@Y %##.d+hK'Eh)hO'zt@1B/990KSX@Y sNO'z)tN'r)u'ew^?1B/990KSX@Y 5](&xyw^O'z1t'56'&56'O'56O&E'E'EO'EO&O'z0'wE&O'wEO&w^O'z?0 3#!38Ygg`nC^^n7]^7nn7]]0d"&533265453zWA@XzCss!AWX@+!U#454&#"#462zX@AWzB+@XWA!s0U!5!2654&#!5!2@XX@s0{X@?X{0U 4&#"32>"&4623X@AWWA@Xz柟C?XW@AWX栠H> %'111 ]]1<203!3CC~K3#K!5!${1V #5#53533zz{{1##5!z$ %{{:'U'"'=wq'h9hK'Eh0hO'ztw^:<1B/0KSX@Y7 5wM40w^O'z)tw^N'r)uw^'w^:21B/0KSX@Y%5^xyw^O'z1t'56&9'56&O'56O&'wE&O'wEO&O'wE&O'wEO&w^N'r1u<291B0KSX@}}}}Y5`sbbs]103C)8)K'E)*@ 8AKTX8Y1  /<03! #4&#"!!ˮî$*\u)O'ztw^ 2 <1 /07! )5! )w5BhPa.,~w^O'ztw^N'ruw^'y` 2<1 /0%! )! !`aPhB5jiy`O'z"t&''&O'O&'w'(O'wO&('y'(O'yO&(' ~21@  0# $54$!3#"3nn͙ nn{'|'|w}'dy'F> %@ 21@  /90"32654&"$54$32#Bz_̀#R3IK'E %@  21@  /90"32654&#4$32#&f̲_ȭT#R3{O'ztF> (@  21@  90%2654&#"3#"$54$3Bf̲_ȭ벃F>O'ztFN'ru (@  21@  90%2654&#"672#"$53z_̀ʃIO'z5t'F'?'~'|?O&~O&|'F&O'FO&?'~&|?O'~O&|?&~  $~ ]21@ 02654&#"632#"&53XP^J\TaaQ_VFTHUGQK})~J8 2654&#"03#"&54632xOaT\J^P_KQGUHTFV}i~F'x'F'x'F> 1 /0#4$32#4&#"#fK'E 1 /04&#"#4$32f#O'ztF> 1 032653#"$5fF>O'zt FN'ru  1 03#"$53326f餗O'z5t 'F&?'~&|?O'~O&|' F& O' FO& ?' ~& |?O' ~O& |?& ~ ] ]1 03#"&53326yaO\T~JPML 32653#"&5T\OaQLMPJ~w:1/0!#!5!)+jK'E!j@ :1/03!!)ժjO'zt!w:1/0!5!_++wO'zt#wN'ru#j/jO'z5t&5&w'&!'!O'"O&"5'#w&#6O'$wO&$'&&&O''O&'&&]10!!3 nC ~21@  0! $54$)!"3͙ nn{3!5 nw} (@  91@  20"32654&'2#"$547!5__ȘLӦnjFY 'i<FY} )@  91@  20"32654&'!!#"$54$C`^ȋMӑnj 'zi<<w "@  91 /20%2654&#"!5!&54$32__ȋfLnjw'z<>w'r<>FY #@  91 /20%2654&#""$54$32!C^`șMgnjFY'zT<AH}':w}';:3'AFY'yA3'BFY&ByFY'rT<A\ 2654&#""&546 !j>_IEcI_(0MJBSKFXCIn~|Q;n."&5332653ܨabaaJPMMPJ\ 2654&#"0!5!&546 _IcEI_>jm0(MICXFKSBJnn;Q|~w 1 /0%2654&#!5!2#bŘ쥒FY 'OFY 1 /0%"$54$3!!"Cꏙƥ᪑FY'z<Ow  1 /052#!5!2654&᪑w'z<Qw'r<QFY 1 /0"3!!"$54$3CbƙFY'z<TH'Mw&M;3'OF&O13'PF&P1H'Qw&Q;H'Rw&R;3'TF&T13'UF&U1\"3!!"&5463RiPYnvDZHCn~}w^ %5-5 ^j22F  ? 1 /0!3#$53TCc Xon2K' Eh @ ? 1 /053#3  cCT-ncCO'z thF   ? 1 /0%#5%3# c--noXF O'ztjFN'ruj @  ? 1 /0%!#3#c-gCcnO'z3tm'fF'f'h'hO'iO&i'jF&jO'kFO&k'm&mO'nO&n&m  ] ] 1  04&+3#XHǜV+.#"#"&'532654'&/&'&54632Cw7Bh#-8GC>=JGBAm'./G?;=~ÇH)@@V\`RʺªV\`RʺªhZ·%XhZ·Fl632#4&#"#"&3326tҪºR`\VҪºR`\VX%Zh۷ZhFlO'ztF'32654 !"/.#"3"54!2!rz|K٬42 swUҤ'4X˧|`í~pX˧|`J3~F'z<F'763 #52654&#"# '4!"326(24׬'Uvr!24֭٣K|zsp~ȕ`|Xp~8=`|F'z<&F&'F&O'FO&'FU''FU&'FU&'FU&'>72#52654&#"#"&'463"326[*'sobI=J>",BR\*$jt_UV) '2654&"#"'&54632! 33265,B:d:B0<~JIjˮîB,">>",BVU_tjN*$u) '"2654&'632#"&5! #4&#",B:d:B0<~JIj!!ˮîUB,">>",BVU_tj$*\) '"2654&74&#"#! #"&547632(B:d:BB®!!jIJ~<UB,">>",Bu$*Njt_UV)O'zt)O'ztS^$264&"&546; )5! '&Vhf# fw_:@ 91@ B /90KSXY%4$32#4&#"!7g#ʲfhXdfF.=@ 1@ B 90KSXY#"$533265!>ʲf"fw_?@  91@ B 90KSXY '!32653#"$5g"ffd餗 K'  '  O' ;' ;O'  '   O'  ( (2654&""&546323326=3#"&=bFntnPX/Q,CEmaZT:KMMKFHn|ppX;oBGj9$ 3>2654&"!&546323326=3#"&=!"&54632!2654&"bFntnP?+/Q,CEmaʔ/bFntnPZT:KMMKFH;XppX;oBGj9|ppX;T:KMMKFHFY<@   91B /0KSX@ Y!"3"$54$3!7YꏙbXhUFY'z<w8  91B /0KSX@ Y!26544#!wb gXw'z\<FY:@  91B /0KSX@ Y'!"$54$3"3!YhbƙXiU𥒥FY'zi<\'%!"&5463"3!\=.̞RiPYB~}nDZHCw%#535!53!3##q=ԭ-!%#5#53!3!3=~0Ԥ!O'ztw533#!#5!5#5q=-ЭԤwO'zt!3#!#!#5353=ԭ0~!O'zVt 33#!#!5#53m unfy~n ,@  221@  /990%2654&#"672#"'"#3z_̀ٷ{O{ʃIH+'sZ@  21  /0# !3! !5aPh//+jiN !!!5!;VnVN#5!5!5!53!!75$i2$i*mւVxnVnՆu!s #'#37 ͉sH+'Y &s & O& 7&  7O&  &  O& !!!!#!YX  !!###!YX  !!#####!YX    H!!#######! \YX     !!#########! YX     !3!!  !333!!&  !33333!!e    G!3333333!!     !333333333!!      !3!!#!?r !333!!###!?r   !33333!!#####!?r      Y#!3333333!!#######!?r        +!333333333!!#########!?r         SC !3!!#!YX\\SC!333!!###!XX\\\\SC!33333!!#####!\X\\\\\\S FC#!3333333!!#######!ZX\\\\\\\\S C+!333333333!!#########!YX\\\\\\\\\\!33!!# #!՚rՙr %!3!!#!!2^DD^ Wc !!!5!5!!!wsX #5!! !!'!%'! !7%!77'7!  ww u||||||||||||u  G7+/37;?CGKO!5#535#535#53533533533533#3#3#!!#3%#3%#3#3%#3%#3#3%#3%#3??????𨨨!!!!aOq:#[!' 7#}CrarCrrD:[! !rarC}rbar=` !#!#3!ff`G [`3!!!!!!!! j /t`Ӕ&{o{4=J%#"'&=!.#"5>32>32#!3267#"'&32767%2654'&#"JԄ℄N ̷hddddj||MI؏ii~ST`Te__ZjkSR\]i߬A@o\]Z^Z5*,=>` #% 54)3#4+327#!5#53!2x9||ԙf_ڪrĐq{Fg`32654&#%! )s7F0Ǔ$g` ! )#53!#32654&+7F0ɖzٍ`` !!!!!! /`Ӕ|1#"&'5327654'&+5327654'&#"567632p<54& #.54! ì++f++$$>:#tNPƳPNM]*U3MY + 3267>54&#"'>3 '# 5467'7*(Ou))Hn.Mw834OMx43N)gA\*g>}66]C_56`?`q{&/=5!&'&#"5>3267632#"'&'#"'&732767276'&#"qN ffjbdjQGhi񈉉ijBN℄RR\]VVUVVVZdc44*,nmn67윜78lkpĘZYWWsttstuq/u{ 4&#"#32/8qu/ 32653#"4/8`!264&#%!2#!#N[cc[H^^>2`!.54763!##"#676#";jpkla;;?î545w?@@?w iQP%$q2^66**TS++2`!&'&'3;3!"'&546#"37545â?;;a|lkp w?@@?wS66^2q$%PQicQ++ST**<m``$ 653 &53sXٹ};ML+%!5!2654&#!5!#TZ`fcL||BtN5353!5!2654&#!5!#Z`fcxzʤ||Dv/{&#!5!2654&#!5!27654'&#!5!#|vz{\MN`_`gb>> E__ru99wSS?yzVU=`YV5`ZX`]x`73264&+5%5!2 'Ӏ{n Fo}ɽBdd>Jm7{3!!I{/=`N`#!#`I``JZ^`367653#5&'&3U9VˆmmV9S`1Ms,}},uMLs` h !3#'!#ZgVXVq`!!!!!5!#!.AeW"___DXI &327654'&#327654'&#%!2#!g1221g̼^-..-^EOO)(N^h+&&MO%%X@? ]65dL.- rUpz 327654'&#%! )[ZZ[vNONN]eefe !!!!!!R-@___S !5!!5!5!5@-_/__H~$5#5!#"'&547632&'&#"326NJYXe|}}|\SRFFPOWWVVWCj]/rssr'y5UVVUL 3!3#!#΀2Wr3# 3+53265A@1(TFDE`Tli 33 ##-<azBm3!!_ 33###|{9="G 33##|_{EEG ##3G|_{EDEH"327654'&$  '&RQQRQQQQwvvwtww[\\[[\\[\vvvvuvG>@"327654'&327654'&'52#"&54767&'&54763sCDDCstDCCBR65<%j<=0ER^X65`l<=ca==ll*6RI)++LK,++,KL++5##,&)$%LY+8:6iG2278PyAAyP87'21I.* 32764'&#%!2+#Y0110YQQQQ))))]?@@?[ #'&'&+#!232654&#=)&''y.,,LPO)*s\^^\$ )(GTD<32#"&'#3t4554455$pMPPPPMp$uuc@AA@@AA86Z[[Z68^gG3#5#"'&76322764'&"Jtt%78NPQQPN874555555S^8Z[([Z@AA@@AAG#!32767#"'&547632&'&#"@AsC?>>>BADbc^]SSt44Va:: 2j88a WW[ZQRmT3210YGMK SX@ 2KSKQZKT[X888Y1@   /0Y5!.#"5>32#"&73267GsC}>?CŻthVau2koamTebXTb2&'&547632.#";#"32767#"&5476G&%HG{065>=f,K,,+*Ib]W-155_;65-9553+,$$4O,, ^$'U13 `fa<))R`1#"'&'532654'&+5327654'&#"5>32FLHG{065>=23-KX+*Ib]V.156_:65-9j2RQ,+ H4O-+]4$'U 12  `33a<))G 14'&#"327#"'&'53276=#"'&763253J44^]4444]^4PP=7633223r99$88NOPPON88$tm=>>==>>FNO e 45k37XX"XX7_z3#53ztttu 33 ##uuZu2u{"4@ $ #32>32#4&#"tHKYhuu'oMLl+yRowtHJZiw[Wk\sa97EBEB~wZXku4@ zx66X6VYYk\sa8BDG 6@ KSKQZKT[X 88Y1@ /0"32654&'2#"&546]ml^]ll]ǁqqpoWGu 67632#"'&'532764'&#"G0336^_]^:5311213p?>>?p3121 XXYY _ ?@@? G4'&"#46320T6667zWVoBAA@qWWG27653#"'&506667zVWoBAA@qWWu#3>32#"&$4'&"27uu$pMPPPPMpf4554455b_86Z[[Z6@AA@@AA#3#;#"'&5#5350Hww33UUPM,V-,vTPn3327653#5#"&nt''N^67tt+78Jy~{Y,-65\c`9nA!5!27654'&#!5!#Ue22<KLg#"FS10gg%dAl88u{(#"&53327653327653#5#"&Q+<=Rnxu$$IZ54t$$KY45tt(78LMlE!"z[+,64\c[+,66Zcb;F&33#&{{y #! !&'3254554#"t nυ9F}攥^ؙ83a _{3#5&+532{t<,||GXG+&#" '&54767&54!232654'&'&yAJZVWVWW!/bL+"766^]l9=P(r(B4?KWXXWr]$,O'(@?Ajp69G  )"27654'&'2##5"'&5476734 )=;67-!XQVVQs~SVV@h)%661FQ:5}t?3XJOZUUXR=\ ,Ajq@:%'#&+53;'&^sa,(^ra,GX]:DFYzg duudnsd&sdyodsdy67632#"&'#44&#"326&_%sNo%ti\[jj[\i92ض78"{qqrG xd%tdV{(!2.#">32#"&'#32654&#"aQQR9||9F,*[cbbc#Lct`5!#3#3!53#53t𰰰त TV/%+53276'7#3/F0j&*06G#367632#"'&$4'&"27tt%87NPQQPN78f5455554_s^8Z[[ZA@@AA@@Gu&'&#"32767#"&54632u1122q>??>q22110h;533` @??@ _ GKu+325&#"47&'&54632&'&#"632#"Z%0\R@5`$^4412/412q>??5{3 * &;/Z ` ?@@biG.&'&#"32654'&7#"&54632''7'37 i:;n\[nO$$ZY drP =67Tb1#"'&'5327654'&+532654'&#"5>32N+,QR2658-56:_651.V]aIV-+K-32==l/|GHL ))unn77wU:8P#P,i/0\+53276=#533343r,Brrtn x66XU P#PG ,5#"3276#"'&'53276=#"'&54763J]4444]^44tPP=7633223r99$88NOPPO>==>>=۠NO e 45k37XXXXn3327653##"&nt''N^67tt+87Jy~{Y,-65\cO9I 5333##53#Irtggttt\\jz~ ;#"&5C,rfpUWlwI 5!#3!53IMjjo\\E\\I5!#3#3!535#535IMjjjjooo\\\\\\V`3#"54;33#'#"3276ztteztry "3rKNB ,|ssW?#5$ z~3;#"&5ztC,rfSVXlx[`+53276'7#3`34r,Bttax66XS gq3!!q_u{467632+53265&7454&#"#4'&#"#367632+=32#4'&#"43r,B0t*pJz>?t'(N^66x66X6V~a88BDwY,-56\uU 4'&#"#367632;#"'&5P''N^66uu)89Jy?>0B,r34Y,-56\sa8BDzV6X66xq 33##q-{{~G 2#"'&5476"!&'!3276WVVWUWWU6//1w &6^]6&WWWXXWWWW@9\[8E-AA.G&.#5!#3!535&'&5476767654'&OpFVVFp^nCWWCnt6%66%4#76$\\FWWG\\FWWE[*,ApoA-9*A@+Fa:.#"#"/;#"'&=32654'&/.547632;1j8W*,]({44MN9> 0Br34@?>=RX l)k`GF@rb/$+*MW33 V6X66x"j2-*TIX00476;#"+5326z73zno>43r,B0]Me30U:Jx66X6#3#;+5326=#"'&5#5350Hw43r,B033UUPM,ax66X6V -,vTP^!533!33##5#"&=)3276^ntgtuut+87Jy~''N^61\\`9Y,-6/G&5!327654'&'5!# '&54767GE()78Z[78*,?G$"ZYYZ!"J\{':?KY7667YR8>#{\8?>LRRQRR<=:u2653#"'&53QHuDEEDuHPZs{>??>{}ZPz3+"&53?27654'&'&gH#"YZ,rftA Z87)2:08?>LRRlwpU67YQ8C&# #3{{ s7n !!!5!G'L\^=R^7!!#;#"&=!5!G'LC,rf>\^=R VXlx ^7^n#47#5!5!3632#'3254#|`\'Ln& m,7!!^R^=jR37!2#"'&'5327654'&+5!5!hCQ>63``;??C5~Ex>?::hn\& =;M|CD m**PJ*)]R^G !32767&'&"2#"&76So/6^]6/ +66,ǗWVVWVV*MWXMmGYXFovw^wwwv[f!5!73[f3!Px[f#'!5f[f!!#PU騋fBf 3#'#35fxBf 73#'#˴fxh'${-{'TDN'zs%N'>E&%&E&%&Esu'l'sLvquf&vCO'zt'qbN'>G''qZ'zG&'qZ&GOw&'z[quZ&Gz'&'qZ'^&GZ&(q^'HZ&(q^&HK&(7qK{&H7v&(qv{&Hum'yu&(zquH&H'zK#O'zvt)/P&I @s&*2"qVZ&JI;N'zs+dN'>K;'+d'K;P&+j@dN'>Kt;&+ztd&Kz9;&+ 9d&Kv&,Jvg'LYZ&,tF&ajl'sv.l'sZvNj&.&Nj&. &Nvj'/''O jk'*u'/S1'q(;j&/J'Oj'&/\'&Ol'ssv0f&PvO'zwt0'FP't0{'P3N'zs1d'Q3'1d{'Q3&1d{&Q3'&1d{'&QsZ&2fqu &RsV&2lqu&R'jotrsZ&2jqu^&RsZ&2hqu^'Rl'sv3Vf&Sv2O'zt3V'STN'zs5J&UT'}5J{' UT1'q}; "J&q #T&5TJ{&UO'zt6o&%V'6o{'Vm'sv'z6of&V&VvW&6o&#"O'zt *o& +*O'zrt77N&W#>'q77'W&7b7&W'r&77''&W)'8X{'{Xv)&8vX{&XK)&87KX{&Xu7)Z&.8X&+v)4&28X'Xh}&9F=7&Ymh&9=`&Y^Dr'u|:V5k'C ZDr's|:V5m'vZDN'j>:V5'jEZDN'zs:V5&ZGD&:V5`&ZJ=;O'zs;;y&[g=;N&;j>;y&[jfO'zps<=V&\f\m'vu=Xf&]\&=X`&]1\&=X`&]d&KfN&Wj->V5&ZB=V&\{a&D/P&A@7&#"#4>32"#"'532654.546m@f_@&9dc07CjjCӴmob)F[dd[F)Z@hoϋ\(Ž}_-C-->T\_EFvX5P3) $2BgCquHh'${-{'!Dh&$u{-{&DTh:&${'Dh:&${-&Dh[&${'Dhu&${-'Dhm&{-f&"hZ&${-'DhZ&${-'Dh&${-5'DhY&${-&Dh&{-&3&(q{&H&(uq{&H^'tu(q7'H:&(q'H:&(q'H[&(q&Hu&(q'Hm&qf'& Z&,#uD|& &,.&Ls&2'qu{&Rss&2'uqu{&R}s:&2lq'Rs:&2jqu'Rs[&2jq'Rsu&2equ'Rsm&'quf's& sgk's'ubvf&vscgk'u'ubvf&Cscg&b'uv{&c}g^'t'ubv7&scg&b'v&cs)&8X{&X{)&8uX{&X}_k'suqif&v{r_k'uuqif&C{r_&qui{&r}_^'tuqi7'r_&qi&r{r&<ur|=Vk&\C!'v<=V`'t\&<r|=V&\`^'tru<=V7&w\qa&E ppqa&E Hqf&E }qf&E qf&E ~qf&E qm&E vqm&E Dha&& p#ha&& f'& }|f'& f'& ~SXf'& om&&1 Qm&&x Na&I pDa&I 9f&I } f&I %f&I ~Of&I R-a'* p-a'* 7f'* }|If'* f'*" ~Sf'*^ oVda&K pVda&K Vdf&K }Vdf&K pVdf&K ~Vdf&K Vdm&K Vdm&K a', pa', f', }|f', nf',3 ~Sf',d om',t Qm', Nna&M pna&M f&M }'f&M <f&M ~Qf&M =nm&M nm&M Aa'. p5a'. Kf'. }|Kf'. f'.4 ~Sf'.p o"m'. Q)m'. Nqua&S pxqua&S nquf&S }equf&S Tquf&S ~quf&S a&4# pVa&4} Of'4v }|Yf'4 f'46 ~SPf'4w o*a&Y p=*a&Y *f&Y }'*f&Y !*f&Y ~`*f&Y W*m&Y 8*m&Y Ia'9b f'9 f'96 o3m'9L N'a&] p^'a&] T'f&] }Y'f&] ^'f&] ~'f&] 'm&] c'm&] ^a&=N pqa'= if'= }|uf'= Cf'=t ~Syf'= om'=B QPm'= Nqf&E tqf@f&I TfAVdf&K VdfBnf&M fCquf&S {quf`*f&Y 0*fa'f&] M'fbqVa& HqVa& HqVf& HqVf& HqVf& HqVf& HqVm& HqVm& HVha&  oVha&  oVf&  oFVf&  oFVf&  ohVXf&  oVm&  oVm&  o2Vda& 8Vda& 8Vdf& 8Vdf& 8Vdf& 8Vdf& 8Vdm& 8Vdm& 8Va&  oVa&  oVf&  oVf&  oVnf&  o#Vf&  oTVm&  odVm&  oV'a& YV'a& YV'f& YV'f& YV'f& YV'f& YV'm& YV'm& YVa&  o\Vqa&  oVif&  oVuf&  oVCf&  oVyf& ! oVm& " oPVPm& # oqH&Ezq&EqyqVf& $HqVy&EHqVf&@Hq7&E qnqV7& gHhm&&yuh1&&q;f&&B RhfVh&& oxa pVxaH <ܲ?]1 Դ?_]KPXY̲?]90IIPX@@88Y#55#53xgJ7FJm'tjVdf& (8Vd{&K8Vdf&B8Vd7&K qVd7& v8f'*b Ruff',n Rf V;&, of' p  f' p. BJm't pnH&M$n&Mqn&M .%x7&M q.zm&M r0gm&.y.uY1&.q.;f'.q R}f!~f'  f'  _Jm't *H&Y'*&Yq$*&Y *DVa&U pVa&U *7&Y q'*m&Y rm&9yvu1&9q;f'9 Rf#5a'6 F)&j lFRfCV'f& 0YV'`&]YV'f&bY'7&] qOV'7& Yf'4; Rf"f'=D Rf$NV&= osRfvxaH ܲ?]<1 Դ?_]KPXY̲?]90IIPX@@88Y53#7"͔gd10!!dd dy/10!!dOydy/10!!d8ydy/10!!d8yy/10!!y&__J&BBB@ 10#53ӤR?@ 103#ӤR՘?@ 10%3#ӤR@#5R՘?m '@   1<20#53#53ӤRӤR??m '@   1<203#%3#ӤRӤRլ@@m '@    1<20%3#%3#ӤRfӤR@@m #5!#5RmRխ??9; '@  YW Y <<1<203!!#!5!oo\]9;>@   Y W Y <<2<<2122220%!#!5!!5!3!!!oooo\\3!   \ 104632#"&3~|}}||}3q31/073#k1/<20%3#%3#V #@   1/<<220%3#%3#%3#ki3#iq L #'3?K@D$%&%&'$'B@ .(F4 :&$L%IC'1+C =  1 =I 7+ ! L9912<<2220KSXY"KTK T[K T[K T[K T[KT[XL@LL878Y"32654&'2#"&5462#"&546!3#"32654&2#"&546"32654&WddWUccUt%ZVcbWWcdWccWUccܻۻۻۼܻۻ q r "-7;EP\"32654&'2#"&546"32654&'2#"&546  &54%3#"26542#"&546"32654& WddWUccUyWddWUccU<¹ߠZucbcNWccWUccۻۻۻۼ5ۻ(`3(`u(`&  ,(`' ,&  X(`#3W`u(`&  ,(`& ' X , #'#Rs#G@%Bon29190KSXY" 5s-+#R#I@&Bop<9190KSXY"5 +-#^R^  &K'N''=NO'^O$#5>323#7>54'&L Za^gHZX/'-93A% #C98ŸLVV/5<4BR-5^1Y7| B_ % ij991@  <202$7#"$'56:<hh~vvuw~ign % ij991@  <202&$#"56$6;>nvv~hhgi~wuI3 # #bbc$$v=' {' { 3_!!V_+@B10KSXY"3#-\X 3!!#3hX^#"#JX 53#5!!53X^JݏޏJ&""gJ&"JJ'^"d] 7 91@ B  <20KSXY327# 'du](; 2###׎辸( 3+"&5463yv}~}|( ';2+v~}O|}=k {B# #5#5R#۬@n&  =o'  BC''Hd1#"'&'&'&#"5>32326撔 錄ܔ撰 錂1OD;>MSOE<>L~ 8| #'7!5!'737!!qaqqaq)`rrbqr2 535353,(`$' ,& '  XfN 53!535353fXp fN 5353535353,p  3#3#'d 3#%3#3#3#dipD %53535353#!5!3!,|f  feP> 3#3#3#>w 3#3#3#3#W "27654/2#"&5462332233VVVVVVVz@ <<1@03#3#zttttg? @   ] <291<290KTKT[KT[KT[K T[K T[X@878YKTKT[X@878Y@T /9IFYi       "5GK S[ e]] !33##5!55bf]myf !!67632#"&'53264&#"y^^a`<~B9>>Eoo4h6_ MLKJq ff\/"327654'&&'&#"67632#"&547632X3333XW33331221DD &9:DTTXWll122m45[Z4554Z[54bg KL1LMONuv l!#!liH30Y *:"32764'%&'&546 #"'&54767327654'&#"55j]\655T./RQ./SZ85UVUV56-/.UQ100/SS0/*,+KLV,++]12Hdt::dJ01:7PyAAAAyN98?&%%$A?&%%$S.532767#"&547632#"'&2654'&#"1220DC #<9EWXWXkl122Xf33XU5443g KK/MNoouv rh\Z4554Z\44k !!#!5!Q_i_k_8_83!!'3_a!!!!''^_o #&'&4767TRRTe^///._~g3#676'&ge_/../_eT)**)~~~u0@ 32tNN^luu)qJy}wYYk\sa88WT dC{d^TtdbTud?C dfC d\T dlC dYT dST d d8 d  doif dgif dMrdGxdGdu!sdGydV##"32.#"3267!!!!!!Oc%eNLbbL:/667756GFDFG ks9'.473&'3267#"'#7&'#7&'&76%73&'hA>/(%:@w]ayA9&AX}R4>C5Ai<)^_HH?WghйKp(`,%6767# !2.#"3>32.#".aXj]aye6{_]w|^0n&<$'/_HGghGG_^ٜu]\Y!!!!3###5qZpP~WHE9Eb#!!53#535#535632.#"!!!5-쿿=OL=tyB_))HB+#&'&#"#3676323632#4&#"#̪m49wSS>YXyzU6%X\xruxGM_a`f21>&>E3\u"&)''#!333#3#!###535#53355KO8~8~OO4&{{&&{{{ P32654&#+#!233!!;532654&/.54632.#"#"&'5#"&5qzzWQeGl`[z_<`HJU];Ufɘ/ϒjqqR>N#55YQKP%$((TT@I!*##`3E326&##.+#! 32654&/.54632.#"#"'&ٿJx}A{>[b`cae@fLNZb?ĥZa,/b؍$~3YQKP%$((TT@I!*;"&)-1'#53'3!73!733#3#####5!73'!!7]:1000019]zu }Luuguuguuuu_ % #4&#!#)"33!3_SV*$oN&1@: "+ /) 2+"!)#&  , & &*!/<29999999999122<20K TK T[K T[KT[KT[KT[X222@878Y@z  1Ti lnooooiko o!o"o#n$l%i'i-  !"#$%&'()*+,-2   USjg ]].#"!!!!3267#"#734&5465#7332[f A78 ʝf[Y`(77(6bbiZȻ{.# .{ZiHH"{/ #/{"G(33!!###5uX_Tws1s!5!!77#'%5'&PPM4Mo؈onوn9 -bw'67>32#"'&'"326767654'&'&67'>7632#"'.'&/#"'&54632326767654'&'&&#"32">1aJ{%A01Q[W7>/W1   >$<  . #dCw-^URB$`>DL_K>.3b @N\uLMiI(S395l9,8G(/&  -9)ЗiRm:3Xwdg7? 2j7#=5(6$ 629T/ (2M !:5S}$@{mbq~Es/4 -& "TAB`]|@8nRkcd]aC".)5'632327&547632#527654'#"'&#"%654'&#"o|@X"07PYtaTk~j[IwmqJ2530D#24!`NkBX``S㫣†qJ323!!!3267# $547#5\J5 ;_srigCS1r{jJ,{ +kv67&&UB{\* {;^~FE/0K?{w!,&'&#2767#&'&576753w[TUeeUT[Y\Y[dsye]Y\[CvlCi----iH$"u9Bt"#BuflC3!~d=!5!'3 G~d=z!#'73!5~~͛=z5!'3#7=~~d͛{ 3#%3#%3#yfP{ 3#%3#%3#%3#ky)=z #'73!'3#7~~<~~͛͛C $(B"326=7#5#"&54634&#"5>32%3#.#"3267#"&54632pSHfmƩogDc\GD^o8yy8o^IICBRCI M >OW\ 7$44"C +EI.46'&#"#&'53254&'"326=7#5#"&54634&#"5>32%3#VNz$p;i0ʪ%={pSHfmƩogDc\GD}|49d$, !5Lf,1BRCI M >OW\ 7$s'!.#"3267# !2'Y藣yyYjzS #bvAZ4-4ZBuHHghG[!!m&r&F+,/-/ܸܸ,(и(/A&6FVfv ]A] и ии# /!"+!0153&'&'6767!!5&'&76wI3cc3I86QLNN7887NNMR48_ki:rq;zn #++$ * rn<(2.#"3267#"&54632%3#"326&$  &54^o8yy8o^IICDkavva`ww~44"K <M-1332653#5#"&.#"3267#"&54632%3#\QPcu`^o8yy8o^IICDLriuD P44"K{Ro#&&r)Io!6767632#"'&#"32767#"'&'&547!#"'&54632327676"#"'&'&54767632l(9BKc{=&%%03!((!,739%7`lG;7 25]hB4,'5  'B[QF$%]c'G  %! }Kr~,1ьIg)*!&!(D;w},75;!_']7:y}[Ϟ\@4>#,!, 'QFj(JG4$$,*)/9yK#%P73276767654'&'&#"&'&"'632654'&'&54767767#"'&'672#"*i(X%# 1FSE/ O.55FuPU[QF[00rl~"KI}!;IFs;n;_T^͌Q79}w^l.Gyr\[4O9%#i#^MX;yv@c}e.ID\7I;>2V秉uӰ3!3%!!!!!!nnq  dx+%H#>54&#"#3>32u j_ y/wFx \/HT^Ȧ^m$RZ3%632##"#'7-P4-> {|a\=BcL;t9#"'&5476323276765"#"'&54767632thn<7# ;KQ>!|Za,4(XM!},‚<7D9#7.M=.1?@ '(MXI(' jF!2?632327654'&54?#"'&#"632327#"&#"jou9!ydG>PPPP5ʺ68^nm{z}}ȋo֏zZ'PVaK~pmdykb^OP681/::b:DnJ327654'7#"'&'$#5"'47676766767632#"'&'&'&#"32nZS_n0VBRny#HB?X!$9BMw>7l. ;7%,;(ӧuy,D0&3273#"'#67&5477632654#0)W:K32#"&'####53&  O:{{:ܧ$}daad}j %# !3!# dX0dd q+6+/BB/,/<-ݰ.<-ް#? < # 9 FhH)##Ii;BB=#IbiF`FaC`#BC`CUXC`C8Y& <BB00<İ< 6< <9 FhH #Ih; < ְ ݰ,9, FhH &ְ& #Ii;/,#Ih:1#IC`#BC`CPX& ,/C`C8K RX #IC`#BC`C@PXC`C@aC`#B C`C8YYYBB=#IbiF`FaC`#BC`CUXC`C8Y#)<BB1#IRX   <  < Y3525!463"!4632#"&732654&#"5!6jgggg92299229k̀k@4nNggNNggD{{ "-! ! ! ! '32654&#%!2+# JR12)uyӲckkc?L00ey wXQPXdn;C0<67632#"'67327654'&#"#"'&57&547276545[ۄFIyeL )qz]E& JEYq:?.蔁0.A ƂMkeLPק<+(h|H=y|n=B {u.F/4_NT 33!27&#%!2+!67654'&,d.@nX<-]\,q jdZ)VV)s!)%#'# ! % 7& 676'&B 3y;:x+lllli$ #ab[ 2222jT%%5$c$B2 _327654'&'&'#"'&5476323276765""'&5476!6?232767#"'&B=]iS\ZV30Fn7;#FfS9!!< #5,h";<2XngZR{,##9>;K!QIag£S D5@7*'S:y}*7H0 5#!,Il @3Xnh0{(2r:=OSlIX&54'&#"#"'&527654'&#"3"'&547632763227767654'&#"R(O*\xggfg-.@@?@@?\QA@@@S6fggfeӻp/$~AB}:1$ -*MJJ@f[+8vuuv zVWWWXWWVVW\uvuuu# bW1W{|^1$h{vC[SK\GChfy /2 &.2&'&+3!.+!! !27&#676'&%3LDEx-Me5q>HJxnu1EA+ZY*01/O~hbb)j)V>U)-  /!/ и/ ܸи!ܸA]A)9IYiy ] и /9 ///+ +0132654&#+#!273 # #s sNCI/ϒ_6۬kk%T$+.3&##&'&''7#!27%7 67654#?\A>:AٿKE6ToF^~_ ,8~|T3Jۏ/HDh0& ,ok؍]-Dbg('4.#"#"&'532654&/.54632733###UW'AG/E8pi4sG[d/EK7?8pc|3iиY"*/( VAO[`*,2,* M=H\T(l0`!!#!!!!!!!3!!rso+` `ffff'F >@!    b b cbc91<<2<<903#######5Jq7rqr/B^^"h %73# ' 3,o-MoF+,\ %#!!!5!8kO8d qddd XL/ 654&#!5!5!5!!2!"'X $''ߦԧc̆eeaԊfJN=NsDU767654'&#"#"'&5733272632632!"'4'&'&#"'6763232767654'&'&#"_}yj#1Q\$####,TGG\n#?QY>kDM4giMqE#"'&'&5476?&'&547632#"'&547654'&#"3"32767'_ilE_ml=Oc{T3-2") %+fa@aP/Z_|{w:maZu> IhA"%@_l$=PczS2VN-2!$+%$+@e}N069na[u>_T M#"'&'!#!"'&547632327676=!7!&#"#"'&5476!27327#X':'7?<=**M_4. B^l{>!'Ba>nG#&#w4$B00!K=DcK_4B( 03B{>ceDInFT=I,Fw7K. 0# )5!!5!3#Pʪ9Bk32767"'&'&47'&'&'#"'&547632326765&#"6767632377632#"'&'&'&#",5(.'*'E`97y{7a;f7;>F3.^PeMD*#7@,j!HhH<=.%_yipp3 T}B',$ *5܀/,,@!;Da97TVM;nwF^O?/,%!;>jytX<;}f?E'_n H''#  .hJ) 4&#"322#"&54WOmVPm˜ݢt}t{أأg4 4'+5654/&4?'&547 '&5474/c2>Bd=VE/b5c2ltc2c2uc1LS2?Bd,>8?]/c6c1LS2tc1LS2c1LS2903#!".54?>3!4'.#!".54>323!2O,""$%@;5H *Y[#$"x2 1[G(  WA,!2#"&/#!"54?>3!!"&5462TPl 0%= -d,mF"$mG- .7#*(/ $"Sae(!q~B;V&!"&54>323!2#"&'&5 mG * 5G 0%9 . q~( 0 (/ &Js!S'DQIF 4632#"&3!53#5!pQOooOQpoTQooQOonuyy5yZR; ! ! ! ! HH#[[breH !#y;:x L`  !!!!#!3#'!#33 # #DjwZDZ֏R``C5MR.}$z`-1%5"'&'&5#2327#"'&5#!#"#463!#3#, 9Yl(Ht*=Z2dr!Z4@'!8 ֦zEB bLs{dYsZ{3#"#4763 3׮UEEl4FũdGQnCF\xB*WbOZ=0 3%!!,:*nq dd3!3!!!! nn8q  qwS ! ! !!5 5Y*dccS!!6$3 !"$'53 !"kJu^uopkoSUggHF_`2/.2%!#!5!)+!5!_++!# #3bef9WJ " )327&#!3676654'&|tK"P"coAfյ|cv~dAA xPfUmZ #2!7#"547632!3 32767654'&#"* 6B8wx!Nbb|˞"#>|OO'vN 2wx87tKsO=  =d01 PD10d^dTd6Jthi[{ (232767# '&5477632!7!654'&#" N&#G_yZ\klmk}Z5fF 9NJC0<7h:J(u*oDMcFPZd82vRsO 3#3#!!ɸ.Ԇ$N9`V 3##676#732767!ɸ.fʆ#5H2K1i0/N)deеT0Hd01``;&0 #473>32#"&'532654&7>54&#";Ht]h202޸SUWDi;2[UԠ_I@Yr~YW׀c?}<$$/1oX3gQX?@Q` $@   F 21@/0!5!!5!`oX&{' 5ud^X&t' 5ud^&{' 5 d^^&t' 5 db^&u' 5 d?^& ' 5 d~&{' 5 df~& ' 5 dw&{' 5 dbw&u' 5 dfw& ' 5 dlw& ' 5 d&{ 5,'&,,&,',,(Q&,9h9&9,,&9',, &9',',,-&,;=;;=&;,=B&;',,j/s'&'0yL&LLpY&L'LpLA&LY=`Y=&YLD=-&Y'LDL=&Y'LD'LL$J&L[;y`[;&[L[;D&['L[LyOq{FqZG{Py }  ) !3 !## !5hPPh55~ji.,w# + ++ A]A)9IYiy ] A]A)9IYiy ]%"+++ + 013 !#3 #32654&#! )5HHNhPaY.,职~y }(1C3 +3 !32654&+! ) #"35# !35#"&546!`HH5NNPhthNN5H/ó., ji~s'H{d?8   2@ @@ 00 ]1@   990@   <<@ <<KSX << Y5!!dx=xUZxx @   991  2@ OO ?? ]0@   <<@ <<KSX << Y3'#'-Zxxvx<xuP8   2@ OO __ ]1@  990@   <<@ <<KSX << Y'7!5!'7Pwx=xZwxx @  991  2@ @@ PP ]0@   <<@ <<KSX << Y#737Zvxxx76767632&'&'&#"#"'&/#7!#/)85,0F"<;NJX[GR7<"#!2)85,/$#?2WG[XJN;?,!F0O<:" %7xxUZxaxxaxuP8 '7!' 7!'7Pwxx>xaxUwxx>>xxwd?8 !5!3#xwx-xZxY %'3'!!5xZxZxvx檪uP8 22@ O O _ _ ]1@   990@   <<@ <<KSX  <<  Y!#3!'7'8窪xwx-\xwZwx !5!!7#7\xxZxx+xvx7!!5!7'3'xxxxxZxxvxxvxd>%52#!5! 767>54&'&'&>42/+-+-':1 Hxwxܪ-)o=  xwZwx(.46<=69)-d>>3276767654'&'&'&"5476767632+#5!5 6 +/24>A1:'-+/24>xwx  =69)-(.46=<69)-xZxvP>54'&'&'&"3)'7'7!#5#"'&'&'&5476767632# 6 +lxwx>42/+-':1A>42/+ׂ  xwZwx-)96<=64.(-)96=dP8X#532267676767632267676;'7'7#""'&'&'&'&'&""'&'&'& xwx 0$#$   "%'-0$' !  ' '- xwx  ('Z&("  "(&Z'( -xZx$ -#%"&* 'xwZwx ""&*  *&"" dPF%'!5!!'7'7!pxwxpdxwx^:5xZxo:xwZwx* %'7 !^ b9YXxbZ  #!5 xwxoxZx[ !'7'7!#xwxxwZwxZ  !5!3 ixwxDxZx[ 3!'7'7xwxDxwZwx 7#7!5xwZwx=xwxd? !5!3?=xwx-xZx,-eX&7#754767676 #4&'&'&"9xxZvx.-\ZnllnZ\-.BB54'&/#7!!#"'&'&'&54767D !BB54'&x\-..0YXplgtTY0../Z#,@#B"!BB@RNJV]xwx]TQ>]xwx]xLii `iiT4]xZx]4]xwZwx]JiiiiuP8!7'!7!5!7!'7'7!'7!5giiyYuI0]xwx]uIiixK]xwZwx]Kxd?8!!5!!]xwx]7Qix]xZx]xi#'3'#'x\xZx^xhP8^xvx^huP87'!5!'7'7!5$iiQ7]xwx]iix]xwZwx]x737#73jhx^xvZxx\x%hh^xvx^8dP8!7'!!5!'7'iili\]xwx]]xwxiii]xZx]]xwZwx7''3'7#7iii]xZx]]xwZwxliii{]xwx]\]xwx  #7!##PU?,UvU,?UP5#'#5!#5'U,?UvU?ԄU4 753!5373U?ԃUPqPU?U 433!'3ɕPU?UqPU?,Ud?8!!!!5!!c$R&xwxxxxZxxuP8!5!'!5!7'!5!Q$܊xwx&RFxxxwZwxxd?8#''''#53777?(FncxwxFn-FnxZxFnuP8577773'7'7#'''unFxwxcnF-nFxwZwxnF3'!!!!#!5!5!5!'-Zx((ت&&xvxTrx#7!5!5!5!3!!!!7Zxx((&&xxrTxd?8 5!!5!35!dxqxUZxxa 3'#'3#3#-ZxxbvxrxVuP8  '7!5!'7%!#'#5PwxqxUwxxw( 737533-vxxvxrxv4k?9 !#3?xvxתx~\xuI9 !'73#'7!uxvxxvvx7?~ 5!! !!  d }*^V 3! !!d}*p  d HP~ !! !!    ^V #!# !!!d e n ^V !! !3 3!!!E*dr*r$| \d^V )3! !3#!5#3 3 ȃ\Pdx @t %#!5#3'!3!3! !33'ȡdxd:tZdd\nt^V%#!3!3! !3!5#3ĹtIt\Px^V%3 3!!! !!3 37r*kd d| ^V %#!5#3 3!3!! !!33 37ȃ:͊` \h u}~ 7!! !5#35! u\Pdx f:bȃ  zM!#7!!#Mc"?,^xc?x^zM35!3!5!73zpc?Jx^cr+a?^xJ^V 3 3# '! !! !  e   dCuP8)5A '7!"'&'&'&'#5367676762!'7$"!&'&'!27676Pwx 21@=:C.2  21@=:C.2 _x_R#)l$h$#R#$Uwx@21.2@@21.2@xw#w;' , utP'7!5!'7!5!'7!5!'7Pwx===xUZwxתתxwZd?D5!3!!#!dx3xUZxmmxuPD '7!#!5!3!'7Pwxͪ3xUwxmmxwdPD3!'7'7!#!5xwxwwxwxmxwZwxmxZxd?D5!333!!###!dx⪪YxUZxmmmmxuPD '7!###!5!333!'7PwxYxUwxmmmmxwdPD333!'7'7!###!5d xwxdxwxmmxwZwxmmxZx7?@  !JBJAu}@ 7'!5! PJBł}BB7}@7'! ! 6BB A}BBh %!3!3۠ՈR+nm+A&6FVfv ]A]+ +0132#&'&#"327673#" B!OO!BzcI7͙7Ic_L 0"'&547632654'&#"563 3276767&#"\m`cu\6% GGnth r5?,/H@3H5,Y:$UeI+HQ\N,tqzSd69->eSY׮l !5!!5!!5>+5!#7#53!5!!5!733!Kcd04+^^``k](673#"'&'#7&'&$32 '&#" 32$767&'&YjiEd80~i?/c`RQQ$g'-"SRR:;nSz_'BTc_ N@DROg`8@91/90@cmpxyvn]] !3!^DC?`%! !3f<?I!!"$54$3!!!W?JGcGK@ sJxNL``ȟMOx]I&/!!!!3!!"''&'&54$;7#"ؖI$$$GA?d`,,cFU;}YI7ʟ 7c``JxH NGx]g% $54$)!!3!+*(FiNv%FrO:0QI&'&'&'!5!2#!5!676767!5?JGcGK@ 'JxNLȟMOx]I&/'7!5!!5!&#!5!2+4'&'&'3276765 I^Q$$GA?d`,,#FT;}YI7ʟ 7c;JxH HNGx]g )5%2767!5&'&!5(*FiNv%FtFgP:1R, //01!!,wq@gg120!#!# }wq@gg1<03!3wJ}w; ]@    91990@0QVPZ spvupz  Z pp{ t  ]]!! !!5 7AJI3!-10!!ת !#!5!3!!5!--+}ת W+и и и / + +и 01!!#!5!3#-Ө-5B<%?P%73% %#'TUUTUTTUDGrXY %=} *@    91903##'%\sB}}`s-Pb;=v& Xus=e& X s 127#"#"'&'&'#"'&547632676;#"3cd3668+MI6641C;ItY^^SI6?+((C;ItK@tkHMfpEF?$Tx5@ejre!93Ex5@#/;&'#"'&54763267632#"'&%27#""327654'&1C;JsY^^TI6?+((C;JsY^^TI666cd3778s~d3778]$Tx5@ejre!93Ex5@ejreMHMfpEFHMfpEFI%!3!~,I%!3IfIA//+к99к901%&'&'3!!#4'!&'7`'JAW`LqR]+X* Pʋs^(Rs57756u5 +  // 9 9 901 7&'7%%'6 676r{EG%y44RW!L!$Ҿ &!L {JP+3#+fJ+ 7+и//9 90137#'PMVo)gnJ+3#3#@+fJ+{//и/ܸи ܸܸ и и// // 9 9 9 9013737##'[P]ME+qd @oxpAn!3# ih^T3 3##"T^32#4&#"#P(*7332653#"RP7*uM>2&#""&'7327~9GA~9G⧅}}uM& i i%uM& i' i% iJuM-6?67632&#"#"'&'7327&'&5476767654'&'SOJMG79GcBnnVsSOJMG79G]InoSu=,EG%,=,HK%DAF7K|oUDAF71IosV/HgjG$4.JhgH$uMMQZc67632&#"!67632&#"#"'&'7327!#"'&'7327&'&54767!!67654'&SOJMG79G~SOJMG79GcBnnVsSOJMG79GSOJMG79G]InoSu~=,HK% =,EG%DAF77DAF7K|oUDAF7$çDAF70IosV!.JhgH$+/HgjG$uMmqu~67632&#"!67632&#"!67632&#"#"'&'7327!#"'&'7327!#"'&'7327&'&54767!)!67654'&SOJMG79G~SOJMG79G~SOJMG79GcBnnVsSOJMG79GSOJMG79GSOJMG79G]InoSu,~=,HK%2=,EG%DAF77DAF77DAF7K|oUDAF7$çDAF7$çDAF70IosV!.JhgH$+/HgjG$uL.3&#"7#'754'&'#"&'7327#4767>32";EY?w^H6H\O3,,HO;E+@/VfmVmHO?u]HH]sM3 gz.VrmV_zuM<%4'>7'7&#"7"&'7327&'&54767>2=,HK%=Q Hl;EYLmHH7'&#"'"&'7327&'&54767>2=,HK%m#6,=iSH;EcHKs;E]InoSuJ.JghH$6B0+@TH?HK|z1IosV32326ian ^Xbian ^V2NE;=LTNE;=K23276767632.#"#"&'gV^ naibX^ nai2UK=;ENTL=;EN1).#"3".54>323265.#72#"&:QHRdhNi\dnx>@HRdhNi\dnx.ttlH=YOHL\}X[lH=YOHL\}W#"'"#322{dfftX{dfftX#*$0!#.5476767654&'30ND:323267#"''cDXbia]yeEVgia`yS LTNE+~F KUNE,F #"/&'&#"5>32326!!ian^Xbian ^VeoNE;=LTNE;=K`#"/&'&#"5>32326!!ian^Xbian^VeOE;=LSNE; =Kkb%&32767#"'!!'7!5!7&#"5>32%H\ iaBP﹉lZXbian3}o -X"OEd8LSNE;I"#"/&'&#"5>32326!!!!ian^Xbian^VeOE;=LSNE;?Kk˪.#"/&'&#"5>32326#5!7!5!7!!!!'ian^Xbian^VLoKɦoOE;=LSNE;?KL˪s˪sB.32767#"'!!!!'7#5!7!5!7'&#"5>327b K`Jqia'+\+zlh>Tm?u2^Xbianc"%]OE˪Nt˪=LSNE;%N;?@.9*-" *19" <-<<219999990#"'&'&'&#"5>32326#"'&'&'&#"5>32326ian ^Xbian ^Vgian ^Xbian ^VoNE;=LTNE;=KڲOE;=LSNE;=K43267#"'3267#"/'&#"5>327&#"5>29+Vgia@LJZVgia}9+Xbia@MHZXbi a KUOE8KUNE; @^ LTNE8LSNE;f@59#"/&'&#"5>32326#"/&'&#"5>32326!!ian^Xbian^Vgiaq^Xbian3VeLOE;=LSNE;?KҲOE;=LSNE;?Ky5P#"/&'&#"5>32326#"/&'&#"5>32326#"/&'&#"5>32326ian^Xbian^Vgian^Xbian^Vgiaq^Xbian3VײOE;=LSNE;?KҲOE;=LSNE;?KҲOE;=LSNE;?K"32?632.#"#"&'!5!5gV^naibX^naiUK?;ENSL=;EOȪ+  %5 % $%5$[g&Y%ZhӦ69%676767!!"'&'&'!5!!5!676762!!&'&'&[C-87VYYW6 8.CC.8d 6WYYV7 e8-,CE[<0[2332[39\DD+N+DD\93[2332[0<[EC,` !5!676762!!&'&'&!![C.8d 6WYYV7 e8-;++DD\93[2332[0<[EC,`'  ' &  ' &  0' &  .62' '  W63& '  ` 3654'!!5!&547!5!!4434w~0IG00GG2?8>;_8` !!!!"264&'2#"&546HdddeH;k'**z{DbFE``bq+((d:svv`K!!!! &!56뗲`!!!! 3# $c'`!!!!33#$'c`!!!!!!'+]^*^]N䰰` !!!!!3!Np!NNf`07GO!!!!#"3###535463!3267#"&546324&#"'53#5#"&4632264&"?$mmC???DNB&H#$J'`qk[Q_C<17HBB@,I\\I,@p`ctiG6B?9i=$#tu#gSSS`*!!!!>32#4&#"#4&#"#3>32!]?U\Z79EPZ7:DPZZV:;S==:xoHOM]QHPL^P%U20=` ,!!!!3#7#546?>54&#"5>324eeb_--B6'Z0/`4\o$-,N2A+,/-7#!^aO&E++ '>@"     <291<2<<990!!!!!'7!5!7!}/H{};fըfӪL !@  <<<<10!!!!!!ת4!5!7!!!!!!'7!5!7!5!DQ"rn遙RoLT˪˪T˪  )@    <<10!!!!!!!!K T@.B $# <2291/90KSXY" 5 !!@po V@/B$ # <<291/90KSXY"55 !5AǪV 3!! 5 !!@poV !!555 !5BkǪ!5!7!5!7!!!!' 5'`ȉ)P"_=6@ss1stFpo!5!7!5!7!!!!'55'`ȉ)P"_=6ss1stF. 5 5:6:6pr pr . 55556:86:'!67&'&54767&'676'&'{)#Y4JJ4Y#))#Y4JJ4Y#)AAAAGF㞢GGGG➣FG2;;;<<;2;5$?$%5%67$'W eĔd?NĔ])]o& bR)`q% Rd%'%5% >zmzF<˶@6 o@hGp%5'75%7-孈m%˶C@ʴ@hGp/V !5!%5%%%!!'/xvH-rf5LOlUrC@=Vlь=/V%'!5!75%7%5!!' GWb[mmNL>ߪwe=ت=$%#"'&'&'&#"5>32326 5jbn ^Xbh`n ^Vg@ND:3232655jbn ^Xbh`n ^VfNF<>LTNF<>L>)P14%&#"5>32%5%%%3267#"'&'&/' k Xbh`'+kuE%sk ^Vhjbn "Pv1-LTND9ATj͊LTNF<= &TN#wf=J;N} 55 58@'poN} 5 55@'pom`!-%5%%%'5%%5 MM`ZDOA@FZDt@m*_TW&o}䎲w&-r~bUm`!7/%5%%'%5%75%Jvad",,V`bL"_D2,/*/&O{¸[&}P %5$r osaa^~||P 55%$so a||^a)W!%5%5$gV$}]]x|)W3%55%$Vg}$BW|]]RW(%#"'&'&'&#"5>32326%5$ian ^Xbian ^Vg$}NE;=LTNE;=K$]]x|RW(%#"'&'&'&#"5>3232655%$ian ^Xbian ^Ve}$NE;=LTNE;=K$|]]&%5$%67%'Et֋$k}uU)?eKtuu" K 9''567$'567&'%=⃹t֋~}uRU)?Kuu,ަK9'_%!"54763!!"3!슊@^`@ƍ^`_75!27654&#!5!2#@`^@Ȋʣ`^; #";3!!!!#"54763^`0rrndflppꊊ^`&pphƍ3 32654'&+ #!5!!5!32#^`0rrpp9^`phƍ7!!!"'&54763!!"3!Ɋ@_`@,ƍ^`7!!5!27654&#!5!2#@`_@Ȋɖ,`^ȋ '!";!!!!'7!5!7&'&54763!7!!ʉ_`'}E=aLT>scL0R^`5ƍ7 '327654'&/!5!7+!!'7!5!7!5!^`__BV 5cTpX?bLm>U`^`C 7 Xȋ5j )5!7!!'!"'&54763!!"3!.Bqx-qxDɊ@_`@Z54&'&'$  &'&'&547676!!#!5!]\LMLLML\]]\LMLLML\bc1111cbbc1111cbdd''LMmjML''''LMjmML'dbcwvwvcbddbcvwvwcbee$7!!"2767>54&'&'$  &'&'&547676r$]\LMLLML\]]\LMLLML\bc1111cbbc1111cbתa''LMmjML''''LMjmML'dbcwvwvcbddbcvwvwcb$3?"2767>54&'&'$  &'&'&547676''7'77]\LMLLML\]]\LMLLML\bc1111cbbc1111cbxyx''LMmjML''''LMjmML'dbcwvwvcbddbcvwvwcbxyx$7 "2767>54&'&'$  &'&'&547676pxg]\LMLLML\]]\LMLLML\bc1111cbbc1111cbpx''LMmjML''''LMjmML'dbcwvwvcbddbcvwvwcb$73#"2767>54&'&'$  &'&'&547676]\LMLLML\]]\LMLLML\bc1111cbbc1111cb''LMmjML''''LMjmML'dbcwvwvcbddbcvwvwcb$ 2L"264&'2#"&54>"2767>54&'&'$  &'&'&547676ZPnnnoO@v+..]\LMLLML\]]\LMLLML\bc1111cbbc1111cbAoPOmmp1.-rB''LMmjML''''LMjmML'dbcwvwvcbddbcvwvwcb$+E %#'-73%"2767>54&'&'$  &'&'&547676C4f4C4/f/]\LMLLML\]]\LMLLML\bc1111cbbc1111cb1XSXYS''LMmjML''''LMjmML'dbcwvwvcbddbcvwvwcb$!;!!!!"2767>54&'&'$  &'&'&547676]\LMLLML\]]\LMLLML\bc1111cbbc1111cbj''LMmjML''''LMjmML'dbcwvwvcbddbcvwvwcb$37"2767>54&'&'$  &'&'&547676!!]\LMLLML\]]\LMLLML\bc1111cbbc1111cb8''LMmjML''''LMjmML'dbcwvwvcbddbcvwvwcb$!%!!!!#!5!QX>ddYee$ !!!%!!rPX>ת\$   ' 7 %!%!!=kyykyjjX>xjyjjyk$$ 3#!%!!aX>J@ <1<033!!upJ!#!5!3JI!#!5IssI35!3!|33!!Nup| !#3!!!!.NN$J !#3!!!!.$J !3!!!#3GupJ !#33!!!#3.GVfupJ!#3#3!!!!.cGGf$J33!!!'!'Ssj\s=u5Y6pJ!!!!'!#3!7!sjshxj56$$J!!'!#3!#3s6s=5Y6puJ!#3!!!!!'!#37!s:jsjG$-56$]*5$%67654&#"'632#"'732654'&'$@e=M>P7sZw㔰Zs7P>M=e.(Y7O0<0:>~jy[<<[yj~>:0<0O7Y]*327#"&5476%$'&54632&#"ee=M>P7sZw㔰Zs7P>M=e@.(Y7O0<0:>~jy[<<[yj~>:0<0O7Y( 51  ^ bb:d 5! 5bd 5! ^bbb:yg62"'&'!"&462!6"264S몧Q3Q3TW4drOOsOOSQ3CB3RU4CDPrOOqyg"&462!6762"'&'!$264&"aS몧Q33TW4QrOOsOSQ3CB3RU4CDPrOOqbgR 7!6762"'&'$&"26b1[륢S4OsPOtO.D/YR3BPQqOOy;d 3#!!#3%!5!( 󀨨 ds <!##5!#T~N 35!3 3#K#"T^ !!3# K@ih^T !!3 3#K@#"쪠T^~ )3!!&'.'&ZVF%,E=Ώ?~%FVZDA?=~ !53*,Ԫ֪w # #}}wJw 3 3!#wJww@ 1@ 0"# #4$H̭9B( w@ 1@ 02$53 3H4CC1 (B9#uTHF103#F1  !!'+]^*^]䰰3#3#!5!7 !! 'RLxxLux66x<ux6xx6x'B  ' ''ٛ>PNq^D^'B %  !'''tNP^D'B 5  5!''6bNP'B5 5tN>]P'B 5 'Nt>P`32?632.#"#"&'!5gV^naibX^naiUK= ;ENSL=;EOȪcy 33#cu?Ik8ff%q#cy 33#cffI?#q% )!"3!!"'&5463!! '&76)!"3!k:((P:jZYk񼽽jȊ ()9:PZXD  ȋ )5!2#!5!2654'&#5!27654'&#!5! !YZj:P((:kɊj XZP:9)(ƍN$!4&"#47632! #4'& PtPZXD|p:PP::ȀZX8x8Ȋ:1$2653#"&5! '&3 765PtPZX1::PP:8ZX:8Ȋ|84'&'##47673#Z:KK:ZllY:::ZaȌlala4###!5!5!5!333!!!!'5#Y~~~~,,33ͨ^ 3# 57Ѧ^ 3#55=d//m.   5 5 5 :6:6:6pr pr pr .  5555556:86::6:.  5 !5! 5?@Npo. 5 5!55?ްop9 %5 5!@op9 7 5 !5!?)W5$%5$Ti}$_|x]])W5$%$5iT$}B!]]|!&!%'&'57&%5$%67&%7*?;i@]0qw^%KA6#(AF+3273267#"'' 5cCXbh`^xnieEVhjb_zl]@LTND*F JVND+Fpo"%&#"5>3273267#"''55cCXbh`^xnieEVhjb_zl[LTND*F JVND+FͰW&&#"5>3273267#"''%5$cDXbia]ymieEVgia`yl]$}. LTNE+F KUNE,F]]x|W&&#"5>3273267#"''55%$cDXbia]ymieEVgia`yl[}$3 LTNE+F KUNE,F|]] 7%'%5 '瞃۞L О  @Y8@\9@a ' 7%͞G۞О@?Y@<9@}5!%57%!!'71|Iv\' :qߦ[@Z8@_}7!!'7#5!7%%%9Jpv\]FGjq8@ǹ@ 3!!"'&5]9Deo>ܚVf]>#3]J] 4'&#!5!29Deo$VfX,&'&3!3#76l<(enP==Kne(!< _EA_ <]> 3#!5!2765oeD9>יfVu(3(7@% !!!5 5!!37d  hrv! !! $<Ff +   276764'&'&">  &vvrn66\]]\6666\]]\65kk\SS]\6666\]]\6666\!;>32#"&'#'%53%&  s:{{:!8#!rܧ$daad]chaam@j.!3!3:^ &ۺ+#+#+A&6FVfv ]A]A]A)9IYiy ]+ + $%+$01! 4$32! 4$#"35%33!??qqW|A?rpG~+/ 8?+3&+3+A&6FVfv ]A]A]A)9IYiy ]3и/A&&]A&)&9&I&Y&i&y&&&&&&& ],9+ + +0)+001! 4$32! 4$#"!!56$7>54&#"5>32??qqWO\R!>/_N;sa=0>A?rpGM"?U(?N&:$}:iF D+B5+B+A&6FVfv ]A]A]A)9IYiy ]A55]A5)595I5Y5i5y5555555 ]5B9,5B9,/A,,]A,),9,I,Y,i,y,,,,,,, ]ܺ&9;9+ + )"+)?8+?2/+2/2901! 4$32! 4$#"#"&'532654&+532654&#"5>32??qqW v@X[}DuskcZX\[4yk_=hA?rpG]0OLGN<:,+>2+201! 4$32! 4$#""32654&.#"632#"&5432??qqWN\\NN\\Ta/w N 5jA?rpGb[ZbbZ[b#P =  "#/$/ܸ#и/A&6FVfv ]A]A]A)9IYiy ] 9!9+ + !+01! 4$32! 4$#"!#!??qqWkQ1A?rpGK '?K +=+1F+1+A&6FVfv ]A]A]A)9IYiy ]A&6FVfv ]A]AFF]AF)F9FIFYFiFyFFFFFFF ]%F19%/A%%]A%)%9%I%Y%i%y%%%%%%% ]+=9+/4F19%7ܸ+@+ + ":+".I+.C+C4C901! 4$32! 4$#""32654&%.54632#"&546732654&#"??qqWT__TT__jivvWQMKRRKMQA?rpGPIIPQHIPIvSttSv\\=BB=>BB 4@+>)+>+/8+/A&6FVfv ]A]A]A)9IYiy ]A>&>6>F>V>f>v>>>>>>> ]A>>])>9A88]A8)898I8Y8i8y8888888 ]+ +  2+ ,;+,5&+501! 4$32! 4$#"532676#"&54632#"&2654&#"??qqWUa.w O 5kN[[NN\\A?rpG$O <b[[bb[[b &2>+#+#*<+*60+6+A&6FVfv ]A]A]A)9IYiy ]A00]A0)090I0Y0i0y0000000 ]A<<]A<)<9<I<Y<i<y<<<<<<< ]+ + -9+-$%+$3'+3$01! 4$32! 4$#"35733!"32654&'2#"&546??qqW͞u>@EE@?FF?A?rpG>>'*6ޗ{5!!X3 2!@ 2 5!!5!!5!4)4𬬬 !!!!!4)4XXX 333 Nf  !!!@@@ Nf  53353353353𬬬 3333333XXXX 333322s's' !!!!@@@@22s's'!!!!\!!#!!#\!5!Z!!X!5!$Z!!$X3!-Ԭ3!-.*!!@Ԭ!!@.*5!3,,(!3,X5!!@,(!!@X3!!- 2Ԭ3!!- 2* #!!!P@ZԬ 33!!P-#,Ԭ!!!@# 2Ԭ #!!!P@.* 33!!P-#\*!!!@# 2*!5!3,Z,!!3,X !5!!#@PZ,( !5!33$,PZ,!5!!$@Z, !!!#@PX !!33$,PX*!!!$@X!5!!Z !!!!-XV !5!5!!,ZV!!!X!5!!$#Z !!!!$#XV !5!5!!$#ZV!!!$#X5!3!,-,Ԭ !3!!,-XԬV 5!3!!5,-3,*V!3!,-X*5!!!@,Ԭ !!!!@#XԬV 5!!!!5@,*V!!!@X* #!5!3!,-Z,Ԭ !!3!!,-XԬ !5!3!!,-Z,* !!3!!,-X* !5!!!!@Z,Ԭ !5!3!!$,-#Z,Ԭ !5!!!!$@#Z,Ԭ !!!!!#@#PXԬV #5!5!!!!P$@V,* !!33!!$,P#X*V !5!533!!$P-#ZV* !!!!!@X* !!3!!$,-#X* !!!!!$@#XԬ !5!!!!$@#Z,* !!!!!$@#X*5!35!,-𬬬!!!-,XX33*!!@@*DH5!5!xX333x 2 2H !!!!-Rx !!##xmsZxH !!3!!xm3-sZRH !5!5!5!,NX 5!###lZZXH !5!!!5!4l t,ND 3!!!--Dx 333!x,ԬxD 3!3!,(D 5!5!5!3,,D|X 5!333,,(DX 5!35!3̠| 3!!!!-- 2Rx 333!!xs 2 2Ԭx 3!33!!-s, 2ZR !5!5!5!3,,X !5!333xtZ, 2X 5!3!5!33t, 2H !5!!5!4R 5!!###sZZH 5!!5!3!!t,-sZRD 5!5!3!,-DX 5!333!,,ԬD 5!5!333!DX,!5!5!5!3!!!!,,--R5!333!!###s,,ԬZZ !!!!5!5!333!-s t,ZR, 4763!!"Q[yY[`~| 4'&#!5!2.-Yx[Q`~=?x 5!2653#xY[Q[~|2Ψx !"'&533![Q[Yyx2|~>3m 2>#3> 2> # # 3 3>ݲ}#$cc|5!F3F~|5!|iF3P|!XF!@F~|!|iXF!@P5!5!!5iVV333PP~P!!!iXVV#!#P@P~P;(;!O;!O ;!O;!O;!O;!O;#!O#;(!O(q(!((!((!((!'(I(!]((!((3(:(' q( #'+/3!33!33!33!33!33!3mnmnm 4('/7?GOW_gow#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573#'573(;(!%)-13#3#3!3!##!#3#3#3#3#3#3#^^(ll(lm#;( #q:(!&9 '( 9(& &!"9(&!"9(& &"'9(&!&"'9( '9(& '9(& &!'$! $!!!,7r+uv ))xxp) )$7632#"'327$%&#"%632#"'~~~~eMM>yJJJJJ6````qq|qq#u"@91990  9%-p) 327$%&#"%632#"'MM>y````qq|qqr' '/7?G%&'&'6767&'&'7%'676727"'64'7&"'62&47\+;.81F9K58.42d;E9G,:.80G9J6&8.;+d1O9FLL&_`JnLL'`_n<1& j(0=Ju &,A=N:0('<1& j(0=Ju &1<>EB0(n_II'[[JnII'[[p) %/36%632#"'327&#"6767&'&6py AAAA,+-,,-+A@@Rqq|qq%%mܱ[0$ %@%|"p) )73276'&#"7632#"'327$%&#"%632#"'r99:9rr9:99XWXXXXWXMM>yB!!BB!!oe33eje33````qq|qqp @ 104767632#"'&'&pihѵhiihҵhiѶiiiiѶiiiip $32#"$27$%&#pkk<MAk^a``p $32#"$"3pkk<MAk^``p $32#"$327$pkk\MMAk^>``p $32#"$%&#"pkkAk^>``p $  $"327$!pkk]<MMgAk^```p $  $"!pkk]<Ak^`p})6%63"'pRqq)#2y|q*q( 2654&#"!|~}}|v< ( $%632#"'327$%&#"!IMM>y_O````|qqqqH( ( !#%&#")%632OyyMMqq>~``  3327$3!#"'$@1>qq``) %63"æqv`) 2#%&#u)q>` 527$3Muyv`>q "'$33yuMq`p)%632#%&#"puqq>``p03327$3#"'$puMMuyy``>qq!$ !$ !$! !$!$3! 2654&#"4632"&nȊce;~|ddcc||}$!%!!d r<$!%!!We r<$!%!W7 r<$!%!W7 r<$ !%!!!!+c,b r<<!$ 462"! W|VV} ,|VV|V !$! c  !$! b  p(  7& $  %;<*X֖$ !!!!!!,7,rWb<)) Ie$ !!!!%!!,crWbM)MM^??@7`d?\gOOOOy>*<?v^h"3263#!5276;'4?'4?26u'6"gP39.4! '*C0.xV#m14He '1l1 Z+dd?33 #&'&+"'&#"/573;2?"#'57#&'#"#5676!5:+#9,p!j[%+ > 7VCCc":8}V .e3B=Se` e9*=9 3@=}k %C`:d;emu}'S3273&'3327&'67&'67&'67'32654'&'2327654&#"3672 $54767&'&47'&327632#"/#"57#"54?'&5432'&27632#"/#"57#"54?'&5432'&327632#"/#"57#"54?'&5432'&27632#"/#"57#"54?'&5432'&327632#"/#"57#"54?'&5432'&27632#"/"57#"54?'&5432'4327632#"/#"57#"54?'&5432'&27632#"/#"57#"54?'&5432'&27632#"/#"57#"54?'&5432'&27632#"/#"57#"4?'&54327'4327632#"/#"57#"54?'&54327'&27632#"/"57#"54?'&5432&'67&'67&'67'&327632#"/#"57#"54?'&5432'&27632#"/"57#"54?'&5432'&27632#"/"57#"54?'&5432'&27632#"/"57#"54?'&5432'&327632#"/#"57#"54?'&5432B~ %<z*+')+(@&'$||e<-A}]\B-71SLoWj\vLL)(0/ (( .1(%%,* # $ )*f$% +) $ #*+f%%,* $ $ )*  \o  [ %)#&'%&)#`#$ *) $ #+,U  Q  0 E%% +) $ $*+&EC&V*,)-)-*,%&%&fБfU 3HhfeefhH2pu^QFs棥sKQGh!99!  !77!  4 4 22 K44 22 22  11                   7        %&%&%'%&%'%&22  //  g               44 22  ->O`q +&'&54?632332?654/&#"2#"/54762#"/54762#"/54762#"/54762#"/54762#"/54762#"/547672#"/54762#"/54762#"/5476%2#"/5476%2#"/5476%2#"/5476D.2`{4&/<) e>O ,4H3R 07K $   $   #  #  #  $   #  $   $  U $   # " $   #  7Q=KG<s-8PZy9z _e""#/2dt0&2j ,: . 4 . = ,  ,   -  -  -  -   .  .   ,   -   !! WV9`8 !! 7 ! !WVDu9`8N I 7%7&54769 }V&7A 6$ 8'^4? !2 7%7&547!&'6I@Y%14HFS"="l-2DC[9 &! 4$32 4$ #"&54>2JJhhq0^mNMn2Z^Z2K7iwBNmmN1Z00Z} C"32654%"32654&%#"&54767654$ #"&767&54! ggJIhIhhIJgg[ZQoy y}WZ[zADgJIggIJggJIhhIJgU\\Q srW\\^} A4&#"26%4&#"326! 547&'&632 $54'&'&632hIJgggMgJIhhIJg#@@z[ZW}yOOyoQZ[sIhhIJggJJggJIgg ][[Xrq Q\\} "32654&7#"32ɏǾ/`T_ȐɎ;P12Y}1"264&"3264#"54327&5432#"'&'3xyx& کZTdIU  k#5AMYer3#"'%&547654'!#"'4%$53!76=332654&#"#"&54632'#"&54632#"&54632&'&67632#"&'&676'.547>'.76$6&'&54%6&'&6>#"'.54>32#"'.54 [$gi< D""D =if%LW쥨驧r^]]^ !! !! . . *)X,),*))+. } +G  G+vKK9__9KKݧꧦ]]_""""s!!""W&. - . - a)," "  ))    !) /     p%-5AMYdp|5#!4'&'5#2#"&546"264"264"2647>'.7>'.676&'&>&'&7>'.%7>'.676&'&676&'&53!76=3%#"'676%27+%&547654'7327&'$%'#327%654'&54718楣. . . .  - -Y - -))G))))U*)>- - ~- - VK; yA C0B Ax ;K'6FJ> $06# >JF6&@@1AeA1@@H磤椣筁 . . . .E - -- ,1))),(9)())u- , - - G77W6 W77G D&& ee˥ &&D "(=pp=("u !!'!Pn8hv "!!'!##+572367676MoL)>u eI3?ba8hA:F;/Itxv !!'!  ##' Mo_h[ei[i8hi[ef[l[@36273 ##'5) U.WW1@ US Vdv#,5>~3+&=43+&=4%3+&=43+&=43+&=43+&=43+&=4%33 #&'&+"'&#"/573;2?"#'57#&'#"#5676!5\:V\9\:\:]:&]9[\::+#9,p!j[%+ > 7VCCc":8 #8d#7$6$8;$7i$7 #9pPL  )Z. ;6ZV Z3%Y63 .87p  3DMy!674#!!6?676545&#'323276767654#3#&'&'454632767!672!&=75$/563&43!32+'!67#>54&53# ? I :W0 96;E,Q 2:&l6x0 bm! o۸"\>%Ef~e2U6g!6V#p5C+ C ? P9 @7H4XmM7RV /M(=H: ,qLUD)8Wqke-Pex NW =$ U  /0c)H?2@[nDF8T$.J? !' !T4XKGwL5_K !'7W4Z~wDS&5476322632%632#"'&'#64'#"'&'&54654&'&54767632xJX%&XA,B:\8 [EMH95##Fl% !9@!#jL p_Mi#"?8" %lF##58HN4hok@RRr*%te BB9'7*$%) "fXS5EIf" )%#,7'9CB >E3#"'4332327$'#"$4727%672567654&5&oJ7.b9M D ,B3 qY 5**]d=HN9% sW$,J ]T-MMm@ed: ,'Z M'cM&T)$$ < I2%!"&54676737#&'&54>;7!"&546767!7!"&54>3!6763!26P+=6/2D>R+>2,+v*>>+2  ,2 =,2  =,3>,2463!2!2#!!#!32#3#!>*v+,1>+R=D206=+P#,>3,=  2,= 2,  2+>{"D%4&#!"!0#"3!!"3!#";#"3&'6737#&'6737!"'67!7!&'63!67!2I0!6OS SS: SS>SS]]J]]]]h\\, Bv*>K%39LKIOKHLKIhghghghgE?-L!D72654'6#"'4#"'54#"'54#"'675674767#%$4:JILLHOKHLKIhghgighgD>-sJ1 b6'SS cRR SS?SS\\K\\;\\]]!A*>K{!C%254+'3254+'!254#!'!24+!&#!"463!!2!!#!3#3SS?SS *vA!,]]j\\\\K\\IKLHKOIKL93%N-?EghghghgiL!C32=732=7325732'654&#'%2&'&5&'5&'IKLHKOHLLIJ:4$N->DghgighghSS=SS SSb SS'6a!0J)K>*B \\]]:]]J]]}O &*.26:> 3656;2#'7+"/#"'+"5&54775%"'5476;25'7&56%635&56;374765'75'76=4'&+ +"'4!#"'4543$365&5&#%#754'&5&&547'5367&547+&'&'735&2?"5%75537'7'3533553535'32767&5%2?&#%55'5757757751:e,$?F?Y>F_LA3ELH3,8LYLlEF'!0< k#gF  EeY!! Gp&iq.8ZN$%`BCf F4"4._?ee3&{E(1-+$Kt8 -  $Gs sM rEF"2 >_plTErf^5.>=9|5"-l)d ,&>vv]cccWpC-+ d8 Bpp>W]oaxvuPp82,D ^8, ^B$K+ "1R[+e*; 2 W QP I&? gpo% w ^SA$ 2 9i-5n02 Ai&IY^P]D%\??\OWC ,,1 /211/=;7777=321811{908hN%b\Dh,)h?17I21!122223 21&2%2#"'&=477654'#"'5473Bq4|l anN ilm b 9 b؍MOb>YaYƮ58l7P P@ $0<FX + &=6&# 3 6=%&#"';27!5%67%!&'&'2+"'&=476r cR~UY082.ԍ_W_V"+}IR8D).P9H'S]ٱZYHYoX(I_ ;.2lOP%.G6R%&I8d)Nl>54'67&54&#"&'632.547#"'&'#"'3267654'7327323.#'654'567654&&5476;'&'%&+"#"8DH$$yU ?L[>!WtJ([Fho*m.2\=w\`|UP7:/E" @7?EP]Eix pF@T5ym,"&eB@q(A _% #+B7!N &".OS$XE/K(Aa]dLP*'FCaYr=C44mo C (FKWYFvbph'UD'R< $d#+?Vm#327&"#"'7'632&'$54#&73254'&#"'5&567#&''5$'67'654'6'5$'67'654$'67&'654'''5$56732#"'&#"&'$'63&47"7&'7&'7&'7&'54'6546767675477&545?&''5&#" '6%35&'.54>23#67!&#"W  OB7[l#> F_Vh " "@.,=6tJ4Vp1EQJqMi vhpHI!:JJJ =4m\8B*?o v!"t,`s&*_~P1>5='g=>24<+-s[,*&sd1PT>3J@='h<42J-H#*YT_Y)*)X^TY*$D  ?>}>  *0t"J.  &b54CUE ''!`9 !,(MTE *! }q~=/+)f[4f !B" <@0&9c?"V+GoMK~a? }b9e\ P&0@k"?c*GEJX ?e}9 \4 \6 '''' 6\ N(&'65&'67327&+!65+"3yyys{w ccޱqXeXc6 6 c ,35'533#3!'#'5!5!5#53!5!5#!!-ʷ}} ckvG G @<<3ffX苜qXGccGJ 326&#!2+73 ### 3(ttvgnؐB(33#!!#'!'57!5#'5735׫$"q~q+!#!573#'5!3!'573!#'73!#'5;jjŠJss<wѡIjj8/w{,32#' 3%+ &5%6323'#57'53^VQ6>ѨABؒ6ʞG2k >Y3~||~Obs32732753"'#"'4323$4'5;+"'#"'53275'&'&5?5572%#&'&5%634%476=%@.!%,BE,#!-Q2" $nL/PuHED832#"&546324&"26%! !  Őb{=&*<<*(;E;R::R;KJ67Ϛ{ɬ)::)*<<**<<*):<'L67I&' &' &' &' &' &' &' &'  @FLRX^djp3264'&#"&47367'676756273#'#'5&'&'7&'677&'67'%%&'&'%6767%&'0/CB^0/AC/pkTcR|'N(OfUippqUfO''NQaQh!$ b)dLQk KRt!% c'd&//^000'N'|P_PfppoQ`Qy'N'P\ QgppmQ \Py,  M N>&`7" bK*V&"g{ M M %1=! !  54 #&'&#"#46324632#"&%4632#"&67KJ]_EASvwSAF͒D10EE01DD10EE01D7IL6a]U@SS@U1DD10EE01DD10EE %1=! !  54 3327673#"&4632#"&%4632#"&67KJ]_F@SwvT@E͑D10EE01DD10EE01D7IL6a]U@SS@U1DD10EE01DD10EE %1! !  5# '&'32654&#"32654&#"67KJ;lWPihQV<=UU=-1\ H0e%FKSwZGr=;=NN$E| 1 ?'_>?@7`d@\hPPPPy?+<>w_VG{?,rCA+ +"'5$76%&'547327676=&#~jt1/Q}](+VRxbO P >nS]] =fP+! &56;2'5$%75#"3ui1.P~N](7P,VSZycOpO >S\^ f0:1>7#'#53'&'&54767&'&=33676=3#326'&i($lm$(($[Uu&tU[$&uU[[UV$|ddb e|$% ZSSZ %_TYYT* $4&#"326&5432!!##53&w衤礡PP䤣L~||* $32654&#"%#"54767!5!33#b衤礡7䤣L~|| $&$76+"'&5'476!7!ttsstEus pid5s qttrtt<֤ꧦg\ulS5264&#"#43233#!5 z{ym㗗y{(|j#53533#632#4654&#"#*jjoon}mZyH{zF2 1"32654'#"&4767!!53#5!!3!!#3!!pOO87O:=0LmkL/>Λ2  1O79NN970LؙL1KӘJJ-'<%#5#535&'&'5'73'3#'73'676=35'73'33◰zhNgeMjzzTThOʍ7NjYYӖy?! #!!!'!27674'&#.d ;6zFH%QM_\ǃ$P<]$!#"#&5463 67!2#654&#"V⩁"T]ts]U"X"1((1"u." 6&'67>3"#"54767&'&#52&͕LVa{.+ؔ)0zHUM\&ϖ=Bll)'ҕ*l8lB=j&'5 %$ 56?63#'[Wtutu4ZZ//[[5  @Eo&<"3264,'532'&54632264&" &$#"#"&547>B_^^l;͓hI^9l:͓hI (+|TlgMLx)+{TlϔgMM M>54'.#"32463227#"&5454&#"#"&'&54767632254&K2q'$#K1o'#0ߴGdAoc.% 3t88bWDs-Kx68<32>32#&'567'45'#&+"#4'3>$4&+"?w(K>R0D32>32gYYYD,.:?#)v$E?w(K>Ro}vvxJvaAjtAO]ƀwϧ!5!3##'!5!~2k<@i8080k<j)127632#"'#576&#"4'5267>327&'"SkQmyz,~zi2@:$(.-)zW] ݾgvx-aX[&ŝ9{'Q32263227632&#""'&#"#"'&#"#'3232762327632&#"#"'&#"#"'&"#'Es- p86rV+)|m^?_354.#"!&'.54>325467675#53533#63232>54.#"P#3JTRJWVJQSOMJ4"?*&ElnhPL$ llill %LOhnlD')----+)QPQ((QPQ)+/ 6klj$?6FWWF6?$jlk6 }++--JHNRh|&'4>32"'4>32&'4>32&54>32&54>32#!5!'!567>54.#"32767>4.#"327732>4.#"327>54.#"732>54.#"M_ 6694S55.+C55C&.66 V\+55 c$M##$ 6$#$s`%#$d0"%)h #"#_33@]22-"40446/*33UJ"+33^1/K=0T* ####  #&$$&##&$$&#  B #### *"$$" U!'-2!35!#3!53573#'5#5!35!75!!5'57!s\\ss]]s JRRIJ~֛E77__vtt4!v7CQ^&54767&'&'5676767&'&54>32! 535#5##3654."!2>4.#"  <$))+N-N*)N-M,**%:  @ v<-MTM-?K5:66459<5&?HPPIK* ')+K**K+)' *KIPPH>&5<:6uN|l||l|-I+N))N+@6:55:5Q)5>o654&547!&54='&'654'67.5476;+"'5#"=6&'76767%25#654&'Fz-6 Z8. ,N0H!h6%`+EH )#M ;,Jga#iR k' M +1^hgo8:(@s.Pmz nx?.#1p#41`&>%!ac,,LHJ x}647| + OJJ)!0 P[32>4.#"32>54.#"!5&54767&'&546767&'&4>32'&'.#":e79e89f76e`[S &(*UM,N)(N-KV)&& \@ECApd88dpg669:%N&KRS* 'TM**MT' *SRK&N۠:9}qyyq}c $Tdhy67&'&"!3!67>54.#"!&'.54>325467675#53533#63232>54.#"!57!&'.54>3234'67632!P#3JTRJWVJQSOMJ4"?*&ElnhPL$ llill %LOhnlD')----s=BDw@>=))==AwDB=+)QPQ((QPQ)+/ 6klj$?6FWWF6?$jlk6 }++-- !yCB{C!$$!C{BCy! JHLP&'4>32"'4>32&'4>32&54>32&54>32#!5!5!M_ 6694S55.+C55C&.66 V\+55 c$))_33@]22-"40446/*33UJ"+33^1/NNOOU%)5!5!!35!#3!53573#'5#5!35!s\\ss]]s ^^/oo#E77v4@4767&'&'5676767&'&54>32!&535#5##3  <$))+N-N*)N-M,**%:  @%v<5&?HPPIK* ')+K**K+)' *KIPPH>&5<:6n5|l||l|L3?HN654&5473#!&5454'+#"#7&'654'67654&547;2547#";65'"3%:U"-6 Bu Zg0krX0c-h8E+`%s H>4wM-'9.QY / o8:qhPSmh #%Bz1"0@)5"@YR0.&54767&'&546767&'&4>32; &(*UM,N)(N-KV)&& 9:%N&KRS* 'TM**MT' *SRK&N۠:9C##"'##56'##"/547?^'5@_*SU&/UL ;Yԧ9UP(` XI.s222732#&547636=4'&# #4'&#"*t pz&=<xQ>hG:V Hek%PF5NP B|-&pA&NFX &&5 <F:^;" V gdG7236;2"##'65##"'&5476;235&'&=476e x<JT`(GeRUdfB3 VNTMT,P$ 66$0_ u3dUdt_}s*$"Rt0XX__/ik=ZG8*F 1 . ъf)MC =g9EkO 9!(-);&  ]t!y" & 2| ba$ U+  #8M35733!&54?'7'327!!"'&%#'7367654'77'7'&#"'676ի,&T>=c#]K9.U:1ʈ%`T?7>54&#"5>32&54?'7'327!!"'&%#'7367654'77'7'&#"'676]T@1$J=c#]K9.U:1ʈ%`T?32&54?'7'327!!"'&%#'7367654'77'7'&#"'676Z _3lFHe5^\VOosHGJI)`VKm1Sj,&T>=c#]K9.U:1ʈ%`T?=c#]K9.U:1ʈ%`T?=c#]K9.U:1ʈ%`T?=c#]K9.U:1ʈ%`T?=c#]K9.U:1ʈ%`T?=c#]K9.U:1ʈ%`T?32#"&e|e(<X<ħñ"32#"&$2#".46e|e(<X<ħñ"@<#"4.#"e|e:<#"< !<"#;zch =B4.#"$32>4."e|e:<#"< !<"#;"< !<"#<@;zch =B54.#"##"'5##"$'&'0!5!5&'.4>32!!676767'%''H&(G()G'%H(%'V W3WImuw>DE}AB|GE=md^JW4W Vs'H''H'(H''H`XAK|@X1(ԁ3"|}DD}|" 2/ "1X@|AX1# / 673&/'67 &'"&'6?&'3 ' K[]><+Gg['fBBe&\h?(K?]\K !;32T $ #AC,MMMv A5p_9D-M**  B@0"@R//>wA&oc/D&3.YaQ/5"1'"uE62/u= =!m- .... y 7%  %  32+#".=!"&'&'#&=4;7337_% 8)0/_^^M^1/ 9534<&&<&*(D>?GGzB6C{GG?>D9/C}&632#"&'.#"'#!#!#Ҹ62K#+~KF0R!9'/Nx_TV_T 'NQ9;:#8HL"CD|))Z) 532>4.#";267#&=&$32735&'.4>22[02[24Z1/[)'5*+X A323#67#&"#"/&'&547&#""'6%676V n*[n%'ZxL0<{2;&b;0&8a>!U*~EmLK}`? {a7c[ O&0>j!>a)E~CKW ={d{7 [+M57LL75M-Z '*''*' Y (5[ J5( \d (5J [4 ''/7O_2#".54>&'32367&%2327654'&''67&'&'&'676765467654'&#"7>326323#"'##"'&'#"&'&54767&'&54767232&'&#"6&%6767&'&'&#"676&5467&'&6732767&$$$$OG3%V cc V%4GL944m/122102/.303112.OF}6&V e"w?>v"pt #87! vn":;@A<:"nx !66# sp%./13/.UVT\<>"$!! !"#">kc V &6|FO 93399 <>#"#><  "$ZTU./43..V5$##$59gT;&'9Z^^Z9'':Tg9'(''&()I8:9889: Z_59eU;'( :8.>euvc>-7:bccb;7-?cwud?/8KWZZW **D@@D+8(':Te95^&)(&''(DA:AD.*!Y[[Y!& !-x67&'67&'4&6%67.'%4'6&#"&'6767&54?67&'&#"#&'#&'5&'"'67&'&47632>4.#"%2#".4>'7,3 3%/0),7=*#0*+3.22'8  YfT,1'').UfY >98 "2 B2;F_ XB?2C 3" 894ihgikce"S[XVWXZ#ejpMcNTvJKrZ1VlLWMI p jk%nA V{ww[11[ ww{V @#fd-#JM 7B/""0C7 NK",df#νhhοggQUXXUd %3!'#!52#"62#".54>" h9|M463%&$$5 O Dn; $$$$33'554#$/[QwGSGUW GJGX .5CK&5432632!!#!##53&4&#"326!&&#"327&54654'XP}}P~C;7?_Xej;A>7'sssLFF~||ב-  䤣lrrr)-5DL&'&6767&'"'&'&'&5'476!7!! 76'&'&'6'&utss-5 l&kpid=pDi/tEust,2}ts5sqtt-ԛ1 k&iꧦ g\}ul  An?\27/rtts,͓}qt)8GO'"'!!##53&'&54326!7!&'&36'&&5'47&#"327674'U`P}zpidu>7;C˂;C>xtsK) ||LGD g\uls螝՞䤣hkrr .4&#"326&54762!7!!!##53&w衤礡ᩨhn&䤣羚 o[tꝇ|| +D#"'&'&'&47>76327'7'%'27>764'&'."(F3"D"&%#}bV`ZZ^;D"&&$[X]:3G9:]:F=~=HS]^X&% iiD^29i\=<<92-1X?:<91*=X62'%'!!#5!5!5&'&'.546767''7'''7"2767>54&'&'&4p69].(EGGE@Z-<81VDEGFF'19T]9T:G5>+.11./:95>+.11./:9 \2:a(Eb_E@( %CE_bG(Hij:ο\ij+.wBAw./+.wABw./4+F!!#"'&'.546767675!5!' 2767>54&'&'&"<-Z@EGGEDVRbfNZ@EGGEDV18kbbjC9:/.11.+>59:/.11.+>5疑 (@E_bEC%##(@Eb_EC% kajP/.wBAw.+/.wABw.+ +F####"&'&'&54767>32333'7 '%32676764'&'.#"ܖU (@E_bEC%##(@Eb_EC% Uܭkaj/.wBAw.+/.wABw.+<-Z@EGGEDVRbfNZ@EGGEDV18kjC9:/.11.+>59:/.11.+>55 @  10432#"732654&#"陽…5 @  10432#"K +@kk k kKTX8Y104632#"&732654&#"ϑϑϘuSSuuSSu͒ΐSuuSSvvdPK!)7eK RX@ *.,&"($ k3,k($kk8991@&"6k0k 8<2<299990Y4632632#"'#"&7323&547&#"%6547232654&#"dϑRDDRϑRDDRϘuS?>Su^222Z>?SuuS ͒!!ΐSuXqpWv28ML88LM{WpqXuSSvTZ`z8Rm3#"2767>54&'&/2"'&'.5467676"2767>54&'&/2"'&'.5467676R#)$#R#$ $LK:C.25521@=:C.25521@=R#)$#R#$ $LK:C.25521@=:C.25521@=zZF)(JG()K.2IF21.2FI21F)(JG()K.2IF21.2FI21 J7Qk>767632"'&'.'!"'&'.546767632$"2767>54&'&'$"2767>54&'&'#61@=HK:C.25521@=:C.5%'21@=:C.25521@=HK:C.6#R#$$#R#$$R#)$#R#$ $5[51.2IF21.4`]21.2FI21.5[F)(GG()FF)(JG()KR 5%%%xr6׊eMM^xxV)7654'&'575#!&54767'5!s_vR$N::N$Rv_{aT,X@X,Ta{4b\)1%==%1)\b4ߴ:`\KDDK\`* 4&#"326&'&5432#w衤礡$PP䤣L~{Y,326& '6 !!#!5!(+~uP.Gjt ~||, # !!#!5!L>>0oJ;||,'!5!737!!!!##53z{{{z{|zhz|{||WxT% ! !5! #3 35!'T??LLwLLJ|A|JZt|J|,$264&"&7673% %&uuu>hH]%VgVYFhݦuuv#gGέҔEgEY$&'&5%6;2#"'!!##53uN)$#<^tfFp!E&J <ԩ;  ||lPj'#"'&#"'&'&'&47>7632327>76&'&'&/&'&'&47>762!2!%327>764'&'.#"&#"327>764'&'&s* 0$+$$$ 1#*# ZaZ%% NT12 4 #HH  ")mROeb  , 0  +   ) . $J . %'.D"&B 1 $C mR )Ky    !   V!Edz267>54&'."#"'%"'&'.5467676;27>4.'&+"'&'.54676762%632$"267>54&'&.&&.&m,mQjP(!N!"(! aVf&&bZ55!("!N!(PjoQm,.&&.&q    l?W,>&#< A#"< " (( " <"#A <#&>,W?~    lOOj3!#!"'.'&47676?6767>'.'&#"#"'.'&47>763276;%32676764'.'&#"676764'.'&#"32eOuRd2!  HH# 7   ZTN +Za21#+$0 4$$$+$0 's  *   * OK) Rd#!>& 3"9*$"D. ' - D! 2 . , T% #: & (  IZx-4H67&'&'&+"'&'&'&476767632%632 #"'%#"'&'&'&54767676;276276767654'&'&'&"276767654'&'&'&""'&'&'&547676762"'&'&'&547676762'&'&'&547654'&'&'&";276-&#"+"276767654'&5476%327%&"'&'&476762I  Q\C--%("(/*0.,+"( /X]\9<\X/"$)0*3')"* %1*0CR[        22 2 2 2 %'   &J  &%C\d#_*]OhXC%&  J&   O]*       ")&`&"'$"/' <%ZS  % SZ%< /'* "%5"-($# ;8\= !  !  " /VC "  !  !  [uV/+    V^au 767>54&'&'&#"&54767632 '.5467&54732#"#"676767#"'&#"'67654 ozwbda_f_zx|wbdaM,krnulspsnunNJ*D$ lQ$" 6*D?"5'K(2- # >   :72 331cd툍i`4331cd퍇>mwn<;;8ro졘wp:;;BV0/M8:D@*|sa  -F(7 "*=8&0!2  1-5$& 6:B4V^ (B\w.'%&'&"632%6767>54$2"'&'.546767" 767>54&'&'&'2 '&'&547676?'*&$ 1$-+h+-$F3782**?1 $&>>9|wbdabc`zwbda_f_zxspsnunˎspsnulwI_"2[$  "" gI $[2!v 55 55 31cd퍅caf31cd툍i`43d;8ro졘wp:;;8rown<;x,A-57'36%33#3#!2#!3#3##$'#7$@d5{sVd]F0 0F]dVs{5⒒d@( jPP,PP` 0 ")- !676762!"'&'&'&54!X$#R#+/RFF$#R#$1Sh,  k-"s!|P476?6763&'&'&547632676767654'&547632!54'&'&54'&&#"'&/&'&'&#"#"'&'&/&'&#"&'&'&?6'&'#"'&'&#"!'476='654'&545454'327654'&'&327654'&/%4-)"$0JK&  )7    %0'# #6 +-L __^/s4* 1( .266 |/(1   \   #:7  lS&   x71]/~[#<$  o_%@,: $";vR $X$+|!5DX&PY;9Do6 b'n2  83eF] 4T&  &  /50$?- 1@& 3l K  C"P1 :03<D:5XI.)D&[+-1:   q/A8   g+jl9Lp{7654'"'&#"+"'&54?67676763276323273#5%6767'&#"6"/67#"27632327654'73654'676547&p/l0&J!cS%YE]{@C"$4>-;% ,(6Y>m!N$X6"/,(4sS?X$U>"sJ?K(`./4+2K2.0>S Zp0+1^' ;cs  /^"|Y/ 428ۇϕl%%ot5oA='Y$ aT* ''G+- %_kj~r}jL`І|\gK@/.85c($ (2LS>54/##326?%%3254'654'3>7632#"&547>32'% ;66I   }g ?6qn   -> 9@ H67;  zh| 8 >6!q    B5>%+?F4&'&/76765'7! !'!654'!4'!!$467>2"&'&!654' 33 ^^^RXI#J2VlP# ~!88!~ Kppph,p<(##(#id (2LS.#"227654&'''%'654+.#"65.'&54632#"'.6#"%  I66; o |>?%6!q   9  ;76H   |h> 86qm    BX{[%G'23 %%.'&"27>7%$!"#232%"'&'.4676762%#"#2%k      A>>dIID`nS   SnGYn 5>5 n)(%$#"#64'232%%&'&'&"27676&22k**!n``n!##3W 2327632#"'&'&5476'( > !~GH ".4F+@xH )0$'*' 23277632#"'&'&54763'( e` }{*279HF`0@xJL 1 ,A  ' 7 Ɏ877Ɏ77ɍ8ɍ? tt7tt7t7tt7uB2632#"'&'#"'&54767'&54763267632676 Q   x L$3 z(   6X3  6*=P*> "#  R26#"'#"'&'+"'&'#"'&547&'&54767&&5476326763276T 디% $$YyX$ zc0 + j :  (̢1#: _$ #- Խ =1 '2ĺ pD #!!!!!%!!!!!!!!#!5!36HVBBXBBUHVPBXyBpD !!!!!!""p"p"#pD35#7!!#!5!3rrsrspD!!%!!!!!!r"p"#p"#Rb !!#!5!3ppEU l3!!'#'!!#!!3!5@,r,,_ r,,_>v #!!!!!'!!!!!!!!#!5!3hm_|P_H_pDK#";54&'&'&#'!326767657'&'&'.+3!76767>5{dIB,$2$*DEh{LGC_RQ|66R_CIJ{hED*$2$,BFd{LGC_RQ66R_CIJKIB`OT|87O\FGKzdGB+%2%+BIdzKGF\OT87O`BHL{dGB+%2%+BId  #!! !!! 373#'7#ZAA:Llحmllmzlmllm|}}|d d}cT`C54'&54762327632#"'&+"'&5476=#"#"'&476323(L,68x86,L zFvd0000dvFz L,68x86,L zFvd0000dvFz zFvd0000dvFz L,68x86,L yFvd0110dvFy L,68x86,LV^&'##"&'&'&4767>32367675&'&'.5467676236767>32#"&'&'&'#"'&'.546767675&   R.-R  R-.R "  *!""! ((\(( !""!#%   " R.-R  R-.R    %#!""! ((\(( !""!**!""! ((\(( !""!#%    R.-R  R-.R "   %#!""! ((\(( !""!*  " R.-R  R-.R   Sa4&'&'&'.546767622676767>32#"&'&'&'.#"'&'.54676767>5"#"&'&'&4767>32(,$ ((*& :.r06$&**& )'De!  'd8:b&$$&b:8d'  )a@/!  ')*&$6/r/6$&*)'  ')?c'  &d8:b&!$&b:=_& (bCc"  &d8:b& $&b:=_& (a?/!  ')*&$6/r/6$&*)'  ')De!  'd8:b&$$&b:8d'  )a@)' ((*& :.r06$&**& ((T`0267632#"'&'&'!&'&'&54676763267632#"'&'#"'&'&'&5476767!6767632#"'&'"'&'&'&54767#"'&'&'&5476767632!#"'&'&'&54767#"'&'&'&476767632&'&5476767632!#"'.'&5476767632&'&54767676Z   ( &            <   4          % (      (   2     6           %    <    %  (   W_2767653"4'&'&Wspsnullunsps;8rown<;;j>-'O^__^Oq44H4"hdd0!% %!-@jjjk**37'73 #'xxxx.xx.x..x  pD #'!5!73!GFdFGrEGdGErFGqFGdGFqGEd@L     - FOFc,OO,cFd,PO,dGOP T` '%%%%%% % -wD{wwe#w%f{wwy||y{xxe#w%f{wwxEy||y % %  Zp/AppA/}}ET`     - Zq NqqN  NrqN qrT`% % -ZyllylyyT`%% %% -ZtGcVGttGVcGGstGWcGtsGcpD/3%!!%#'''%!5!%777xo:U.cF.d;UǩoxoU:e.Ec.U9oE.f:UūoxoU9g.Ff.U:oxo9U. 54'&5476276767632+"#"32;2#"'&'&/"'&5476=&'&'#"'&'&547676;232?&547'&#"+"'&'&54767632676'K,68x86,L qA'C<4GW>L d  f L>WG4L d  d L>WG454&'&/54'&5476276767632+"#"32;2#"'&'&/"'&5476=&'&'#"'&'&547676;232?&547'&#"+"'&'&54767632676o**YK,68x86,L qA'C<4GW>L d  f L>WG4L d  d L>WG42#'"372"'&'&/"'&476="'&547>Q!//VZ *nN+G80j@6RR6@j0/P1N TP#00VZ ,lO@W+G80j@6RN6@j03L/N  ]H,`,H Yc!77\4OO4VA7gU3',H^ ]H,`,L&3c!77\4OO7VA7fV4&,H^67654'&"327632#"'&'&/#"'&5476=#"'&'&5476763232?'&#"#"'&'&5476763254'&5476276767632#"'&#"#"'&#"327676%32767654'&'&#"#"Z8%1T1%85e %ZF\ +m8BS/?JV@6RTXN6@VGB1QB8n* \FZ% e53e!&ZFZ *n8BS/?JV@6RR6@VGB1QB8m+ \FZ&!e3DA 5<; > +F$H$F+ > ;<5 AcJ2QD++DQ2J (5H,'9,J&0f) T|\`j4OO7g`\|T 'g/& H,9',I4( (3J,&9-H &0f) T|\`j4OO4j`\|T 'g/&J,9',H5(""'!$(:UJJU:($!'""nFw"2767>54&'&'767632"'"'&'.'"'&'.546767"'&'.546767632.546767632=>343343>==>343343>x>%85670-),(-%8/[0!-(,)-02y/8%0%)-02y/8%-(.'&$W/:#-(,)-02;>/;),)-02;>/8%-( 06{IF{6006{FI{605+'g>:c.&".c;=g'+&1N%&W'+&.c:>k#"$.c:>g'+,B:>g'+&.c;=?nF\v%"'&'.546767"'&'.546767632.5467676267632"'"'&'.27654&'&'&"67&'&'&'276767&5467'&'&#"32767>54&/76767>54&'&'&#"Z0%8/y20-),(-!0[/8%-(,)0-<1:3%>(-%8/|/8%-(>%85670-),(-%8/[0!-(,)-02y/8%0M=  H C# B/g H /*x#$  8## H g/B PP  $#x*/%N1&+'g=;c."&.c:>g'.5 ?=;c.&&.c;=? 5+'g>:c.&".c;=g'+&1N8GG$> >$ c.,bB$#>  Ir0C >'#> LM >#$Bb,.$ >#'> C0rI T`)T:e&'#"&'&'&4767>3267'&#"327%32676764'&'.#"7632#"#.4767676324676762>322##"&'"'&'.5#"'.'&467"&'&'&4767>&'&'.'&'>76?&'326767767>5&'&'.#"767>7.'&/32>7674&'&'67'&'.#"67'&'.'67676767"2767>54&'&'"'&'.54?&'2767>54'7654&'&'&"67'&54676762:    $4 4$ww4 4 xy   %" !()-+U$"! ((\(( !"&S+-)(! '7M"# V2% A()-.R$"! ((\(( !"(O-,*(A"#2P"# "M    ! *4 2 kk  4 2 uKK        i2 4* !== 2 4  `_  wR#$$#R#$$  8 < c !<>     8 < d!!<>   "%UV*) !!$3R  R3&!-(-%Z& "#%(.2$( &&S+,))A!$3R  R3'A))XT$""#%(`$( "      i3+!x== 3 _`        !+3 kk 3 uKJ   F)(GG()F$    %3 3%ww3 3 xy   V^3N^"2767>54&'&/2"'&'.4676762 '&'&547676% %-z35++++++53z35++++++5pWDM69?=;9JHDM69?=;9JHSspsnunˎspsnul}}(.h<;h.((.h; +F$$> +F$H ;<5 A~ ;<5 A+DQ2J (5H,'9,J&0f) T|\`j4OO7g`\|T 'g/& H,9',I4( (3J,&9-H &0f) T|\`j4OO4j`\|T 'g/&J,9',H5(G+DQ2J$(:U$(:U3!'""!'""A''7'753'75377537'7'#5''#5'7#5'7'7<B-DH2#"2767>5!"&54$3!57!#"'&'.5467676#_>I-743TP>CPNDG-2.1/&D9 88 '.* !-8D_2{j@F'%.3r@Md7+4V/2&'&54676762"'&'.546767Zy*,&''&%1]~|45,-++-,54|45,-++-,5(+&a4|d΃fz4a&$(F*.j=3"&'&'&54767>32rJ6464NN4646Jp`684F@NLBD64:866D@NLBD668^~* i654'&#"632327632!"'&5!267&'&#"#"'&54763247632327654'&547632#" 6+Jo.^V|;-˙it36?̺fQMeEJS?(*$ s]vh2K)*NL13^v:Mc*ZeC03N35%&-Kt\K%9S >BWN=!$?$8(F!5{^?Z Q67654 547&'&+327#"'#536767&'&'&5432&5476323254'&5432?-BO>=v06&%K`dC+(k$'eM?$#=Hb B=)+8=.m9eb PB>$3g:84!EB7WPfG+1KHP<Ff#&T'0P+A'<}DC/'"05276767654'&'4rceNS((((`hm@DDF/CD}>C/GFCG !&547>2; 0!!6P<:! !$ ! "#{! !{54&#">32!5!>??qq>0ţ=as;N_/>!RL}A?rFi:}$:&N?(U?"Mt 6+A]A)9IYiy ]1.+. + !'+!+9*'!901! 4$32%4&#">32+32#"&'32654&'26??qq|=_ky4[\XZcksuD}[X@v hA?rs ?<:32#"&'32654&#"75!5!??qqYe2hvvhDw_X@ϰ?A?r%aVUa/  23/4/3и/4ܸA]A)9IYiy ]A&6FVfv ]A] +  + +,&+,/&,901! 4$32#"&54632"32654&#"7>325.??qq\NN\\NN\qºN w/aTJjA?rZbbZ[bb*= P# + + 01! 4$32%!35!??qqlUA?rv]K 1=++ +A]A)9IYiy ]A&6FVfv ]A]A ]A ) 9 I Y i y ]/9;9;/A;;]A;);9;I;Y;i;y;;;;;;; ]5+ )+ +28+201! 4$32#"&5463232654&'>54&#"2#"&546??qq_TT__TT_⾭vijvkKRRKMQQA?rlHQPIIPPI\vSttSvB>=BB=>B &23/4/ܸA]A)9IYiy ]3'и'/-A-&-6-F-V-f-v------- ]A--]+ +  +*0+*# 901! 4$32254&#"326#"&'4632#"&??qq鿹ºO w.aUJk<\NN[[NN\A?rK < O$[bb[[bb $0Ӻ%+%+++A]A)9IYiy ]A++]A+)+9+I+Y+i+y+++++++ ]+ .+ (01! 4$32!5##7##"&5463232654&#"??qq$ŸuF?@EE@?FpA?r*'$ =$>  767654'&'!5%3!!  '&'&54767̆mommom4mommomP\|~{{~||~{{~|96oooo6996oo  oo6}9:݈@>}~Ա~}>@@>}~,,~}> =6P  767654'&'!!567>54&#"5>32  '&'&54767̆mommom4mommom)4 \=)N=kP`aF7I׺\|~{{~||~{{~|96oooo6996oo  oo6_A.Xx;_x55'(IZV@>}~Ա~}>@@>}~,,~}> =B\  767654'&'#"&'532654&+532654&#"5>32  '&'&54767̆mommom4mommomttLUDWx~zB\RGr=\|~{{~||~{{~|96oooo6996oo  oo6yt'(xrjw_Z\bd @>}~Ա~}>@@>}~,,~}> ='A  767654'&'!33##!5  '&'&54767̆mommom4mommomh*˪+\|~{{~||~{{~|96oooo6996oo  oo6 @>}~Ա~}>@@>}~,,~}> =7Q  767654'&'!!>32#"&'532654&#"  '&'&54767̆mommom4mommomz#G#KSLVAC\|~{{~||~{{~|96oooo6996oo  oo6c ۻ)%}|X@>}~Ա~}>@@>}~,,~}> =%>X  767654'&'"32654&.#">32#"32  '&'&54767̆mommom4mommomllm=|< /Vڵ =|^\|~{{~||~{{~|96oooo6996oo  oo6EKۼ>-O@>}~Ա~}>@@>}~,,~}> = :  767654'&'!#!  '&'&54767̆mommom4mommom\N\|~{{~||~{{~|96oooo6996oo  oo6`E#@>}~Ա~}>@@>}~,,~}> =#9E_  767654'&'"2654&%.546  &54632654&#"  '&'&54767̆mommom4mommoms慄htdthutԄ9tihvvhit0\|~{{~||~{{~|96oooo6996oo  oo6,{{|kl{Eggss\hh\]hh@>}~Ա~}>@@>}~,,~}> =2>X  767654'&'53267#"&54632#"&2654&#"  '&'&54767̆mommom4mommom=|< .Vڴ=}mmlJ\|~{{~||~{{~|96oooo6996oo  oo6DJټ@>}~Ա~}>@@>}~,,~}> =+8Ca  76767654'&'&'"32654'.  735733!  '&'&'&5476767̆mo5885om4mo5885omT,+VUVV++2QPPQΠP3p\|~-,g%&݈@>}~~}>@@>}~~}> = $!5!#%  '&'&54767{\|~{{~||~{{~|#:9q @>}~Ա~}>@@>}~,,~}> =6>7>54&#">32!5  '&'&54767I7ݺFa`Lk=N)\\|~{{~||~{{~| ZI('55x_;xX._@>}~Ա~}>@@>}~,,~}> =(B>54&#">32+32#"&'32654&  '&'&54767ir׸G\\Bz~xWDUL2\|~{{~||~{{~|db\Z_wjrx('°t=@>}~Ա~}>@@>}~,,~}> = '! !335#$  '&'&54767hno\|~{{~||~{{~|  @>}~Ա~}>@@>}~,,~}> =7>32#"&'32654&#"!5  '&'&54767CAVHSK#G#\|~{{~||~{{~|=|}'' %@>}~Ա~}>@@>}~,,~}> = $>2#"&546.#"32654&#">32  '&'&54767PmmlC|=ϵѴV/ <|=\|~{{~||~{{~|+޸KE@>}~Ա~}>@@>}~,,~}> = !35$  '&'&54767>h\|~{{~||~{{~|@fE@>}~Ա~}>@@>}~,,~}> = +E2"&46' 654&'>54& 74632#"&  '&'&54767Yt愄/tԃuhtt-tihvvhit0\|~{{~||~{{~|{lk|{{Essgg]hh]\hh@>}~Ա~}>@@>}~,,~}> =$>%32#"3267#"&'"&54632  '&'&54767!C}= дѳV. <|=Allm\|~{{~||~{{~|Q/=޸JDg@>}~Ա~}>@@>}~,,~}> =  :2#"&546$  !5##7  '&'&54767eddedddB¡\|~{{~||~{{~|>-/#&%q @>}~Ա~}>@@>}~,,~}>uPj !!5!!Pp#@pppt 7%FN4NGuP85 zD<22pJJt '-ZKFGNuP!!u\lE>~~>uu+"&'.546?!".4>3!'.5467>2p4,,$$,,42.p ,.".2."., puP8!5! %JZPJJuP8!5! %JHJJuP8 #3#3#3!!5 xx<<oJpppJJuP8 55!#3#3#3oPxx<<΄ΊXXXXuP8!!5 %JJJPD! 6>l>>PD ! DR>l>>P  BlvvuPb3!5 5! '&'.u$##+* ZJMM*+##$0U%!JJ!%UuP84676763!5 5! u$##+* ZJMM*+##$0U%!JJ!%U0!! ^r{VXeoouP855!Dq΄Ξ0uj%5!!53  !<9h9>uj%5!!53  !<9h9>+Z !73#57!!+ Id&+ъ2&+Z 5!'53#'!!!+dI|&22 !'!'!53 !Odcndh 2 3#5!7!!! ndnd;ch dd !53#'5!'! !]n2n22r-hJdc;dJdd 7!573#5!! !2+2n2nr-hLJd;cdJ<6767632"'&'&'! <'CZmo~yti^Z\X^Vqoti^?)X6nGCZ.//+]Y݀z_X0//+]>Iʞ BP "&*.37#37#37#37#5!!!!3'#3'#3'#3'#<<< 7&#"7'7 !%*BF8WU{FC*9oX:WubP 55!5!!'!XXddPRt '327'' !!iFB*8X:*CF9XUpt>*%&#">7'&'&">327&5467>7tBEH#&NKX$W/,0$" D5Hp*G6$"!0,0Y"W!F&'&#GGCuaP'467#"!4676?'&'.5!3!.5P5#$%"//"%X$# 5eeJ(0Y! "X0(Jet*.'.54?'#"&'2767.'32t)H5 X"$ #0,0X"KN&#EHEBCGG&'&KW"Y0,0$"E6GsPX'<6%"'&'.54676$4676762"'&'&&'.54676762$/+z >_ $#R#af#R#)>xbQu 88RK68# 88  vc<*676767632#"'&'&'&%.5467.546A ''+/54<3o8n23'9%%%%bb%%%&:?$ fLLf#&#/:&'X23X'rr'X32XV2c"'&'.54?654&'&'&#!"#!".4?64/&4676763!23!2767>54/&546767622 Z ;:td Z   c   uu  c  2c"'&'.54?654&'&'&+"#!".4?64'&4676763!2;2767>54/&546767622pW\xj IJ \W   8  uP^'#76767&'&/3#>7!5!!5!.'PSJl..&GG&GlHSi7*nK Kn**7OUnm'66'1U=Hd)dH=n&*'$&'&#"'67667 h7Hm^:-3 RE SRQO1̡LHO&57$'&54&#""OER 3-:^mH7hH܏1OQ S #u ! ! j.u-10 3%!#3!Zddd/ #3!53#5ddZd{3 #pph # 3hp&T&T[[ '#'#'##'x\xxjjxx\x,x\ehhP8\xYY73373737+.x\xxjjxx\x.x\8Phhe\x,OlD=072767>54'&'&'&"7#7676767632#"'&ew@RNJV !'7$"!3!&'&'&'!#!2767676wx !1cbbc1! "1cbbc1" `x]\LM&  &ML\;RR &ML\]]\LM&ZwxZQvcbddbcvQZ[RwcbddbcwR[xV''LM\7=e=7\ML'e;6\ML''''LM\6d 8   2@ @@ 00 ]1@   990@   <<@ <<KSX << Y5!!dx yxUZxxu 8   2@ OO __ ]1@  990@   <<@ <<KSX << Y'7!5!'7 wxy xZwxxd 8ڶ 22@ PP_ _O O]1@    9220@   <<@ <<@ <<@ <<KSX <<<< Y5!'7'7!dxxwxxUZxxwZwxxd 8!!5!! s]xwx]ix]xZx]xiu 87'!5!'7'7!5 ii]xwx]iix]xwZwx]xd 8!7'!!5!'7'XiiiI]xwx]h]xwxiii]xZx]]xwZwxd 8 !5!3# Y#xwxݪ-xZxYu 8 #3!'7'7xwx-\xwZwxd 8 !5!53#5! Y]xwx]Q7ii]xZx]Eiiu 8 !'7'7!#3!7'Q]xwx]iic]xwZwx]\iiu 8%77777773'7'7#'''''''uFFxwxcnFFFxwZwxnF,X@,,X ,,X@',,,X,,X@',,,X ',,,X@',',,@,@',,@',,@',',,@',,@',',,@',',,@',',', ,@',, ',,@',',, ',,@',',, ',',,@',',',@',@',',@',',@',',',@',',@',',',@',',',@',',',',@',, ',,@',',,',,@',',, ',',,@',',',@',@',',@',',@',',',@',',@',',',@',',',@',',',' ',@',', ',',@',',', ',',@',',', ',',',@',',','@'',@','',@','',@',','',@','',@',','',@',','',@',',','',pX,p,pX@',,p,pX ',,p,pX@',',,p,pX',,p,pX@',',,p,pX ',',,p,pX@',',',,p,p@',p,p@',',p,p@',',p,p@',',',p,p@',',p,p@',',',p,p@',',',p,p@',',',',p,p ',p,p@',',p,p ',',p,p@',',',p,p ',',p,p@',',',p,p ',',',p,p@',',',',p,p@'',p,p@','',p,p@','',p,p@',','',p,p@','',p,p@',','',p,p@',','',p,p@',',','',p,p',p,p@',',p,p ',',p,p@',',',p,p',',p,p@',',',p,p ',',',p,p@',',',',p,p@'',p,p@','',p,p@','',p,p@',','',p,p@','',p,p@',','',p,p@',','',p,p@',',','',p,p '',p,p@','',p,p ','',p,p@',','',p,p ','',p,p@',','',p,p ',','',p,p@',',','',p,p@''',p,p@',''',p,p@',''',p,p@',',''',p,p@',''',p,p@',',''',p,p@',',''',p,p@',',',''',ppp,p@',p,p ',p,p@',',p,p',p,p@',',p,p ',',p,p@',',',pp@'p,p@','p,p@','p,p@',','p,p@','p,p@',','p,p@',','p,p@',',','pp 'p,p@','p,p ','p,p@',','p,p ','p,p@',','p,p ',','p,p@',',','pp@''p,p@',''p,p@',''p,p@',',''p,p@',''p,p@',',''p,p@',',''p,p@',',',''pp'p,p@','p,p ','p,p@',','p,p','p,p@',','p,p ',','p,p@',',','pp@''p,p@',''p,p@',''p,p@',',''p,p@',''p,p@',',''p,p@',',''p,p@',',',''pp ''p,p@',''p,p ',''p,p@',',''p,p ',''p,p@',',''p,p ',',''p,p@',',',''pp@'''p,p@','''p,p@','''p,p@',','''p,p@','''p,p@',','''p,p@',','''p,p@',',','''p,p',pp,p@',',pp,p ',',pp,p@',',',pp,p',',pp,p@',',',pp,p ',',',pp,p@',',',',pp,p@'',pp,p@','',pp,p@','',pp,p@',','',pp,p@','',pp,p@',','',pp,p@',','',pp,p@',',','',pp,p '',pp,p@','',pp,p ','',pp,p@',','',pp,p ','',pp,p@',','',pp,p ',','',pp,p@',',','',pp,p@''',pp,p@',''',pp,p@',''',pp,p@',',''',pp,p@',''',pp,p@',',''',pp,p@',',''',pp,p@',',',''',pp,p'',pp,p@','',pp,p ','',pp,p@',','',pp,p','',pp,p@',','',pp,p ',','',pp,p@',',','',pp,p@''',pp,p@',''',pp,p@',''',pp,p@',',''',pp,p@',''',pp,p@',',''',pp,p@',',''',pp,p@',',',''',pp,p ''',pp,p@',''',pp,p ',''',pp,p@',',''',pp,p ',''',pp,p@',',''',pp,p ',',''',pp,p@',',',''',pp,p@'''',pp,p@','''',pp,p@','''',pp,p@',','''',pp,p@','''',pp,p@',','''',pp,p@',','''',pp,p@',',','''',ppd?8 !5!53#5!s]xwx]ii]xZx]EiiuP8 !'7'7!#3!7']xwx]siic]xwZwx]\ii 3'#'##-Z-x\xxx\.x\n #\733737#x\xxx\xZ'x\# n\xO'=%"'&'&'&767670327676764'&'&'&pk_V1..1Vbrx`Xk_V1..1V_kpIxXE?#!!';B]YQS@?#!!';BQ9.-\ZnllnZ_.x$-\ZnllnZ\-.)xF!F@RNJV>lmGСBk>DdW0Xdtsݓ.W@#.  -&.%)/K TX)8Y299ܴ]<<999991@ &$-/22907&54&'>5!2;#"#!532654&+CI02Kl>>l5UU5D>kB0GmstݔdXЎW2  5 1Vd22h' %#3 5' :' 73 ٪L^8bb:'B 7''ٛ>PNq'B '''ٛ>PNq^D'B ''>PN'B%  '''tNP'B5  5''bNP#u  u-3!3!!#!#!5 L3ͨ--Ӫ--333333#######5Ϩ---Ӫ---:k7!!  767654'&'$  $'&'&547676h08rtrrtr@rtrrtr VGFFGrGFFG;:rs죟sr:;;:rssr:Ŭɪ:k3?  767654'&'$  $'&'&547676!!#!5!rtrrtr@rtrrtr VGFFGrGFFGssB;:rs죟sr:;;:rssr:ŬɪKss:k3?  767654'&'$  $'&'&547676   ' rtrrtr@rtrrtr VGFFGrGFFG]x3w32x3B;:rs죟sr:;;:rssr:Ŭɪ3x23w3xuM %' io& i' i% iJuM327!5!>2&#"!!"&' ;E 2&#"!!!!"&' ;E $;E Ϊ@z٨zuM&#"%"&'73275%>2";EC;EJ綠mzzuM*3&#"&'67"&'7327&'&54767>2";EIq(P >6D;E]InoSu=,HK%)AH!+p$ z1IosV2";E+@/V]H6H\nUm;D [>wfP3,,I6x/Ur]HH]lVzM>wrN3 F4uM!3#!!>2&#"!!"&'732w~9F 9 }9Gr0}}uM+3#>2&#""&'73273264&c)~9GcBnnVs~9F (6o~ç|K|oU}uMp.3#327264&#">2&#"632#"'"&'z;E-8pƖqS;E;DܛWI3>6я]z!zuM 13#64&"327&'&767>2&#""&'˔֐;E]InoSu;EcBnnVszяϐ-1Io7sV2&#"!!"&'73273!#3;~9G9G ūI}ޭ{ tMm-&#"!2#567&'!"&'7327!5!>2";Ed_``!;D ܻ`;`*I6ƌebIz`:H:`*F4uM#&#"7'"&'7327'7'7>2";Exx;EzxXyxzyxإzuM*327#467>2&#"#4'"&' ;E-A 4yy;E Z>Vy|-2PIϼ+zEa82JzuM'&#"63"&'7327&'&53>2";E*y;E\?Vy~+&8'zLFaI1zuM>32&#"#"&'7327!5KL~9GALK~9G⧅}}gkb>32&#"#"&'73275!KL~9GALK~9G⧅}}Р? 5 5FѶeѦ 55FѶ///m' //& 0'' /'' 0' // ' 0N:A%#"'&'&'&#"5>32326#"'&'&'&#"5>32326 5jbn ^Xbh`n ^Vhjbn ^Xbh`n ^Vg@PNE;=LTNE;=KPD:32326#"'&'&'&#"5>3232655jbn ^Xbh`n ^Vhjbn ^Xbh`n ^VePNE;=LTNE;=KPD:327&#"56767326 5jbDS4WVhjbm\Y@/Xbh`ES3VXbhZmMp[Y@1Vg@PD4KUNE;@LTNE4LRN"*,@J^po_N5<#"'3267#"/'7&#"5>327&#"5>32732655jbDS4WVhjbm\Y@/Xbh`ES3VXbh`n[Y@1VePD4KUNE;@LTNE4LRND:@J^T 5!5!-5 !5!uu/0\^ҲЪ~T -55!55!usҲЪ᪪/0N%#"/&'&#"5>32326!! 5jan^Xbh`n^Vf@PD:32326!!55jan^Xbh`n^VfPD:323265-5ian^Xbian^VgsuOE;=LSNE; =KJ/0:ҲЪ !(#"/&'&#"5>32326-5 5ian^Xbian^VeuOE;=LSNE; =KJҲЪ/0, -55!55!us%ҲЪ᪪(/0٪, 5!5!-5 !5!uu%/0\~ҲЪ^6 5 5 -55uu/0V/ҲЪа/6 -555 5uuҲЪ۰/'/0K/& 55p/ѦѶ& 5 5p/om//&' /G&' H{ 5!5 5!@Ѫop9{ !5! 5 !5!@Ѫ555@pNpop 55 5@p pU(".#"#"&'5327>76325hV^ n`hbX^ nbj@TL>7632 5hV^ n`hbX^ nbj?TL>֪VJ<:DNTL<:DNDop$+5!5!.#"#"&'53276767632 5hV^ n`hbX^ nbj@>֪VJ<:DNTL<:DNDf $!!!5!676762!!&'&'&!!C.8d 6WYYV7 e8-;Z{+DD\93[2332[0<[EC,W7!!%5$$}y]]x|W%!5505%$}$y|]]W !!'7!5!%5$ZZ N$}qPP]]x|W !!'7!5!55%$ZZ N}$qPP|]] K75!5!%5$!:[]3֪k-QtXVv K75!5!55$%$][:!3֪kVXQ-qK!5!7!5!7!!!!'%5$&`ȉ)P"_=6!:[]ss1st-QtXVvqK!5!7!5!7!!!!'55$%$&`ȉ)P"_=6][:!ss1stVXQ-y:E#"'&'&'&#"5>76326#"'&'&'&#"5>32>%5$ian ^Xbib` ^Vgian ^Xbian g!:[](NE;=LTN9 A=KOE;=LSNE;C E-QtXVvy:E#"'&'&'&#"5>76326#"'&'&'&#"5>32>55$%$ian ^Xbib` ^Vgian ^Xbian e][:!(NE;=LTN9 A=KOE;=LSNE;C EVXQ-6A#"'3267#"/'7&#"5>327&#"56767326%5$jbDS4WVhjbm\Y@/Xbh`ES3VXbhZmMp[Y@1Vg!:[]$PD4KUNE;@LTNE4LRN"*,@J-QtXVv6A#"'3267#"/'7&#"5>327&#"5676732655$%$jbDS4WVhjbm\Y@/Xbh`ES3VXbhZmMp[Y@1Ve][:!$PD4KUNE;@LTNE4LRN"*,@JVXQ-7 5@pppo%5555òi ' '!]#\e#N\#]x#L   !77 ! \ݿ##N]##4 !7 7:\#]x#L]ݿ#\eL#1 4  %''' !]ݿ#\eL#1\ݿ#]j#7P~ % ! !!5 5!3!   7?~% !!3 *^V !!^*  ^V!!!^ ' '!##L  !  ##4%7 7#L4L#1 4  ! L#1#7P~ % ! !3!߆^V ! !! !ECuR #7!5!7Zxx/{xx:xu-R '!5!'xx vx:xH% 7!!7vx{/xxxƪxvH-% 3'!!'Zxx vxx$!%!!W7 r$!!!W7 $!!,7r32 &}f[_ &}f[, %$R/ %$R !2+##5332654&+!ʿ[qrqqϐђАfT$@  $ !? %29999991@&  B  $/999990KSX9Y"@&]@Bz%%%&'&&& &66FFhuuw]]#.+;#"&! 32654&#A{>ٿJxn?M~hb–m؍OH#(07#5#"''7&546;7&'&#"5>327354326=-?\g`n;) T`TeZx_958>cc3Vfa<}NV{ E..''rOs+Ax.ٴ) 3{ B333#;#"'&'##53w1ѪKsQ fև3͏oNP r>6!#4&#"#3676323#d||BYZucce22wxLj%3###3!E3A1wH33 3###%̟8ǹiEL#\ !!#!5!sP=g՚oAX` !!#!5!qjLl}e`R%sw-@ 221/053#5# !232#"MT+焀\\xEEf! !+53265##-}-MDnh %!#3!3҈R={0#3 632#54&"$\^TރQr)m`Tῆrr:T*D  # #3 3 67632#54&#"f:9:54'&'&s~&&~~ڢ~.]=@N\N\.]=zz❞zz}qa !SM!R}|pas?#-n@.  '&$ /$ .9999991@ .'& ) )./9999999046$327#"''7&7&#"4'32>s~&Ġn~ڢĠnՑꏧw֜\w֜\zvijޝzwkj!^`|g^` .@   <<<2221/03#3#3#3#):@  1/<0@22 # #3.]F; -@    1@  /<<03!#!#!"9q><@  9/1 ]@ /<220KBPX@     @     @ Y333 # # \Xds3{ 1@   <2<2??]1/<2<20%3#3#3#3#\ 7@  91/0@ BKSXY" !!!!&TdD՚ohh $@    1/<<2203#3#3#hhh7o !@  /221/220!!!!5!!o&.-ժo1/,@! ',01*$ 022122<20!"'53 !"563 676!2&# !27# '&%4rmyymrO4%%4Trmyymr4*B6!*:'(8) 6AB6 )*!6oP@   <<222<<<<21@   /<2<<22<<2203!3!!!!#!#!5!!5!!n""xxyyrr3@21/03!!!ժ,o7@   /<<2<<21@ /<2<203!!!!#!5!!5!CCPPxyr7@ KTX@8Y221/0@ 0 @ P ` ]73#3#>@ 10@ BKSXY"47!5!32654'3! $x˿ßwNetwc #/9@1E- !'E0<2<21@ 0*$002654&#""$54$322654&#""$54$32,,,,PIIPPIIPPIIPPIIPs'(@ ) (1@ #(046$32#"$&732>54.#"s~&&~~ڢ~\ww֜\\ww֜\zz❞zz}``}|``s,P@  ! #.# -9991@ ! ((-99046$32'#"$&73277654.#"s~&&~l~\wj\ww֜\zz➞ikwz|`^jI|``; -@   1@   /2203!3!#,dq9d (@   <<<<1/03#3#3#QIh ?@     <2<2??? ]1/<2<20#53#533#3#3#h+Is'+>@- )(( ,9//)]1@+(#,046$32#"$&732>54.#"3#s~&&~~ڢ~\ww֜\\ww֜\zz❞zz}``}|``s>,P@  %$#& !.! -9991@ #&$%((-99046$327#"$&732>54''&#"s~&Ġn~ڢ~\ww֜\pw֜\zvikzz|``|?l^`sr%1=G@8&,20><2<21@/; 5 )##>9//0! #"&547 !&54632! 32654&#"4&#"326sS_  _mz,,,,,,,,gs'O;H66H;O'sz<11<;22<11<;//d #@   <<1/<203!!#!5!IIjk=;;sr3?Kf@F4%+6:0L2<2<29/<<1@=(I C (7##11L9///<20! #"&547"333###3&54632! 32654&#"4&#"326sS_ ̻A;z,,,,,,,,gs'O;H6ߊ6H;OO4z<11<;22<11<;//;@   2<21/220]!!!33##!!!>ժFh);@ 1/<0)3!3;+y=@ B <1/20KSX@Y!# 5!!!8ks#O@%$!  /<<22<2<21@  /<<<2<<<2032653#2#4&##"#3"3ʊyʊy+VVF%F.@ KTX@8Y1/0!##u-s+f@- ,&'  #+ /<<<222<2<21@+*   #*'"/<<<2<<<29/<205!5"3332653#!!2#4&##"#35ʊAyʊy>FV>=VF=6-@ 1/20!3!3M-$36767#"&546?>7>5#53!Ya^gHZX/'-93B$BS #C98ŸLVV/5<4,5^1Y7:X!##:o#5!#&X3!3hXo!533oXKK'464';6;'769'96:'469&496'96;&9;6'468&456&;46';64&466'466&;:6&7;6'765'86:'56;&8;6'766&:66&:;6'76;'764&:46&:76&586&996&666&5:6&786':64&746';66&;66&866&656&9:6'967&:56&876&546&486&5;6&;86'965&986&566&686&776&::6&8:6&756&766&6:6&886&556&896&956&856&7:6&966'966rid{jXn`+v)4>@01, *$6E591@ $ *052220#"'&'&#"#"'&547673!27676323 4'&'3ft[na`zxz{n[tfCGo~[U]LKfdKJ]U[~oFCD@@DDDk63366336Fk!<@!  # E"91@  ! "2220!"$"# 33276762324rTRrƒ>IxddyI?ВP8[ 77 [8G<r&,>{&s   !3#!! ! H0x:;hLH+fabgp{ "326&33###" rhո  983#!#!#3! !9҈_:o%+kj{"-#5#"&547!#3!63!54&#"5>32"326=?/j`TeZ߬ofasP`A"..''f{bsٴ)e767!!3##!#!!&aO)p(?x4&A D+k`76765!!3##!#!![(bR-f}v(UԓR:d6T356765!!#!T:WO)fb0d+L`356765!!+!L3DS{X^}з3oP! !!+##-}) `! !!### >?h˸ʹ`3'Ps'y2qu{&Ry.se3#%3# '&76   1L  F<HqC{3#%3#"32654&' ! hJ IHn98s j&m'yryq{'yo'y.n:W '/7?GO%3#%3#3#%3#3#%3#"264"264$"264"264$"264"264$"2642+ '&' &547"#"&546;&546 676 3#J"{iihiihiihiihiihiihiihG4UU32UU4IF]97R̬\dfʬ\ʫZee̫ZҜf!!!2+5327654&#!#!qmL>87||ժFwrKK"9+32+532765||BuƣF1n!&edH08L*!!!2!"'&'5327654'&+5!#!^eicUQsj~cd\]ժ˚8+lhzy$1KKIJJ+7L402!"'&'5327654'&+5!;#"&5#533!AicUQ^cdjTmcd\[jKsբe8+lh%12KKKJN`>¨{Rg|1&'&547632&'&#";#"32767#"$546p<HmmFEMUUU8%~` !!!!#+`Ӕo{V 3 3#!+!# ! !J9҈_҈_%s%>+{'{ 5@M"326=%#5#"'#5#"&5463!54&#"5>3205>32"326=63!54&#"߬o?nQ?`TeZxeZ߬o5y`[A3f{bsٴ)Lfa' fa..''~D''f{bsٴ)hn< - 3676! ! '&'!# !  J-p;:xżP.g%H}[[Xr%H{{{"-82 '&'#"&5463!54&#"5>3 6"326="32654&y7!``TeZ*qO߬o{ǝ>REa..''f{bsٴ)nq !3!2653! '!#%{J®sv%_r\4h{{(3%#"&5463!54&#"5>3232653#5# "326=H`TeZ||Cu߬oߍo..''{fcPf{bsٴ) !!#3 3%Lj_:+{N{ ("326=5#"&5463!54&#"5>323߬o?`TeZ^\3f{bsٴ)ͪfa..''5 )!#!#333#%~gY_:gci5R{N{"-0!5#"&5463!54&#"5>32333#"326=!#u?`TeZxgƚÛ߬oGfa..''~mc3f{bsٴ)V !+53276?!#3 3%lKMJ|ثL*+2_:q?=$%2@{VN{'2!5#"&5463!54&#"5>323+5326?"326=u?`TeZ^N|lLT3߬ofa..''wj8zHB3f{bsٴ)s'{f 37!!_(^M*c37#xIS 33#!!#53ʨ_YQx 33###53YR j% 3#! '&#5376 !&'! 76;:~ ż ~HjiF wvҵCҤֆ {'23##"'&'#53676"!&'&!3276o ~~ oV?s?VLVVM{~͐~sUUu%gstgs j$. 676! ! '&'!     ':/##.;:xŽ.$#.yHH5==5[[4=<4HHHq{ 1"32654&!"32654&'267632#"'&'#",nn霜ǝ98 !#!5!)+Vy{3#\{V4&#"#367632#PQfeCBVd{#4&#"#3>32d||Bu\ ed#Ib !5!5!5!b>>I5:@ K TX8Y991@ _]0 P]3#5qeo7@ KTKT[X8Y10@ @P`p]#o+w #!5!!5Pp+ɪF #";##"$54$3@/+X 3333! +m3#mD U%3 3# # #3>:9w+: #'+/37ڷ/$0(7,48<<<<<#+ 3'<<<<< <<<<< <<<<<9̰XKRX8K bf TX30<32#4&#"#9`M1Cuȸ||MM 7BuƸ||e,'"xMfca?'Gzed\V5<!"'&76763!!32653#5#"&5#3!#"&5332765!"3ە^SWsv||CusCuȸ||WVۃ^SBWLa{fcBVfcf__{{V H!&#5#"&5332654/&763!6763232653#5#"'&=4&#"#9`M1Cuȸ||MM 7c%Zk>8nClbd||xe,'"xMfca?'Gz2XO{fcx{䟞[t`&-V 332673 &Vv aWV` v ޞKKJL[`&ASN~`6@  F991B /2<0KSXY%2767653)5!3$Wq2!dj±/8s4tVg` ##4673>=3|u˷d7<T "yX`#!5!e/я`!#3#4&#!5!2snJvy–X`35!26&#!5! #X-뒦yX4=!3!#T\[CLzl` 3!2%!4&#!Wn`–X` !#4&#!5!2nKy–X`!#4&#!+5265#5!2nã rLy–a;- 1 <05!3!----Ӫ&=&= && `&$u`&$`&$\X`&%BCZ`&&Xh`&'d`&(Q`')ZX`&*`&,&Q`&-ZXV`&.X`&/:X&0X`&2%X`&4X(`&5Vd`&7Id`&8{C!`&:nV`&;X`&<I`&=`&><t&)X&%X&/d&8X3>=3##67'#3x]GgG.i=dB`ԛ":T)C '9 '9 X& ~X' ' ' X&c ~X&c ' ' X&c ~X&c'9'9&L~&L'&&cL~&cL'I&I0a&I+p~a&I+p'x~\F&x?&,~ x&>'xx\F&x?&,x x&> (f'X >f'}D>\/&E 8>>/&F 8 (f'~X >f'~&D8\/&E~88>/&F~8 (f'X >f'2D>\/&E8>>/&F8 (f'X >f'2D>\/&E8>>/&F8 ' \ ~&P /&\I> ~/&PI>)7%#"'$47332767654'&54767;#"'&/cͷ?Ahž#62 #dGG&+@XA:g!axLn 6r'|>X %+53276=3+HZ#c,1VV,1jٻ~X%+53276=3;#"+MZ#c,11,c7nVV,1jj1,JoX&~c~X&~cpn"56$3=gi~wun52&$=Ԛuw~ig* '/&'&#"#67632O,$e5Fqp[?8WH7  $0GJI  '327673#"'&'O,$a9Gqp[?8W7  $,KJI Pq,l&fq,Pr,i,k ;#"'&=3!1,cK\WL71,\W+Ps,Pt,l't,fPu,l'u,fPv,l'v,fdw,l'w,f<x,l&fx,UL'yR&0yl9'zRl9&0z @'z>n 6&z>l '{Rl &0{'z>o&zXD&z+p~&z+pyR 3;#"'&1,cKPWskj1,\e'}9&}9X&}~X&}'~m^&~^ '~ &~&~cR~&~cR'&&cR~&cR (f'}X >f&D}\/&E} >/&F} (fX >f0%3#"'&'&'!27# '&5767"#"5$3 "(1{R=IrbJIԖ^` __&m3HZdP^vc–e4)?6 [_w\/&'&'&5672+5327676SSgURHKLXJKݣdht^#4b4bBPH:jV>/);#"'&'+53276767&'&'&5672~AI2hrBV~(;E)Kݣdht^eSgURHK 4b)N"w6a.%PH:jV# ('}?X >&D}?\L&E} >L&F} }RZ}GR &'3;#"'#"'532767654"9aRQS,cKa].-fgsT!"#?zNuIS,!&* 1p*D}'}EZ}G&L}E b&\ ~&3;#"'!5 767654x I*eK2D0# &pgM,>ꅗ:H~ b'}q \ ~&P}q ^ GF%7653323;#"'#"'&''&'#&'$473327676'&/3N0%@nS,cKvDm% I01_@8'TPxmil_Qb_y^@@$:|_2&aS,`[ F{GHܳ&%0l}=J<~ 1%+53276=3327653763#"'&'#"'&+8LcKc,P,+hm,%@n\Kf%#?70`DAbH<;!.,Pd@dczg2&q\ =!1(78#"'&'#"'&'+53276=3327653763;#"'%#?70`DAbH<)+8LcKc,P,+hm,%@nS,cKvD =!1(I;!.,Pd@dczg2&aS,`Z ' ^ G&T  &U 7&V ` <I)"'&5#&'$47332767654'367676;#"/"3276'&'&u&4-JXPxmil_Qf[+!' (s{lHX}a*=RKgL~큻%MGHܳ&%Dl7(2l^F"%GMF ,\v7Ql?[F2 .327654'&#"!"'&'+53276=36767632Ш큺%0LJNA'fKc,P-e_KUskl?[F*#=,PdrNP2T?!'Dmx+8)"'&'+53276=36767632;#"/327654'&#"JNA'fKc,P-e_KUqm*=RKg਑큺%0L*#=,PdrNP2T?!'DKH ,\vl?[F '} ` &\} 2&]} &^} b))5!3%632;#"/%3276'&'&#"@o\Dui*=RKg큻%0Pz\?c!'EMF ,\v?]DQx %3276'&'&#")5!3%6329큻%0Pzu \Duiʸ?]DQx\?c!'Emx))5!3%632;#"/%3276'&'&#"8 \Dui*=RKg큻%0Pz\?c!'EMF ,\v?]DQx'}Rb&d}R&e}R&f}Ru *du %+! '&7.54762;# '!2764"[b=D}a_[9^DU)k_1ocz2t*n@00@p[C+ @Mkl=v8`3$*727&'&5763"327%+5SF7J \X];d}M4F!Ť$/%+532767&'&5476762;#""654'v`kB;(aD hYYh MXD=p`vʨ4/gg/($'UZ'-)74--47)-'bM,(U __ u F'}wdu L&l}F&m}wL&n}'}~\L&}?&}~ ~&}kH'~R~k &~k?&~,~ ~&~8i!D#"'5327654'&'&7676'&'$54733276763;#"'J&P DfXRNB8D-<9_h$$EB|=Q#!v+6(  %{{qe))5!27654'&54767;#"'&/66-62 hGG&+@XA:g!a_h$$EB|=Q#!v+6(  %?+)x.j#$%653;#"'#"'$&733276N1,cKpNyUcE@A(IPmI~jkj1,3.(B"[\ss~B"5 +5327653WPKc,1se\,1j%+5327653;#"SMKc,11,cKVV,1jkj1,^kgt5%327654'&'&#"#"'&#4763&547632;#"bzL,5;(.;D K2KxAZM\HT((&iK*9:X DD(PNNOmf7*(?$GC,,m$%#"'+5326767632%327654'&#"dan@ht4W^Q[a>/4(*X.[4fb0G1P8TYNE5EK&)/4:''5)24fb0$#1P8S1>,E5EX !a%H'}?  +&}?&'}R~'}Rm^ $&'&'&'3;#"'&'#"'&5476 xRot$8pKZI-&8:m*12e CY>)2'+eO,3;I0D-=67654'&#"27&'&5476&'5#"'+5327654'&$"':A4N--0M,Q@(Jxb 41}! @H=.%4-+#%v iEN@TSZ 'D49g=ql)D%'i.C!v-3j  ;AWE L9P)8K6(S/VL_+Y9K1\SJo765&'&'&54767632;#"'&#"#"'$4733276L[/,4PT*uW ##rpl$-AIqYhu?AB[M!3!+ (;=A<^ĸ#0{bV` )gZZrN J'~ o '~ X&~c~X&~c.&y,.&y,&z,&z, &{ &{T#"'53273676537M͞jK`Uq%BUG FA+7T#"'5327367653;#"'&4;IʡjK`Uq%"@Pif<[A FA+7DT)TL* 35'5467676?67654&#">32,X\"$߸g^aOl39ZZ8L{4<+VZ@EL89CFnY1^5YVe !5!5!)5!S2SR7'XF: 'b:= ']C; '<b= ']bH'&'H'''H' ''H'&'H'''H''' H&&'H&&'H' ''H''&H'''H' ''H&''H&''H' ''H&''H&&'H&'' H' '&H&'' H' ' 'H''& H' &'H' ' 'H' '&H' '&H' &' H'''H'&'H''' H'''H'&'H'' 'H''&H''&H'&' H'&'H'&'H''' H'''H'''H''' H'&'H''&H'' 'H'&' H'' 'H'''  H'' &H''& H'''  H'&& H'&& H'' & H'&'H'''H'' 'H'&'H'''H''' H'&&H'&&H'' 'H'''H'''H'' 'H'&'H'&'H'' 'H'&'H'&&H'&' H'' 'H'&' H'' ' H''& H'' &H'' ' H'' &H'' &H'' &  #3 !!#!]W:\w98qq+_N  %*!2#!327&#363&#!3654/654'f;33;$ $#>]a{w DD663! )327&#!36'hPcp~qAA k{qS3%!!!!!!-x9vq dddsd !!!!!#3#oQn.ddqs&&$#"32767!5!# !2deVRuu^oRaG@;@&5dSUmnHFcIf3%!#3!53#.nXddddq dddd fY6765%!#!53265-V?O?nqd J^ dd0 !3 #!3pdw@1q 2 !!!3ddo o !#!! !3!3_Gbn}qR+q  r'( ! '&76 7& 676'&&:żGlllli$ #ab2222jT%%5$c$-6&/.4%&  %5 64&/.$ Pdo&nŢmngzoʷ-[ʚ)'NXd''pui$2Xf| / 3%!!!!rpq ddq $!&%! 65! X!!Y fqba@`|gd5\*$ 3%! 3!dq d+D 3!3%! ! 3! !D5D:9:9d|q  d+l 3%! 3 ! #(\~vbL:H|dq d22{ 3!! #3ndp29V{{",34&'3!5#"&546;54&#"5>3 5#">76/=Kd?Vu`Tw86/^b;:gCzӆ]YfaH..t''UNHGgwt-!>32#"&'!4'&'676763&#"327N:||:^,<<,9RKM_]daadt= z =OsKTdihtJq{#%#"!2&'&#"3276%M]-ULEmGJXHCQRHV,${z$d$$>:##dWS%&-!!5#"323327654'&'&#"N:||v9,<<,^(]_MK^daDDaZKsO=  =Td6Jthio}{!327# 32!.#"}K_mk)#i̩J@b]u-)8 CqzӾ/ 3476%#"!!!#5354763g.9:9|WX -8J_D8d97ddddTVqV{#.=65326=#"325!!"&32767654'&#"jlQR:||:Nry^,<<,9/KM_]=ʌo,*qdaDDad-w=  =OsKihtJH "34'&3'!>32!4&#"! GS5‡OIƁkk h@[:Lded\ПU5 33#!!JKOhV #676#532765!3#%G(=1l$%OQRaеT0Hd01``2 !3 #!3OHіmdi#L&5#"'&5!3J=(G%RQOLiH0T0Z``~J^d{"&1<!>32>32!4&#"!4&#"!3%34'&%34'&OIƁԝTށkkkkd[ GS5 GS5`edJv\П\ПUh h@[: h@[:H{ "34'&%3'!>32!4&#"! GS5‡OIƁkk h@[:hded\ПUqu{ #2#"27&"676'&s3x33x3d4'pp'3(pp({98  kp-$-R-ۀ-qV{-%!!>32#"&4'&'&'676#&#"32N:||9,<<,^؆]_MKdaaKsO= z =oHJthiqV{-%#"325!!3#32767654'&#":||:N<^,<<,9(KM_]daDDad=  =OsK2HHihtJ{3'!>32.#"!N:4I,hdfc˾zo{E67654'&/&'&5432654&/.54632.#"#"&'i'K&'q4=B%%U+.39GSOjqL4vfLJ\_opPx3Zl=vf03"3;@{R?Bsl37'*7CoT78^UNO,, z1$YXDL#/%%7%&7#!!;!"&5#53*\{KsբjU|7N(dUNdudTD` "%&'&5##!5#"&5!3265! GS5CIƁTkkTS hl[:hded0=` 3%! 3!YT^^d\hdTV`3!3%!!3! !bTNdhhdjjjL` 3%! 3 ! #U|p|[hd-s=V`7%! 3+53267>^]_lP|XQ+ۙdi8{dCYXb` 3%!!!5!\vwhddhddh$%s'&'(#)s*;+f-j.j/031s23s4T567)8h9D:=;;<\={-{DEq{FqZGq{H/IqVZ{JdKyLVyMN9{Pd{Qqu{RV{SqVZ{TJ{Uo{V7WX{X=`YV5`Z;y`[=V`\X`]   6/&"27 d3{44{3s s#Տ0,-k37!!5!5%6bJJgq ddd HdH(7!676'&'$32!!7676&#")`"LlDbZE0Q](=ymd͕@9\9pd9hbiddAbs$*0"'5327&+5327&#"56325654&'>54+!ĪeO6?;2:L uWEdJj D d <h@Ѳ|!ŐUl$yXZ#3 !!3#!!5Qpq3d\#66'&#"!! !"'532gd1jKEн܁\`I Kd# F32v cSRav 6978w{z9 j@ VV120K TX@878YKTX@878YKTKT[X@878Y332673#"&v cSRav 6978w{zfGd10KTKT[X@878YKTX@878Y3#@1<203#3#䙋N#!#ęę53#73#'3# 3#3#'3#}}d 3#3#'3#}}d3#3#d 3#3#3#3#dd&;#"'&'#"'$&733$767654'3F??7KX~X\,>%!$'$&73!2%7&'&547676323!!"'654'&'&#"xhn}@AQ+"R:4RQP ioh4"(=)1$+<'g\^sM6,|y$K2S%jAzG' <8BN?0654'&323276767'&54767632#!V)B,4((7(*HTO<?aNbNLZB`.NJ|m+M;3*)3P& ]027EW4,E$2Hf3Џ,' !5;#"'+5327&'&54767632"67654'&'&f$'و'$A??8 D?$ 9P2*I1C299(M.L,0W 5+5DE2.4! k .@%&'&'&547676323!!#'$'&5473!2766'&'&#"B.y9()Wp8c20-=^E>><l/"'"3 9Ld/  #+m=E2X:zFNV}`kL:DbZzWK# :<,; ? &}R~&}R %4'&"2>"'&4762<R8R8z?@?@@?@(8)*8@@@@@?? '~'&'~cRP~&'~cRP' &cL~&cL >&Dz8\K&EzX>K&FzX >&D?\F&E >F&F  >&D\F&E>F&F >&D'}?>\L&E'8} >>L&F'8} 3_+ 5__bV'J@!B  6991/<2990KSXY"]33+532765#ոRQi&&}``01}` 2@  F <<221/<20@  @ P ` p ]33###53ø`<ĤV.` 54!333##"3276!5R w{i&V`p?`3A0c3'q=rUa4'qr[^3'zPq=cZ'sdrUcZ'udrUaZ'sdqaZ'udqvj 3't\q=cZ'wbrUvj V'r}t\cW'wuz|vj0Z's@dt\c:'vus(Dcm:'uDvuvc u'vutvV Y'yPtpVZ'yPsdVZ'yPudV'yPc['vu{Pj&Z,,!!,,O=32653#"&[hq`=QQ, &&| &3;#"'!5 767654x I*e2D0# &pgM,>ꅗ:H~#'|`'|S'|SF'|8@'|+ '~c~@'|+ '~c ~r'|>P9 9F KSKQZX8Y1/0@  @ P ` p ]3;#"&5Li a^q%qqu {&JOw`73#!!dž$Nd`Vw`#676#732767!5ʆ#5H2K1i0/N)deеT0Hd01``vg{'{&3#3## +@     22221/220!#3!53#^ժ ?!5 ?8'qXw8 U'rXw8'wq8'tXw8 U'uXw8 'w,t$'tz$'uzN@ T1/0333N@T 1/20%3!533yոBy@ T1/0)533ysոBq8@ E EԶ0]991@  /0 6& #" 3 *NYh> éA@E E Զ0]91@    /<20 6& "'!53&54 3 *NNJhh> é!8@ E EԶ0]991@  /0 6& &54 #"'!5 hYNJ>z=x 4@   2291@  /290)33!x³j*]Qix 6@   2291@    /2290%!5!33xtj³瓓]Qi' 4@     2291@    /290#5!33j³]Q=q) #33mCq"q )5333!mm"q)533#mOq $@  1/2<0)3!33OkUq""Oq (@   1 /22<0)533!33OιUΓ""q $@  1/2<0)533!3kιU"Oq $@   <1/2035!!5!3ΓK"Oq $@   1/20#5!!5!3ΓK"q @ 1/0!5!!5kqKq:@!E E ܲ@]ܲ@ ]1@  /<0!&'.4> !2>4."RJr 惃sKR9[ZZ 1ũbbŨ1 p`88`p`88!>@#E E"ܲ@]ܲ@]1@  /2<0%!!5!&'.4> 2>4."RJr 惃sKRQ[ZZ{ 1ũbbŨ1 p`88`p`88O:@!EE ܲ@]ܲ@]1@  /<0#5!&'.4> 2>4."RJr 惃sKRQ[ZZ{ 1ũbbŨ1 p`88`p`88O &@    21 /03"3#!5!>k fO "  21 /03"3#!5!>c f $@   21 /03"3#!5!pk fq7@ E<21@  /<20!!##"&6 !354'&"3.Cf^v ]8mr^<Uf"qɃ]8ƃ;@! E <21@ /2<20%!##"&6 !3!554'&"3.Cf^v7]8mr^K<Uf"Ƀ]8ƃ7@ E<21@  /<20%!##"&6 !!554'&"3.Cf^v]8mr^K<UfɃ]8ƃ ,@   <<1@  /03!!!!!55Փ/ 0@   <<1@   /20#53!!!!!55B/D ,@    <<1@  /0)53!!!!ys55B/= ,@  <<1@  /0!!5!!5!355ߒѓ 0@  <<1@  /20#5!!5!!5!355ՓLѓ ,@    <<1@  /0)5!!5!!5!,55Lѓ *@  <1@   20!!27654'&3!23,R4,,=ٹUiXO]Oz}I_"_Ҥ.@  <1@  /220#533!23!!27654'&ιUiXO,R4,,=B_Ҥ]Oz}I_ *@  <1@   /20!!27654'&533!2#,R4,,= ιUiXXXl]Oz}I_"B_ҭ@@  ܲ_]9@  /999@  10!4'&'5!!5Mc4B_9V@9D@   ܲ_]9@  /2999@  10#5!&'&'&'5!! 5Mc4BX]9V@9$@@   ܲ_]9@  /999@  10#5!&'&'&'5! 5Mc4B X]9Vq=:@   91@ /̲]촍]0!533T9 >@  91@ /2̲]촍]0#5!533hՓL9 :@  91@ /̲]촍]0#5!53hL9+#1@%!$1@  #/2203432>3234&#"!4&#"!}x5%^qZHZlK--Xh|ŕnc%5@'#&1@  $/2220#53432>3234&#"!4&#"!}x5%^qZHZl[K--Xh|ŕnc#1@%!$1@  "/220#53432>324&#"!4&#"!}x5%^ZHZl[K--Xh&|ŕnc= -@   <<1@  /<<0!!5!3!!!KK?1@   <<1@  /2<<0#5!!5!3!!!KK? -@   <<1@  /<<0)5!!5!3!!@KK?=X>@ <<<<1@  /2<<<220%!!5!3!3!!!=KøL??XB@  <<<<1@  /22<<<220#5!!5!3!3!!!%!KøL=??>@  <<<<1@  /2<<<<<0)5!!5!3!3!!!0KøL=??Oq %@   1/203!3!$Uq"KOq *@    1@  /220#53!3!$U"Kq %@  1 /20)53!!kUޓK=C  1@ B/0KSX@Y!!!tFs0hB~ F  1@ B /20KSX@Y!5!!!tFlhhB~BC  1@ B/0KSX@Y!5!!tFlh0B~B+ 8@!  <<1@    /2<20327654'&+!!!2/!m]%i ; @ED\qQE=4."RJrCEoJRXErrJS9[ZZ 1SV/ { 2Ʀ1 "p_88_p`88*#5!5&'.4767675!5!!2>4."RJrCEoJRXErrJS9[ZZ 1SV/ { 2Ʀ1 "p_88_p`88O(#5!5&'.4767675!5!2>4."RJrCEoJRXErrJSQ[ZZ 1SV/ { 2Ʀ1 {"p_88_p`88Q %@   1/0!!#!3BQ *@  1@  /20#5!!#!3ԓ} %@   1/0#5!!#!+Q (@   <1 /0!!#3!3OQ -@   <1@   /20#5!!#3!3ԓ} (@    <1 /0#5!!#3!B /@   <<1@   /20!!!5!3z;  K"qѓB3@   <<1@  /220!53!!5!3z;7 K"ѓm /@    <<1@  /20!53!!5!z;7 K"ѓ+q &B@%(E# E'ܲ@ ]<<ܲ@]1@ # $ /<<02>4."&'.4767673! [ZZRJrCEoJRXErrJS"p_88_p`88~ 1SV/ { 2Ʀ1  (F@ *E#'E)ܲ@]<<ܲ@#]1@' (/2<<02>4."!5!5&'.4767673 [ZZlRJrCEoJRXErrJS"p_88_p`88 1SV/ { 2Ʀ1 O &B@(E# E&'ܲ@ ]<<ܲ@]1@ #  %/<<02>4."5&'.4767673!5 [ZZRJrCEoJRXErrJS0"p_88_p`88 1SV/ { 2Ʀ1 {q*!&'.4767675!5!!!2>4."RJrCEoJRNXErrJS9[ZZ 1SV/ 2Ʀ1 "p_88_p`88 ,%!5!5&'.4767675!5!!2>4."RJrCEoJRNXErrJSQ[ZZ 1SV/ 2Ʀ1 p_88_p`88O*)5!5&'.4767675!5!!2>4."0RJrCEoJRNXErrJSQ[ZZ 1SV/ 2Ʀ1 p_88_p`88 '' '' '' '' '' '' '' ''  :@   @ ? o ]9999991 2<0#'##'##'d2222222dddddV!#!3!3#3jժVV8`!##333#{}`9VVX{ %5#"&5332653!"&'5326Cuȸ||aQQRjBfca{+,*X10!5!-ЈX'3I(sInhX#'3h'OW`4X#'3v5]dDZX#'3 |;d07!X#(ẌI$@h$An4$B`$CnhX#7OhWh$Eh@4AnB`4X#7]vDdn4$J4E4@dAdZX%#7d|!70`$OnJEd@0<0^X133ֈXLt_<ƼHƼH3 r Um Q rZf55q=3=dd?y}s)3s\\?uLsLsyD{={\{fqqq/q999qqJ+o#7=V;=3X55^R\sd5^5bs#5`b?yyyyyys\;\\\3 LsLsLsLsLsLf {{{{{{{fqqqqq9999qqqqqqH==y{y{y{sfqsfqsfqsfq)q3 qqqqqq3sq3sq3sq3sqTx\9\9\9\9\9r\9?u9u9uuFLsqLsqLsqs/qJJJ+o+o+o+o#7#7#7DV={\3X{\3X{\3X/ }}ssfq3 }qqLu3s~\ 9 =LsNgvsq7r+d#7#7N={\3XTT\h3qT]hX\] ` d <qKsday{\9Lsqqy{y{{3sq3sq?LsqLsqTX9 ` d <q3squy{{LfHy{y{qq\9\9LsqLsqJJ+o#7,Gqqq{\3Xy{qLsqLsqLsqLsq=79qqy f u +o3XPP}  yq\9@sq J qefqqqqq|SA4Pq9qq q``9t*KM:+#qqGpPPOJI>>t+o7#7#7q=V=f3X3XXmXXXXLsPqq;VVqXXqvqq77:7/ <66JO<u1ufu]H^H 6&:uuuuuu  3s3soouuuuddLhuTzuuu%q7]yq$U $ zw(j#Lcxh!c+qc3x+x.pppp*pw<.::3efqesDy}uy{\Ls\?yLsLs{=LsN\FqSFq qSZkq=xJvkqJqqdGp;Gpq?qWWGpAOpLsq0q@GGrwxssFqU-~Od$s6sq,J7Opfq9Lsqs5UsssJs\\\T\J#y}}@e(!TLss#y{=6|<}o{p4kq5FA33L ;q;fq<=p;rR>Qdqtqq/4dq+o9998L07/3=;xs*` D3 GLsk7sS[2Lsq@R2@R2s<qsq pv9xssfq;XXX.j}!&4fG8=(5F!A!=2*ISsqsfq<=={=;yt|||\(5F?56].I6r|29y{y{{qLuqLuq(5F!ATX33LsqLsqLsqodq#=#=#=|4QfG8{=;{=;}q -qn6.3sGq/STL ZTL'AtLsqDVT>LLXv&tuA&7\\S&eLsR\Lsuu^x"6^Zq"qDq;' qqF92 F &q/qzw`DDcc/NDdc\\fcXCX.X0.XsXXEX.XXN*CCMXwBS(?99l9lC91***}} ffuuXK5k1CCOOLLLRLLLLLUL<L<LdL\W5kVz*******KKK))*CC1LLLRLLLRLjLL<L<Ld9qd==;;q;q=x==D=;==p==q==.qqB[B[{d{d7]xmxs[")>WE_IIY"~h~h@sx2OsOsxMo`P{P@@@@`NzBza\d>N c c]ccY]dji::PZ"ZPZ|ZPZ}PPZPZXZPPP|ZPP*FZnP\ZZZFdZWPPWFZdZddDPGd.e#edade%dvd-d/Cd$d/dWd/?d1<Nd/dBd/d-d-d/d/F.Z#d{ddddddd.nemdndyyyy'''''w'w'ww'w Xc^c^%H Ewyyyywwwwwwywwwwwwwwwyy^^^l4wl4w4y4yywyFFFF*F*F*FAA8F3F3FFFF*F*F*Fzzwuuuwwwuu&w&w&wwFF wwwFFGwyFyFFwFFFwwwFFGwy=Fy=FGwGw=F=FwFFFFFV+V+FFV+V+VY]YFFF"F"F"F"FGFGFGF F F F F wwww?w?w?wYSSwSwSSSFFFFYwyyyyMMwwdwSSyy4yFwwFFww```````FwFw     FFwwFF%w%!%!%w%w%!%!Y )#su` z    s 4 s 3  E p 2 O 3wq= {>fq$S9( 3qfyqyqy3/qqq222</=V3X5x=2ZLr u//SH||NYHG p+"M"M>G/Mmu>GVGVGTR>GnzhuuEuOGGOGOGmu\#=nnuV&7yGSG%nzu=nV&7yKySG%t9>GGGOGT_>G=nIzIIVz[quuIuEqOGOGFK\#^YGu@zV&7~77#7OG[[[[BBy{}}}sfq)q)q)q)q)qqqqqq/3sq\9\9???uMuMu9u9LsqLsqLsqLsqJJJJT+o+o+o+o+o#7#7#7#7y=y=DVDVDVDVDV{=;{=;={\3X{\3X{\3X#V={/&qy{y{y{y{y{y{y{y{y{y{y{y{qqqqqqqq\Z9D\9LsqLsqLsqLsqLsqLsqLsqNgvNgvNgvNgvNgv====FqFqFqFqFqFqFqFqyy'iSSSSSS0l7hx qqqqqqoE.k_FqFqSc<qqFqFqFqFqFqFqFqFqyy'i7hxk_FqFqFqFqFqFqFqyyy<pr\\D~{aNsVddddd%%%%9933W q q(()((()( 33?nn=V`Jd=n=dn8N(ffadp5Wnz5?5f5\5l5Y5S999og0u5W55^5b5?5f5\5l5Y5S999og"MVGOGuVGVs`u .;F_( ..D]1u!===P=&C&Cs#&<<oI HZ;jDN hR6nLsbBSV,y('y\XNND?yJ\}WJT9hgd(V FhZ $<|3uuWZ[O=;6Q^^b?fbfl\bya W{=w= =us)9~=}== ]=;;;9fqq y) ysedud    du,dudududvdvdd*ZZd-Opdduudwddxvxddddudud  dududuku7^H^^^@^^^uzz^uwududdud7u7y#_ZZ,dDX===,,ff+uPuuu+uPuuu+u+u+uyyy``>>**yyby*cc| a aXXJr;xxdxxd++* 8 8 P 8 x PFq 8#+7',,,,,,,,,,xxxxxxx||''''''''''''''''''''''q''''''''''llgg'''''''''''''''''pprppppppppp7p7Tpp''''3'''ppppp'''',h,d,,,,+,}}_}} ,,,B,d,,,,,,,,,,},,,dZd2E\,,,,,,,,,,,,,,,,,,,,,,,S,,,,,],,,,,m,,E,,,,A,,,U,,Q,0,,,U,,L,0,C,,X,,B,,X,,,x, ,,,,,,,,,,,,,,1,,,,,,,,,,,X,X,j,, T},y,},),,,,,d %6  dT YxEVIVVx+5X3ppppR >pTVSTWW/V0/0002p@TTTTpnnTVaaTT,f,z,z,z,z,xNNx>NnX~#9Uwlf,,,,,,,,,,                    uuuuuuuuuuuuuu++<uusunOss[YOO Bu xd xu xd xd xu xd xd xu xd xu xu,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,duwOwO::: u+u+u+u+u+u+u+u+u+u+u++u+u+u+u+k  77^^  7^uuHH''''$$"pMMu 9 u H#?{\3X@sy= DVh<GpPqbfr ,qssu@xC@~yyv{\{\ssg)?>8{\(oo:o\:o\csssss$d{=syNsNs6??,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,r+d pv9;<@>speKkT5L mLsqsq s&q:Bz<<|ff7S+o { { #{{{{seq#Sjxt  s&qu 9553wF\ Dq/ / ///}/o } <.VN1X?,XXuXXwwwwXCX.QX0QXsXXEXXXCMXwB.XsXX:j:j:j:j:j:jKH KH ************jj))k))k":jC:jp*XXXiXXXXXXXXXXX9p9lpl"9lplC:j9p:j1J:j:j*********}3}}3}jj 3# 3#  f^f^uBuuBu/KH 5kk kpSI:j1J8"CC:j..TT4,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,,c3s$f"=3LrDrlK{fqo/q5 "qqq+o7=HVhL=Xy}s)3s\?uLsLsyD{={\{fqqq/q999qqJ+o#7=V;=3XkZqAjds N:jH k :j:j:j********_9xxxxxxxxvxxvxxvxxxvxvxxxx,p:jj9Jqq9O99:::qd=dd=;;;;;;q;;;q=xxx==D=DD;;;====p==q======...qq,,,,,,,,.jn`#Zn`nn`n#Z`n3>?@<@<@ABPChDDFFGHIIJKPKLLM$MN0NO@OlOP$PQ|QQQRRSS0S`STUUUUVV8VPVhVVW|WWWXX<XlY4ZlZZZ[[[\\]]4]`]]____``$`<`T`x`bLbdb|bbbc chdde e,e\etffDfpffffgg,gDghggggghh,h<hii4iXi|iiiijj,jPjtjjjjjkk@kl lllm m0mTmxmmmn$nHnlnnnnoop$p<p`pxpppqdqrr<rTrlrrrsxtt@t`ttttu|vvvvww(wPwhwwwwwx$xHx`xxxxyLyzz4zdzzzz{{,{D{\{t{{{||$|<|T|l|||}}~~t8X|T`P0\t(@XD L@  8Ph0Pt4D\t<Tl $<Tl,D\t4Ld| $<Tl4xld| $<TlX8$ t,l,<äPňH,ȸhʤ<̌(x\ 0@\(԰ՔLLڐhܜX(ddL`lt` 0THX \hX, 0  T   < L d t   $      T $,@`|8L`|PpHT\,T(<Pd Lh@h<\ Dh$8  <    !!!,!@!T!!!""("t""##<#####$$$,$P$x$$%<%%&&(&(&h&&&&'L'`'t''( (4(\(l(|(() )<)L)\)))))*0*`*x*****++(+@+P+`+,,,$,4,,--h-x---...../t/00011(1@1X1p123t3456L6778`889:@:P:;`< <==>L?X?@@@@@@A8BBChCCDdEEFxG$GHdHtI$IIJhJKLMHMNOpOPXQ QRPRSXST`UU(U8UHUV$V4VDVTW$WX0X@XXXpXY(YYZxZZZZ[P[\P\h\\\]]]]^T^d_X```aabbb bhbxbbcccd8dde\eefhgghphiHijjjklhlmmnnnno@oPo`ooppqqqrHrrsLstu$u<uvvw<wLw\wlw|xxy<yTylyyzz{d{||}<}|}~0x<Tlxh4\,TXt8Ph<\8, ,`$pl<8(d@P|$Hl|,<Tl0H`x 8x(xl<<$<HXhh4 x 0@PT0`l|ìDx\ƸXǠȨ@0ʤ@˰,̘̈́,<Πΰ hx(8TdҸӬ8h֠ה،(٠|p݀l,<hx`tLd P0X@hx0LxLl(\ |@0 ,4<  T0PL4Ph0H0H(DP|`0L  T h |    H  H   H   D   @D\t $<Tl$D\lT8HXhD$hT `XDd@4  l!!`!"0"##d#$$%X%%%&P&''l''((X(()$)*+\,,-`.<//0X1123 345<6678889:L;;<=l=>>??4?@@AALAB,BC@CCDpEEF<FdFGGGH4HIIJJKDLLtMxMNOP`PQ,QRRRSlST TUUVPVWWWXLY YYZ,Z|[[P[\H\]h]^^`^_t_`(`aDab$bccd dxde$ef,ffg`gh<hhiPijLjk,klllmDmn(noop(pqq|qrhrs8sstttttu4uLudu|uvvv4vLvdv|vvvvvw w$w<wTwlwwwwxxDxxyy4y|yyyzzz0zHz`zpzzz{{,{D{\{{{|| |8|P|h||||||}}(}@}}}}~h~~0(@XptPh|,D\t4Ld|$x,D $< $<Tll,D|4Ld| $<xt $D\tT<T,D(@Xp8t8P,D\t4Ld| d| 8Phl8P8Ph(@Xp(d<40Xp(@ $<$D\ $h`x(@Xp8< $<Tl $8P $`x <4Ld|D0l4`$h,LPÄü TdŬ4$4l|njǜǬ\ɨ\<Lˈ(̜̬̼<Lẗ́$p<lϜ <XЈмDtҐHpӴl\4֘tذ@,\H܄ܼ `ݬtޜ4߼8dx \`tH`00$$tT$Th<\0H`x 8Ph(@Xx(@Xp0H`x(@Xp0H`x 8Xp0H`x 8Xx 8Ph(@Xp0H`x 8Ph(@Xp 0H`x 8Ph(@Xp0H`x(@Xp0H`x(@Xp0H`x 8Ph  ( @ X p       $ < T l        8 T p        0 L h       $ < T l      8Tp 8Ph4Ld|0H`x(D`|(8P`x(@Xp0H`x 8Ph(@Xp0H`x 0HXh0H`x4Ld|4Ld|4Lhx,D`p00000000000000000\l  0 H   !!x!"0"d"#@###$$X$p$p$p$p$p$p$p%' ','D'd''''(L(() )))*\***++@+p+++,(,`,,,---8-\--.$.X../ /0/l/00<0<0<0<0<0<0<0<0<0<0<0<0<0012D223484l4445$55555566$686L6`6t666666777(78L899::;p<@<=P=h??d?AHAB|CC|DDDDEEDE|EEFGHH IHIJ|JJJKLM8MMNO4PPQQTSTUXUVhWX|Y,ZDZ[[\x\] ]x]]^^^^_`a$abhcHctde ef@fgDghhiiijjTjjkk4klhmm@mn@nnnnoo0oPopoooopp(p8pPpppppppqq q8qXqhqxqqqqqqrr r@rhrrrrrrrssuuuvvwhxxy{ {<{l{{||d} }~~L~~,xDPL<th$8P<Xt hP8x80p0p( h<x@8d8|t\8tH|<4,488<P`@`0dP|$txX0dt8dLTx( $Dd$\Ph Ōƨ0ǘDȈ|$ʐ|̨\͠t8pФ0ѠTҘpԐ|H`Dx׬xH۸ܠ݄DH߄ \ P@\h4 \0d@@t$ddXT(`l0|l84hT4lDxT@`8`8Xx(tx 0    0 @ P    H d    ( H d      t  X(T| #\%%&&&8&l&&''P''($(H(l(((() )D)d))))**0*T*|***+$+T++++,$,P,x,,,-$-P-|---.$.L.p...//D/p///000d001181p1122H2|223343`3334444h4445 5L5556 6<6p6677X777808`889,999:$:X:x:::; ;(;D;`;|;;;<<$>>ABBBBBBCC(CDC`CtCCCCDDD\DEFPFG`I I<IhIIIIJJLJhJJJJKK8KdKKKKLL<LXLLLLMM4MhMN<NNOPQ`QRRtRS,SST T4TpTU<UUUVVDVVVWWW4W|WWWX$X`XXXYdYYZ$ZdZ[d[\d\\\]]$]P]l]^^_hkpkl l\lmTn noPorxuXuvv|vx4yz(z\{P|$|}T~~hl0x4(Hh\,XhXlx|LdL8   ,pp8 h,` ,hhŒİńƐ $0όLҨӜӸ(@Ք֌8\٠DL4<p|t(p8|<P(@D8`,p | t  ( d   8  4pTdX40\ x8 "#%'P)/0T23h405689h:<==>X>?(????@ @l@@AxBBC<CDEF$FFG G4G`GGGHH4H`HI(IJPKLM0NO8QSTUXV\WtXPYPZh[4\`]x^_(_`a,abccdeeeff4fdfgg@gghh@hphhi0i\iijjpjk k\kl lxmmtmnno op|q r4s`stLttuuPuxuuuv(v|w@xxyz\{|{{|X||}}h}}~~~0~D~`~|~~~~,Pt,Pt0T,Pl Dp <`,`<p,Pl Dp <`,`<p Dp Dp0dP| L$`,Pl Dp <`,`<p Dp Dp0dP| L$` Dp Dp0dP| L$`0\$`0d L$`P P,x|\ T8lPx\tPlpT8PhdDHh(Đ0lńŜ(p8ǴHdɬTʴ\H(Ϩ<Є\Ѹ0\҈ҴPӄӼ(TԀԬ4dՔ@d֠ 8tט\(dpۀP܄ܸPݠ$ޔT|ߤ$p 4`(   LH t<HX4H,l8 t@PD @Ph(@Xp0H`x 8Ph(@Xp0H`x 8P`pl4L,|d  @     h      h  Xh0X8\$Pd$T0hXxl$Px\<\|@d "%d%&','()L)*+,8,-.L.d../(///0$0d0011X1p1111122202H2`2x2222233 383P3h33333344(4@4X44455505H5`5x5555566 686P6h66666677(7@7X7p7777788808H8`8x8888899 989P9h999:T:d:t:::::;\;t;;;< <<4 > >8>L>d>x>>>>>???0?H?`?x????@@@4@L@d@|@@@@@A A$A<ATAlAAAABXBCDC\CtCCCDD0DHDXDDDDEFPFGG G8GPG`H<HIlIIIIIJ`JKPKhKKKKLHLM0MHM`MxMMMMMNN N8NPN`O,OP P0PPQQ,QR<RRRSS,S<STpUUUUVXVpVVVVVWWW0WHWXXXXXXXXXYYY8YTY|YYYZ ZLZtZZZ[[@[h[[[\ \4\\\\\]],]T]|]]]^ ^H^p^^^__<_d___` `4`\```aa(aPa|aaabbDbpbbbcc<cdcccdd0d\dddde$ePexeeeffDfg gghhhii`iijk$k\kl ltlmmnPnodopDq qqrrXrs`st`tuuvw wwxxpxyyy$y4yDyTydytyyyyyyyyzzz$z4zDzTzdztzzzzzzzz{{{${4{D{T{d{t{{{{{{{{|||$|4|D||}~~`~\t 0@P`p,@  \$H x0(@Xp @`p0Lh,Hd$\t(Hh,X\x 8pxHthHDP(D`dt hp$PlxHltTT xX4H\4X|$`<`„¤¸,@ThÌàô(<XĀZT+h >2   : `   (Z4;b ;; 0    " F m " : %: h: ; ;Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. DejaVu changes are in public domain Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. DejaVu changes are in public domain DejaVu SansDejaVu SansBookBookDejaVu SansDejaVu SansDejaVu SansDejaVu SansVersion 2.30Version 2.30DejaVuSansDejaVuSansDejaVu fonts teamDejaVu fonts teamhttp://dejavu.sourceforge.nethttp://dejavu.sourceforge.netFonts are (c) Bitstream (see below). DejaVu changes are in public domain. Glyphs imported from Arev fonts are (c) Tavmjung Bah (see below) Bitstream Vera Fonts Copyright ------------------------------ Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org. Arev Fonts Copyright ------------------------------ Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the modifications to the Bitstream Vera Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Tavmjong Bah" or the word "Arev". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Tavmjong Bah Arev" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the name of Tavmjong Bah shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from Tavmjong Bah. For further information, contact: tavmjong @ free . fr.Fonts are (c) Bitstream (see below). DejaVu changes are in public domain. Glyphs imported from Arev fonts are (c) Tavmjung Bah (see below) Bitstream Vera Fonts Copyright ------------------------------ Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Bitstream" or the word "Vera". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Bitstream Vera" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the names of Gnome, the Gnome Foundation, and Bitstream Inc., shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from the Gnome Foundation or Bitstream Inc., respectively. For further information, contact: fonts at gnome dot org. Arev Fonts Copyright ------------------------------ Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved. Permission is hereby granted, free of charge, to any person obtaining a copy of the fonts accompanying this license ("Fonts") and associated documentation files (the "Font Software"), to reproduce and distribute the modifications to the Bitstream Vera Font Software, including without limitation the rights to use, copy, merge, publish, distribute, and/or sell copies of the Font Software, and to permit persons to whom the Font Software is furnished to do so, subject to the following conditions: The above copyright and trademark notices and this permission notice shall be included in all copies of one or more of the Font Software typefaces. The Font Software may be modified, altered, or added to, and in particular the designs of glyphs or characters in the Fonts may be modified and additional glyphs or characters may be added to the Fonts, only if the fonts are renamed to names not containing either the words "Tavmjong Bah" or the word "Arev". This License becomes null and void to the extent applicable to Fonts or Font Software that has been modified and is distributed under the "Tavmjong Bah Arev" names. The Font Software may be sold as part of a larger software package but no copy of one or more of the Font Software typefaces may be sold by itself. THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE. Except as contained in this notice, the name of Tavmjong Bah shall not be used in advertising or otherwise to promote the sale, use or other dealings in this Font Software without prior written authorization from Tavmjong Bah. For further information, contact: tavmjong @ free . fr.http://dejavu.sourceforge.net/wiki/index.php/Licensehttp://dejavu.sourceforge.net/wiki/index.php/LicenseDejaVu SansDejaVu SansBookBook~ZZ  !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghjikmlnoqprsutvwxzy{}|~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~                           ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~                            ! " # $ % & ' ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ ` a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~        !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~      !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ sfthyphenAmacronamacronAbreveabreveAogonekaogonek Ccircumflex ccircumflex Cdotaccent cdotaccentDcarondcaronDcroatEmacronemacronEbreveebreve Edotaccent edotaccentEogonekeogonekEcaronecaron Gcircumflex gcircumflex Gdotaccent gdotaccent Gcommaaccent gcommaaccent Hcircumflex hcircumflexHbarhbarItildeitildeImacronimacronIbreveibreveIogonekiogonekIJij Jcircumflex jcircumflex Kcommaaccent kcommaaccent kgreenlandicLacutelacute Lcommaaccent lcommaaccentLcaronlcaronLdotldotNacutenacute Ncommaaccent ncommaaccentNcaronncaron napostropheEngengOmacronomacronObreveobreve Ohungarumlaut ohungarumlautRacuteracute Rcommaaccent rcommaaccentRcaronrcaronSacutesacute Scircumflex scircumflex Tcommaaccent tcommaaccentTcarontcaronTbartbarUtildeutildeUmacronumacronUbreveubreveUringuring Uhungarumlaut uhungarumlautUogonekuogonek Wcircumflex wcircumflex Ycircumflex ycircumflexZacutezacute Zdotaccent zdotaccentlongsuni0180uni0181uni0182uni0183uni0184uni0185uni0186uni0187uni0188uni0189uni018Auni018Buni018Cuni018Duni018Euni018Funi0190uni0191uni0193uni0194uni0195uni0196uni0197uni0198uni0199uni019Auni019Buni019Cuni019Duni019Euni019FOhornohornuni01A2uni01A3uni01A4uni01A5uni01A6uni01A7uni01A8uni01A9uni01AAuni01ABuni01ACuni01ADuni01AEUhornuhornuni01B1uni01B2uni01B3uni01B4uni01B5uni01B6uni01B7uni01B8uni01B9uni01BAuni01BBuni01BCuni01BDuni01BEuni01BFuni01C0uni01C1uni01C2uni01C3uni01C4uni01C5uni01C6uni01C7uni01C8uni01C9uni01CAuni01CBuni01CCuni01CDuni01CEuni01CFuni01D0uni01D1uni01D2uni01D3uni01D4uni01D5uni01D6uni01D7uni01D8uni01D9uni01DAuni01DBuni01DCuni01DDuni01DEuni01DFuni01E0uni01E1uni01E2uni01E3uni01E4uni01E5Gcarongcaronuni01E8uni01E9uni01EAuni01EBuni01ECuni01EDuni01EEuni01EFuni01F0uni01F1uni01F2uni01F3uni01F4uni01F5uni01F6uni01F7uni01F8uni01F9 Aringacute aringacuteAEacuteaeacute Oslashacute oslashacuteuni0200uni0201uni0202uni0203uni0204uni0205uni0206uni0207uni0208uni0209uni020Auni020Buni020Cuni020Duni020Euni020Funi0210uni0211uni0212uni0213uni0214uni0215uni0216uni0217 Scommaaccent scommaaccentuni021Auni021Buni021Cuni021Duni021Euni021Funi0220uni0221uni0222uni0223uni0224uni0225uni0226uni0227uni0228uni0229uni022Auni022Buni022Cuni022Duni022Euni022Funi0230uni0231uni0232uni0233uni0234uni0235uni0236dotlessjuni0238uni0239uni023Auni023Buni023Cuni023Duni023Euni023Funi0240uni0241uni0242uni0243uni0244uni0245uni0246uni0247uni0248uni0249uni024Auni024Buni024Cuni024Duni024Euni024Funi0250uni0251uni0252uni0253uni0254uni0255uni0256uni0257uni0258uni0259uni025Auni025Buni025Cuni025Duni025Euni025Funi0260uni0261uni0262uni0263uni0264uni0265uni0266uni0267uni0268uni0269uni026Auni026Buni026Cuni026Duni026Euni026Funi0270uni0271uni0272uni0273uni0274uni0275uni0276uni0277uni0278uni0279uni027Auni027Buni027Cuni027Duni027Euni027Funi0280uni0281uni0282uni0283uni0284uni0285uni0286uni0287uni0288uni0289uni028Auni028Buni028Cuni028Duni028Euni028Funi0290uni0291uni0292uni0293uni0294uni0295uni0296uni0297uni0298uni0299uni029Auni029Buni029Cuni029Duni029Euni029Funi02A0uni02A1uni02A2uni02A3uni02A4uni02A5uni02A6uni02A7uni02A8uni02A9uni02AAuni02ABuni02ACuni02ADuni02AEuni02AFuni02B0uni02B1uni02B2uni02B3uni02B4uni02B5uni02B6uni02B7uni02B8uni02B9uni02BAuni02BBuni02BCuni02BDuni02BEuni02BFuni02C0uni02C1uni02C2uni02C3uni02C4uni02C5uni02C8uni02C9uni02CAuni02CBuni02CCuni02CDuni02CEuni02CFuni02D0uni02D1uni02D2uni02D3uni02D4uni02D5uni02D6uni02D7uni02DEuni02DFuni02E0uni02E1uni02E2uni02E3uni02E4uni02E5uni02E6uni02E7uni02E8uni02E9uni02ECuni02EDuni02EEuni02F3uni02F7 gravecomb acutecombuni0302 tildecombuni0304uni0305uni0306uni0307uni0308 hookabovecombuni030Auni030Buni030Cuni030Duni030Euni030Funi0310uni0311uni0312uni0313uni0314uni0315uni0316uni0317uni0318uni0319uni031Auni031Buni031Cuni031Duni031Euni031Funi0320uni0321uni0322 dotbelowcombuni0324uni0325uni0326uni0327uni0328uni0329uni032Auni032Buni032Cuni032Duni032Euni032Funi0330uni0331uni0332uni0333uni0334uni0335uni0336uni0337uni0338uni0339uni033Auni033Buni033Cuni033Duni033Euni033Funi0340uni0341uni0342uni0343uni0344uni0345uni0346uni0347uni0348uni0349uni034Auni034Buni034Cuni034Duni034Euni034Funi0351uni0352uni0353uni0357uni0358uni035Auni035Cuni035Duni035Euni035Funi0360uni0361uni0362uni0370uni0371uni0372uni0373uni0374uni0375uni0376uni0377uni037Auni037Buni037Cuni037Duni037Etonos dieresistonos Alphatonos anoteleia EpsilontonosEtatonos Iotatonos Omicrontonos Upsilontonos OmegatonosiotadieresistonosAlphaBetaGammauni0394EpsilonZetaEtaThetaIotaKappaLambdaMuNuXiOmicronPiRhoSigmaTauUpsilonPhiChiPsi IotadieresisUpsilondieresis alphatonos epsilontonosetatonos iotatonosupsilondieresistonosalphabetagammadeltaepsilonzetaetathetaiotakappalambdauni03BCnuxiomicronrhosigma1sigmatauupsilonphichipsiomega iotadieresisupsilondieresis omicrontonos upsilontonos omegatonosuni03CFuni03D0theta1Upsilon1uni03D3uni03D4phi1omega1uni03D7uni03D8uni03D9uni03DAuni03DBuni03DCuni03DDuni03DEuni03DFuni03E0uni03E1uni03E2uni03E3uni03E4uni03E5uni03E6uni03E7uni03E8uni03E9uni03EAuni03EBuni03ECuni03EDuni03EEuni03EFuni03F0uni03F1uni03F2uni03F3uni03F4uni03F5uni03F6uni03F7uni03F8uni03F9uni03FAuni03FBuni03FCuni03FDuni03FEuni03FFuni0400uni0401uni0402uni0403uni0404uni0405uni0406uni0407uni0408uni0409uni040Auni040Buni040Cuni040Duni040Euni040Funi0410uni0411uni0412uni0413uni0414uni0415uni0416uni0417uni0418uni0419uni041Auni041Buni041Cuni041Duni041Euni041Funi0420uni0421uni0422uni0423uni0424uni0425uni0426uni0427uni0428uni0429uni042Auni042Buni042Cuni042Duni042Euni042Funi0430uni0431uni0432uni0433uni0434uni0435uni0436uni0437uni0438uni0439uni043Auni043Buni043Cuni043Duni043Euni043Funi0440uni0441uni0442uni0443uni0444uni0445uni0446uni0447uni0448uni0449uni044Auni044Buni044Cuni044Duni044Euni044Funi0450uni0451uni0452uni0453uni0454uni0455uni0456uni0457uni0458uni0459uni045Auni045Buni045Cuni045Duni045Euni045Funi0460uni0461uni0462uni0463uni0464uni0465uni0466uni0467uni0468uni0469uni046Auni046Buni046Cuni046Duni046Euni046Funi0470uni0471uni0472uni0473uni0474uni0475uni0476uni0477uni0478uni0479uni047Auni047Buni047Cuni047Duni047Euni047Funi0480uni0481uni0482uni0483uni0484uni0485uni0486uni0487uni0488uni0489uni048Auni048Buni048Cuni048Duni048Euni048Funi0490uni0491uni0492uni0493uni0494uni0495uni0496uni0497uni0498uni0499uni049Auni049Buni049Cuni049Duni049Euni049Funi04A0uni04A1uni04A2uni04A3uni04A4uni04A5uni04A6uni04A7uni04A8uni04A9uni04AAuni04ABuni04ACuni04ADuni04AEuni04AFuni04B0uni04B1uni04B2uni04B3uni04B4uni04B5uni04B6uni04B7uni04B8uni04B9uni04BAuni04BBuni04BCuni04BDuni04BEuni04BFuni04C0uni04C1uni04C2uni04C3uni04C4uni04C5uni04C6uni04C7uni04C8uni04C9uni04CAuni04CBuni04CCuni04CDuni04CEuni04CFuni04D0uni04D1uni04D2uni04D3uni04D4uni04D5uni04D6uni04D7uni04D8uni04D9uni04DAuni04DBuni04DCuni04DDuni04DEuni04DFuni04E0uni04E1uni04E2uni04E3uni04E4uni04E5uni04E6uni04E7uni04E8uni04E9uni04EAuni04EBuni04ECuni04EDuni04EEuni04EFuni04F0uni04F1uni04F2uni04F3uni04F4uni04F5uni04F6uni04F7uni04F8uni04F9uni04FAuni04FBuni04FCuni04FDuni04FEuni04FFuni0500uni0501uni0502uni0503uni0504uni0505uni0506uni0507uni0508uni0509uni050Auni050Buni050Cuni050Duni050Euni050Funi0510uni0511uni0512uni0513uni0514uni0515uni0516uni0517uni0518uni0519uni051Auni051Buni051Cuni051Duni0520uni0521uni0522uni0523uni0524uni0525uni0531uni0532uni0533uni0534uni0535uni0536uni0537uni0538uni0539uni053Auni053Buni053Cuni053Duni053Euni053Funi0540uni0541uni0542uni0543uni0544uni0545uni0546uni0547uni0548uni0549uni054Auni054Buni054Cuni054Duni054Euni054Funi0550uni0551uni0552uni0553uni0554uni0555uni0556uni0559uni055Auni055Buni055Cuni055Duni055Euni055Funi0561uni0562uni0563uni0564uni0565uni0566uni0567uni0568uni0569uni056Auni056Buni056Cuni056Duni056Euni056Funi0570uni0571uni0572uni0573uni0574uni0575uni0576uni0577uni0578uni0579uni057Auni057Buni057Cuni057Duni057Euni057Funi0580uni0581uni0582uni0583uni0584uni0585uni0586uni0587uni0589uni058Auni05B0uni05B1uni05B2uni05B3uni05B4uni05B5uni05B6uni05B7uni05B8uni05B9uni05BAuni05BBuni05BCuni05BDuni05BEuni05BFuni05C0uni05C1uni05C2uni05C3uni05C6uni05C7uni05D0uni05D1uni05D2uni05D3uni05D4uni05D5uni05D6uni05D7uni05D8uni05D9uni05DAuni05DBuni05DCuni05DDuni05DEuni05DFuni05E0uni05E1uni05E2uni05E3uni05E4uni05E5uni05E6uni05E7uni05E8uni05E9uni05EAuni05F0uni05F1uni05F2uni05F3uni05F4uni0606uni0607uni0609uni060Auni060Cuni0615uni061Buni061Funi0621uni0622uni0623uni0624uni0625uni0626uni0627uni0628uni0629uni062Auni062Buni062Cuni062Duni062Euni062Funi0630uni0631uni0632uni0633uni0634uni0635uni0636uni0637uni0638uni0639uni063Auni0640uni0641uni0642uni0643uni0644uni0645uni0646uni0647uni0648uni0649uni064Auni064Buni064Cuni064Duni064Euni064Funi0650uni0651uni0652uni0653uni0654uni0655uni065Auni0660uni0661uni0662uni0663uni0664uni0665uni0666uni0667uni0668uni0669uni066Auni066Buni066Cuni066Duni066Euni066Funi0674uni0679uni067Auni067Buni067Cuni067Duni067Euni067Funi0680uni0681uni0682uni0683uni0684uni0685uni0686uni0687uni0691uni0692uni0695uni0698uni06A1uni06A4uni06A6uni06A9uni06AFuni06B5uni06BAuni06BFuni06C6uni06CCuni06CEuni06D5uni06F0uni06F1uni06F2uni06F3uni06F4uni06F5uni06F6uni06F7uni06F8uni06F9uni07C0uni07C1uni07C2uni07C3uni07C4uni07C5uni07C6uni07C7uni07C8uni07C9uni07CAuni07CBuni07CCuni07CDuni07CEuni07CFuni07D0uni07D1uni07D2uni07D3uni07D4uni07D5uni07D6uni07D7uni07D8uni07D9uni07DAuni07DBuni07DCuni07DDuni07DEuni07DFuni07E0uni07E1uni07E2uni07E3uni07E4uni07E5uni07E6uni07E7uni07EBuni07ECuni07EDuni07EEuni07EFuni07F0uni07F1uni07F2uni07F3uni07F4uni07F5uni07F8uni07F9uni07FAuni0E3Funi0E81uni0E82uni0E84uni0E87uni0E88uni0E8Auni0E8Duni0E94uni0E95uni0E96uni0E97uni0E99uni0E9Auni0E9Buni0E9Cuni0E9Duni0E9Euni0E9Funi0EA1uni0EA2uni0EA3uni0EA5uni0EA7uni0EAAuni0EABuni0EADuni0EAEuni0EAFuni0EB0uni0EB1uni0EB2uni0EB3uni0EB4uni0EB5uni0EB6uni0EB7uni0EB8uni0EB9uni0EBBuni0EBCuni0EBDuni0EC0uni0EC1uni0EC2uni0EC3uni0EC4uni0EC6uni0EC8uni0EC9uni0ECAuni0ECBuni0ECCuni0ECDuni0ED0uni0ED1uni0ED2uni0ED3uni0ED4uni0ED5uni0ED6uni0ED7uni0ED8uni0ED9uni0EDCuni0EDDuni10A0uni10A1uni10A2uni10A3uni10A4uni10A5uni10A6uni10A7uni10A8uni10A9uni10AAuni10ABuni10ACuni10ADuni10AEuni10AFuni10B0uni10B1uni10B2uni10B3uni10B4uni10B5uni10B6uni10B7uni10B8uni10B9uni10BAuni10BBuni10BCuni10BDuni10BEuni10BFuni10C0uni10C1uni10C2uni10C3uni10C4uni10C5uni10D0uni10D1uni10D2uni10D3uni10D4uni10D5uni10D6uni10D7uni10D8uni10D9uni10DAuni10DBuni10DCuni10DDuni10DEuni10DFuni10E0uni10E1uni10E2uni10E3uni10E4uni10E5uni10E6uni10E7uni10E8uni10E9uni10EAuni10EBuni10ECuni10EDuni10EEuni10EFuni10F0uni10F1uni10F2uni10F3uni10F4uni10F5uni10F6uni10F7uni10F8uni10F9uni10FAuni10FBuni10FCuni1401uni1402uni1403uni1404uni1405uni1406uni1407uni1409uni140Auni140Buni140Cuni140Duni140Euni140Funi1410uni1411uni1412uni1413uni1414uni1415uni1416uni1417uni1418uni1419uni141Auni141Buni141Duni141Euni141Funi1420uni1421uni1422uni1423uni1424uni1425uni1426uni1427uni1428uni1429uni142Auni142Buni142Cuni142Duni142Euni142Funi1430uni1431uni1432uni1433uni1434uni1435uni1437uni1438uni1439uni143Auni143Buni143Cuni143Duni143Euni143Funi1440uni1441uni1442uni1443uni1444uni1445uni1446uni1447uni1448uni1449uni144Auni144Cuni144Duni144Euni144Funi1450uni1451uni1452uni1454uni1455uni1456uni1457uni1458uni1459uni145Auni145Buni145Cuni145Duni145Euni145Funi1460uni1461uni1462uni1463uni1464uni1465uni1466uni1467uni1468uni1469uni146Auni146Buni146Cuni146Duni146Euni146Funi1470uni1471uni1472uni1473uni1474uni1475uni1476uni1477uni1478uni1479uni147Auni147Buni147Cuni147Duni147Euni147Funi1480uni1481uni1482uni1483uni1484uni1485uni1486uni1487uni1488uni1489uni148Auni148Buni148Cuni148Duni148Euni148Funi1490uni1491uni1492uni1493uni1494uni1495uni1496uni1497uni1498uni1499uni149Auni149Buni149Cuni149Duni149Euni149Funi14A0uni14A1uni14A2uni14A3uni14A4uni14A5uni14A6uni14A7uni14A8uni14A9uni14AAuni14ABuni14ACuni14ADuni14AEuni14AFuni14B0uni14B1uni14B2uni14B3uni14B4uni14B5uni14B6uni14B7uni14B8uni14B9uni14BAuni14BBuni14BCuni14BDuni14C0uni14C1uni14C2uni14C3uni14C4uni14C5uni14C6uni14C7uni14C8uni14C9uni14CAuni14CBuni14CCuni14CDuni14CEuni14CFuni14D0uni14D1uni14D2uni14D3uni14D4uni14D5uni14D6uni14D7uni14D8uni14D9uni14DAuni14DBuni14DCuni14DDuni14DEuni14DFuni14E0uni14E1uni14E2uni14E3uni14E4uni14E5uni14E6uni14E7uni14E8uni14E9uni14EAuni14ECuni14EDuni14EEuni14EFuni14F0uni14F1uni14F2uni14F3uni14F4uni14F5uni14F6uni14F7uni14F8uni14F9uni14FAuni14FBuni14FCuni14FDuni14FEuni14FFuni1500uni1501uni1502uni1503uni1504uni1505uni1506uni1507uni1510uni1511uni1512uni1513uni1514uni1515uni1516uni1517uni1518uni1519uni151Auni151Buni151Cuni151Duni151Euni151Funi1520uni1521uni1522uni1523uni1524uni1525uni1526uni1527uni1528uni1529uni152Auni152Buni152Cuni152Duni152Euni152Funi1530uni1531uni1532uni1533uni1534uni1535uni1536uni1537uni1538uni1539uni153Auni153Buni153Cuni153Duni153Euni1540uni1541uni1542uni1543uni1544uni1545uni1546uni1547uni1548uni1549uni154Auni154Buni154Cuni154Duni154Euni154Funi1550uni1552uni1553uni1554uni1555uni1556uni1557uni1558uni1559uni155Auni155Buni155Cuni155Duni155Euni155Funi1560uni1561uni1562uni1563uni1564uni1565uni1566uni1567uni1568uni1569uni156Auni1574uni1575uni1576uni1577uni1578uni1579uni157Auni157Buni157Cuni157Duni157Euni157Funi1580uni1581uni1582uni1583uni1584uni1585uni158Auni158Buni158Cuni158Duni158Euni158Funi1590uni1591uni1592uni1593uni1594uni1595uni1596uni15A0uni15A1uni15A2uni15A3uni15A4uni15A5uni15A6uni15A7uni15A8uni15A9uni15AAuni15ABuni15ACuni15ADuni15AEuni15AFuni15DEuni15E1uni1646uni1647uni166Euni166Funi1670uni1671uni1672uni1673uni1674uni1675uni1676uni1680uni1681uni1682uni1683uni1684uni1685uni1686uni1687uni1688uni1689uni168Auni168Buni168Cuni168Duni168Euni168Funi1690uni1691uni1692uni1693uni1694uni1695uni1696uni1697uni1698uni1699uni169Auni169Buni169Cuni1D00uni1D01uni1D02uni1D03uni1D04uni1D05uni1D06uni1D07uni1D08uni1D09uni1D0Auni1D0Buni1D0Cuni1D0Duni1D0Euni1D0Funi1D10uni1D11uni1D12uni1D13uni1D14uni1D16uni1D17uni1D18uni1D19uni1D1Auni1D1Buni1D1Cuni1D1Duni1D1Euni1D1Funi1D20uni1D21uni1D22uni1D23uni1D26uni1D27uni1D28uni1D29uni1D2Auni1D2Buni1D2Cuni1D2Duni1D2Euni1D30uni1D31uni1D32uni1D33uni1D34uni1D35uni1D36uni1D37uni1D38uni1D39uni1D3Auni1D3Buni1D3Cuni1D3Duni1D3Euni1D3Funi1D40uni1D41uni1D42uni1D43uni1D44uni1D45uni1D46uni1D47uni1D48uni1D49uni1D4Auni1D4Buni1D4Cuni1D4Duni1D4Euni1D4Funi1D50uni1D51uni1D52uni1D53uni1D54uni1D55uni1D56uni1D57uni1D58uni1D59uni1D5Auni1D5Buni1D5Duni1D5Euni1D5Funi1D60uni1D61uni1D62uni1D63uni1D64uni1D65uni1D66uni1D67uni1D68uni1D69uni1D6Auni1D77uni1D78uni1D7Buni1D85uni1D9Buni1D9Cuni1D9Duni1D9Euni1D9Funi1DA0uni1DA1uni1DA2uni1DA3uni1DA4uni1DA5uni1DA6uni1DA7uni1DA8uni1DA9uni1DAAuni1DABuni1DACuni1DADuni1DAEuni1DAFuni1DB0uni1DB1uni1DB2uni1DB3uni1DB4uni1DB5uni1DB6uni1DB7uni1DB8uni1DB9uni1DBAuni1DBBuni1DBCuni1DBDuni1DBEuni1DBFuni1DC4uni1DC5uni1DC6uni1DC7uni1DC8uni1DC9uni1E00uni1E01uni1E02uni1E03uni1E04uni1E05uni1E06uni1E07uni1E08uni1E09uni1E0Auni1E0Buni1E0Cuni1E0Duni1E0Euni1E0Funi1E10uni1E11uni1E12uni1E13uni1E14uni1E15uni1E16uni1E17uni1E18uni1E19uni1E1Auni1E1Buni1E1Cuni1E1Duni1E1Euni1E1Funi1E20uni1E21uni1E22uni1E23uni1E24uni1E25uni1E26uni1E27uni1E28uni1E29uni1E2Auni1E2Buni1E2Cuni1E2Duni1E2Euni1E2Funi1E30uni1E31uni1E32uni1E33uni1E34uni1E35uni1E36uni1E37uni1E38uni1E39uni1E3Auni1E3Buni1E3Cuni1E3Duni1E3Euni1E3Funi1E40uni1E41uni1E42uni1E43uni1E44uni1E45uni1E46uni1E47uni1E48uni1E49uni1E4Auni1E4Buni1E4Cuni1E4Duni1E4Euni1E4Funi1E50uni1E51uni1E52uni1E53uni1E54uni1E55uni1E56uni1E57uni1E58uni1E59uni1E5Auni1E5Buni1E5Cuni1E5Duni1E5Euni1E5Funi1E60uni1E61uni1E62uni1E63uni1E64uni1E65uni1E66uni1E67uni1E68uni1E69uni1E6Auni1E6Buni1E6Cuni1E6Duni1E6Euni1E6Funi1E70uni1E71uni1E72uni1E73uni1E74uni1E75uni1E76uni1E77uni1E78uni1E79uni1E7Auni1E7Buni1E7Cuni1E7Duni1E7Euni1E7FWgravewgraveWacutewacute Wdieresis wdieresisuni1E86uni1E87uni1E88uni1E89uni1E8Auni1E8Buni1E8Cuni1E8Duni1E8Euni1E8Funi1E90uni1E91uni1E92uni1E93uni1E94uni1E95uni1E96uni1E97uni1E98uni1E99uni1E9Auni1E9Buni1E9Euni1E9Funi1EA0uni1EA1uni1EA2uni1EA3uni1EA4uni1EA5uni1EA6uni1EA7uni1EA8uni1EA9uni1EAAuni1EABuni1EACuni1EADuni1EAEuni1EAFuni1EB0uni1EB1uni1EB2uni1EB3uni1EB4uni1EB5uni1EB6uni1EB7uni1EB8uni1EB9uni1EBAuni1EBBuni1EBCuni1EBDuni1EBEuni1EBFuni1EC0uni1EC1uni1EC2uni1EC3uni1EC4uni1EC5uni1EC6uni1EC7uni1EC8uni1EC9uni1ECAuni1ECBuni1ECCuni1ECDuni1ECEuni1ECFuni1ED0uni1ED1uni1ED2uni1ED3uni1ED4uni1ED5uni1ED6uni1ED7uni1ED8uni1ED9uni1EDAuni1EDBuni1EDCuni1EDDuni1EDEuni1EDFuni1EE0uni1EE1uni1EE2uni1EE3uni1EE4uni1EE5uni1EE6uni1EE7uni1EE8uni1EE9uni1EEAuni1EEBuni1EECuni1EEDuni1EEEuni1EEFuni1EF0uni1EF1Ygraveygraveuni1EF4uni1EF5uni1EF6uni1EF7uni1EF8uni1EF9uni1F00uni1F01uni1F02uni1F03uni1F04uni1F05uni1F06uni1F07uni1F08uni1F09uni1F0Auni1F0Buni1F0Cuni1F0Duni1F0Euni1F0Funi1F10uni1F11uni1F12uni1F13uni1F14uni1F15uni1F18uni1F19uni1F1Auni1F1Buni1F1Cuni1F1Duni1F20uni1F21uni1F22uni1F23uni1F24uni1F25uni1F26uni1F27uni1F28uni1F29uni1F2Auni1F2Buni1F2Cuni1F2Duni1F2Euni1F2Funi1F30uni1F31uni1F32uni1F33uni1F34uni1F35uni1F36uni1F37uni1F38uni1F39uni1F3Auni1F3Buni1F3Cuni1F3Duni1F3Euni1F3Funi1F40uni1F41uni1F42uni1F43uni1F44uni1F45uni1F48uni1F49uni1F4Auni1F4Buni1F4Cuni1F4Duni1F50uni1F51uni1F52uni1F53uni1F54uni1F55uni1F56uni1F57uni1F59uni1F5Buni1F5Duni1F5Funi1F60uni1F61uni1F62uni1F63uni1F64uni1F65uni1F66uni1F67uni1F68uni1F69uni1F6Auni1F6Buni1F6Cuni1F6Duni1F6Euni1F6Funi1F70uni1F71uni1F72uni1F73uni1F74uni1F75uni1F76uni1F77uni1F78uni1F79uni1F7Auni1F7Buni1F7Cuni1F7Duni1F80uni1F81uni1F82uni1F83uni1F84uni1F85uni1F86uni1F87uni1F88uni1F89uni1F8Auni1F8Buni1F8Cuni1F8Duni1F8Euni1F8Funi1F90uni1F91uni1F92uni1F93uni1F94uni1F95uni1F96uni1F97uni1F98uni1F99uni1F9Auni1F9Buni1F9Cuni1F9Duni1F9Euni1F9Funi1FA0uni1FA1uni1FA2uni1FA3uni1FA4uni1FA5uni1FA6uni1FA7uni1FA8uni1FA9uni1FAAuni1FABuni1FACuni1FADuni1FAEuni1FAFuni1FB0uni1FB1uni1FB2uni1FB3uni1FB4uni1FB6uni1FB7uni1FB8uni1FB9uni1FBAuni1FBBuni1FBCuni1FBDuni1FBEuni1FBFuni1FC0uni1FC1uni1FC2uni1FC3uni1FC4uni1FC6uni1FC7uni1FC8uni1FC9uni1FCAuni1FCBuni1FCCuni1FCDuni1FCEuni1FCFuni1FD0uni1FD1uni1FD2uni1FD3uni1FD6uni1FD7uni1FD8uni1FD9uni1FDAuni1FDBuni1FDDuni1FDEuni1FDFuni1FE0uni1FE1uni1FE2uni1FE3uni1FE4uni1FE5uni1FE6uni1FE7uni1FE8uni1FE9uni1FEAuni1FEBuni1FECuni1FEDuni1FEEuni1FEFuni1FF2uni1FF3uni1FF4uni1FF6uni1FF7uni1FF8uni1FF9uni1FFAuni1FFBuni1FFCuni1FFDuni1FFEuni2000uni2001uni2002uni2003uni2004uni2005uni2006uni2007uni2008uni2009uni200Auni200Buni200Cuni200Duni200Euni200Funi2010uni2011 figuredashuni2015uni2016 underscoredbl quotereverseduni201Funi2023onedotenleadertwodotenleaderuni2027uni202Auni202Buni202Cuni202Duni202Euni202Funi2031minuteseconduni2034uni2035uni2036uni2037uni2038uni203B exclamdbluni203Duni203Euni203Funi2040uni2041uni2042uni2043uni2045uni2046uni2047uni2048uni2049uni204Auni204Buni204Cuni204Duni204Euni204Funi2050uni2051uni2052uni2053uni2054uni2055uni2056uni2057uni2058uni2059uni205Auni205Buni205Cuni205Duni205Euni205Funi2060uni2061uni2062uni2063uni2064uni206Auni206Buni206Cuni206Duni206Euni206Funi2070uni2071uni2074uni2075uni2076uni2077uni2078uni2079uni207Auni207Buni207Cuni207Duni207Euni207Funi2080uni2081uni2082uni2083uni2084uni2085uni2086uni2087uni2088uni2089uni208Auni208Buni208Cuni208Duni208Euni2090uni2091uni2092uni2093uni2094uni20A0 colonmonetaryuni20A2lirauni20A5uni20A6pesetauni20A8uni20A9uni20AAdongEurouni20ADuni20AEuni20AFuni20B0uni20B1uni20B2uni20B3uni20B4uni20B5uni20D0uni20D1uni20D6uni20D7uni20DBuni20DCuni20E1uni2100uni2101uni2102uni2103uni2104uni2105uni2106uni2107uni2108uni2109uni210Buni210Cuni210Duni210Euni210Funi2110Ifrakturuni2112uni2113uni2114uni2115uni2116uni2117 weierstrassuni2119uni211Auni211BRfrakturuni211D prescriptionuni211Funi2120uni2121uni2123uni2124uni2125uni2126uni2127uni2128uni2129uni212Auni212Buni212Cuni212D estimateduni212Funi2130uni2131uni2132uni2133uni2134alephuni2136uni2137uni2138uni2139uni213Auni213Buni213Cuni213Duni213Euni213Funi2140uni2141uni2142uni2143uni2144uni2145uni2146uni2147uni2148uni2149uni214Buni214Eonethird twothirdsuni2155uni2156uni2157uni2158uni2159uni215A oneeighth threeeighths fiveeighths seveneighthsuni215Funi2160uni2161uni2162uni2163uni2164uni2165uni2166uni2167uni2168uni2169uni216Auni216Buni216Cuni216Duni216Euni216Funi2170uni2171uni2172uni2173uni2174uni2175uni2176uni2177uni2178uni2179uni217Auni217Buni217Cuni217Duni217Euni217Funi2180uni2181uni2182uni2183uni2184 arrowleftarrowup arrowright arrowdown arrowboth arrowupdnuni2196uni2197uni2198uni2199uni219Auni219Buni219Cuni219Duni219Euni219Funi21A0uni21A1uni21A2uni21A3uni21A4uni21A5uni21A6uni21A7 arrowupdnbseuni21A9uni21AAuni21ABuni21ACuni21ADuni21AEuni21AFuni21B0uni21B1uni21B2uni21B3uni21B4carriagereturnuni21B6uni21B7uni21B8uni21B9uni21BAuni21BBuni21BCuni21BDuni21BEuni21BFuni21C0uni21C1uni21C2uni21C3uni21C4uni21C5uni21C6uni21C7uni21C8uni21C9uni21CAuni21CBuni21CCuni21CDuni21CEuni21CF arrowdblleft arrowdblup arrowdblright arrowdbldown arrowdblbothuni21D5uni21D6uni21D7uni21D8uni21D9uni21DAuni21DBuni21DCuni21DDuni21DEuni21DFuni21E0uni21E1uni21E2uni21E3uni21E4uni21E5uni21E6uni21E7uni21E8uni21E9uni21EAuni21EBuni21ECuni21EDuni21EEuni21EFuni21F0uni21F1uni21F2uni21F3uni21F4uni21F5uni21F6uni21F7uni21F8uni21F9uni21FAuni21FBuni21FCuni21FDuni21FEuni21FF universaluni2201 existentialuni2204emptysetgradientelement notelementuni220Asuchthatuni220Cuni220Duni220Euni2210uni2213uni2214uni2215uni2216 asteriskmathuni2218uni2219uni221Buni221C proportional orthogonalangleuni2221uni2222uni2223uni2224uni2225uni2226 logicaland logicalor intersectionunionuni222Cuni222Duni222Euni222Funi2230uni2231uni2232uni2233 thereforeuni2235uni2236uni2237uni2238uni2239uni223Auni223Bsimilaruni223Duni223Euni223Funi2240uni2241uni2242uni2243uni2244 congruentuni2246uni2247uni2249uni224Auni224Buni224Cuni224Duni224Euni224Funi2250uni2251uni2252uni2253uni2254uni2255uni2256uni2257uni2258uni2259uni225Auni225Buni225Cuni225Duni225Euni225F equivalenceuni2262uni2263uni2266uni2267uni2268uni2269uni226Auni226Buni226Cuni226Duni226Euni226Funi2270uni2271uni2272uni2273uni2274uni2275uni2276uni2277uni2278uni2279uni227Auni227Buni227Cuni227Duni227Euni227Funi2280uni2281 propersubsetpropersuperset notsubsetuni2285 reflexsubsetreflexsupersetuni2288uni2289uni228Auni228Buni228Cuni228Duni228Euni228Funi2290uni2291uni2292uni2293uni2294 circleplusuni2296circlemultiplyuni2298uni2299uni229Auni229Buni229Cuni229Duni229Euni229Funi22A0uni22A1uni22A2uni22A3uni22A4 perpendicularuni22A6uni22A7uni22A8uni22A9uni22AAuni22ABuni22ACuni22ADuni22AEuni22AFuni22B0uni22B1uni22B2uni22B3uni22B4uni22B5uni22B6uni22B7uni22B8uni22B9uni22BAuni22BBuni22BCuni22BDuni22BEuni22BFuni22C0uni22C1uni22C2uni22C3uni22C4dotmathuni22C6uni22C7uni22C8uni22C9uni22CAuni22CBuni22CCuni22CDuni22CEuni22CFuni22D0uni22D1uni22D2uni22D3uni22D4uni22D5uni22D6uni22D7uni22D8uni22D9uni22DAuni22DBuni22DCuni22DDuni22DEuni22DFuni22E0uni22E1uni22E2uni22E3uni22E4uni22E5uni22E6uni22E7uni22E8uni22E9uni22EAuni22EBuni22ECuni22EDuni22EEuni22EFuni22F0uni22F1uni22F2uni22F3uni22F4uni22F5uni22F6uni22F7uni22F8uni22F9uni22FAuni22FBuni22FCuni22FDuni22FEuni22FFuni2300uni2301houseuni2303uni2304uni2305uni2306uni2307uni2308uni2309uni230Auni230Buni230Cuni230Duni230Euni230F revlogicalnotuni2311uni2318uni2319uni231Cuni231Duni231Euni231F integraltp integralbtuni2324uni2325uni2326uni2327uni2328uni232Buni232Cuni2373uni2374uni2375uni237Auni237Duni2387uni2394uni239Buni239Cuni239Duni239Euni239Funi23A0uni23A1uni23A2uni23A3uni23A4uni23A5uni23A6uni23A7uni23A8uni23A9uni23AAuni23ABuni23ACuni23ADuni23AEuni23CEuni23CFuni23E3uni23E5uni2422uni2423uni2460uni2461uni2462uni2463uni2464uni2465uni2466uni2467uni2468uni2469SF100000uni2501SF110000uni2503uni2504uni2505uni2506uni2507uni2508uni2509uni250Auni250BSF010000uni250Duni250Euni250FSF030000uni2511uni2512uni2513SF020000uni2515uni2516uni2517SF040000uni2519uni251Auni251BSF080000uni251Duni251Euni251Funi2520uni2521uni2522uni2523SF090000uni2525uni2526uni2527uni2528uni2529uni252Auni252BSF060000uni252Duni252Euni252Funi2530uni2531uni2532uni2533SF070000uni2535uni2536uni2537uni2538uni2539uni253Auni253BSF050000uni253Duni253Euni253Funi2540uni2541uni2542uni2543uni2544uni2545uni2546uni2547uni2548uni2549uni254Auni254Buni254Cuni254Duni254Euni254FSF430000SF240000SF510000SF520000SF390000SF220000SF210000SF250000SF500000SF490000SF380000SF280000SF270000SF260000SF360000SF370000SF420000SF190000SF200000SF230000SF470000SF480000SF410000SF450000SF460000SF400000SF540000SF530000SF440000uni256Duni256Euni256Funi2570uni2571uni2572uni2573uni2574uni2575uni2576uni2577uni2578uni2579uni257Auni257Buni257Cuni257Duni257Euni257Fupblockuni2581uni2582uni2583dnblockuni2585uni2586uni2587blockuni2589uni258Auni258Blfblockuni258Duni258Euni258Frtblockltshadeshadedkshadeuni2594uni2595uni2596uni2597uni2598uni2599uni259Auni259Buni259Cuni259Duni259Euni259F filledboxH22073uni25A2uni25A3uni25A4uni25A5uni25A6uni25A7uni25A8uni25A9H18543H18551 filledrectuni25ADuni25AEuni25AFuni25B0uni25B1triagupuni25B3uni25B4uni25B5uni25B6uni25B7uni25B8uni25B9triagrtuni25BBtriagdnuni25BDuni25BEuni25BFuni25C0uni25C1uni25C2uni25C3triaglfuni25C5uni25C6uni25C7uni25C8uni25C9circleuni25CCuni25CDuni25CEH18533uni25D0uni25D1uni25D2uni25D3uni25D4uni25D5uni25D6uni25D7 invbullet invcircleuni25DAuni25DBuni25DCuni25DDuni25DEuni25DFuni25E0uni25E1uni25E2uni25E3uni25E4uni25E5 openbulletuni25E7uni25E8uni25E9uni25EAuni25EBuni25ECuni25EDuni25EEuni25EFuni25F0uni25F1uni25F2uni25F3uni25F4uni25F5uni25F6uni25F7uni25F8uni25F9uni25FAuni25FBuni25FCuni25FDuni25FEuni25FFuni2600uni2601uni2602uni2603uni2604uni2605uni2606uni2607uni2608uni2609uni260Auni260Buni260Cuni260Duni260Euni260Funi2610uni2611uni2612uni2613uni2614uni2615uni2616uni2617uni2618uni2619uni261Auni261Buni261Cuni261Duni261Euni261Funi2620uni2621uni2622uni2623uni2624uni2625uni2626uni2627uni2628uni2629uni262Auni262Buni262Cuni262Duni262Euni262Funi2630uni2631uni2632uni2633uni2634uni2635uni2636uni2637uni2638uni2639 smileface invsmilefacesununi263Duni263Euni263Ffemaleuni2641maleuni2643uni2644uni2645uni2646uni2647uni2648uni2649uni264Auni264Buni264Cuni264Duni264Euni264Funi2650uni2651uni2652uni2653uni2654uni2655uni2656uni2657uni2658uni2659uni265Auni265Buni265Cuni265Duni265Euni265Fspadeuni2661uni2662clubuni2664heartdiamonduni2667uni2668uni2669 musicalnotemusicalnotedbluni266Cuni266Duni266Euni266Funi2670uni2671uni2672uni2673uni2674uni2675uni2676uni2677uni2678uni2679uni267Auni267Buni267Cuni267Duni267Euni267Funi2680uni2681uni2682uni2683uni2684uni2685uni2686uni2687uni2688uni2689uni268Auni268Buni268Cuni268Duni268Euni268Funi2690uni2691uni2692uni2693uni2694uni2695uni2696uni2697uni2698uni2699uni269Auni269Buni269Cuni26A0uni26A1uni26A2uni26A3uni26A4uni26A5uni26A6uni26A7uni26A8uni26A9uni26AAuni26ABuni26ACuni26ADuni26AEuni26AFuni26B0uni26B1uni26B2uni26B3uni26B4uni26B5uni26B6uni26B7uni26B8uni2701uni2702uni2703uni2704uni2706uni2707uni2708uni2709uni270Cuni270Duni270Euni270Funi2710uni2711uni2712uni2713uni2714uni2715uni2716uni2717uni2718uni2719uni271Auni271Buni271Cuni271Duni271Euni271Funi2720uni2721uni2722uni2723uni2724uni2725uni2726uni2727uni2729uni272Auni272Buni272Cuni272Duni272Euni272Funi2730uni2731uni2732uni2733uni2734uni2735uni2736uni2737uni2738uni2739uni273Auni273Buni273Cuni273Duni273Euni273Funi2740uni2741uni2742uni2743uni2744uni2745uni2746uni2747uni2748uni2749uni274Auni274Buni274Duni274Funi2750uni2751uni2752uni2756uni2758uni2759uni275Auni275Buni275Cuni275Duni275Euni2761uni2762uni2763uni2764uni2765uni2766uni2767uni2768uni2769uni276Auni276Buni276Cuni276Duni276Euni276Funi2770uni2771uni2772uni2773uni2774uni2775uni2776uni2777uni2778uni2779uni277Auni277Buni277Cuni277Duni277Euni277Funi2780uni2781uni2782uni2783uni2784uni2785uni2786uni2787uni2788uni2789uni278Auni278Buni278Cuni278Duni278Euni278Funi2790uni2791uni2792uni2793uni2794uni2798uni2799uni279Auni279Buni279Cuni279Duni279Euni279Funi27A0uni27A1uni27A2uni27A3uni27A4uni27A5uni27A6uni27A7uni27A8uni27A9uni27AAuni27ABuni27ACuni27ADuni27AEuni27AFuni27B1uni27B2uni27B3uni27B4uni27B5uni27B6uni27B7uni27B8uni27B9uni27BAuni27BBuni27BCuni27BDuni27BEuni27C5uni27C6uni27E0uni27E6uni27E7uni27E8uni27E9uni27EAuni27EBuni27F0uni27F1uni27F2uni27F3uni27F4uni27F5uni27F6uni27F7uni27F8uni27F9uni27FAuni27FBuni27FCuni27FDuni27FEuni27FFuni2800uni2801uni2802uni2803uni2804uni2805uni2806uni2807uni2808uni2809uni280Auni280Buni280Cuni280Duni280Euni280Funi2810uni2811uni2812uni2813uni2814uni2815uni2816uni2817uni2818uni2819uni281Auni281Buni281Cuni281Duni281Euni281Funi2820uni2821uni2822uni2823uni2824uni2825uni2826uni2827uni2828uni2829uni282Auni282Buni282Cuni282Duni282Euni282Funi2830uni2831uni2832uni2833uni2834uni2835uni2836uni2837uni2838uni2839uni283Auni283Buni283Cuni283Duni283Euni283Funi2840uni2841uni2842uni2843uni2844uni2845uni2846uni2847uni2848uni2849uni284Auni284Buni284Cuni284Duni284Euni284Funi2850uni2851uni2852uni2853uni2854uni2855uni2856uni2857uni2858uni2859uni285Auni285Buni285Cuni285Duni285Euni285Funi2860uni2861uni2862uni2863uni2864uni2865uni2866uni2867uni2868uni2869uni286Auni286Buni286Cuni286Duni286Euni286Funi2870uni2871uni2872uni2873uni2874uni2875uni2876uni2877uni2878uni2879uni287Auni287Buni287Cuni287Duni287Euni287Funi2880uni2881uni2882uni2883uni2884uni2885uni2886uni2887uni2888uni2889uni288Auni288Buni288Cuni288Duni288Euni288Funi2890uni2891uni2892uni2893uni2894uni2895uni2896uni2897uni2898uni2899uni289Auni289Buni289Cuni289Duni289Euni289Funi28A0uni28A1uni28A2uni28A3uni28A4uni28A5uni28A6uni28A7uni28A8uni28A9uni28AAuni28ABuni28ACuni28ADuni28AEuni28AFuni28B0uni28B1uni28B2uni28B3uni28B4uni28B5uni28B6uni28B7uni28B8uni28B9uni28BAuni28BBuni28BCuni28BDuni28BEuni28BFuni28C0uni28C1uni28C2uni28C3uni28C4uni28C5uni28C6uni28C7uni28C8uni28C9uni28CAuni28CBuni28CCuni28CDuni28CEuni28CFuni28D0uni28D1uni28D2uni28D3uni28D4uni28D5uni28D6uni28D7uni28D8uni28D9uni28DAuni28DBuni28DCuni28DDuni28DEuni28DFuni28E0uni28E1uni28E2uni28E3uni28E4uni28E5uni28E6uni28E7uni28E8uni28E9uni28EAuni28EBuni28ECuni28EDuni28EEuni28EFuni28F0uni28F1uni28F2uni28F3uni28F4uni28F5uni28F6uni28F7uni28F8uni28F9uni28FAuni28FBuni28FCuni28FDuni28FEuni28FFuni2906uni2907uni290Auni290Buni2940uni2941uni2983uni2984uni29CEuni29CFuni29D0uni29D1uni29D2uni29D3uni29D4uni29D5uni29EBuni29FAuni29FBuni2A00uni2A01uni2A02uni2A0Cuni2A0Duni2A0Euni2A0Funi2A10uni2A11uni2A12uni2A13uni2A14uni2A15uni2A16uni2A17uni2A18uni2A19uni2A1Auni2A1Buni2A1Cuni2A2Funi2A7Duni2A7Euni2A7Funi2A80uni2A81uni2A82uni2A83uni2A84uni2A85uni2A86uni2A87uni2A88uni2A89uni2A8Auni2A8Buni2A8Cuni2A8Duni2A8Euni2A8Funi2A90uni2A91uni2A92uni2A93uni2A94uni2A95uni2A96uni2A97uni2A98uni2A99uni2A9Auni2A9Buni2A9Cuni2A9Duni2A9Euni2A9Funi2AA0uni2AAEuni2AAFuni2AB0uni2AB1uni2AB2uni2AB3uni2AB4uni2AB5uni2AB6uni2AB7uni2AB8uni2AB9uni2ABAuni2AF9uni2AFAuni2B00uni2B01uni2B02uni2B03uni2B04uni2B05uni2B06uni2B07uni2B08uni2B09uni2B0Auni2B0Buni2B0Cuni2B0Duni2B0Euni2B0Funi2B10uni2B11uni2B12uni2B13uni2B14uni2B15uni2B16uni2B17uni2B18uni2B19uni2B1Auni2B1Funi2B20uni2B21uni2B22uni2B23uni2B24uni2B53uni2B54uni2C60uni2C61uni2C62uni2C63uni2C64uni2C65uni2C66uni2C67uni2C68uni2C69uni2C6Auni2C6Buni2C6Cuni2C6Duni2C6Euni2C6Funi2C71uni2C72uni2C73uni2C74uni2C75uni2C76uni2C77uni2C79uni2C7Auni2C7Buni2C7Cuni2C7Duni2D30uni2D31uni2D32uni2D33uni2D34uni2D35uni2D36uni2D37uni2D38uni2D39uni2D3Auni2D3Buni2D3Cuni2D3Duni2D3Euni2D3Funi2D40uni2D41uni2D42uni2D43uni2D44uni2D45uni2D46uni2D47uni2D48uni2D49uni2D4Auni2D4Buni2D4Cuni2D4Duni2D4Euni2D4Funi2D50uni2D51uni2D52uni2D53uni2D54uni2D55uni2D56uni2D57uni2D58uni2D59uni2D5Auni2D5Buni2D5Cuni2D5Duni2D5Euni2D5Funi2D60uni2D61uni2D62uni2D63uni2D64uni2D65uni2D6Funi2E18uni2E22uni2E23uni2E24uni2E25uni2E2Euni4DC0uni4DC1uni4DC2uni4DC3uni4DC4uni4DC5uni4DC6uni4DC7uni4DC8uni4DC9uni4DCAuni4DCBuni4DCCuni4DCDuni4DCEuni4DCFuni4DD0uni4DD1uni4DD2uni4DD3uni4DD4uni4DD5uni4DD6uni4DD7uni4DD8uni4DD9uni4DDAuni4DDBuni4DDCuni4DDDuni4DDEuni4DDFuni4DE0uni4DE1uni4DE2uni4DE3uni4DE4uni4DE5uni4DE6uni4DE7uni4DE8uni4DE9uni4DEAuni4DEBuni4DECuni4DEDuni4DEEuni4DEFuni4DF0uni4DF1uni4DF2uni4DF3uni4DF4uni4DF5uni4DF6uni4DF7uni4DF8uni4DF9uni4DFAuni4DFBuni4DFCuni4DFDuni4DFEuni4DFFuniA644uniA645uniA646uniA647uniA64CuniA64DuniA650uniA651uniA654uniA655uniA656uniA657uniA662uniA663uniA664uniA665uniA666uniA667uniA668uniA669uniA66AuniA66BuniA66CuniA66DuniA66EuniA68AuniA68BuniA68CuniA68DuniA694uniA695uniA708uniA709uniA70AuniA70BuniA70CuniA70DuniA70EuniA70FuniA710uniA711uniA712uniA713uniA714uniA715uniA716uniA71BuniA71CuniA71DuniA71EuniA71FuniA726uniA727uniA728uniA729uniA72AuniA72BuniA730uniA731uniA732uniA733uniA734uniA735uniA736uniA737uniA738uniA739uniA73AuniA73BuniA73CuniA73DuniA73EuniA73FuniA746uniA747uniA748uniA749uniA74AuniA74BuniA74EuniA74FuniA780uniA781uniA782uniA783uniA789uniA78AuniA78BuniA78CuniA7FBuniA7FCuniA7FDuniA7FEuniA7FFuniF000uniF001uniF6C5uniFB00uniFB03uniFB04uniFB05uniFB06uniFB13uniFB14uniFB15uniFB16uniFB17uniFB1DuniFB1EuniFB1FuniFB20uniFB21uniFB22uniFB23uniFB24uniFB25uniFB26uniFB27uniFB28uniFB29uniFB2AuniFB2BuniFB2CuniFB2DuniFB2EuniFB2FuniFB30uniFB31uniFB32uniFB33uniFB34uniFB35uniFB36uniFB38uniFB39uniFB3AuniFB3BuniFB3CuniFB3EuniFB40uniFB41uniFB43uniFB44uniFB46uniFB47uniFB48uniFB49uniFB4AuniFB4BuniFB4CuniFB4DuniFB4EuniFB4FuniFB52uniFB53uniFB54uniFB55uniFB56uniFB57uniFB58uniFB59uniFB5AuniFB5BuniFB5CuniFB5DuniFB5EuniFB5FuniFB60uniFB61uniFB62uniFB63uniFB64uniFB65uniFB66uniFB67uniFB68uniFB69uniFB6AuniFB6BuniFB6CuniFB6DuniFB6EuniFB6FuniFB70uniFB71uniFB72uniFB73uniFB74uniFB75uniFB76uniFB77uniFB78uniFB79uniFB7AuniFB7BuniFB7CuniFB7DuniFB7EuniFB7FuniFB80uniFB81uniFB8AuniFB8BuniFB8CuniFB8DuniFB8EuniFB8FuniFB90uniFB91uniFB92uniFB93uniFB94uniFB95uniFB9EuniFB9FuniFBD9uniFBDAuniFBE8uniFBE9uniFBFCuniFBFDuniFBFEuniFBFFuniFE00uniFE01uniFE02uniFE03uniFE04uniFE05uniFE06uniFE07uniFE08uniFE09uniFE0AuniFE0BuniFE0CuniFE0DuniFE0EuniFE0FuniFE20uniFE21uniFE22uniFE23uniFE70uniFE71uniFE72uniFE73uniFE74uniFE76uniFE77uniFE78uniFE79uniFE7AuniFE7BuniFE7CuniFE7DuniFE7EuniFE7FuniFE80uniFE81uniFE82uniFE83uniFE84uniFE85uniFE86uniFE87uniFE88uniFE89uniFE8AuniFE8BuniFE8CuniFE8DuniFE8EuniFE8FuniFE90uniFE91uniFE92uniFE93uniFE94uniFE95uniFE96uniFE97uniFE98uniFE99uniFE9AuniFE9BuniFE9CuniFE9DuniFE9EuniFE9FuniFEA0uniFEA1uniFEA2uniFEA3uniFEA4uniFEA5uniFEA6uniFEA7uniFEA8uniFEA9uniFEAAuniFEABuniFEACuniFEADuniFEAEuniFEAFuniFEB0uniFEB1uniFEB2uniFEB3uniFEB4uniFEB5uniFEB6uniFEB7uniFEB8uniFEB9uniFEBAuniFEBBuniFEBCuniFEBDuniFEBEuniFEBFuniFEC0uniFEC1uniFEC2uniFEC3uniFEC4uniFEC5uniFEC6uniFEC7uniFEC8uniFEC9uniFECAuniFECBuniFECCuniFECDuniFECEuniFECFuniFED0uniFED1uniFED2uniFED3uniFED4uniFED5uniFED6uniFED7uniFED8uniFED9uniFEDAuniFEDBuniFEDCuniFEDDuniFEDEuniFEDFuniFEE0uniFEE1uniFEE2uniFEE3uniFEE4uniFEE5uniFEE6uniFEE7uniFEE8uniFEE9uniFEEAuniFEEBuniFEECuniFEEDuniFEEEuniFEEFuniFEF0uniFEF1uniFEF2uniFEF3uniFEF4uniFEF5uniFEF6uniFEF7uniFEF8uniFEF9uniFEFAuniFEFBuniFEFCuniFEFFuniFFF9uniFFFAuniFFFBuniFFFCuniFFFDu1D300u1D301u1D302u1D303u1D304u1D305u1D306u1D307u1D308u1D309u1D30Au1D30Bu1D30Cu1D30Du1D30Eu1D30Fu1D310u1D311u1D312u1D313u1D314u1D315u1D316u1D317u1D318u1D319u1D31Au1D31Bu1D31Cu1D31Du1D31Eu1D31Fu1D320u1D321u1D322u1D323u1D324u1D325u1D326u1D327u1D328u1D329u1D32Au1D32Bu1D32Cu1D32Du1D32Eu1D32Fu1D330u1D331u1D332u1D333u1D334u1D335u1D336u1D337u1D338u1D339u1D33Au1D33Bu1D33Cu1D33Du1D33Eu1D33Fu1D340u1D341u1D342u1D343u1D344u1D345u1D346u1D347u1D348u1D349u1D34Au1D34Bu1D34Cu1D34Du1D34Eu1D34Fu1D350u1D351u1D352u1D353u1D354u1D355u1D356u1D538u1D539u1D53Bu1D53Cu1D53Du1D53Eu1D540u1D541u1D542u1D543u1D544u1D546u1D54Au1D54Bu1D54Cu1D54Du1D54Eu1D54Fu1D550u1D552u1D553u1D554u1D555u1D556u1D557u1D558u1D559u1D55Au1D55Bu1D55Cu1D55Du1D55Eu1D55Fu1D560u1D561u1D562u1D563u1D564u1D565u1D566u1D567u1D568u1D569u1D56Au1D56Bu1D5A0u1D5A1u1D5A2u1D5A3u1D5A4u1D5A5u1D5A6u1D5A7u1D5A8u1D5A9u1D5AAu1D5ABu1D5ACu1D5ADu1D5AEu1D5AFu1D5B0u1D5B1u1D5B2u1D5B3u1D5B4u1D5B5u1D5B6u1D5B7u1D5B8u1D5B9u1D5BAu1D5BBu1D5BCu1D5BDu1D5BEu1D5BFu1D5C0u1D5C1u1D5C2u1D5C3u1D5C4u1D5C5u1D5C6u1D5C7u1D5C8u1D5C9u1D5CAu1D5CBu1D5CCu1D5CDu1D5CEu1D5CFu1D5D0u1D5D1u1D5D2u1D5D3u1D7D8u1D7D9u1D7DAu1D7DBu1D7DCu1D7DDu1D7DEu1D7DFu1D7E0u1D7E1u1D7E2u1D7E3u1D7E4u1D7E5u1D7E6u1D7E7u1D7E8u1D7E9u1D7EAu1D7EB dlLtcaronDieresisAcuteTildeGrave CircumflexCaron uni0311.caseBreve Dotaccent Hungarumlaut Doubleacute arabic_dot arabic_2dots arabic_3dotsarabic_3dots_aarabic_2dots_a arabic_4dots uni066E.fina uni066E.init uni066E.medi uni06A1.fina uni06A1.init uni06A1.medi uni066F.fina uni066F.init uni066F.medi uni06BA.init uni06BA.medi arabic_ring uni067C.fina uni067C.init uni067C.medi uni067D.fina uni067D.init uni067D.medi uni0681.fina uni0681.init uni0681.medi uni0682.fina uni0682.init uni0682.medi uni0685.fina uni0685.init uni0685.medi uni06BF.fina uni06BF.init uni06BF.mediarabic_gaf_barEng.altuni0268.dotlessuni029D.dotless uni03080304 uni03040308 uni03070304 uni03080301 uni03080300 uni03040301 uni03040300 uni03030304 uni0308030C uni03030308 uni030C0307 uni03030301 uni03020301 uni03020300 uni03020303 uni03060303 uni03060301 uni03060300 uni03060309 uni03020309 uni03010307 brailledotJ.alt uni0695.finauniFEAE.fina.longstart uni06B5.fina uni06B5.init uni06B5.medi uni06CE.fina uni06CE.init uni06CE.medi uni0692.final.alt uni06D5.finauni0478.monographuni0479.monographiogonek.dotlessuni2148.dotlessuni2149.dotlessuni1E2D.dotlessuni1ECB.dotlessdcoI.alt arrow.base uni0651064B uni0651064C uni064B0651 uni0651064E uni0651064F uni064E0651 uni0654064E uni0654064F uni07CA.fina uni07CA.medi uni07CA.init uni07CB.fina uni07CB.medi uni07CB.init uni07CC.fina uni07CC.medi uni07CC.init uni07CD.fina uni07CD.medi uni07CD.init uni07CE.fina uni07CE.medi uni07CE.init uni07CF.fina uni07CF.medi uni07CF.init uni07D0.fina uni07D0.medi uni07D0.init uni07D1.fina uni07D1.medi uni07D1.init uni07D2.fina uni07D2.medi uni07D2.init uni07D3.fina uni07D3.medi uni07D3.init uni07D4.fina uni07D4.medi uni07D4.init uni07D5.fina uni07D5.medi uni07D5.init uni07D6.fina uni07D6.medi uni07D6.init uni07D7.fina uni07D7.medi uni07D7.init uni07D8.fina uni07D8.medi uni07D8.init uni07D9.fina uni07D9.medi uni07D9.init uni07DA.fina uni07DA.medi uni07DA.init uni07DB.fina uni07DB.medi uni07DB.init uni07DC.fina uni07DC.medi uni07DC.init uni07DD.fina uni07DD.medi uni07DD.init uni07DE.fina uni07DE.medi uni07DE.init uni07DF.fina uni07DF.medi uni07DF.init uni07E0.fina uni07E0.medi uni07E0.init uni07E1.fina uni07E1.medi uni07E1.init uni07E2.fina uni07E2.medi uni07E2.init uni07E3.fina uni07E3.medi uni07E3.init uni07E4.fina uni07E4.medi uni07E4.init uni07E5.fina uni07E5.medi uni07E5.init uni07E6.fina uni07E6.medi uni07E6.init uni07E7.fina uni07E7.medi uni07E7.init Ringabove uni2630.alt uni2631.alt uni2632.alt uni2633.alt uni2634.alt uni2635.alt uni2636.alt uni2637.alt uni047E.diacuni048A.brevelessuni048B.brevelessy.alt uni02E5.5 uni02E6.5 uni02E7.5 uni02E8.5 uni02E9.5 uni02E5.4 uni02E6.4 uni02E7.4 uni02E8.4 uni02E9.4 uni02E5.3 uni02E6.3 uni02E7.3 uni02E8.3 uni02E9.3 uni02E5.2 uni02E6.2 uni02E7.2 uni02E8.2 uni02E9.2 uni02E5.1 uni02E6.1 uni02E7.1 uni02E8.1 uni02E9.1stem@%2%%A:B2SAS//2ݖ}ٻ֊A}G}G͖2ƅ%]%]@@%d%d%A2dA  d   A(]%]@%..%A  %d%@~}}~}}|d{T{%zyxw v utsrqponl!kjBjSih}gBfedcba:`^ ][ZYX YX WW2VUTUBTSSRQJQP ONMNMLKJKJIJI IH GFEDC-CBAK@?>=>=<=<; <@; :987876765 65 43 21 21 0/ 0 / .- .- ,2+*%+d*)*%)('%(A'%&% &% $#"!! d d BBBdB-B}d       -d@--d++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++critterding-beta12.1/share/critterding/pixmaps/0000755000175000017500000000000011347266042020643 5ustar bobkebobkecritterding-beta12.1/share/critterding/pixmaps/cd.bmp0000644000175000017500000316017211344065077021745 0ustar bobkebobkeBMz zl  ?d?dVuDg@l2f}PLqk1&PPPPPPPPPPP%aRRRRRRRRRRRRRTOs>MoWm~V2e'PPPPPPPPPPPP%aRRRRRRRRRRRRRRR,d#h}Rj}T&` PPPPPPPPPPPPP%aRRRRRRRRRRRRRRRR WUvCbf|Q[PPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRR5h)j~TazMW PPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRY[xGy[wH{SPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRR=l0%lUSsAYQPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRR\_zKHo9:PPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRSEo64mVnW;i/"PPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRR _c|Nl~U/d%PPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRTLrLPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR W WvDhoWCm5/PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR7i+kTmV7g+PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRZ\xHk~T*b!PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR?m2)lUh|R]PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR]`zLc{NXPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRSGp88nV^xJ UPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR#` d|OVuDfRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRTNs=KoWLqj1&PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR(c f}Qm~V1e'PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRVRtAWj}S&` PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR0f&i~Sf|P[PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRX XwFoazMW PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR9j-kT[wGySPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR[]yJRsAXQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRAm3,mVGo89PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR^b{MnW;i/"PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRSIq:=nWl~U/d%PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR$a e|Pi}S#_ PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRUPs?PoWe{PZPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR-e$h~R`yLV PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR W VvDfYvFsSPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR6i+jTPr?QQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRZ\xH~oWEn64PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR?l1'lUnV9h-PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR]`zLl~U-c#PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRSFo77nVi}R!^PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR!`d|Od{OYPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRTMr=IoW_yK U PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR*c!g}QXuElRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR VTuB]Nq=KPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR2g(j~SoWBl4/PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRY YwFtmV6g+PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR;k/"lUk~T*b!PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR[_zJh|R]PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRCn50mVczNXPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR_c{N]xJ UPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRSKq;AnWVuDfRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR'b f}PLpPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR$a e|OnW>j1&PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRTOs>NoWl~U1e'PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR,d#h}Rj}S%` PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR W UvCcf|P[PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR5h*jTazLW PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRY[xH{[wGySPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR>l1&lURsAXQPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR\`zKoWGo89PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRSEo75mVnW;i.!PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR!`c|Nl~U/d%PPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRTLrLoWLpPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP%aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRTLr{8SRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPQ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk*z&)k%RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPNZ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkl>9[RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPM ckkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkks;x6RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPN ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk/|,$h!RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOU kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkl?: X RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP M^kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkku8u3RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPM fkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk4~/dRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPQ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkn@~:VRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPNY kkkkkkkkkkkkkkkkkkf^ULDBBAA@ELT\ckkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkv4r/RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPM bkkkkkkkkkkkkk]I8'#4DVikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk83aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPN ikkkkkkkkkkaE) 2Jckkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk o ?}:TRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOT kkkkkkkkk`;7Xkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk$x /o+RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP N] kkkkkkkg@ -Ukkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk;6^RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPM ekkkkkkc5<ckkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkq>{9SRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP kkkkkk`,%Ukkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk)z&*l&RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPNX kkkkkg6Nkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkl>8\RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPM akkkkkD Hkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkrkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkv5s0RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPM `kkkkh%bkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk7~2bRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPM gkkkkh Mkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk o ?}:URRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPR kkkkkh2jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk"x0p,RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPN[ kkkkkhckkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk;5_RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPM ckkkkkg Vkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkp >|9TRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPN ikkkkkk$Ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk(z$+m'RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOU kkkkkkk5;kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk=8\RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP M^kkkkkkkG-jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkr9Z RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOT kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk"]kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkf hkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkFVkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkks;x6RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP M^kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk+kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk>bkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkQ5ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk/|,#g RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPM ekkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk7 kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkh Zkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk[Ykkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkl?: X RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkGkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk@Okkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkb:jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkku7u3RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPNY kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkWkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkki Bkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkg\kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk4~0dRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPM akkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkhkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk]kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk#?kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkn@~:VRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPM hkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk0_kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkw3r/RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOS kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk2kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk?Ckkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk84aRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP N] kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkNkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkL!akkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk p ?}:TRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPM ekkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkki^kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkVHkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk$y!.o*RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk'Ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk^ %dkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk;6^RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOW kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkL4kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkke Lkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkq>{8SRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPM `kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkj kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkki*fkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk){&)k&RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPM hkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk6Xkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk) Pkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkl>8[RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOR kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkka3kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk7/gkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkks;y6RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP N[ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk+ gkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkETkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk.|+$h!RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPM dkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\:kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkQ4ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkm?: Y RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPO jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk( fkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkZYkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkku8v3RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOV kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk`2kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkb:jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk3}/eRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP M _kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk6Tkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkg^kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkm@~:WRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPM gkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkggkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkj"Ckkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkv4s0RRRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPQ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkQ'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk/$dkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk7~2bRRRRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPNZ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk,3kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk> Qkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk o ?}:URRRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPM ckkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkf>kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkK4ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk#x /p+RRRRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPN ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkX?kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkV^kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk;6_RRRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPOT kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkA5kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk^ Ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkp >|9SRRRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPP M^kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk,+jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkke-hkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk(z%+l'RRRRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPM fkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkki`kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkki\kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkl=8\RRRRRRRRRRRRRRRRRPPPPPPPPPPPPPPPPPPPPPPPPPPPPPPQ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdMkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk(Lkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkr"{pPPPPPPPPPPPPO jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkF Vkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkiekkkkkkkkkkkkkkkkkkkkkkkkfekkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkwj`PPPPPPPPPPOV kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkc(Jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk' _kkkkkkkkkkkkkkkkkkkkkkkkkki#ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkF@%|qPPPPPPPPP M _kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkT<kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk5Vkkkkkkkkkkkkkkkkkkkkkkkkkkkki#-kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkxkaPPPPPPPPM gkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkD ,kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkCKkkkkkkkkkkkkkkkkkkkkkkkkkkkkkki#GkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkHB(|qPPPPPPPQ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkf9jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkO>kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkh\kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkylcPPPPPNZ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkf9fkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkY/kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkb jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkJD+|rPPPPM ckkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkf; _kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkka "jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkY9kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkzmcPPPN ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkiEUkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkggkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkD[kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkLF/}rPOU kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkP#Ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkj! akkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk {ne M^kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk`5 :kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk.Zkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk_LkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkklNH2}r W2jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkiI"+kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk<Okkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk<kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk"|of/R\#kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkd@ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkICkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkg GkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkklPI6}s.R^ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk`?ekkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkT5kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk<kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk$}!pf,S` kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdD$ ^kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk] 'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkgQkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkklRK9~s+Ta kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkjT6Tkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdhkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk*'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk&~"qg)UyckkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkhdkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkNfkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkmTM=~s2P'Vh ekkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk' ]kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkiFkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk($ rh2P%WW fkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk4Tkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk"kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkmVNA~s1Q#XIhkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkCHkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk1jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk*& si0Q!Y;ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkO:kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkDVkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkknWPE~t0Q[/jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkY+kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkQ<kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk,( tj/R\$jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkka jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkT'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkoYQIt.R^ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkffkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkWkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk.* uk,S` kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkj `kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkXjkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk oZSMt+Ta kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk-WkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkLakkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk1,vk)U{ckkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk;Lkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk?Vkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk p \TQt2P'Vi ekkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkI?kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk1Mkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk3.vl2P%WX fkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkT1kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkJkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk q ^VVt1P#XJgkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk] #kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkcHkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk50wm0Q!Y<ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkcgkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkEIkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk q _W[t0Q[/jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkhbkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkNkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk72xm/R\%jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk&ZkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkUTkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkr aX_.R^ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk4Pkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk$]kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk94xn,S_ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkBDkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkTjkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkrbZd+Ta kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkke 6kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkikkkkkkkkkkkkkkkkkkkkkkkkkkkkkk;6yn)U|ckkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkka!'kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk9"kkkkkkkkkkkkkkkkkkkkkkkkkkkksd[i2P'Vk dkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkCMkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkT:kkkkkkkkkkkkkkkkkkkkkkkkkkk=8yo2P%W[ fkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk_.gkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk` Skkkkkkkkkkkkkkkkkkkkkkkkkte]o1P#XKgkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk?Skkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkhikkkkkkkkkkkkkkkkkkkkkkkk@:zo1Q!Y=ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk\2hkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkh %kkkkkkkkkkkkkkkkkkkkkkkug^t0Q[0jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkj;VkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkhEkkkkkkkkkkkkkkkkkkkkkkB<{p/R\&jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkY5ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkhfkkkkkkkkkkkkkkkkkkkkvh_y.R^ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkki6Vkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkka+kkkkkkkkkkkkkkkkkkkkD>"{p-S_ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkV2gkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkV Ukkkkkkkkkkkkkkkkkkwi`~+Ta kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkh2KkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkFkkkkkkkkkkkkkkkkkkF@%{q)U~ckkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkSYkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkf)Mkkkkkkkkkkkkkkkkxka2P'Vl dkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkg-*]kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkQkkkkkkkkkkkkkkkkHB(|q2P&W\ fkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkO )[kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk^$Qkkkkkkkkkkkkkkylc1P#XLgkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkke)Mkkkkkkkkkkkkkkkkkkkkkkkkkkk^,"kkkkkkkkkkkkkkJD+|r1Q!Y>ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkL 3WkkkkkkkkkkkkkkkkkkkkkjM%]kkkkkkkkkkkkymc0QZ2jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkc%,HckkkkkkkkkkkkkkfK. =kkkkkkkkkkkkLF/}r/R\&jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkG 1<GPQSRKB7&kkkkkkkkkkk {nd.R] kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkka"^kkkkkkkkklNH2}r-S_ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkFKkkkkkkkkk"|of+Ta kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkb$2kkkkkkkklPI5}s)Uc kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkI %kkkkkkkk#| pf2P(Vm dkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkc&hkkkkkklRK8~s2P&W] fkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkK ekkkkkk&~"qg1P#XMgkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkd,ekkkkkmSL<~s1Q!Y?hkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkTekkkkk($ rh0QZ3ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkj= gkkkkmUN@~s/R\'jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkka%*jkkkk*& si.R] kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkN<kkkknWOD~t-S_ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkh: Qkkkk,( tj+Ta kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkc/akkknYQIt*Ub kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk]%@kkkk.* uk2P(Vo dkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkT\kkk oZSMt2P&W^ fkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkN Ajkkk0,uk1P$XNgkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkT"2fkkk p \TQt1Q!Y@hkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkZ(&^kkkk3.vl0QZ4ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkb:0_kkkk p ^VVt/R\(jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkR);ekkkkk40wl.R]kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkfH( 3Xkkkkkk q _W[t-S_ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkT48Vkkkkkkkk72xm+Ta kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkiV@*%9Tikkkkkkkkkr aX_*Tb kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkdXL?620.+)-4:@FQakkkkkkkkkkkkkk94xn2P(Up dkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkrbZd2P&W_ ekkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk;6yn1P$XPgkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkksc[h1Q"YAhkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk=8yo0QZ5ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkte\m/R[*jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk@:zo.R]kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkuf^s-S_ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkB<{p,S` kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkvh_x*Tb kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkD>!{p2P(Uq dkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkwi`~2P&Va ekkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkF@${q1P$XQgkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkwka1Q"YBhkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkHB'|q0QZ6ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkylb/Q[*jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkJC*|q.R] kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkymc-S^ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkLE.}r,S` kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk {nd*Tb kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkklNG1}r2P(Utdkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk!{oe2P&Vb ekkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkklPI5}s1P$WRgkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk#| pf1Q"YChkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkklRK8~s0Q Z7ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk&~"qg/Q[+jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkmSL<~s.R] kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk($ rh-S^ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkmUN@~s,S` kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk*& si*Tb kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkknWOD~t(Uudkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk,( tj2P&Vc ekkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkknYQIt1P$WTgkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk.* tj1Q"XEhkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk oZRLt0Q Z8ikkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk0,uk/Q[,jkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk p \TPt.R]!kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk2.vl-S^ kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk p ]UUt,S` kkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkkk40wl*Tb kkkkkkkkkkkkkkkkkkkkkkkkkkkkkk q _WYt)Uwckkkkkkkkkkkkkkkkkkkkkkkkkkk62xm2P'Vd ekkkkkkkkkkkkkkkkkkkkkkk r `X^1P%WUgkkkkkkkkkkkkkkkkkkkk94xn1Q"XFhkkkkkkkkkkkkkkkkrbYc0Q Z8ikkkkkkkkkkkkk;6yn0Q[-jkkkkkkkkksc[h/R\#kkkkkkk=8yo-R^ kkkte\m,S` ?:zocritterding-beta12.1/README0000644000175000017500000003371111344004722014417 0ustar bobkebobkeINSTALLATION - Installation instructions can be found in the INSTALL file TERMINOLOGY - Adam : new (random) critter - Adam Distance (ad) : generations with mutations since adam OPTIONS option [default] [range] [comment] --autoload 0 0-1 autoload critters from ~/.critterding/load --benchmark 0 0-1 run the critterding benchmark --body_maxbodyparts 30 0-1000000 maximum body parts per critter --body_maxbodypartsatbuildtime 6 1-1000000 maximum body parts for a new critter --body_maxbodypartsize 200 1-1000000 maximum size of a critters body part --body_maxheadsize 80 1-1000000 maximum size of a critters head --body_maxmutations 3 1-1000000 maximum mutations on a body mutant --body_minbodypartsize 20 1-1000000 minimum size of a critters body part --body_minheadsize 30 1-1000000 minimum size of a critters head --body_mutationrate 10 0-100 percentage of newborns that mutate bodies --body_percentmutateeffectaddbodypart 1 0-100 chance of adding a body part --body_percentmutateeffectchangecolor 1 0-100 chance of changing body color --body_percentmutateeffectchangecolor_slightly 5 0-100 chance of changing body color --body_percentmutateeffectchangeconstraintangles 1 0-100 chance of changing a joints position angles --body_percentmutateeffectchangeconstraintangles_slightly 5 0-100 chance of changing a joints position angles --body_percentmutateeffectchangeconstraintlimits 1 0-100 chance of changing a joints motion limits --body_percentmutateeffectchangeconstraintlimits_slightly 5 0-100 chance of slightly changing a joints motion limits --body_percentmutateeffectchangeconstraintposition 1 0-100 chance of changing a joints position --body_percentmutateeffectchangeconstraintposition_slightly 5 0-100 chance of slightly changing a joints position --body_percentmutateeffectremovebodypart 1 0-100 chance of removing a body part --body_percentmutateeffectrepositionhead 5 0-100 chance of repositioning head --body_percentmutateeffectresizebodypart 1 0-100 chance of resizing a body part --body_percentmutateeffectresizebodypart_slightly 5 0-100 chance of slightly resizing a body part --body_percentmutateeffectresizehead 1 0-100 chance of resizing a head --body_percentmutateeffectresizehead_slightly 5 0-100 chance of slightly resizing a head --brain_costfiringmotorneuron 100 0-1000000 cost of firing a motor neuron --brain_costfiringneuron 10 0-1000000 cost of firing a neuron --brain_costhavingneuron 50 0-1000000 cost of having a neuron (1/100000 energy) --brain_costhavingsynapse 1 0-1000000 cost of having a synapse --brain_maxdendridicbranches 3 1-1000000 maximum number of dendrites per neuron --brain_maxfiringthreshold 10 1-1000000 maximum firingthreshold of a neuron --brain_maxmutations 10 1-1000000 maximum mutations on a brain mutant --brain_maxneurons 1000 1-1000000 maximum neurons per critter --brain_maxneuronsatbuildtime 200 1-1000000 maximum neurons for a new critter --brain_maxplasticitystrengthen 1000 1-1000000 maximum weight by which plastic synapses strengthen --brain_maxplasticityweaken 10000 1-1000000 maximum weight by which plastic synapses weaken --brain_maxsynapses 100 1-1000000 maximum synapses per neuron --brain_maxsynapsesatbuildtime 40 1-1000000 maximum synapses for a new neuron of a new critter --brain_minfiringthreshold 2 1-1000000 minimum firingthreshold of a neuron --brain_minneuronsatbuildtime 50 1-1000000 minimum neurons for a new critter --brain_minplasticitystrengthen 100 1-1000000 minimum weight by which plastic synapses strengthen --brain_minplasticityweaken 1000 1-1000000 minimum weight by which plastic synapses weaken --brain_minsynapses 1 1-1000000 minimum synapses per neuron --brain_minsynapsesatbuildtime 1 1-1000000 minimum synapses for a new neuron --brain_mutate_maxdendridicbranches 0 0-1 mutate this value --brain_mutate_maxfiringthreshold 0 0-1 mutate this value --brain_mutate_minfiringthreshold 0 0-1 mutate this value --brain_mutate_mutateeffects 0 0-1 mutate mutation effects --brain_mutate_percentchanceconsistentsynapses 0 0-1 mutate this value --brain_mutate_percentchanceinhibitoryneuron 0 0-1 mutate this value --brain_mutate_percentchanceinhibitorysynapses 0 0-1 mutate this value --brain_mutate_percentchancemotorneuron 0 0-1 mutate this value --brain_mutate_percentchanceplasticneuron 0 0-1 mutate this value --brain_mutate_percentchancesensorysynapse 0 0-1 mutate this value --brain_mutate_plasticityfactors 0 0-1 mutate min/max plasticity values --brain_mutationrate 10 0-100 percentage of newborns that mutate brains --brain_percentchanceconsistentsynapses 0 0-100 percent chance a neurons synapses are all inhibitory or excitatory --brain_percentchanceinhibitoryneuron 50 0-100 percent chance a neuron is inhibotory --brain_percentchanceinhibitorysynapses 50 0-100 percent chance a synapse is inhibitory --brain_percentchancemotorneuron 50 0-100 percent chance a neuron is a motor neuron --brain_percentchanceplasticneuron 20 0-100 percent chance a neuron has plastic synapses --brain_percentchancesensorysynapse 20 0-100 percent change a synapse connects to an input --brain_percentmutateeffectaddneuron 1 0-100 chance of adding a neuron --brain_percentmutateeffectaddsynapse 5 0-100 chance of adding a synapse --brain_percentmutateeffectaltermutable 1 0-100 mutate value of a mutatable option --brain_percentmutateeffectalterneuron 2 0-100 chance of altering a neuron --brain_percentmutateeffectremoveneuron 1 0-100 chance of removing a neuron --brain_percentmutateeffectremovesynapse 5 0-100 chance of removing a synapse --camerasensitivity 20 1-1000 sensitivity of the camera --colormode 0 0-1 colors genetically exact critters identically --critter_autoexchangeinterval 0 0-1000000 save critters every n seconds --critter_autosaveinterval 0 0-1000000 save critters every n seconds --critter_enableomnivores 1 0-1 enables critters to eat each other --critter_insertevery 0 0-1000000 inserts a random critter every n frames --critter_killhalfat 120 2-1000000 kill 50% of critters if population reaches n --critter_maxenergy 5000 1-1000000 maximum amount of energy a critter has --critter_maxlifetime 40000 1-1000000 maximum number of frames a critter lives --critter_minenergyproc 3000 1-1000000 energy a critters needs to procreate --critter_procinterval 20 1-1000000 minimum frames between procreations --critter_raycastvision 0 0-1 use raycast vision instead of opengl --critter_retinasize 8 1-1000 size of a critters eye retina --critter_sightrange 70 1-1000000 distance a critter can see (10 = 1 worldsize) --critter_startenergy 3000 1-1000000 energy a new critter (adam) starts with --drawscene 1 0-1 draw the scene --energy 400 0-1000000 energy in the system by number of food cubes --exit_if_empty 0 0-1 exit simulation if there are no critters --food_maxenergy 1500 1-1000000 maximum amount of energy a food unit has --food_maxlifetime 10000 1-1000000 maximum number of frames a food unit exists --food_size 200 1-1000000 size of a food unit --fpslimit 30 1-1000 frames per second for the fps limiter --fsX 800 1-1000000 fullscreen resolution X --fsY 600 1-1000000 fullscreen resolution Y --fullscreen 0 0-1 enable fullscreen mode --headless 0 0-1 do not open gl context --killhalf_decrenergypct 1 0-100 decrease energy by n percent when killhalfat triggers --killhalf_decrmaxlifetimepct 0 0-100 decrease critter_maxlifetime by n when killhalfat triggers --killhalf_incrworldsizeX 0 0-100 increase worldsizeX by n when killhalfat triggers --killhalf_incrworldsizeY 0 0-100 increase worldsizeY by n when killhalfat triggers --mincritters 10 0-1000 minimum number of critters --race 0 0-1 enable race simulation --retinasperrow 20 1-1000 number of vision retinas to stack per row onscreen --roundworld 0 0-1 enable round planet --startseed 0 0-4000000000 enable fullscreen mode --testworld 0 0-1 a world for test purposes --threads 1 1-16 threads to use --worldsizeX 23 1-5000 size of the world along axis X --worldsizeY 13 1-5000 size of the world along axis Y --worldwalls 1 0-1 enable walls around the world To save the default settings to a profile, press "s" in the simulation. It will be saved to ./default and can be loaded by using "--profile ./default" Use F1 in the simulation for more information about keys. OTHER THINGS - Make sure the retina boxes in the lower left of the window never leave the boundaries of the window. Offscreen rendering is not supported by many video card drivers. For some drivers vision will not work if you minimize the window or change desktops. Bob Winckelmans IRC: #critterding@irc.freenode.orgcritterding-beta12.1/LICENSE0000644000175000017500000004610611054613550014551 0ustar bobkebobke GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc. 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too. When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.critterding-beta12.1/configure.in0000644000175000017500000000617211337510627016061 0ustar bobkebobkeAC_INIT(configure.in) AC_CONFIG_MACRO_DIR([m4]) AM_CONFIG_HEADER(config.h) AM_INIT_AUTOMAKE(bengine, 0.1) AC_LANG_CPLUSPLUS AC_PROG_CXX AM_PROG_LIBTOOL AC_MSG_CHECKING([host type]) case "$host" in *-apple-darwin*) HOST_LIBS="-lz" HOST_GL_LIBS="-framework OpenGL" HOST_SDL_LIBS="-framework SDL -framework Cocoa" SDLMAIN="SDLMain.o" OS=OSX AC_MSG_RESULT(OS X) AC_DEFINE_UNQUOTED(_OSX, 1, [Define this if you're building for native OS X]) m4_ifdef( [AC_PROG_OBJC], [AC_PROG_OBJC], [AC_CHECK_TOOL([OBJC], [gcc]) AC_SUBST(OBJC) AC_SUBST(OBJCFLAGS)] ) ;; *-*-mingw*) HOST_LIBS="-lmingw32 -lopengl32 -lfreetype -lSDLmain -lSDL -mwindows" SDLMAIN="" OS=WIN32 AC_MSG_RESULT(win32) ;; *) HOST_LIBS="-lGL -lSDL" SDLMAIN="" AC_MSG_RESULT(generic unix) OS=UNIX ;; esac AM_CONDITIONAL([am__fastdepOBJC], false) AC_SUBST(OS) AC_SUBST(HOST_LIBS) AC_SUBST(SDLMAIN) # SYSTEM FTGL / COMPILE IN FTGL AC_SUBST(FTGL_LOCALDIR) AC_SUBST(FTGL_LA) FTGL_LOCALDIR="" FTGL_LA="" # have_ftgl PKG_PROG_PKG_CONFIG PKG_CHECK_MODULES(FTGL, ftgl >= 2.1.3, [FTGL="yes"], [FTGL="no"]) AS_IF([test "x$FTGL" == "xyes"], [ # --enable-system-ftgl AC_MSG_CHECKING(--enable-system-ftgl) AC_ARG_ENABLE(system_ftgl, [ --disable-system-ftgl Do not build against system ftgl.], [enable_system_ftgl=$enableval], [enable_system_ftgl="yes"] ) AC_MSG_RESULT($enable_system_ftgl) ]) # POST CHECKS # was system ftgl requested if test "${enable_system_ftgl}" = "yes"; then if test "${FTGL}" = "yes"; then CPPFLAGS="$CPPFLAGS $FTGL_CFLAGS" HOST_LIBS="${HOST_LIBS} -lftgl" else if test "${FTGL}" = "no"; then # have Freetype2 AC_MSG_CHECKING(for Freetype) AC_CHECK_PROG([FREETYPE_CONFIG],[freetype-config],yes,no) if test "$FREETYPE_CONFIG" = yes; then FT2_CFLAGS=`freetype-config --cflags` FT2_LIBS=`freetype-config --libs` AC_MSG_RESULT($FT2_CFLAGS) CPPFLAGS="$CPPFLAGS $FT2_CFLAGS" HOST_LIBS="$HOST_LIBS $FT2_LIBS" FTGL_LOCALDIR="ftgl" FTGL_LA="\$(top_builddir)/src/utils/ftgl/libftgl.la" else AC_MSG_ERROR([Could not find freetype-config. FreeType2 is required by FTGL.]) fi fi fi else # have Freetype2 AC_MSG_CHECKING(for Freetype) AC_CHECK_PROG([FREETYPE_CONFIG],[freetype-config],yes,no) if test "$FREETYPE_CONFIG" = yes; then FT2_CFLAGS=`freetype-config --cflags` FT2_LIBS=`freetype-config --libs` AC_MSG_RESULT($FT2_CFLAGS) CPPFLAGS="$CPPFLAGS $FT2_CFLAGS" HOST_LIBS="$HOST_LIBS $FT2_LIBS" FTGL_LOCALDIR="ftgl" FTGL_LA="\$(top_builddir)/src/utils/ftgl/libftgl.la" else AC_MSG_ERROR([Could not find freetype-config. FreeType2 is required by FTGL.]) fi fi AC_OUTPUT(Makefile src/Makefile src/brainz/Makefile \ src/math/Makefile \ src/gl/Makefile \ src/scenes/Makefile \ src/scenes/entities/Makefile \ src/scenes/modes/Makefile \ src/utils/Makefile \ src/utils/ftgl/Makefile \ src/utils/bullet/Makefile \ src/gui/Makefile \ src/scenes/gui/Makefile ) critterding-beta12.1/Changelog0000644000175000017500000000732211347256620015361 0ustar bobkebobke1.0-beta12.1 ------------ catch segfault and warn when using headless without critter_raycastvision some fixes and cleanups 1.0-beta12 ---------- critter selection and actions (kill, duplicate) new panels: neural net brainviewer, hud, species list touchingcritter brain input fix profile saves to ~/critterding/save/(profile)/(profile).pro toggle rendering of gui and scene (h & r) font switch to DejaVuSans an icon thanks to jrabbit new options: --roundworld: a round planet --benchmark: times a scene of 10000 frames --headless: console mode --startseed: seed for the random number generator --killhalf_incrworldsizeX/Y: option to increase worldsize when killhalf triggers --killhalf_decrmaxlifetimepct: option to decrease critter maxlifetime when killhalf triggers --critter_raycastvision: raycast vision for critters --threads, number of threads, making openmp (comes with gcc4.2+) a requirement build system: if available, build against system ftgl (pass --disable-system-ftgl to use internal) make install many fixes, cleanups & changes 1.0-beta11 --------- improved keyboard / mouse input handling improved gui with panels for realtime setting manipulation, critters vs food graph, exit panel (esc no longer exits) a few more body mutations fix: critter autosaving timer fix: crashes on exit many more fixes and cleanups 1.0-beta10 --------- changed the physics backend to Bullet Physics changed input and window backend to SDL a racing mode mouse support for looking and interactivity profile saving (patch from Eric Burton) fullscreen support many improvements, fixes and cleanups overall 1.0-beta9 --------- dedicated skincolors for herbivores(Red/Blue) / carnivores(Green/Blue) bullets no longer shoot through walls world is no longer fixed to a square fps limiter introduced text rendering with fglx improved synaptic plasticity slightly improved wall system --autoload option cleaned up critter files color inputneurons get less discrete input many fixes and cleanups 1.0-beta8 --------- new: custom settings profiles, critter autosaving, exit-if-empty corpses and carrying are disabled at default various fixes and cleanups 1.0-beta7 --------- critters are now classified as herbivore or carnivore corpse is poison to a herbivore/green food is poison to a carnivore fixed a alpha color bug in critter vision (vidia cards) engine improvements: backface & frustrum culling + display lists more efficient copying of brains at procreation time simplified (more usable) camera with adjustable sensitivity critters can now pick up and drop food 1.0-beta6 --------- age input neurons started testing a corpse entity discovered and fixed retina to input mapping bug visibility enhancement by allowing only bright colors bullet hit: half of lifetime lost camera autopositioning according to world size --small, --medium, --big and --huge options 1.0-beta5 --------- Options have boundary checks now improved command line option handling f1 pauses and prints settings / keys increased evolution rate by tuned defaults settings fixed README mistakes 1.0-beta4 --------- adaptable colorneurons, default is now 3 instead of 2 adaptable retinasize, default is nog 7 instead of 10 all (38) initial brain settings have been made adaptable provided an option to flip newborn critters 180 degrees simple --help implemented many minor fixes and cleanups 1.0-beta3 --------- fixes minor memleaks & speedups brain.clearInputs() implementation critter & food size have been made adaptable make sure we only load files with extension cr Retinas Per Row is now adaptable default critter sight distance reduced from 50 to 40: performance boost follow camera handles critter sight distance cleaned up settings reporting updated README Start of a Changelog critterding-beta12.1/AUTHORS0000644000175000017500000000005511056254610014605 0ustar bobkebobkeBob Winckelmans