diff --git a/build3/premake4.lua b/build3/premake4.lua index 9e0f13f8c..45ff4560b 100644 --- a/build3/premake4.lua +++ b/build3/premake4.lua @@ -130,6 +130,7 @@ -- include "../test/hello_gtest" include "../test/collision" include "../test/TestBullet3OpenCL" + include "../test/GwenOpenGLTest" end diff --git a/examples/CommonInterfaces/CommonRigidBodyBase.h b/examples/CommonInterfaces/CommonRigidBodyBase.h index e42e42545..6b5adb9ca 100644 --- a/examples/CommonInterfaces/CommonRigidBodyBase.h +++ b/examples/CommonInterfaces/CommonRigidBodyBase.h @@ -45,6 +45,12 @@ struct CommonRigidBodyBase : public ExampleInterface { } + + btDiscreteDynamicsWorld* getDynamicsWorld() + { + return m_dynamicsWorld; + } + virtual void createEmptyDynamicsWorld() { ///collision configuration contains default setup for memory, collision setup diff --git a/examples/ExampleBrowser/ExampleEntries.cpp b/examples/ExampleBrowser/ExampleEntries.cpp index d5a5e85be..a5c84607e 100644 --- a/examples/ExampleBrowser/ExampleEntries.cpp +++ b/examples/ExampleBrowser/ExampleEntries.cpp @@ -22,16 +22,25 @@ #include "../MultiBody/TestJointTorqueSetup.h" #include "../MultiBody/MultiDofDemo.h" #include "../MultiBody/MultiBodyCustomURDFDemo.h" +#include "../VoronoiFracture/VoronoiFractureDemo.h" +#include "../SoftDemo/SoftDemo.h" + struct ExampleEntry { int m_menuLevel; const char* m_name; + const char* m_description; ExampleInterface::CreateFunc* m_createFunc; int m_option; - ExampleEntry(int menuLevel, const char* name,ExampleInterface::CreateFunc* createFunc, int option=0) - :m_menuLevel(menuLevel), m_name(name), m_createFunc(createFunc), m_option(option) + ExampleEntry(int menuLevel, const char* name) + :m_menuLevel(menuLevel), m_name(name), m_description(0), m_createFunc(0), m_option(0) + { + } + + ExampleEntry(int menuLevel, const char* name,const char* description, ExampleInterface::CreateFunc* createFunc, int option=0) + :m_menuLevel(menuLevel), m_name(name), m_description(description), m_createFunc(createFunc), m_option(option) { } }; @@ -41,50 +50,101 @@ static ExampleEntry gDefaultExamples[]= { - ExampleEntry(0,"API",0), - ExampleEntry(1,"Basic Example",BasicExampleCreateFunc), + ExampleEntry(0,"API"), + ExampleEntry(1,"Basic Example","Create some rigid bodies using box collision shapes.", BasicExampleCreateFunc), - ExampleEntry(1,"Gyroscopic", GyroscopicCreateFunc), + ExampleEntry(1,"Gyroscopic", "Show the Dzhanibekov effect using various settings of the gyroscopic mode.", GyroscopicCreateFunc), - ExampleEntry(1,"Planar 2D",Planar2DCreateFunc), - ExampleEntry(1,"Constraints",ConstraintCreateFunc), - ExampleEntry(1,"6DofSpring2",Dof6Spring2CreateFunc), + ExampleEntry(1,"Planar 2D","Show the use of 2D collision shapes and rigid body simulation.",Planar2DCreateFunc), + ExampleEntry(1,"Constraints","Basic use of a btHingeConstraint.", ConstraintCreateFunc), + ExampleEntry(1,"6DofSpring2","Show the use of the btGeneric6DofSpring2Constraint.", + Dof6Spring2CreateFunc), + ExampleEntry(1,"Voronoi Fracture", "Automatically create a compound rigid body using voronoi tesselation. Individual parts are modeled as rigid bodies using a btConvexHullShape.", + VoronoiFractureCreateFunc), + + ExampleEntry(0,"MultiBody"), + ExampleEntry(1,"MultiDofCreateFunc","Create a basic btMultiBody.", MultiDofCreateFunc), + ExampleEntry(1,"TestJointTorque","Apply a torque to a btMultiBody.", TestJointTorqueCreateFunc), + ExampleEntry(1,"Custom URDF","Load a URDF file to allow creation of custom data structures.", MultiBodyCustomURDFDemoCreateFunc), - ExampleEntry(0,"MultiBody",0), - ExampleEntry(1,"TestJointTorque",TestJointTorqueCreateFunc), - ExampleEntry(1,"MultiDofCreateFunc",MultiDofCreateFunc), - ExampleEntry(1,"Custom URDF",MultiBodyCustomURDFDemoCreateFunc), +#ifdef INCLUDE_CLOTH_DEMOS + ExampleEntry(0,"Soft Body"), + ExampleEntry(1,"Cloth","Simulate a patch of cloth.", SoftDemoCreateFunc,0), + + ExampleEntry(1,"Pressure","Simulate 3d soft body using a pressure constraint.",SoftDemoCreateFunc,1), + ExampleEntry(1,"Volume","Simulate 3d soft body using a volume constraint.",SoftDemoCreateFunc,2), + ExampleEntry(1,"Ropes","Simulate ropes", SoftDemoCreateFunc,3), + ExampleEntry(1,"Rope Attach","Simulate a rigid body connected to a rope.", SoftDemoCreateFunc,4), + ExampleEntry(1,"Cloth Attach","A rigid body attached to a cloth.", SoftDemoCreateFunc,5), + ExampleEntry(1,"Sticks","Show simulation of ropes fixed to the ground.", SoftDemoCreateFunc,6), + ExampleEntry(1,"Capsule Collision","Collision detection between a capsule shape and cloth.", SoftDemoCreateFunc,7), + + ExampleEntry(1,"Collide","Soft body collision", SoftDemoCreateFunc,8), + ExampleEntry(1,"Collide 2","Soft body collision",SoftDemoCreateFunc,9), + ExampleEntry(1,"Collide 3","Soft body collision",SoftDemoCreateFunc,10), + ExampleEntry(1,"Impact","Soft body impact",SoftDemoCreateFunc,11), + ExampleEntry(1,"Aero","Rudimentary aero dynamics simulation", SoftDemoCreateFunc,12), + ExampleEntry(1,"Aero 2","Rudimentary aero dynamics simulation",SoftDemoCreateFunc,13), + ExampleEntry(1,"Friction","Simulate soft body friction with friction coefficients ranging from 0 to 1.", SoftDemoCreateFunc,14), + ExampleEntry(1,"Torus","Simulate a soft body torus.",SoftDemoCreateFunc,15), + ExampleEntry(1,"Torus (Shape Match)","Simulate a soft body torus using shape matching.", SoftDemoCreateFunc,16), + ExampleEntry(1,"Bunny","Simulate the Stanford bunny as deformable object.", SoftDemoCreateFunc,17), + ExampleEntry(1,"Bunny (Shape Match)","Simulate the Stanford bunny as deformable object including shape matching.", SoftDemoCreateFunc,18), + ExampleEntry(1,"Cutting","Allow cutting of the soft body, by clicking on the cloth", SoftDemoCreateFunc,19), + ExampleEntry(1,"Cluster Deform","Soft body collision detection using convex collision clusters.", SoftDemoCreateFunc,20), + ExampleEntry(1,"Cluster Collide1","Collision detection between soft bodies using convex collision clusters.", SoftDemoCreateFunc,21), + ExampleEntry(1,"Cluster Collide2","Collision detection between soft bodies using convex collision clusters.",SoftDemoCreateFunc,22), + ExampleEntry(1,"Cluster Socket","Soft bodies connected by a point to point (ball-socket) constraints. This requires collision clusters, in order to define a frame of reference for the constraint." + , SoftDemoCreateFunc,23), + ExampleEntry(1,"Cluster Hinge","Soft bodies connected by a hinge constraints. This requires collision clusters, in order to define a frame of reference for the constraint.", SoftDemoCreateFunc,24), + ExampleEntry(1,"Cluster Combine","Simulate soft bodies using collision clusters.", SoftDemoCreateFunc,25), + ExampleEntry(1,"Cluster Car","Simulate the Stanford bunny by multiple soft bodies connected by constraints.", SoftDemoCreateFunc,26), + ExampleEntry(1,"Cluster Robot","A rigid body base connected by soft body wheels, connected by constraints.", SoftDemoCreateFunc,27), + ExampleEntry(1,"Cluster Stack Soft","Stacking of soft bodies.", SoftDemoCreateFunc,28), + ExampleEntry(1,"Cluster Stack Mixed","Stacking of soft bodies and rigid bodies.",SoftDemoCreateFunc,29), + ExampleEntry(1,"Tetra Cube","Simulate a volumetric soft body cube defined by tetrahedra.", SoftDemoCreateFunc,30), + ExampleEntry(1,"Tetra Bunny","Simulate a volumetric soft body Stanford bunny defined by tetrahedra.", SoftDemoCreateFunc,31), + +#endif //INCLUDE_CLOTH_DEMOS + ///we disable the benchmarks in debug mode, they are way too slow and benchmarking in debug mode is not recommended #ifndef _DEBUG - ExampleEntry(0,"Benchmarks", 0), - ExampleEntry(1,"3000 boxes", BenchmarkCreateFunc, 1), - ExampleEntry(1,"1000 stack", BenchmarkCreateFunc, 2), - ExampleEntry(1,"Ragdolls", BenchmarkCreateFunc, 3), - ExampleEntry(1,"Convex stack", BenchmarkCreateFunc, 4), - ExampleEntry(1,"Prim vs Mesh", BenchmarkCreateFunc, 5), - ExampleEntry(1,"Convex vs Mesh", BenchmarkCreateFunc, 6), - ExampleEntry(1,"Raycast", BenchmarkCreateFunc, 7), + ExampleEntry(0,"Benchmarks"), + ExampleEntry(1,"3000 boxes", "Benchmark a stack of 3000 boxes. It will stress the collision detection, a specialized box-box implementation based on the separating axis test, and the constraint solver. ", BenchmarkCreateFunc, 1), + ExampleEntry(1,"1000 stack", "Benchmark a stack of 3000 boxes. It will stress the collision detection, a specialized box-box implementation based on the separating axis test, and the constraint solver. ", + BenchmarkCreateFunc, 2), + ExampleEntry(1,"Ragdolls", "Benchmark the performance of the ragdoll constraints, btHingeConstraint and btConeTwistConstraint, in addition to capsule collision detection.", BenchmarkCreateFunc, 3), + ExampleEntry(1,"Convex stack", "Benchmark the performance and stability of rigid bodies using btConvexHullShape.", BenchmarkCreateFunc, 4), + ExampleEntry(1,"Prim vs Mesh", "Benchmark the performance and stability of rigid bodies using primitive collision shapes (btSphereShape, btBoxShape), resting on a triangle mesh, btBvhTriangleMeshShape.", BenchmarkCreateFunc, 5), + ExampleEntry(1,"Convex vs Mesh", "Benchmark the performance and stability of rigid bodies using convex hull collision shapes (btConvexHullShape), resting on a triangle mesh, btBvhTriangleMeshShape.", BenchmarkCreateFunc, 6), + ExampleEntry(1,"Raycast", "Benchmark the performance of the btCollisionWorld::rayTest. Note that currently the rays are not rendered.", BenchmarkCreateFunc, 7), #endif - ExampleEntry(0,"Importers", 0), - ExampleEntry(1,"Wavefront Obj", ImportObjCreateFunc, 0), + ExampleEntry(0,"Importers"), + ExampleEntry(1,"Wavefront Obj", "Import a Wavefront .obj file", ImportObjCreateFunc, 0), - ExampleEntry(1,"Quake BSP", ImportBspCreateFunc, 0), - ExampleEntry(1,"COLLADA dae", ImportColladaCreateFunc, 0), - ExampleEntry(1,"STL", ImportSTLCreateFunc, 0), - ExampleEntry(1,"URDF (RigidBody)", ImportURDFCreateFunc, 0), - ExampleEntry(1,"URDF (MultiBody)", ImportURDFCreateFunc, 1), + ExampleEntry(1,"Quake BSP", "Import a Quake .bsp file", ImportBspCreateFunc, 0), + ExampleEntry(1,"COLLADA dae", "Import the geometric mesh data from a COLLADA file. This is used as part of the URDF importer. This loader can also be used to import collision geometry in general. ", + ImportColladaCreateFunc, 0), + ExampleEntry(1,"STL", "Import the geometric mesh data from a STL file. This is used as part of the URDF importer. This loader can also be used to import collision geometry in general. ",ImportSTLCreateFunc, 0), + ExampleEntry(1,"URDF (RigidBody)", "Import a URDF file, and create rigid bodies (btRigidBody) connected by constraints.", ImportURDFCreateFunc, 0), + ExampleEntry(1,"URDF (MultiBody)", "Import a URDF file and create a single multibody (btMultiBody) with tree hierarchy of links (mobilizers).", + ImportURDFCreateFunc, 1), - ExampleEntry(0,"Vehicles",0), + ExampleEntry(0,"Vehicles"), - ExampleEntry(1,"ForkLift",ForkLiftCreateFunc), + ExampleEntry(1,"ForkLift","Simulate a fork lift vehicle with a working fork lift that can be moved using the cursor keys. The wheels collision is simplified using ray tests." + "There are currently some issues with the wheel rendering, the wheels rotate when picking up the object." + "The demo implementation allows to choose various MLCP constraint solvers.", + ForkLiftCreateFunc), - ExampleEntry(0,"Rendering",0), - ExampleEntry(1,"Instanced Rendering", RenderInstancingCreateFunc), - ExampleEntry(1,"CoordinateSystemDemo",CoordinateSystemCreateFunc), - ExampleEntry(1,"Raytracer",RayTracerCreateFunc), + ExampleEntry(0,"Rendering"), + ExampleEntry(1,"Instanced Rendering", "Simple example of fast instanced rendering, only active when using OpenGL3+.",RenderInstancingCreateFunc), + ExampleEntry(1,"CoordinateSystemDemo","Show the axis and positive rotation direction around the axis.", CoordinateSystemCreateFunc), + ExampleEntry(1,"Raytracer","Implement an extremely simple ray tracer using the ray trace functionality in btCollisionWorld.", + RayTracerCreateFunc), }; @@ -124,21 +184,21 @@ void ExampleEntries::initExampleEntries() { { - ExampleEntry e(0,"Empty", 0); + ExampleEntry e(0,"Empty"); m_data->m_allExamples.push_back(e); } { - ExampleEntry e(1,"Empty",EmptyExample::CreateFunc); + ExampleEntry e(1,"Empty","Empty Description", EmptyExample::CreateFunc); m_data->m_allExamples.push_back(e); } } } -void ExampleEntries::registerExampleEntry(int menuLevel, const char* name,ExampleInterface::CreateFunc* createFunc, int option) +void ExampleEntries::registerExampleEntry(int menuLevel, const char* name,const char* description, ExampleInterface::CreateFunc* createFunc, int option) { - ExampleEntry e( menuLevel,name,createFunc, option); + ExampleEntry e( menuLevel,name,description, createFunc, option); gAdditionalRegisteredExamples.push_back(e); } @@ -161,3 +221,8 @@ const char* ExampleEntries::getExampleName(int index) { return m_data->m_allExamples[index].m_name; } + +const char* ExampleEntries::getExampleDescription(int index) +{ + return m_data->m_allExamples[index].m_description; +} \ No newline at end of file diff --git a/examples/ExampleBrowser/ExampleEntries.h b/examples/ExampleBrowser/ExampleEntries.h index a728d3e2d..07171b41b 100644 --- a/examples/ExampleBrowser/ExampleEntries.h +++ b/examples/ExampleBrowser/ExampleEntries.h @@ -17,7 +17,7 @@ public: ExampleEntries(); virtual ~ExampleEntries(); - static void registerExampleEntry(int menuLevel, const char* name,ExampleInterface::CreateFunc* createFunc, int option=0); + static void registerExampleEntry(int menuLevel, const char* name,const char* description, ExampleInterface::CreateFunc* createFunc, int option=0); void initExampleEntries(); @@ -26,6 +26,8 @@ public: ExampleInterface::CreateFunc* getExampleCreateFunc(int index); const char* getExampleName(int index); + + const char* getExampleDescription(int index); int getExampleOption(int index); diff --git a/examples/ExampleBrowser/GwenGUISupport/gwenInternalData.h b/examples/ExampleBrowser/GwenGUISupport/gwenInternalData.h index 50e408cac..ec0982571 100644 --- a/examples/ExampleBrowser/GwenGUISupport/gwenInternalData.h +++ b/examples/ExampleBrowser/GwenGUISupport/gwenInternalData.h @@ -42,6 +42,10 @@ struct GwenInternalData Gwen::Controls::TreeControl* m_explorerTreeCtrl; Gwen::Controls::MenuItem* m_viewMenu; class MyMenuItems* m_menuItems; + Gwen::Controls::ListBox* m_TextOutput; + Gwen::Controls::Label* m_exampleInfoGroupBox; + Gwen::Controls::ListBox* m_exampleInfoTextOutput; + int m_curYposition; diff --git a/examples/ExampleBrowser/GwenGUISupport/gwenUserInterface.cpp b/examples/ExampleBrowser/GwenGUISupport/gwenUserInterface.cpp index 1c0082a5c..42086312f 100644 --- a/examples/ExampleBrowser/GwenGUISupport/gwenUserInterface.cpp +++ b/examples/ExampleBrowser/GwenGUISupport/gwenUserInterface.cpp @@ -140,6 +140,78 @@ struct MyButtonHander :public Gwen::Event::Handler }; +void GwenUserInterface::textOutput(const char* message) +{ + Gwen::UnicodeString msg = Gwen::Utility::StringToUnicode(message); + m_data->m_TextOutput->AddItem( msg ); + m_data->m_TextOutput->Scroller()->ScrollToBottom(); +} + + +void GwenUserInterface::setExampleDescription(const char* message) +{ + //Gwen apparently doesn't have text/word wrap, so do rudimentary brute-force implementation here. + + std::string wrapmessage=message; + int startPos = 0; + + std::string lastFit = ""; + bool hasSpace = false; + std::string lastFitSpace = ""; + int spacePos = 0; + + m_data->m_exampleInfoTextOutput->Clear(); + int fixedWidth = m_data->m_exampleInfoTextOutput->GetBounds().w-25; + + for (int endPos=0;endPos<=wrapmessage.length();endPos++) + { + std::string sub = wrapmessage.substr(startPos,(endPos-startPos)); + Gwen::Point pt = m_data->pRenderer->MeasureText(m_data->pCanvas->GetSkin()->GetDefaultFont(),sub); + + if (pt.x <= fixedWidth) + { + lastFit = sub; + + if (message[endPos]==' ' ||message[endPos]=='.' || message[endPos]==',' ) + { + hasSpace = true; + lastFitSpace = sub; + spacePos = endPos; + } + } else + { + //submit and + if (hasSpace) + { + endPos = spacePos+1; + hasSpace = false; + lastFit = lastFitSpace; + startPos = endPos; + } else + { + startPos = endPos-1; + } + Gwen::UnicodeString msg = Gwen::Utility::StringToUnicode(lastFit); + + m_data->m_exampleInfoTextOutput->AddItem( msg ); + m_data->m_exampleInfoTextOutput->Scroller()->ScrollToBottom(); + + } + } + + if (lastFit.length()) + { + Gwen::UnicodeString msg = Gwen::Utility::StringToUnicode(lastFit); + m_data->m_exampleInfoTextOutput->AddItem( msg ); + m_data->m_exampleInfoTextOutput->Scroller()->ScrollToBottom(); + + } + +} + + + + void GwenUserInterface::setStatusBarMessage(const char* message, bool isLeft) { Gwen::UnicodeString msg = Gwen::Utility::StringToUnicode(message); @@ -171,10 +243,13 @@ void GwenUserInterface::init(int width, int height,Gwen::Renderer::Base* rendere m_data->pCanvas->SetDrawBackground( false); m_data->pCanvas->SetBackgroundColor( Gwen::Color( 150, 170, 170, 255 ) ); + + MyTestMenuBar* menubar = new MyTestMenuBar(m_data->pCanvas); m_data->m_viewMenu = menubar->m_viewMenu; m_data->m_menuItems = menubar->m_menuItems; + Gwen::Controls::StatusBar* bar = new Gwen::Controls::StatusBar(m_data->pCanvas); @@ -183,6 +258,10 @@ void GwenUserInterface::init(int width, int height,Gwen::Renderer::Base* rendere //m_data->m_rightStatusBar->SetText( L"Label Added to Right" ); bar->AddControl( m_data->m_rightStatusBar, true ); + m_data->m_TextOutput = new Gwen::Controls::ListBox( m_data->pCanvas ); + m_data->m_TextOutput->Dock( Gwen::Pos::Bottom ); + m_data->m_TextOutput->SetHeight( 100 ); + m_data->m_leftStatusBar = new Gwen::Controls::Label( bar ); //m_data->m_leftStatusBar->SetText( L"Label Added to Left" ); m_data->m_leftStatusBar->SetWidth(width/2); @@ -266,6 +345,14 @@ void GwenUserInterface::init(int width, int height,Gwen::Renderer::Base* rendere //tab->Dock(Gwen::Pos::Left); explorerTab->Dock(Gwen::Pos::Fill); + + + + + //m_data->m_exampleInfoTextOutput->SetBounds(2, 10, 236, 400); + + //windowRight + Gwen::UnicodeString explorerStr1(L"Explorer"); m_data->m_explorerPage = explorerTab->AddPage(explorerStr1); Gwen::UnicodeString shapesStr1(L"Shapes"); @@ -279,6 +366,21 @@ void GwenUserInterface::init(int width, int height,Gwen::Renderer::Base* rendere ctrl->Focus(); ctrl->SetBounds(2, 10, 236, 400); + m_data->m_exampleInfoGroupBox = new Gwen::Controls::Label( m_data->m_explorerPage->GetPage() ); + m_data->m_exampleInfoGroupBox->SetPos(2, 414); + m_data->m_exampleInfoGroupBox->SetHeight( 15 ); + m_data->m_exampleInfoGroupBox->SetWidth(234); + m_data->m_exampleInfoGroupBox->SetText("Example Description"); + + m_data->m_exampleInfoTextOutput = new Gwen::Controls::ListBox(m_data->m_explorerPage->GetPage()); + + + //m_data->m_exampleInfoTextOutput->Dock( Gwen::Pos::Bottom ); + m_data->m_exampleInfoTextOutput->SetPos(2, 432); + m_data->m_exampleInfoTextOutput->SetHeight( 150 ); + m_data->m_exampleInfoTextOutput->SetWidth(233); + + } diff --git a/examples/ExampleBrowser/GwenGUISupport/gwenUserInterface.h b/examples/ExampleBrowser/GwenGUISupport/gwenUserInterface.h index 4b7fac785..ce2c3bafe 100644 --- a/examples/ExampleBrowser/GwenGUISupport/gwenUserInterface.h +++ b/examples/ExampleBrowser/GwenGUISupport/gwenUserInterface.h @@ -48,6 +48,10 @@ class GwenUserInterface void setStatusBarMessage(const char* message, bool isLeft=true); + void textOutput(const char* msg); + void setExampleDescription(const char* msg); + + void registerFileOpenCallback(b3FileOpenCallback callback); GwenInternalData* getInternalData() diff --git a/examples/ExampleBrowser/OpenGLExampleBrowser.cpp b/examples/ExampleBrowser/OpenGLExampleBrowser.cpp index cf822ae90..ea0b8b3ce 100644 --- a/examples/ExampleBrowser/OpenGLExampleBrowser.cpp +++ b/examples/ExampleBrowser/OpenGLExampleBrowser.cpp @@ -246,7 +246,8 @@ void selectDemo(int demoIndex) bool isLeft = true; gui->setStatusBarMessage("Status: OK", false); } - + b3Printf("Selected demo: %s",gAllExamples->getExampleName(demoIndex)); + gui->setExampleDescription(gAllExamples->getExampleDescription(demoIndex)); sCurrentDemo->initPhysics(); } } @@ -303,6 +304,17 @@ void MyComboBoxCallback(int comboId, const char* item) } +void MyGuiPrintf(const char* msg) +{ + printf("b3Printf: %s\n",msg); + if (gui) + { + gui->textOutput(msg); + gui->forceUpdateScrollBars(); + } +} + + void MyStatusBarPrintf(const char* msg) { @@ -364,13 +376,14 @@ struct MyMenuItemHander :public Gwen::Event::Handler } void onButtonC(Gwen::Controls::Base* pControl) { -// Gwen::Controls::Label* label = (Gwen::Controls::Label*) pControl; - // Gwen::UnicodeString la = label->GetText();// node->GetButton()->GetName();// GetText(); - // Gwen::String laa = Gwen::Utility::UnicodeToString(la); - // const char* ha = laa.c_str(); + /*Gwen::Controls::Label* label = (Gwen::Controls::Label*) pControl; + Gwen::UnicodeString la = label->GetText();// node->GetButton()->GetName();// GetText(); + Gwen::String laa = Gwen::Utility::UnicodeToString(la); + const char* ha = laa.c_str(); -// printf("onButtonC ! %s\n", ha); + printf("onButtonC ! %s\n", ha); + */ } void onButtonD(Gwen::Controls::Base* pControl) { @@ -390,6 +403,7 @@ struct MyMenuItemHander :public Gwen::Event::Handler { // printf("select %d\n",m_buttonId); sCurrentHightlighted = m_buttonId; + gui->setExampleDescription(gAllExamples->getExampleDescription(sCurrentHightlighted)); } void onButtonF(Gwen::Controls::Base* pControl) @@ -559,7 +573,8 @@ bool OpenGLExampleBrowser::init(int argc, char* argv[]) s_app->m_renderer->getActiveCamera()->setCameraTargetPosition(0,0,0); b3SetCustomWarningMessageFunc(MyStatusBarWarning); - b3SetCustomPrintfFunc(MyStatusBarPrintf); + //b3SetCustomPrintfFunc(MyStatusBarPrintf); + b3SetCustomPrintfFunc(MyGuiPrintf); assert(glGetError()==GL_NO_ERROR); @@ -580,6 +595,10 @@ bool OpenGLExampleBrowser::init(int argc, char* argv[]) // gui->init(width,height,gwenRenderer,s_window->getRetinaScale()); + + + + // gui->getInternalData()->m_explorerPage Gwen::Controls::TreeControl* tree = gui->getInternalData()->m_explorerTreeCtrl; @@ -727,6 +746,7 @@ void OpenGLExampleBrowser::update(float deltaTime) s_app->drawText(bla,10,10); } + if (sCurrentDemo) { if (!pauseSimulation) @@ -758,19 +778,18 @@ void OpenGLExampleBrowser::update(float deltaTime) //if (!pauseSimulation) // processProfileData(profWindow,false); - { - if (sUseOpenGL2) - { + if (sUseOpenGL2) + { - saveOpenGLState(s_instancingRenderer->getScreenWidth(),s_instancingRenderer->getScreenHeight()); - } - BT_PROFILE("Draw Gwen GUI"); - gui->draw(s_instancingRenderer->getScreenWidth(),s_instancingRenderer->getScreenHeight()); - if (sUseOpenGL2) - { - restoreOpenGLState(); - } + saveOpenGLState(s_instancingRenderer->getScreenWidth(),s_instancingRenderer->getScreenHeight()); + } + BT_PROFILE("Draw Gwen GUI"); + gui->draw(s_instancingRenderer->getScreenWidth(),s_instancingRenderer->getScreenHeight()); + if (sUseOpenGL2) + { + restoreOpenGLState(); } + } toggle=1-toggle; { @@ -781,7 +800,7 @@ void OpenGLExampleBrowser::update(float deltaTime) BT_PROFILE("Swap Buffers"); s_app->swapBuffer(); } - + gui->forceUpdateScrollBars(); } diff --git a/examples/ExampleBrowser/OpenGLGuiHelper.cpp b/examples/ExampleBrowser/OpenGLGuiHelper.cpp index aaa4ce503..71061ac30 100644 --- a/examples/ExampleBrowser/OpenGLGuiHelper.cpp +++ b/examples/ExampleBrowser/OpenGLGuiHelper.cpp @@ -195,6 +195,11 @@ static void createCollisionShapeGraphicsObjectInternal(btCollisionShape* collisi //todo: support all collision shape types switch (collisionShape->getShapeType()) { + case SOFTBODY_SHAPE_PROXYTYPE: + { + //skip the soft body collision shape for now + break; + } case STATIC_PLANE_PROXYTYPE: { //draw a box, oriented along the plane normal diff --git a/examples/ExampleBrowser/premake4.lua b/examples/ExampleBrowser/premake4.lua index f9d37b437..d913dd178 100644 --- a/examples/ExampleBrowser/premake4.lua +++ b/examples/ExampleBrowser/premake4.lua @@ -12,11 +12,12 @@ } - links{"gwen", "OpenGL_Window","BulletDynamics","BulletCollision","LinearMath","Bullet3Common"} + links{"gwen", "OpenGL_Window","BulletSoftBody", "BulletDynamics","BulletCollision","LinearMath","Bullet3Common"} initOpenGL() initGlew() - + defines {"INCLUDE_CLOTH_DEMOS"} + files { "**.cpp", "**.h", @@ -27,6 +28,8 @@ "../Importers/**", "../Planar2D/Planar2D.*", "../RenderingExamples/*", + "../VoronoiFracture/*", + "../SoftDemo/*", "../Constraints/*", "../MultiBody/MultiBodyCustomURDFDemo.cpp", "../MultiBody/MultiDofDemo.cpp", diff --git a/examples/SoftDemo/BunnyMesh.h b/examples/SoftDemo/BunnyMesh.h new file mode 100644 index 000000000..818bd0248 --- /dev/null +++ b/examples/SoftDemo/BunnyMesh.h @@ -0,0 +1,1379 @@ +#ifndef BUNNY_MESH_H_ +#define BUNNY_MESH_H_ + + + +//***************************THE FAMOUS BUNNY TRIMESH********************************************// + +#define REAL btScalar +const int BUNNY_NUM_TRIANGLES =902; +const int BUNNY_NUM_VERTICES = 453; +const int BUNNY_NUM_INDICES = BUNNY_NUM_TRIANGLES * 3; + + +static REAL gVerticesBunny[BUNNY_NUM_VERTICES * 3] = { + REAL(-0.334392), REAL(0.133007), REAL(0.062259), + REAL(-0.350189), REAL(0.150354), REAL(-0.147769), + REAL(-0.234201), REAL(0.343811), REAL(-0.174307), + REAL(-0.200259), REAL(0.285207), REAL(0.093749), + REAL(0.003520), REAL(0.475208), REAL(-0.159365), + REAL(0.001856), REAL(0.419203), REAL(0.098582), + REAL(-0.252802), REAL(0.093666), REAL(0.237538), + REAL(-0.162901), REAL(0.237984), REAL(0.206905), + REAL(0.000865), REAL(0.318141), REAL(0.235370), + REAL(-0.414624), REAL(0.164083), REAL(-0.278254), + REAL(-0.262213), REAL(0.357334), REAL(-0.293246), + REAL(0.004628), REAL(0.482694), REAL(-0.338626), + REAL(-0.402162), REAL(0.133528), REAL(-0.443247), + REAL(-0.243781), REAL(0.324275), REAL(-0.436763), + REAL(0.005293), REAL(0.437592), REAL(-0.458332), + REAL(-0.339884), REAL(-0.041150), REAL(-0.668211), + REAL(-0.248382), REAL(0.255825), REAL(-0.627493), + REAL(0.006261), REAL(0.376103), REAL(-0.631506), + REAL(-0.216201), REAL(-0.126776), REAL(-0.886936), + REAL(-0.171075), REAL(0.011544), REAL(-0.881386), + REAL(-0.181074), REAL(0.098223), REAL(-0.814779), + REAL(-0.119891), REAL(0.218786), REAL(-0.760153), + REAL(-0.078895), REAL(0.276780), REAL(-0.739281), + REAL(0.006801), REAL(0.310959), REAL(-0.735661), + REAL(-0.168842), REAL(0.102387), REAL(-0.920381), + REAL(-0.104072), REAL(0.177278), REAL(-0.952530), + REAL(-0.129704), REAL(0.211848), REAL(-0.836678), + REAL(-0.099875), REAL(0.310931), REAL(-0.799381), + REAL(0.007237), REAL(0.361687), REAL(-0.794439), + REAL(-0.077913), REAL(0.258753), REAL(-0.921640), + REAL(0.007957), REAL(0.282241), REAL(-0.931680), + REAL(-0.252222), REAL(-0.550401), REAL(-0.557810), + REAL(-0.267633), REAL(-0.603419), REAL(-0.655209), + REAL(-0.446838), REAL(-0.118517), REAL(-0.466159), + REAL(-0.459488), REAL(-0.093017), REAL(-0.311341), + REAL(-0.370645), REAL(-0.100108), REAL(-0.159454), + REAL(-0.371984), REAL(-0.091991), REAL(-0.011044), + REAL(-0.328945), REAL(-0.098269), REAL(0.088659), + REAL(-0.282452), REAL(-0.018862), REAL(0.311501), + REAL(-0.352403), REAL(-0.131341), REAL(0.144902), + REAL(-0.364126), REAL(-0.200299), REAL(0.202388), + REAL(-0.283965), REAL(-0.231869), REAL(0.023668), + REAL(-0.298943), REAL(-0.155218), REAL(0.369716), + REAL(-0.293787), REAL(-0.121856), REAL(0.419097), + REAL(-0.290163), REAL(-0.290797), REAL(0.107824), + REAL(-0.264165), REAL(-0.272849), REAL(0.036347), + REAL(-0.228567), REAL(-0.372573), REAL(0.290309), + REAL(-0.190431), REAL(-0.286997), REAL(0.421917), + REAL(-0.191039), REAL(-0.240973), REAL(0.507118), + REAL(-0.287272), REAL(-0.276431), REAL(-0.065444), + REAL(-0.295675), REAL(-0.280818), REAL(-0.174200), + REAL(-0.399537), REAL(-0.313131), REAL(-0.376167), + REAL(-0.392666), REAL(-0.488581), REAL(-0.427494), + REAL(-0.331669), REAL(-0.570185), REAL(-0.466054), + REAL(-0.282290), REAL(-0.618140), REAL(-0.589220), + REAL(-0.374238), REAL(-0.594882), REAL(-0.323298), + REAL(-0.381071), REAL(-0.629723), REAL(-0.350777), + REAL(-0.382112), REAL(-0.624060), REAL(-0.221577), + REAL(-0.272701), REAL(-0.566522), REAL(0.259157), + REAL(-0.256702), REAL(-0.663406), REAL(0.286079), + REAL(-0.280948), REAL(-0.428359), REAL(0.055790), + REAL(-0.184974), REAL(-0.508894), REAL(0.326265), + REAL(-0.279971), REAL(-0.526918), REAL(0.395319), + REAL(-0.282599), REAL(-0.663393), REAL(0.412411), + REAL(-0.188329), REAL(-0.475093), REAL(0.417954), + REAL(-0.263384), REAL(-0.663396), REAL(0.466604), + REAL(-0.209063), REAL(-0.663393), REAL(0.509344), + REAL(-0.002044), REAL(-0.319624), REAL(0.553078), + REAL(-0.001266), REAL(-0.371260), REAL(0.413296), + REAL(-0.219753), REAL(-0.339762), REAL(-0.040921), + REAL(-0.256986), REAL(-0.282511), REAL(-0.006349), + REAL(-0.271706), REAL(-0.260881), REAL(0.001764), + REAL(-0.091191), REAL(-0.419184), REAL(-0.045912), + REAL(-0.114944), REAL(-0.429752), REAL(-0.124739), + REAL(-0.113970), REAL(-0.382987), REAL(-0.188540), + REAL(-0.243012), REAL(-0.464942), REAL(-0.242850), + REAL(-0.314815), REAL(-0.505402), REAL(-0.324768), + REAL(0.002774), REAL(-0.437526), REAL(-0.262766), + REAL(-0.072625), REAL(-0.417748), REAL(-0.221440), + REAL(-0.160112), REAL(-0.476932), REAL(-0.293450), + REAL(0.003859), REAL(-0.453425), REAL(-0.443916), + REAL(-0.120363), REAL(-0.581567), REAL(-0.438689), + REAL(-0.091499), REAL(-0.584191), REAL(-0.294511), + REAL(-0.116469), REAL(-0.599861), REAL(-0.188308), + REAL(-0.208032), REAL(-0.513640), REAL(-0.134649), + REAL(-0.235749), REAL(-0.610017), REAL(-0.040939), + REAL(-0.344916), REAL(-0.622487), REAL(-0.085380), + REAL(-0.336401), REAL(-0.531864), REAL(-0.212298), + REAL(0.001961), REAL(-0.459550), REAL(-0.135547), + REAL(-0.058296), REAL(-0.430536), REAL(-0.043440), + REAL(0.001378), REAL(-0.449511), REAL(-0.037762), + REAL(-0.130135), REAL(-0.510222), REAL(0.079144), + REAL(0.000142), REAL(-0.477549), REAL(0.157064), + REAL(-0.114284), REAL(-0.453206), REAL(0.304397), + REAL(-0.000592), REAL(-0.443558), REAL(0.285401), + REAL(-0.056215), REAL(-0.663402), REAL(0.326073), + REAL(-0.026248), REAL(-0.568010), REAL(0.273318), + REAL(-0.049261), REAL(-0.531064), REAL(0.389854), + REAL(-0.127096), REAL(-0.663398), REAL(0.479316), + REAL(-0.058384), REAL(-0.663401), REAL(0.372891), + REAL(-0.303961), REAL(0.054199), REAL(0.625921), + REAL(-0.268594), REAL(0.193403), REAL(0.502766), + REAL(-0.277159), REAL(0.126123), REAL(0.443289), + REAL(-0.287605), REAL(-0.005722), REAL(0.531844), + REAL(-0.231396), REAL(-0.121289), REAL(0.587387), + REAL(-0.253475), REAL(-0.081797), REAL(0.756541), + REAL(-0.195164), REAL(-0.137969), REAL(0.728011), + REAL(-0.167673), REAL(-0.156573), REAL(0.609388), + REAL(-0.145917), REAL(-0.169029), REAL(0.697600), + REAL(-0.077776), REAL(-0.214247), REAL(0.622586), + REAL(-0.076873), REAL(-0.214971), REAL(0.696301), + REAL(-0.002341), REAL(-0.233135), REAL(0.622859), + REAL(-0.002730), REAL(-0.213526), REAL(0.691267), + REAL(-0.003136), REAL(-0.192628), REAL(0.762731), + REAL(-0.056136), REAL(-0.201222), REAL(0.763806), + REAL(-0.114589), REAL(-0.166192), REAL(0.770723), + REAL(-0.155145), REAL(-0.129632), REAL(0.791738), + REAL(-0.183611), REAL(-0.058705), REAL(0.847012), + REAL(-0.165562), REAL(0.001980), REAL(0.833386), + REAL(-0.220084), REAL(0.019914), REAL(0.768935), + REAL(-0.255730), REAL(0.090306), REAL(0.670782), + REAL(-0.255594), REAL(0.113833), REAL(0.663389), + REAL(-0.226380), REAL(0.212655), REAL(0.617740), + REAL(-0.003367), REAL(-0.195342), REAL(0.799680), + REAL(-0.029743), REAL(-0.210508), REAL(0.827180), + REAL(-0.003818), REAL(-0.194783), REAL(0.873636), + REAL(-0.004116), REAL(-0.157907), REAL(0.931268), + REAL(-0.031280), REAL(-0.184555), REAL(0.889476), + REAL(-0.059885), REAL(-0.184448), REAL(0.841330), + REAL(-0.135333), REAL(-0.164332), REAL(0.878200), + REAL(-0.085574), REAL(-0.170948), REAL(0.925547), + REAL(-0.163833), REAL(-0.094170), REAL(0.897114), + REAL(-0.138444), REAL(-0.104250), REAL(0.945975), + REAL(-0.083497), REAL(-0.084934), REAL(0.979607), + REAL(-0.004433), REAL(-0.146642), REAL(0.985872), + REAL(-0.150715), REAL(0.032650), REAL(0.884111), + REAL(-0.135892), REAL(-0.035520), REAL(0.945455), + REAL(-0.070612), REAL(0.036849), REAL(0.975733), + REAL(-0.004458), REAL(-0.042526), REAL(1.015670), + REAL(-0.004249), REAL(0.046042), REAL(1.003240), + REAL(-0.086969), REAL(0.133224), REAL(0.947633), + REAL(-0.003873), REAL(0.161605), REAL(0.970499), + REAL(-0.125544), REAL(0.140012), REAL(0.917678), + REAL(-0.125651), REAL(0.250246), REAL(0.857602), + REAL(-0.003127), REAL(0.284070), REAL(0.878870), + REAL(-0.159174), REAL(0.125726), REAL(0.888878), + REAL(-0.183807), REAL(0.196970), REAL(0.844480), + REAL(-0.159890), REAL(0.291736), REAL(0.732480), + REAL(-0.199495), REAL(0.207230), REAL(0.779864), + REAL(-0.206182), REAL(0.164608), REAL(0.693257), + REAL(-0.186315), REAL(0.160689), REAL(0.817193), + REAL(-0.192827), REAL(0.166706), REAL(0.782271), + REAL(-0.175112), REAL(0.110008), REAL(0.860621), + REAL(-0.161022), REAL(0.057420), REAL(0.855111), + REAL(-0.172319), REAL(0.036155), REAL(0.816189), + REAL(-0.190318), REAL(0.064083), REAL(0.760605), + REAL(-0.195072), REAL(0.129179), REAL(0.731104), + REAL(-0.203126), REAL(0.410287), REAL(0.680536), + REAL(-0.216677), REAL(0.309274), REAL(0.642272), + REAL(-0.241515), REAL(0.311485), REAL(0.587832), + REAL(-0.002209), REAL(0.366663), REAL(0.749413), + REAL(-0.088230), REAL(0.396265), REAL(0.678635), + REAL(-0.170147), REAL(0.109517), REAL(0.840784), + REAL(-0.160521), REAL(0.067766), REAL(0.830650), + REAL(-0.181546), REAL(0.139805), REAL(0.812146), + REAL(-0.180495), REAL(0.148568), REAL(0.776087), + REAL(-0.180255), REAL(0.129125), REAL(0.744192), + REAL(-0.186298), REAL(0.078308), REAL(0.769352), + REAL(-0.167622), REAL(0.060539), REAL(0.806675), + REAL(-0.189876), REAL(0.102760), REAL(0.802582), + REAL(-0.108340), REAL(0.455446), REAL(0.657174), + REAL(-0.241585), REAL(0.527592), REAL(0.669296), + REAL(-0.265676), REAL(0.513366), REAL(0.634594), + REAL(-0.203073), REAL(0.478550), REAL(0.581526), + REAL(-0.266772), REAL(0.642330), REAL(0.602061), + REAL(-0.216961), REAL(0.564846), REAL(0.535435), + REAL(-0.202210), REAL(0.525495), REAL(0.475944), + REAL(-0.193888), REAL(0.467925), REAL(0.520606), + REAL(-0.265837), REAL(0.757267), REAL(0.500933), + REAL(-0.240306), REAL(0.653440), REAL(0.463215), + REAL(-0.309239), REAL(0.776868), REAL(0.304726), + REAL(-0.271009), REAL(0.683094), REAL(0.382018), + REAL(-0.312111), REAL(0.671099), REAL(0.286687), + REAL(-0.268791), REAL(0.624342), REAL(0.377231), + REAL(-0.302457), REAL(0.533996), REAL(0.360289), + REAL(-0.263656), REAL(0.529310), REAL(0.412564), + REAL(-0.282311), REAL(0.415167), REAL(0.447666), + REAL(-0.239201), REAL(0.442096), REAL(0.495604), + REAL(-0.220043), REAL(0.569026), REAL(0.445877), + REAL(-0.001263), REAL(0.395631), REAL(0.602029), + REAL(-0.057345), REAL(0.442535), REAL(0.572224), + REAL(-0.088927), REAL(0.506333), REAL(0.529106), + REAL(-0.125738), REAL(0.535076), REAL(0.612913), + REAL(-0.126251), REAL(0.577170), REAL(0.483159), + REAL(-0.149594), REAL(0.611520), REAL(0.557731), + REAL(-0.163188), REAL(0.660791), REAL(0.491080), + REAL(-0.172482), REAL(0.663387), REAL(0.415416), + REAL(-0.160464), REAL(0.591710), REAL(0.370659), + REAL(-0.156445), REAL(0.536396), REAL(0.378302), + REAL(-0.136496), REAL(0.444358), REAL(0.425226), + REAL(-0.095564), REAL(0.373768), REAL(0.473659), + REAL(-0.104146), REAL(0.315912), REAL(0.498104), + REAL(-0.000496), REAL(0.384194), REAL(0.473817), + REAL(-0.000183), REAL(0.297770), REAL(0.401486), + REAL(-0.129042), REAL(0.270145), REAL(0.434495), + REAL(0.000100), REAL(0.272963), REAL(0.349138), + REAL(-0.113060), REAL(0.236984), REAL(0.385554), + REAL(0.007260), REAL(0.016311), REAL(-0.883396), + REAL(0.007865), REAL(0.122104), REAL(-0.956137), + REAL(-0.032842), REAL(0.115282), REAL(-0.953252), + REAL(-0.089115), REAL(0.108449), REAL(-0.950317), + REAL(-0.047440), REAL(0.014729), REAL(-0.882756), + REAL(-0.104458), REAL(0.013137), REAL(-0.882070), + REAL(-0.086439), REAL(-0.584866), REAL(-0.608343), + REAL(-0.115026), REAL(-0.662605), REAL(-0.436732), + REAL(-0.071683), REAL(-0.665372), REAL(-0.606385), + REAL(-0.257884), REAL(-0.665381), REAL(-0.658052), + REAL(-0.272542), REAL(-0.665381), REAL(-0.592063), + REAL(-0.371322), REAL(-0.665382), REAL(-0.353620), + REAL(-0.372362), REAL(-0.665381), REAL(-0.224420), + REAL(-0.335166), REAL(-0.665380), REAL(-0.078623), + REAL(-0.225999), REAL(-0.665375), REAL(-0.038981), + REAL(-0.106719), REAL(-0.665374), REAL(-0.186351), + REAL(-0.081749), REAL(-0.665372), REAL(-0.292554), + REAL(0.006943), REAL(-0.091505), REAL(-0.858354), + REAL(0.006117), REAL(-0.280985), REAL(-0.769967), + REAL(0.004495), REAL(-0.502360), REAL(-0.559799), + REAL(-0.198638), REAL(-0.302135), REAL(-0.845816), + REAL(-0.237395), REAL(-0.542544), REAL(-0.587188), + REAL(-0.270001), REAL(-0.279489), REAL(-0.669861), + REAL(-0.134547), REAL(-0.119852), REAL(-0.959004), + REAL(-0.052088), REAL(-0.122463), REAL(-0.944549), + REAL(-0.124463), REAL(-0.293508), REAL(-0.899566), + REAL(-0.047616), REAL(-0.289643), REAL(-0.879292), + REAL(-0.168595), REAL(-0.529132), REAL(-0.654931), + REAL(-0.099793), REAL(-0.515719), REAL(-0.645873), + REAL(-0.186168), REAL(-0.605282), REAL(-0.724690), + REAL(-0.112970), REAL(-0.583097), REAL(-0.707469), + REAL(-0.108152), REAL(-0.665375), REAL(-0.700408), + REAL(-0.183019), REAL(-0.665378), REAL(-0.717630), + REAL(-0.349529), REAL(-0.334459), REAL(-0.511985), + REAL(-0.141182), REAL(-0.437705), REAL(-0.798194), + REAL(-0.212670), REAL(-0.448725), REAL(-0.737447), + REAL(-0.261111), REAL(-0.414945), REAL(-0.613835), + REAL(-0.077364), REAL(-0.431480), REAL(-0.778113), + REAL(0.005174), REAL(-0.425277), REAL(-0.651592), + REAL(0.089236), REAL(-0.431732), REAL(-0.777093), + REAL(0.271006), REAL(-0.415749), REAL(-0.610577), + REAL(0.223981), REAL(-0.449384), REAL(-0.734774), + REAL(0.153275), REAL(-0.438150), REAL(-0.796391), + REAL(0.358414), REAL(-0.335529), REAL(-0.507649), + REAL(0.193434), REAL(-0.665946), REAL(-0.715325), + REAL(0.118363), REAL(-0.665717), REAL(-0.699021), + REAL(0.123515), REAL(-0.583454), REAL(-0.706020), + REAL(0.196851), REAL(-0.605860), REAL(-0.722345), + REAL(0.109788), REAL(-0.516035), REAL(-0.644590), + REAL(0.178656), REAL(-0.529656), REAL(-0.652804), + REAL(0.061157), REAL(-0.289807), REAL(-0.878626), + REAL(0.138234), REAL(-0.293905), REAL(-0.897958), + REAL(0.066933), REAL(-0.122643), REAL(-0.943820), + REAL(0.149571), REAL(-0.120281), REAL(-0.957264), + REAL(0.280989), REAL(-0.280321), REAL(-0.666487), + REAL(0.246581), REAL(-0.543275), REAL(-0.584224), + REAL(0.211720), REAL(-0.302754), REAL(-0.843303), + REAL(0.086966), REAL(-0.665627), REAL(-0.291520), + REAL(0.110634), REAL(-0.665702), REAL(-0.185021), + REAL(0.228099), REAL(-0.666061), REAL(-0.036201), + REAL(0.337743), REAL(-0.666396), REAL(-0.074503), + REAL(0.376722), REAL(-0.666513), REAL(-0.219833), + REAL(0.377265), REAL(-0.666513), REAL(-0.349036), + REAL(0.281411), REAL(-0.666217), REAL(-0.588670), + REAL(0.267564), REAL(-0.666174), REAL(-0.654834), + REAL(0.080745), REAL(-0.665602), REAL(-0.605452), + REAL(0.122016), REAL(-0.662963), REAL(-0.435280), + REAL(0.095767), REAL(-0.585141), REAL(-0.607228), + REAL(0.118944), REAL(0.012799), REAL(-0.880702), + REAL(0.061944), REAL(0.014564), REAL(-0.882086), + REAL(0.104725), REAL(0.108156), REAL(-0.949130), + REAL(0.048513), REAL(0.115159), REAL(-0.952753), + REAL(0.112696), REAL(0.236643), REAL(0.386937), + REAL(0.128177), REAL(0.269757), REAL(0.436071), + REAL(0.102643), REAL(0.315600), REAL(0.499370), + REAL(0.094535), REAL(0.373481), REAL(0.474824), + REAL(0.136270), REAL(0.443946), REAL(0.426895), + REAL(0.157071), REAL(0.535923), REAL(0.380222), + REAL(0.161350), REAL(0.591224), REAL(0.372630), + REAL(0.173035), REAL(0.662865), REAL(0.417531), + REAL(0.162808), REAL(0.660299), REAL(0.493077), + REAL(0.148250), REAL(0.611070), REAL(0.559555), + REAL(0.125719), REAL(0.576790), REAL(0.484702), + REAL(0.123489), REAL(0.534699), REAL(0.614440), + REAL(0.087621), REAL(0.506066), REAL(0.530188), + REAL(0.055321), REAL(0.442365), REAL(0.572915), + REAL(0.219936), REAL(0.568361), REAL(0.448571), + REAL(0.238099), REAL(0.441375), REAL(0.498528), + REAL(0.281711), REAL(0.414315), REAL(0.451121), + REAL(0.263833), REAL(0.528513), REAL(0.415794), + REAL(0.303284), REAL(0.533081), REAL(0.363998), + REAL(0.269687), REAL(0.623528), REAL(0.380528), + REAL(0.314255), REAL(0.670153), REAL(0.290524), + REAL(0.272023), REAL(0.682273), REAL(0.385343), + REAL(0.311480), REAL(0.775931), REAL(0.308527), + REAL(0.240239), REAL(0.652714), REAL(0.466159), + REAL(0.265619), REAL(0.756464), REAL(0.504187), + REAL(0.192562), REAL(0.467341), REAL(0.522972), + REAL(0.201605), REAL(0.524885), REAL(0.478417), + REAL(0.215743), REAL(0.564193), REAL(0.538084), + REAL(0.264969), REAL(0.641527), REAL(0.605317), + REAL(0.201031), REAL(0.477940), REAL(0.584002), + REAL(0.263086), REAL(0.512567), REAL(0.637832), + REAL(0.238615), REAL(0.526867), REAL(0.672237), + REAL(0.105309), REAL(0.455123), REAL(0.658482), + REAL(0.183993), REAL(0.102195), REAL(0.804872), + REAL(0.161563), REAL(0.060042), REAL(0.808692), + REAL(0.180748), REAL(0.077754), REAL(0.771600), + REAL(0.175168), REAL(0.128588), REAL(0.746368), + REAL(0.175075), REAL(0.148030), REAL(0.778264), + REAL(0.175658), REAL(0.139265), REAL(0.814333), + REAL(0.154191), REAL(0.067291), REAL(0.832578), + REAL(0.163818), REAL(0.109013), REAL(0.842830), + REAL(0.084760), REAL(0.396004), REAL(0.679695), + REAL(0.238888), REAL(0.310760), REAL(0.590775), + REAL(0.213380), REAL(0.308625), REAL(0.644905), + REAL(0.199666), REAL(0.409678), REAL(0.683003), + REAL(0.190143), REAL(0.128597), REAL(0.733463), + REAL(0.184833), REAL(0.063516), REAL(0.762902), + REAL(0.166070), REAL(0.035644), REAL(0.818261), + REAL(0.154361), REAL(0.056943), REAL(0.857042), + REAL(0.168542), REAL(0.109489), REAL(0.862725), + REAL(0.187387), REAL(0.166131), REAL(0.784599), + REAL(0.180428), REAL(0.160135), REAL(0.819438), + REAL(0.201823), REAL(0.163991), REAL(0.695756), + REAL(0.194206), REAL(0.206635), REAL(0.782275), + REAL(0.155438), REAL(0.291260), REAL(0.734412), + REAL(0.177696), REAL(0.196424), REAL(0.846693), + REAL(0.152305), REAL(0.125256), REAL(0.890786), + REAL(0.119546), REAL(0.249876), REAL(0.859104), + REAL(0.118369), REAL(0.139643), REAL(0.919173), + REAL(0.079410), REAL(0.132973), REAL(0.948652), + REAL(0.062419), REAL(0.036648), REAL(0.976547), + REAL(0.127847), REAL(-0.035919), REAL(0.947070), + REAL(0.143624), REAL(0.032206), REAL(0.885913), + REAL(0.074888), REAL(-0.085173), REAL(0.980577), + REAL(0.130184), REAL(-0.104656), REAL(0.947620), + REAL(0.156201), REAL(-0.094653), REAL(0.899074), + REAL(0.077366), REAL(-0.171194), REAL(0.926545), + REAL(0.127722), REAL(-0.164729), REAL(0.879810), + REAL(0.052670), REAL(-0.184618), REAL(0.842019), + REAL(0.023477), REAL(-0.184638), REAL(0.889811), + REAL(0.022626), REAL(-0.210587), REAL(0.827500), + REAL(0.223089), REAL(0.211976), REAL(0.620493), + REAL(0.251444), REAL(0.113067), REAL(0.666494), + REAL(0.251419), REAL(0.089540), REAL(0.673887), + REAL(0.214360), REAL(0.019258), REAL(0.771595), + REAL(0.158999), REAL(0.001490), REAL(0.835374), + REAL(0.176696), REAL(-0.059249), REAL(0.849218), + REAL(0.148696), REAL(-0.130091), REAL(0.793599), + REAL(0.108290), REAL(-0.166528), REAL(0.772088), + REAL(0.049820), REAL(-0.201382), REAL(0.764454), + REAL(0.071341), REAL(-0.215195), REAL(0.697209), + REAL(0.073148), REAL(-0.214475), REAL(0.623510), + REAL(0.140502), REAL(-0.169461), REAL(0.699354), + REAL(0.163374), REAL(-0.157073), REAL(0.611416), + REAL(0.189466), REAL(-0.138550), REAL(0.730366), + REAL(0.247593), REAL(-0.082554), REAL(0.759610), + REAL(0.227468), REAL(-0.121982), REAL(0.590197), + REAL(0.284702), REAL(-0.006586), REAL(0.535347), + REAL(0.275741), REAL(0.125287), REAL(0.446676), + REAL(0.266650), REAL(0.192594), REAL(0.506044), + REAL(0.300086), REAL(0.053287), REAL(0.629620), + REAL(0.055450), REAL(-0.663935), REAL(0.375065), + REAL(0.122854), REAL(-0.664138), REAL(0.482323), + REAL(0.046520), REAL(-0.531571), REAL(0.391918), + REAL(0.024824), REAL(-0.568450), REAL(0.275106), + REAL(0.053855), REAL(-0.663931), REAL(0.328224), + REAL(0.112829), REAL(-0.453549), REAL(0.305788), + REAL(0.131265), REAL(-0.510617), REAL(0.080746), + REAL(0.061174), REAL(-0.430716), REAL(-0.042710), + REAL(0.341019), REAL(-0.532887), REAL(-0.208150), + REAL(0.347705), REAL(-0.623533), REAL(-0.081139), + REAL(0.238040), REAL(-0.610732), REAL(-0.038037), + REAL(0.211764), REAL(-0.514274), REAL(-0.132078), + REAL(0.120605), REAL(-0.600219), REAL(-0.186856), + REAL(0.096985), REAL(-0.584476), REAL(-0.293357), + REAL(0.127621), REAL(-0.581941), REAL(-0.437170), + REAL(0.165902), REAL(-0.477425), REAL(-0.291453), + REAL(0.077720), REAL(-0.417975), REAL(-0.220519), + REAL(0.320892), REAL(-0.506363), REAL(-0.320874), + REAL(0.248214), REAL(-0.465684), REAL(-0.239842), + REAL(0.118764), REAL(-0.383338), REAL(-0.187114), + REAL(0.118816), REAL(-0.430106), REAL(-0.123307), + REAL(0.094131), REAL(-0.419464), REAL(-0.044777), + REAL(0.274526), REAL(-0.261706), REAL(0.005110), + REAL(0.259842), REAL(-0.283292), REAL(-0.003185), + REAL(0.222861), REAL(-0.340431), REAL(-0.038210), + REAL(0.204445), REAL(-0.664380), REAL(0.513353), + REAL(0.259286), REAL(-0.664547), REAL(0.471281), + REAL(0.185402), REAL(-0.476020), REAL(0.421718), + REAL(0.279163), REAL(-0.664604), REAL(0.417328), + REAL(0.277157), REAL(-0.528122), REAL(0.400208), + REAL(0.183069), REAL(-0.509812), REAL(0.329995), + REAL(0.282599), REAL(-0.429210), REAL(0.059242), + REAL(0.254816), REAL(-0.664541), REAL(0.290687), + REAL(0.271436), REAL(-0.567707), REAL(0.263966), + REAL(0.386561), REAL(-0.625221), REAL(-0.216870), + REAL(0.387086), REAL(-0.630883), REAL(-0.346073), + REAL(0.380021), REAL(-0.596021), REAL(-0.318679), + REAL(0.291269), REAL(-0.619007), REAL(-0.585707), + REAL(0.339280), REAL(-0.571198), REAL(-0.461946), + REAL(0.400045), REAL(-0.489778), REAL(-0.422640), + REAL(0.406817), REAL(-0.314349), REAL(-0.371230), + REAL(0.300588), REAL(-0.281718), REAL(-0.170549), + REAL(0.290866), REAL(-0.277304), REAL(-0.061905), + REAL(0.187735), REAL(-0.241545), REAL(0.509437), + REAL(0.188032), REAL(-0.287569), REAL(0.424234), + REAL(0.227520), REAL(-0.373262), REAL(0.293102), + REAL(0.266526), REAL(-0.273650), REAL(0.039597), + REAL(0.291592), REAL(-0.291676), REAL(0.111386), + REAL(0.291914), REAL(-0.122741), REAL(0.422683), + REAL(0.297574), REAL(-0.156119), REAL(0.373368), + REAL(0.286603), REAL(-0.232731), REAL(0.027162), + REAL(0.364663), REAL(-0.201399), REAL(0.206850), + REAL(0.353855), REAL(-0.132408), REAL(0.149228), + REAL(0.282208), REAL(-0.019715), REAL(0.314960), + REAL(0.331187), REAL(-0.099266), REAL(0.092701), + REAL(0.375463), REAL(-0.093120), REAL(-0.006467), + REAL(0.375917), REAL(-0.101236), REAL(-0.154882), + REAL(0.466635), REAL(-0.094416), REAL(-0.305669), + REAL(0.455805), REAL(-0.119881), REAL(-0.460632), + REAL(0.277465), REAL(-0.604242), REAL(-0.651871), + REAL(0.261022), REAL(-0.551176), REAL(-0.554667), + REAL(0.093627), REAL(0.258494), REAL(-0.920589), + REAL(0.114248), REAL(0.310608), REAL(-0.798070), + REAL(0.144232), REAL(0.211434), REAL(-0.835001), + REAL(0.119916), REAL(0.176940), REAL(-0.951159), + REAL(0.184061), REAL(0.101854), REAL(-0.918220), + REAL(0.092431), REAL(0.276521), REAL(-0.738231), + REAL(0.133504), REAL(0.218403), REAL(-0.758602), + REAL(0.194987), REAL(0.097655), REAL(-0.812476), + REAL(0.185542), REAL(0.011005), REAL(-0.879202), + REAL(0.230315), REAL(-0.127450), REAL(-0.884202), + REAL(0.260471), REAL(0.255056), REAL(-0.624378), + REAL(0.351567), REAL(-0.042194), REAL(-0.663976), + REAL(0.253742), REAL(0.323524), REAL(-0.433716), + REAL(0.411612), REAL(0.132299), REAL(-0.438264), + REAL(0.270513), REAL(0.356530), REAL(-0.289984), + REAL(0.422146), REAL(0.162819), REAL(-0.273130), + REAL(0.164724), REAL(0.237490), REAL(0.208912), + REAL(0.253806), REAL(0.092900), REAL(0.240640), + REAL(0.203608), REAL(0.284597), REAL(0.096223), + REAL(0.241006), REAL(0.343093), REAL(-0.171396), + REAL(0.356076), REAL(0.149288), REAL(-0.143443), + REAL(0.337656), REAL(0.131992), REAL(0.066374) +}; + +static int gIndicesBunny[BUNNY_NUM_TRIANGLES][3] = { + {126,134,133}, + {342,138,134}, + {133,134,138}, + {126,342,134}, + {312,316,317}, + {169,163,162}, + {312,317,319}, + {312,319,318}, + {169,162,164}, + {169,168,163}, + {312,314,315}, + {169,164,165}, + {169,167,168}, + {312,315,316}, + {312,313,314}, + {169,165,166}, + {169,166,167}, + {312,318,313}, + {308,304,305}, + {308,305,306}, + {179,181,188}, + {177,173,175}, + {177,175,176}, + {302,293,300}, + {322,294,304}, + {188,176,175}, + {188,175,179}, + {158,177,187}, + {305,293,302}, + {305,302,306}, + {322,304,308}, + {188,181,183}, + {158,173,177}, + {293,298,300}, + {304,294,296}, + {304,296,305}, + {185,176,188}, + {185,188,183}, + {187,177,176}, + {187,176,185}, + {305,296,298}, + {305,298,293}, + {436,432, 28}, + {436, 28, 23}, + {434,278,431}, + { 30,208,209}, + { 30,209, 29}, + { 19, 20, 24}, + {208,207,211}, + {208,211,209}, + { 19,210,212}, + {433,434,431}, + {433,431,432}, + {433,432,436}, + {436,437,433}, + {277,275,276}, + {277,276,278}, + {209,210, 25}, + { 21, 26, 24}, + { 21, 24, 20}, + { 25, 26, 27}, + { 25, 27, 29}, + {435,439,277}, + {439,275,277}, + {432,431, 30}, + {432, 30, 28}, + {433,437,438}, + {433,438,435}, + {434,277,278}, + { 24, 25,210}, + { 24, 26, 25}, + { 29, 27, 28}, + { 29, 28, 30}, + { 19, 24,210}, + {208, 30,431}, + {208,431,278}, + {435,434,433}, + {435,277,434}, + { 25, 29,209}, + { 27, 22, 23}, + { 27, 23, 28}, + { 26, 22, 27}, + { 26, 21, 22}, + {212,210,209}, + {212,209,211}, + {207,208,278}, + {207,278,276}, + {439,435,438}, + { 12, 9, 10}, + { 12, 10, 13}, + { 2, 3, 5}, + { 2, 5, 4}, + { 16, 13, 14}, + { 16, 14, 17}, + { 22, 21, 16}, + { 13, 10, 11}, + { 13, 11, 14}, + { 1, 0, 3}, + { 1, 3, 2}, + { 15, 12, 16}, + { 19, 18, 15}, + { 19, 15, 16}, + { 19, 16, 20}, + { 9, 1, 2}, + { 9, 2, 10}, + { 3, 7, 8}, + { 3, 8, 5}, + { 16, 17, 23}, + { 16, 23, 22}, + { 21, 20, 16}, + { 10, 2, 4}, + { 10, 4, 11}, + { 0, 6, 7}, + { 0, 7, 3}, + { 12, 13, 16}, + {451,446,445}, + {451,445,450}, + {442,440,439}, + {442,439,438}, + {442,438,441}, + {421,420,422}, + {412,411,426}, + {412,426,425}, + {408,405,407}, + {413, 67, 68}, + {413, 68,414}, + {391,390,412}, + { 80,384,386}, + {404,406,378}, + {390,391,377}, + {390,377, 88}, + {400,415,375}, + {398,396,395}, + {398,395,371}, + {398,371,370}, + {112,359,358}, + {112,358,113}, + {351,352,369}, + {125,349,348}, + {345,343,342}, + {342,340,339}, + {341,335,337}, + {328,341,327}, + {331,323,333}, + {331,322,323}, + {327,318,319}, + {327,319,328}, + {315,314,324}, + {302,300,301}, + {302,301,303}, + {320,311,292}, + {285,284,289}, + {310,307,288}, + {310,288,290}, + {321,350,281}, + {321,281,282}, + {423,448,367}, + {272,273,384}, + {272,384,274}, + {264,265,382}, + {264,382,383}, + {440,442,261}, + {440,261,263}, + {252,253,254}, + {252,254,251}, + {262,256,249}, + {262,249,248}, + {228,243,242}, + {228, 31,243}, + {213,215,238}, + {213,238,237}, + { 19,212,230}, + {224,225,233}, + {224,233,231}, + {217,218, 56}, + {217, 56, 54}, + {217,216,239}, + {217,239,238}, + {217,238,215}, + {218,217,215}, + {218,215,214}, + { 6,102,206}, + {186,199,200}, + {197,182,180}, + {170,171,157}, + {201,200,189}, + {170,190,191}, + {170,191,192}, + {175,174,178}, + {175,178,179}, + {168,167,155}, + {122,149,158}, + {122,158,159}, + {135,153,154}, + {135,154,118}, + {143,140,141}, + {143,141,144}, + {132,133,136}, + {130,126,133}, + {124,125,127}, + {122,101,100}, + {122,100,121}, + {110,108,107}, + {110,107,109}, + { 98, 99, 97}, + { 98, 97, 64}, + { 98, 64, 66}, + { 87, 55, 57}, + { 83, 82, 79}, + { 83, 79, 84}, + { 78, 74, 50}, + { 49, 71, 41}, + { 49, 41, 37}, + { 49, 37, 36}, + { 58, 44, 60}, + { 60, 59, 58}, + { 51, 34, 33}, + { 39, 40, 42}, + { 39, 42, 38}, + {243,240, 33}, + {243, 33,229}, + { 39, 38, 6}, + { 44, 46, 40}, + { 55, 56, 57}, + { 64, 62, 65}, + { 64, 65, 66}, + { 41, 71, 45}, + { 75, 50, 51}, + { 81, 79, 82}, + { 77, 88, 73}, + { 93, 92, 94}, + { 68, 47, 46}, + { 96, 97, 99}, + { 96, 99, 95}, + {110,109,111}, + {111,112,110}, + {114,113,123}, + {114,123,124}, + {132,131,129}, + {133,137,136}, + {135,142,145}, + {145,152,135}, + {149,147,157}, + {157,158,149}, + {164,150,151}, + {153,163,168}, + {153,168,154}, + {185,183,182}, + {185,182,184}, + {161,189,190}, + {200,199,191}, + {200,191,190}, + {180,178,195}, + {180,195,196}, + {102,101,204}, + {102,204,206}, + { 43, 48,104}, + { 43,104,103}, + {216,217, 54}, + {216, 54, 32}, + {207,224,231}, + {230,212,211}, + {230,211,231}, + {227,232,241}, + {227,241,242}, + {235,234,241}, + {235,241,244}, + {430,248,247}, + {272,274,253}, + {272,253,252}, + {439,260,275}, + {225,224,259}, + {225,259,257}, + {269,270,407}, + {269,407,405}, + {270,269,273}, + {270,273,272}, + {273,269,268}, + {273,268,267}, + {273,267,266}, + {273,266,265}, + {273,265,264}, + {448,279,367}, + {281,350,368}, + {285,286,301}, + {290,323,310}, + {290,311,323}, + {282,281,189}, + {292,311,290}, + {292,290,291}, + {307,306,302}, + {307,302,303}, + {316,315,324}, + {316,324,329}, + {331,351,350}, + {330,334,335}, + {330,335,328}, + {341,337,338}, + {344,355,354}, + {346,345,348}, + {346,348,347}, + {364,369,352}, + {364,352,353}, + {365,363,361}, + {365,361,362}, + {376,401,402}, + {373,372,397}, + {373,397,400}, + {376, 92,377}, + {381,378,387}, + {381,387,385}, + {386, 77, 80}, + {390,389,412}, + {416,417,401}, + {403,417,415}, + {408,429,430}, + {419,423,418}, + {427,428,444}, + {427,444,446}, + {437,436,441}, + {450,445, 11}, + {450, 11, 4}, + {447,449, 5}, + {447, 5, 8}, + {441,438,437}, + {425,426,451}, + {425,451,452}, + {417,421,415}, + {408,407,429}, + {399,403,400}, + {399,400,397}, + {394,393,416}, + {389,411,412}, + {386,383,385}, + {408,387,378}, + {408,378,406}, + {377,391,376}, + { 94,375,415}, + {372,373,374}, + {372,374,370}, + {359,111,360}, + {359,112,111}, + {113,358,349}, + {113,349,123}, + {346,343,345}, + {343,340,342}, + {338,336,144}, + {338,144,141}, + {327,341,354}, + {327,354,326}, + {331,350,321}, + {331,321,322}, + {314,313,326}, + {314,326,325}, + {300,298,299}, + {300,299,301}, + {288,287,289}, + {189,292,282}, + {287,288,303}, + {284,285,297}, + {368,280,281}, + {448,447,279}, + {274,226,255}, + {267,268,404}, + {267,404,379}, + {429,262,430}, + {439,440,260}, + {257,258,249}, + {257,249,246}, + {430,262,248}, + {234,228,242}, + {234,242,241}, + {237,238,239}, + {237,239,236}, + { 15, 18,227}, + { 15,227,229}, + {222,223, 82}, + {222, 82, 83}, + {214,215,213}, + {214,213, 81}, + { 38,102, 6}, + {122,159,200}, + {122,200,201}, + {174,171,192}, + {174,192,194}, + {197,193,198}, + {190,170,161}, + {181,179,178}, + {181,178,180}, + {166,156,155}, + {163,153,152}, + {163,152,162}, + {120,156,149}, + {120,149,121}, + {152,153,135}, + {140,143,142}, + {135,131,132}, + {135,132,136}, + {130,129,128}, + {130,128,127}, + {100,105,119}, + {100,119,120}, + {106,104,107}, + {106,107,108}, + { 91, 95, 59}, + { 93, 94, 68}, + { 91, 89, 92}, + { 76, 53, 55}, + { 76, 55, 87}, + { 81, 78, 79}, + { 74, 73, 49}, + { 69, 60, 45}, + { 58, 62, 64}, + { 58, 64, 61}, + { 53, 31, 32}, + { 32, 54, 53}, + { 42, 43, 38}, + { 35, 36, 0}, + { 35, 0, 1}, + { 34, 35, 1}, + { 34, 1, 9}, + { 44, 40, 41}, + { 44, 41, 45}, + { 33,240, 51}, + { 63, 62, 58}, + { 63, 58, 59}, + { 45, 71, 70}, + { 76, 75, 51}, + { 76, 51, 52}, + { 86, 85, 84}, + { 86, 84, 87}, + { 89, 72, 73}, + { 89, 73, 88}, + { 91, 92, 96}, + { 91, 96, 95}, + { 72, 91, 60}, + { 72, 60, 69}, + {104,106,105}, + {119,105,117}, + {119,117,118}, + {124,127,128}, + {117,116,129}, + {117,129,131}, + {118,117,131}, + {135,140,142}, + {146,150,152}, + {146,152,145}, + {149,122,121}, + {166,165,151}, + {166,151,156}, + {158,172,173}, + {161,160,189}, + {199,198,193}, + {199,193,191}, + {204,201,202}, + {178,174,194}, + {200,159,186}, + {109, 48, 67}, + { 48,107,104}, + {216, 32,236}, + {216,236,239}, + {223,214, 81}, + {223, 81, 82}, + { 33, 12, 15}, + { 32,228,234}, + { 32,234,236}, + {240, 31, 52}, + {256,255,246}, + {256,246,249}, + {258,263,248}, + {258,248,249}, + {275,260,259}, + {275,259,276}, + {207,276,259}, + {270,271,429}, + {270,429,407}, + {413,418,366}, + {413,366,365}, + {368,367,279}, + {368,279,280}, + {303,301,286}, + {303,286,287}, + {283,282,292}, + {283,292,291}, + {320,292,189}, + {298,296,297}, + {298,297,299}, + {318,327,326}, + {318,326,313}, + {329,330,317}, + {336,333,320}, + {326,354,353}, + {334,332,333}, + {334,333,336}, + {342,339,139}, + {342,139,138}, + {345,342,126}, + {347,357,356}, + {369,368,351}, + {363,356,357}, + {363,357,361}, + {366,367,368}, + {366,368,369}, + {375,373,400}, + { 92, 90,377}, + {409,387,408}, + {386,385,387}, + {386,387,388}, + {412,394,391}, + {396,398,399}, + {408,406,405}, + {415,421,419}, + {415,419,414}, + {425,452,448}, + {425,448,424}, + {444,441,443}, + {448,452,449}, + {448,449,447}, + {446,444,443}, + {446,443,445}, + {250,247,261}, + {250,261,428}, + {421,422,423}, + {421,423,419}, + {427,410,250}, + {417,403,401}, + {403,402,401}, + {420,392,412}, + {420,412,425}, + {420,425,424}, + {386,411,389}, + {383,382,381}, + {383,381,385}, + {378,379,404}, + {372,371,395}, + {372,395,397}, + {371,372,370}, + {361,359,360}, + {361,360,362}, + {368,350,351}, + {349,347,348}, + {356,355,344}, + {356,344,346}, + {344,341,340}, + {344,340,343}, + {338,337,336}, + {328,335,341}, + {324,352,351}, + {324,351,331}, + {320,144,336}, + {314,325,324}, + {322,308,309}, + {310,309,307}, + {287,286,289}, + {203,280,279}, + {203,279,205}, + {297,295,283}, + {297,283,284}, + {447,205,279}, + {274,384, 80}, + {274, 80,226}, + {266,267,379}, + {266,379,380}, + {225,257,246}, + {225,246,245}, + {256,254,253}, + {256,253,255}, + {430,247,250}, + {226,235,244}, + {226,244,245}, + {232,233,244}, + {232,244,241}, + {230, 18, 19}, + { 32, 31,228}, + {219,220, 86}, + {219, 86, 57}, + {226,213,235}, + {206, 7, 6}, + {122,201,101}, + {201,204,101}, + {180,196,197}, + {170,192,171}, + {200,190,189}, + {194,193,195}, + {183,181,180}, + {183,180,182}, + {155,154,168}, + {149,156,151}, + {149,151,148}, + {155,156,120}, + {145,142,143}, + {145,143,146}, + {136,137,140}, + {133,132,130}, + {128,129,116}, + {100,120,121}, + {110,112,113}, + {110,113,114}, + { 66, 65, 63}, + { 66, 63, 99}, + { 66, 99, 98}, + { 96, 46, 61}, + { 89, 88, 90}, + { 86, 87, 57}, + { 80, 78, 81}, + { 72, 69, 49}, + { 67, 48, 47}, + { 67, 47, 68}, + { 56, 55, 53}, + { 50, 49, 36}, + { 50, 36, 35}, + { 40, 39, 41}, + {242,243,229}, + {242,229,227}, + { 6, 37, 39}, + { 42, 47, 48}, + { 42, 48, 43}, + { 61, 46, 44}, + { 45, 70, 69}, + { 69, 70, 71}, + { 69, 71, 49}, + { 74, 78, 77}, + { 83, 84, 85}, + { 73, 74, 77}, + { 93, 96, 92}, + { 68, 46, 93}, + { 95, 99, 63}, + { 95, 63, 59}, + {115,108,110}, + {115,110,114}, + {125,126,127}, + {129,130,132}, + {137,133,138}, + {137,138,139}, + {148,146,143}, + {148,143,147}, + {119,118,154}, + {161,147,143}, + {165,164,151}, + {158,157,171}, + {158,171,172}, + {159,158,187}, + {159,187,186}, + {194,192,191}, + {194,191,193}, + {189,202,201}, + {182,197,184}, + {205, 8, 7}, + { 48,109,107}, + {218,219, 57}, + {218, 57, 56}, + {207,231,211}, + {232,230,231}, + {232,231,233}, + { 53, 52, 31}, + {388,411,386}, + {409,430,250}, + {262,429,254}, + {262,254,256}, + {442,444,428}, + {273,264,383}, + {273,383,384}, + {429,271,251}, + {429,251,254}, + {413,365,362}, + { 67,413,360}, + {282,283,295}, + {285,301,299}, + {202,281,280}, + {284,283,291}, + {284,291,289}, + {320,189,160}, + {308,306,307}, + {307,309,308}, + {319,317,330}, + {319,330,328}, + {353,352,324}, + {332,331,333}, + {340,341,338}, + {354,341,344}, + {349,358,357}, + {349,357,347}, + {364,355,356}, + {364,356,363}, + {364,365,366}, + {364,366,369}, + {374,376,402}, + {375, 92,373}, + { 77,389,390}, + {382,380,381}, + {389, 77,386}, + {393,394,412}, + {393,412,392}, + {401,394,416}, + {415,400,403}, + {411,410,427}, + {411,427,426}, + {422,420,424}, + {247,248,263}, + {247,263,261}, + {445,443, 14}, + {445, 14, 11}, + {449,450, 4}, + {449, 4, 5}, + {443,441, 17}, + {443, 17, 14}, + {436, 23, 17}, + {436, 17,441}, + {424,448,422}, + {448,423,422}, + {414,419,418}, + {414,418,413}, + {406,404,405}, + {399,397,395}, + {399,395,396}, + {420,416,392}, + {388,410,411}, + {386,384,383}, + {390, 88, 77}, + {375, 94, 92}, + {415,414, 68}, + {415, 68, 94}, + {370,374,402}, + {370,402,398}, + {361,357,358}, + {361,358,359}, + {125,348,126}, + {346,344,343}, + {340,338,339}, + {337,335,334}, + {337,334,336}, + {325,353,324}, + {324,331,332}, + {324,332,329}, + {323,322,309}, + {323,309,310}, + {294,295,297}, + {294,297,296}, + {289,286,285}, + {202,280,203}, + {288,307,303}, + {282,295,321}, + { 67,360,111}, + {418,423,367}, + {418,367,366}, + {272,252,251}, + {272,251,271}, + {272,271,270}, + {255,253,274}, + {265,266,380}, + {265,380,382}, + {442,428,261}, + {440,263,258}, + {440,258,260}, + {409,250,410}, + {255,226,245}, + {255,245,246}, + { 31,240,243}, + {236,234,235}, + {236,235,237}, + {233,225,245}, + {233,245,244}, + {220,221, 85}, + {220, 85, 86}, + { 81,213,226}, + { 81,226, 80}, + { 7,206,205}, + {186,184,198}, + {186,198,199}, + {204,203,205}, + {204,205,206}, + {195,193,196}, + {171,174,172}, + {173,174,175}, + {173,172,174}, + {155,167,166}, + {160,161,143}, + {160,143,144}, + {119,154,155}, + {148,151,150}, + {148,150,146}, + {140,137,139}, + {140,139,141}, + {127,126,130}, + {114,124,128}, + {114,128,115}, + {117,105,106}, + {117,106,116}, + {104,105,100}, + {104,100,103}, + { 59, 60, 91}, + { 97, 96, 61}, + { 97, 61, 64}, + { 91, 72, 89}, + { 87, 84, 79}, + { 87, 79, 76}, + { 78, 80, 77}, + { 49, 50, 74}, + { 60, 44, 45}, + { 61, 44, 58}, + { 51, 50, 35}, + { 51, 35, 34}, + { 39, 37, 41}, + { 33, 34, 9}, + { 33, 9, 12}, + { 0, 36, 37}, + { 0, 37, 6}, + { 40, 46, 47}, + { 40, 47, 42}, + { 53, 54, 56}, + { 65, 62, 63}, + { 72, 49, 73}, + { 79, 78, 75}, + { 79, 75, 76}, + { 52, 53, 76}, + { 92, 89, 90}, + { 96, 93, 46}, + {102,103,100}, + {102,100,101}, + {116,106,108}, + {116,108,115}, + {123,125,124}, + {116,115,128}, + {118,131,135}, + {140,135,136}, + {148,147,149}, + {120,119,155}, + {164,162,152}, + {164,152,150}, + {157,147,161}, + {157,161,170}, + {186,187,185}, + {186,185,184}, + {193,197,196}, + {202,203,204}, + {194,195,178}, + {198,184,197}, + { 67,111,109}, + { 38, 43,103}, + { 38,103,102}, + {214,223,222}, + {214,222,221}, + {214,221,220}, + {214,220,219}, + {214,219,218}, + {213,237,235}, + {221,222, 83}, + {221, 83, 85}, + { 15,229, 33}, + {227, 18,230}, + {227,230,232}, + { 52, 51,240}, + { 75, 78, 50}, + {408,430,409}, + {260,258,257}, + {260,257,259}, + {224,207,259}, + {268,269,405}, + {268,405,404}, + {413,362,360}, + {447, 8,205}, + {299,297,285}, + {189,281,202}, + {290,288,289}, + {290,289,291}, + {322,321,295}, + {322,295,294}, + {333,323,311}, + {333,311,320}, + {317,316,329}, + {320,160,144}, + {353,325,326}, + {329,332,334}, + {329,334,330}, + {339,338,141}, + {339,141,139}, + {348,345,126}, + {347,356,346}, + {123,349,125}, + {364,353,354}, + {364,354,355}, + {365,364,363}, + {376,391,394}, + {376,394,401}, + { 92,376,374}, + { 92,374,373}, + {377, 90, 88}, + {380,379,378}, + {380,378,381}, + {388,387,409}, + {388,409,410}, + {416,393,392}, + {399,398,402}, + {399,402,403}, + {250,428,427}, + {421,417,416}, + {421,416,420}, + {426,427,446}, + {426,446,451}, + {444,442,441}, + {452,451,450}, + {452,450,449} +}; + + +//***************************THE END OF FAMOUS BUNNY TRIMESH********************************************// + + +#endif //BUNNY_MESH_H_ diff --git a/examples/SoftDemo/SoftDemo.cpp b/examples/SoftDemo/SoftDemo.cpp new file mode 100644 index 000000000..1eb62fc0a --- /dev/null +++ b/examples/SoftDemo/SoftDemo.cpp @@ -0,0 +1,2332 @@ +/* +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 "btBulletDynamicsCommon.h" +#include "BulletSoftBody/btSoftRigidDynamicsWorld.h" + +#include "BulletCollision/CollisionDispatch/btSphereSphereCollisionAlgorithm.h" +#include "BulletCollision/NarrowPhaseCollision/btGjkEpa2.h" +#include "LinearMath/btQuickprof.h" +#include "LinearMath/btIDebugDraw.h" + +#include "BunnyMesh.h" +#include "TorusMesh.h" +#include //printf debugging +#include "LinearMath/btConvexHull.h" +#include "BulletSoftBody/btSoftBodyRigidBodyCollisionConfiguration.h" +#include "BulletSoftBody/btSoftBodyHelpers.h" + +#include "SoftDemo.h" +#include "GL_ShapeDrawer.h" + + +#include "LinearMath/btAlignedObjectArray.h" +#include "BulletSoftBody/btSoftBody.h" + + +class btBroadphaseInterface; +class btCollisionShape; +class btOverlappingPairCache; +class btCollisionDispatcher; +class btConstraintSolver; +struct btCollisionAlgorithmCreateFunc; +class btDefaultCollisionConfiguration; + +///collisions between two btSoftBody's +class btSoftSoftCollisionAlgorithm; + +///collisions between a btSoftBody and a btRigidBody +class btSoftRididCollisionAlgorithm; +class btSoftRigidDynamicsWorld; + +#include "../CommonInterfaces/CommonRigidBodyBase.h" + + +class SoftDemo : public CommonRigidBodyBase +{ +public: + + btAlignedObjectArray m_SoftSoftCollisionAlgorithms; + + btAlignedObjectArray m_SoftRigidCollisionAlgorithms; + + btSoftBodyWorldInfo m_softBodyWorldInfo; + + + + bool m_autocam; + bool m_cutting; + bool m_raycast; + btScalar m_animtime; + btClock m_clock; + int m_lastmousepos[2]; + btVector3 m_impact; + btSoftBody::sRayCast m_results; + btSoftBody::Node* m_node; + btVector3 m_goal; + bool m_drag; + + + //keep the collision shapes, for deletion/cleanup + btAlignedObjectArray m_collisionShapes; + + btBroadphaseInterface* m_broadphase; + + btCollisionDispatcher* m_dispatcher; + + + btConstraintSolver* m_solver; + + btCollisionAlgorithmCreateFunc* m_boxBoxCF; + + btDefaultCollisionConfiguration* m_collisionConfiguration; + + +public: + + void initPhysics(); + + void exitPhysics(); + + SoftDemo(struct GUIHelperInterface* helper) + : CommonRigidBodyBase(helper), + m_drag(false) + + { + + } + virtual ~SoftDemo() + { + btAssert(m_dynamicsWorld==0); + } + + //virtual void clientMoveAndDisplay(); + + //virtual void displayCallback(); + + void createStack( btCollisionShape* boxShape, float halfCubeSize, int size, float zPos ); + + + + virtual void setDrawClusters(bool drawClusters); + + virtual const btSoftRigidDynamicsWorld* getSoftDynamicsWorld() const + { + ///just make it a btSoftRigidDynamicsWorld please + ///or we will add type checking + return (btSoftRigidDynamicsWorld*) m_dynamicsWorld; + } + + virtual btSoftRigidDynamicsWorld* getSoftDynamicsWorld() + { + ///just make it a btSoftRigidDynamicsWorld please + ///or we will add type checking + return (btSoftRigidDynamicsWorld*) m_dynamicsWorld; + } + + // + //void clientResetScene(); + void renderme(); + void keyboardCallback(unsigned char key, int x, int y); + void mouseFunc(int button, int state, int x, int y); + void mouseMotionFunc(int x,int y); + + GUIHelperInterface* getGUIHelper() + { + return m_guiHelper; + } +}; + + +#define MACRO_SOFT_DEMO(a) class SoftDemo##a : public SoftDemo\ +{\ +public:\ + static DemoApplication* Create()\ + {\ + SoftDemo* demo = new SoftDemo##a;\ + extern int current_demo;\ + current_demo=a;\ + demo->initPhysics();\ + return demo;\ + }\ +}; + + + +//MACRO_SOFT_DEMO(0) //Init_Cloth +#if 0 +MACRO_SOFT_DEMO(1) //Init_Pressure +MACRO_SOFT_DEMO(2)//Init_Volume +MACRO_SOFT_DEMO(3)//Init_Ropes +MACRO_SOFT_DEMO(4)//Init_Ropes_Attach +MACRO_SOFT_DEMO(5)//Init_ClothAttach +MACRO_SOFT_DEMO(6)//Init_Sticks +MACRO_SOFT_DEMO(7)//Init_Collide +MACRO_SOFT_DEMO(8)//Init_Collide2 +MACRO_SOFT_DEMO(9)//Init_Collide3 +MACRO_SOFT_DEMO(10)//Init_Impact +MACRO_SOFT_DEMO(11)//Init_Aero +MACRO_SOFT_DEMO(12)//Init_Friction +MACRO_SOFT_DEMO(13)//Init_Torus +MACRO_SOFT_DEMO(14)//Init_TorusMatch +MACRO_SOFT_DEMO(15)//Init_Bunny +MACRO_SOFT_DEMO(16)//Init_BunnyMatch +MACRO_SOFT_DEMO(17)//Init_Cutting1 +MACRO_SOFT_DEMO(18)//Init_ClusterDeform +MACRO_SOFT_DEMO(19)//Init_ClusterCollide1 +MACRO_SOFT_DEMO(20)//Init_ClusterCollide2 +MACRO_SOFT_DEMO(21)//Init_ClusterSocket +MACRO_SOFT_DEMO(22)//Init_ClusterHinge +MACRO_SOFT_DEMO(23)//Init_ClusterCombine +MACRO_SOFT_DEMO(24)//Init_ClusterCar +MACRO_SOFT_DEMO(25)//Init_ClusterRobot +MACRO_SOFT_DEMO(26)//Init_ClusterStackSoft +MACRO_SOFT_DEMO(27)//Init_ClusterStackMixed +MACRO_SOFT_DEMO(28)//Init_TetraCube +MACRO_SOFT_DEMO(29)//Init_TetraBunny + +#endif + +extern float eye[3]; +extern int glutScreenWidth; +extern int glutScreenHeight; + +static bool sDemoMode = false; + +const int maxProxies = 32766; +const int maxOverlap = 65535; + +static btVector3* gGroundVertices=0; +static int* gGroundIndices=0; +static btBvhTriangleMeshShape* trimeshShape =0; +static btRigidBody* staticBody = 0; +static float waveheight = 5.f; + +const float TRIANGLE_SIZE=8.f; +int current_demo=20; +#define DEMO_MODE_TIMEOUT 15.f //15 seconds for each demo + + +#ifdef _DEBUG +const int gNumObjects = 1; +#else +const int gNumObjects = 1;//try this in release mode: 3000. never go above 16384, unless you increate maxNumObjects value in DemoApplication.cp +#endif + +const int maxNumObjects = 32760; + +#define CUBE_HALF_EXTENTS 1.5 +#define EXTRA_HEIGHT -10.f + + + +// +void SoftDemo::createStack( btCollisionShape* boxShape, float halfCubeSize, int size, float zPos ) +{ + btTransform trans; + trans.setIdentity(); + + for(int i=0; igetWorldUserInfo(); + + if(softDemo->m_drag) + { + const int x=softDemo->m_lastmousepos[0]; + const int y=softDemo->m_lastmousepos[1]; + float rf[3]; + softDemo->getGUIHelper()->getRenderInterface()->getActiveCamera()->getCameraPosition(rf); + float target[3]; + softDemo->getGUIHelper()->getRenderInterface()->getActiveCamera()->getCameraTargetPosition(target); + btVector3 cameraTargetPosition(target[0],target[1],target[2]); + + const btVector3 cameraPosition(rf[0],rf[1],rf[2]); + const btVector3 rayFrom=cameraPosition; + + const btVector3 rayTo=softDemo->getRayTo(x,y); + const btVector3 rayDir=(rayTo-rayFrom).normalized(); + const btVector3 N=(cameraTargetPosition-cameraPosition).normalized(); + const btScalar O=btDot(softDemo->m_impact,N); + const btScalar den=btDot(N,rayDir); + if((den*den)>0) + { + const btScalar num=O-btDot(N,rayFrom); + const btScalar hit=num/den; + if((hit>0)&&(hit<1500)) + { + softDemo->m_goal=rayFrom+rayDir*hit; + } + } + btVector3 delta=softDemo->m_goal-softDemo->m_node->m_x; + static const btScalar maxdrag=10; + if(delta.length2()>(maxdrag*maxdrag)) + { + delta=delta.normalized()*maxdrag; + } + softDemo->m_node->m_v+=delta/timeStep; + } + +} + + + + + +// +// ImplicitShape +// + +// +struct ImplicitSphere : btSoftBody::ImplicitFn +{ + btVector3 center; + btScalar sqradius; + ImplicitSphere() {} + ImplicitSphere(const btVector3& c,btScalar r) : center(c),sqradius(r*r) {} + btScalar Eval(const btVector3& x) + { + return((x-center).length2()-sqradius); + } +}; + +// +// Tetra meshes +// + +struct TetraBunny +{ +#include "bunny.inl" +}; + +struct TetraCube +{ +#include "cube.inl" +}; + + +// +// Random +// + +static inline btScalar UnitRand() +{ + return(rand()/(btScalar)RAND_MAX); +} + +static inline btScalar SignedUnitRand() +{ + return(UnitRand()*2-1); +} + +static inline btVector3 Vector3Rand() +{ + const btVector3 p=btVector3(SignedUnitRand(),SignedUnitRand(),SignedUnitRand()); + return(p.normalized()); +} + +// +// Rb rain +// +static void Ctor_RbUpStack(SoftDemo* pdemo,int count) +{ + float mass=10; + + btCompoundShape* cylinderCompound = new btCompoundShape; + btCollisionShape* cylinderShape = new btCylinderShapeX(btVector3(4,1,1)); + btCollisionShape* boxShape = new btBoxShape(btVector3(4,1,1)); + btTransform localTransform; + localTransform.setIdentity(); + cylinderCompound->addChildShape(localTransform,boxShape); + btQuaternion orn(SIMD_HALF_PI,0,0); + localTransform.setRotation(orn); + // localTransform.setOrigin(btVector3(1,1,1)); + cylinderCompound->addChildShape(localTransform,cylinderShape); + + + btCollisionShape* shape[]={cylinderCompound, + new btBoxShape(btVector3(1,1,1)), + new btSphereShape(1.5) + + }; + static const int nshapes=sizeof(shape)/sizeof(shape[0]); + for(int i=0;icreateRigidBody(mass,startTransform,shape[i%nshapes]); + //pdemo->createRigidBody(mass,startTransform,shape[0]); + } +} + +// +// Big ball +// +static void Ctor_BigBall(SoftDemo* pdemo,btScalar mass=10) +{ + btTransform startTransform; + startTransform.setIdentity(); + startTransform.setOrigin(btVector3(0,13,0)); + pdemo->createRigidBody(mass,startTransform,new btSphereShape(3)); +} + +// +// Big plate +// +static btRigidBody* Ctor_BigPlate(SoftDemo* pdemo,btScalar mass=15,btScalar height=4) +{ + btTransform startTransform; + startTransform.setIdentity(); + startTransform.setOrigin(btVector3(0,height,0.5)); + btRigidBody* body=pdemo->createRigidBody(mass,startTransform,new btBoxShape(btVector3(5,1,5))); + body->setFriction(1); + return(body); +} + +// +// Linear stair +// +static void Ctor_LinearStair(SoftDemo* pdemo,const btVector3& org,const btVector3& sizes,btScalar angle,int count) +{ + btBoxShape* shape=new btBoxShape(sizes); + for(int i=0;icreateRigidBody(0,startTransform,shape); + body->setFriction(1); + } +} + +// +// Softbox +// +static btSoftBody* Ctor_SoftBox(SoftDemo* pdemo,const btVector3& p,const btVector3& s) +{ + const btVector3 h=s*0.5; + const btVector3 c[]={ p+h*btVector3(-1,-1,-1), + p+h*btVector3(+1,-1,-1), + p+h*btVector3(-1,+1,-1), + p+h*btVector3(+1,+1,-1), + p+h*btVector3(-1,-1,+1), + p+h*btVector3(+1,-1,+1), + p+h*btVector3(-1,+1,+1), + p+h*btVector3(+1,+1,+1)}; + btSoftBody* psb=btSoftBodyHelpers::CreateFromConvexHull(pdemo->m_softBodyWorldInfo,c,8); + psb->generateBendingConstraints(2); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + + return(psb); + +} + +// +// SoftBoulder +// +static btSoftBody* Ctor_SoftBoulder(SoftDemo* pdemo,const btVector3& p,const btVector3& s,int np,int id) +{ + btAlignedObjectArray pts; + if(id) srand(id); + for(int i=0;im_softBodyWorldInfo,&pts[0],pts.size()); + psb->generateBendingConstraints(2); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + + return(psb); +} + +//#define TRACEDEMO { pdemo->demoname=__FUNCTION__+5;printf("Launching demo: " __FUNCTION__ "\r\n"); } + +// +// Basic ropes +// +static void Init_Ropes(SoftDemo* pdemo) +{ + //TRACEDEMO + const int n=15; + for(int i=0;im_softBodyWorldInfo, btVector3(-10,0,i*0.25), + btVector3(10,0,i*0.25), + 16, + 1+2); + psb->m_cfg.piterations = 4; + psb->m_materials[0]->m_kLST = 0.1+(i/(btScalar)(n-1))*0.9; + psb->setTotalMass(20); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + + } +} + +// +// Rope attach +// +static void Init_RopeAttach(SoftDemo* pdemo) +{ + //TRACEDEMO + pdemo->m_softBodyWorldInfo.m_sparsesdf.RemoveReferences(0); + struct Functors + { + static btSoftBody* CtorRope(SoftDemo* pdemo,const btVector3& p) + { + btSoftBody* psb=btSoftBodyHelpers::CreateRope(pdemo->m_softBodyWorldInfo,p,p+btVector3(10,0,0),8,1); + psb->setTotalMass(50); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + return(psb); + } + }; + btTransform startTransform; + startTransform.setIdentity(); + startTransform.setOrigin(btVector3(12,8,0)); + btRigidBody* body=pdemo->createRigidBody(50,startTransform,new btBoxShape(btVector3(2,6,2))); + btSoftBody* psb0=Functors::CtorRope(pdemo,btVector3(0,8,-1)); + btSoftBody* psb1=Functors::CtorRope(pdemo,btVector3(0,8,+1)); + psb0->appendAnchor(psb0->m_nodes.size()-1,body); + psb1->appendAnchor(psb1->m_nodes.size()-1,body); +} + +// +// Cloth attach +// +static void Init_ClothAttach(SoftDemo* pdemo) +{ + //TRACEDEMO + const btScalar s=4; + const btScalar h=6; + const int r=9; + btSoftBody* psb=btSoftBodyHelpers::CreatePatch(pdemo->m_softBodyWorldInfo,btVector3(-s,h,-s), + btVector3(+s,h,-s), + btVector3(-s,h,+s), + btVector3(+s,h,+s),r,r,4+8,true); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + + btTransform startTransform; + startTransform.setIdentity(); + startTransform.setOrigin(btVector3(0,h,-(s+3.5))); + btRigidBody* body=pdemo->createRigidBody(20,startTransform,new btBoxShape(btVector3(s,1,3))); + psb->appendAnchor(0,body); + psb->appendAnchor(r-1,body); + pdemo->m_cutting=true; +} + +// +// Impact +// +static void Init_Impact(SoftDemo* pdemo) +{ + //TRACEDEMO + btSoftBody* psb=btSoftBodyHelpers::CreateRope(pdemo->m_softBodyWorldInfo, btVector3(0,0,0), + btVector3(0,-1,0), + 0, + 1); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + psb->m_cfg.kCHR=0.5; + btTransform startTransform; + startTransform.setIdentity(); + startTransform.setOrigin(btVector3(0,20,0)); + pdemo->createRigidBody(10,startTransform,new btBoxShape(btVector3(2,2,2))); +} + +static void Init_CapsuleCollision(SoftDemo* pdemo) +{ +#ifdef USE_AMD_OPENCL + btAlignedObjectArray emptyArray; + if (g_openCLSIMDSolver) + g_openCLSIMDSolver->optimize(emptyArray); +#endif //USE_AMD_OPENCL + + //TRACEDEMO + const btScalar s=4; + const btScalar h=6; + const int r=20; + + btTransform startTransform; + startTransform.setIdentity(); + startTransform.setOrigin(btVector3(0,h-2,0)); + + btCollisionShape* capsuleShape= new btCapsuleShapeX(1,5); + capsuleShape->setMargin( 0.5 ); + + // capsule->setLocalScaling(btVector3(5,1,1)); +// btRigidBody* body=pdemo->createRigidBody(20,startTransform,capsuleShape); + btRigidBody* body=pdemo->createRigidBody(0,startTransform,capsuleShape); + body->setFriction( 0.8f ); + + int fixed=0;//4+8; + btSoftBody* psb=btSoftBodyHelpers::CreatePatch(pdemo->m_softBodyWorldInfo,btVector3(-s,h,-s), + btVector3(+s,h,-s), + btVector3(-s,h,+s), + btVector3(+s,h,+s),r,r,fixed,true); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + psb->setTotalMass(0.1); + + psb->m_cfg.piterations = 10; + psb->m_cfg.citerations = 10; + psb->m_cfg.diterations = 10; +// psb->m_cfg.viterations = 10; + + + // psb->appendAnchor(0,body); +// psb->appendAnchor(r-1,body); +// pdemo->m_cutting=true; +} + +// +// Collide +// +static void Init_Collide(SoftDemo* pdemo) +{ + //TRACEDEMO + struct Functor + { + static btSoftBody* Create(SoftDemo* pdemo,const btVector3& x,const btVector3& a) + { + btSoftBody* psb=btSoftBodyHelpers::CreateFromTriMesh(pdemo->m_softBodyWorldInfo,gVertices, + &gIndices[0][0], + NUM_TRIANGLES); + psb->generateBendingConstraints(2); + psb->m_cfg.piterations=2; + psb->m_cfg.collisions|=btSoftBody::fCollision::VF_SS; + psb->randomizeConstraints(); + btMatrix3x3 m; + m.setEulerZYX(a.x(),a.y(),a.z()); + psb->transform(btTransform(m,x)); + psb->scale(btVector3(2,2,2)); + psb->setTotalMass(50,true); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + return(psb); + } + }; + for(int i=0;i<3;++i) + { + Functor::Create(pdemo,btVector3(3*i,2,0),btVector3(SIMD_PI/2*(1-(i&1)),SIMD_PI/2*(i&1),0)); + } + pdemo->m_cutting=true; +} + +// +// Collide2 +// +static void Init_Collide2(SoftDemo* pdemo) +{ + //TRACEDEMO + struct Functor + { + static btSoftBody* Create(SoftDemo* pdemo,const btVector3& x,const btVector3& a) + { + btSoftBody* psb=btSoftBodyHelpers::CreateFromTriMesh(pdemo->m_softBodyWorldInfo,gVerticesBunny, + &gIndicesBunny[0][0], + BUNNY_NUM_TRIANGLES); + btSoftBody::Material* pm=psb->appendMaterial(); + pm->m_kLST = 0.5; + pm->m_flags -= btSoftBody::fMaterial::DebugDraw; + psb->generateBendingConstraints(2,pm); + psb->m_cfg.piterations = 2; + psb->m_cfg.kDF = 0.5; + psb->m_cfg.collisions |= btSoftBody::fCollision::VF_SS; + psb->randomizeConstraints(); + btMatrix3x3 m; + m.setEulerZYX(a.x(),a.y(),a.z()); + psb->transform(btTransform(m,x)); + psb->scale(btVector3(6,6,6)); + psb->setTotalMass(100,true); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + return(psb); + } + }; + for(int i=0;i<3;++i) + { + Functor::Create(pdemo,btVector3(0,-1+5*i,0),btVector3(0,SIMD_PI/2*(i&1),0)); + } + pdemo->m_cutting=true; +} + +// +// Collide3 +// +static void Init_Collide3(SoftDemo* pdemo) +{ + //TRACEDEMO + { + const btScalar s=8; + btSoftBody* psb=btSoftBodyHelpers::CreatePatch( pdemo->m_softBodyWorldInfo,btVector3(-s,0,-s), + btVector3(+s,0,-s), + btVector3(-s,0,+s), + btVector3(+s,0,+s), + 15,15,1+2+4+8,true); + psb->m_materials[0]->m_kLST = 0.4; + psb->m_cfg.collisions |= btSoftBody::fCollision::VF_SS; + psb->setTotalMass(150); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + } + { + const btScalar s=4; + const btVector3 o=btVector3(5,10,0); + btSoftBody* psb=btSoftBodyHelpers::CreatePatch( pdemo->m_softBodyWorldInfo, + btVector3(-s,0,-s)+o, + btVector3(+s,0,-s)+o, + btVector3(-s,0,+s)+o, + btVector3(+s,0,+s)+o, + 7,7,0,true); + btSoftBody::Material* pm=psb->appendMaterial(); + pm->m_kLST = 0.1; + pm->m_flags -= btSoftBody::fMaterial::DebugDraw; + psb->generateBendingConstraints(2,pm); + psb->m_materials[0]->m_kLST = 0.5; + psb->m_cfg.collisions |= btSoftBody::fCollision::VF_SS; + psb->setTotalMass(150); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + pdemo->m_cutting=true; + } +} + +// +// Aerodynamic forces, 50x1g flyers +// +static void Init_Aero(SoftDemo* pdemo) +{ + //TRACEDEMO + const btScalar s=2; + const btScalar h=10; + const int segments=6; + const int count=50; + for(int i=0;im_softBodyWorldInfo,btVector3(-s,h,-s), + btVector3(+s,h,-s), + btVector3(-s,h,+s), + btVector3(+s,h,+s), + segments,segments, + 0,true); + btSoftBody::Material* pm=psb->appendMaterial(); + pm->m_flags -= btSoftBody::fMaterial::DebugDraw; + psb->generateBendingConstraints(2,pm); + psb->m_cfg.kLF = 0.004; + psb->m_cfg.kDG = 0.0003; + psb->m_cfg.aeromodel = btSoftBody::eAeroModel::V_TwoSided; + btTransform trs; + btQuaternion rot; + btVector3 ra=Vector3Rand()*0.1; + btVector3 rp=Vector3Rand()*15+btVector3(0,20,80); + rot.setEuler(SIMD_PI/8+ra.x(),-SIMD_PI/7+ra.y(),ra.z()); + trs.setIdentity(); + trs.setOrigin(rp); + trs.setRotation(rot); + psb->transform(trs); + psb->setTotalMass(0.1); + psb->addForce(btVector3(0,2,0),0); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + + } + pdemo->m_autocam=true; +} + +static void Init_Aero2(SoftDemo* pdemo) +{ + //TRACEDEMO + const btScalar s=5; + //psb->getWorldInfo()->m_gravity.setValue(0,0,0); + + const int segments=10; + const int count=5; + btVector3 pos(-s*segments, 0, 0); + btScalar gap = 0.5; + + for(int i=0;im_softBodyWorldInfo,btVector3(-s,0,-s*3), + btVector3(+s,0,-s*3), + btVector3(-s,0,+s), + btVector3(+s,0,+s), + segments,segments*3, + 1+2,true); + + psb->getCollisionShape()->setMargin(0.5); + btSoftBody::Material* pm=psb->appendMaterial(); + pm->m_kLST = 0.0004; + pm->m_flags -= btSoftBody::fMaterial::DebugDraw; + psb->generateBendingConstraints(2,pm); + + psb->m_cfg.kLF = 0.05; + psb->m_cfg.kDG = 0.01; + + //psb->m_cfg.kLF = 0.004; + //psb->m_cfg.kDG = 0.0003; + + psb->m_cfg.piterations = 2; + psb->m_cfg.aeromodel = btSoftBody::eAeroModel::V_TwoSidedLiftDrag; + + + psb->setWindVelocity(btVector3(4, -12.0, -25.0)); + + btTransform trs; + btQuaternion rot; + pos += btVector3(s*2 + gap, 0, 0); + rot.setRotation(btVector3(1, 0, 0), btScalar(SIMD_PI/2)); + trs.setIdentity(); + trs.setOrigin(pos); + trs.setRotation(rot); + psb->transform(trs); + psb->setTotalMass(2.0); + + + + //this could help performance in some cases + btSoftBodyHelpers::ReoptimizeLinkOrder(psb); + + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + } + + pdemo->m_autocam=true; +} + +// +// Friction +// +static void Init_Friction(SoftDemo* pdemo) +{ + //TRACEDEMO + const btScalar bs=2; + const btScalar ts=bs+bs/4; + for(int i=0,ni=20;im_cfg.kDF = 0.1 * ((i+1)/(btScalar)ni); + psb->addVelocity(btVector3(0,0,-10)); + } +} + +// +// Pressure +// +static void Init_Pressure(SoftDemo* pdemo) +{ + //TRACEDEMO + btSoftBody* psb=btSoftBodyHelpers::CreateEllipsoid(pdemo->m_softBodyWorldInfo,btVector3(35,25,0), + btVector3(1,1,1)*3, + 512); + psb->m_materials[0]->m_kLST = 0.1; + psb->m_cfg.kDF = 1; + psb->m_cfg.kDP = 0.001; // fun factor... + psb->m_cfg.kPR = 2500; + psb->setTotalMass(30,true); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + + Ctor_BigPlate(pdemo); + Ctor_LinearStair(pdemo,btVector3(0,0,0),btVector3(2,1,5),0,10); + pdemo->m_autocam=true; + +} + +// +// Volume conservation +// +static void Init_Volume(SoftDemo* pdemo) +{ + //TRACEDEMO + btSoftBody* psb=btSoftBodyHelpers::CreateEllipsoid(pdemo->m_softBodyWorldInfo,btVector3(35,25,0), + btVector3(1,1,1)*3, + 512); + psb->m_materials[0]->m_kLST = 0.45; + psb->m_cfg.kVC = 20; + psb->setTotalMass(50,true); + psb->setPose(true,false); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + + Ctor_BigPlate(pdemo); + Ctor_LinearStair(pdemo,btVector3(0,0,0),btVector3(2,1,5),0,10); + pdemo->m_autocam=true; + +} + +// +// Stick+Bending+Rb's +// +static void Init_Sticks(SoftDemo* pdemo) +{ + //TRACEDEMO + const int n=16; + const int sg=4; + const btScalar sz=5; + const btScalar hg=4; + const btScalar in=1/(btScalar)(n-1); + for(int y=0;ym_softBodyWorldInfo, org, + org+btVector3(hg*0.001,hg,0), + sg, + 1); + psb->m_cfg.kDP = 0.005; + psb->m_cfg.kCHR = 0.1; + for(int i=0;i<3;++i) + { + psb->generateBendingConstraints(2+i); + } + psb->setMass(1,0); + psb->setTotalMass(0.01); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + + } + } + Ctor_BigBall(pdemo); +} + +// +// Bending +// +static void Init_Bending(SoftDemo* pdemo) +{ + //TRACEDEMO + const btScalar s=4; + const btVector3 x[]={ btVector3(-s,0,-s), + btVector3(+s,0,-s), + btVector3(+s,0,+s), + btVector3(-s,0,+s)}; + const btScalar m[]={ 0,0,0,1}; + btSoftBody* psb=new btSoftBody(&pdemo->m_softBodyWorldInfo,4,x,m); + psb->appendLink(0,1); + psb->appendLink(1,2); + psb->appendLink(2,3); + psb->appendLink(3,0); + psb->appendLink(0,2); + + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); +} + +// +// 100kg cloth locked at corners, 10 falling 10kg rb's. +// +static void Init_Cloth(SoftDemo* pdemo) +{ + //TRACEDEMO + const btScalar s=8; + btSoftBody* psb=btSoftBodyHelpers::CreatePatch( pdemo->m_softBodyWorldInfo,btVector3(-s,0,-s), + btVector3(+s,0,-s), + btVector3(-s,0,+s), + btVector3(+s,0,+s), + 31,31, + // 31,31, + 1+2+4+8,true); + + psb->getCollisionShape()->setMargin(0.5); + btSoftBody::Material* pm=psb->appendMaterial(); + pm->m_kLST = 0.4; + pm->m_flags -= btSoftBody::fMaterial::DebugDraw; + psb->generateBendingConstraints(2,pm); + psb->setTotalMass(150); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + + Ctor_RbUpStack(pdemo,10); + pdemo->m_cutting=true; +} + +// +// 100kg Stanford's bunny +// +static void Init_Bunny(SoftDemo* pdemo) +{ + //TRACEDEMO + btSoftBody* psb=btSoftBodyHelpers::CreateFromTriMesh(pdemo->m_softBodyWorldInfo,gVerticesBunny, + &gIndicesBunny[0][0], + BUNNY_NUM_TRIANGLES); + btSoftBody::Material* pm=psb->appendMaterial(); + pm->m_kLST = 0.5; + pm->m_flags -= btSoftBody::fMaterial::DebugDraw; + psb->generateBendingConstraints(2,pm); + psb->m_cfg.piterations = 2; + psb->m_cfg.kDF = 0.5; + psb->randomizeConstraints(); + psb->scale(btVector3(6,6,6)); + psb->setTotalMass(100,true); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + pdemo->m_cutting=true; + +} + +// +// 100kg Stanford's bunny with pose matching +// +static void Init_BunnyMatch(SoftDemo* pdemo) +{ + //TRACEDEMO + btSoftBody* psb=btSoftBodyHelpers::CreateFromTriMesh(pdemo->m_softBodyWorldInfo, gVerticesBunny, + &gIndicesBunny[0][0], + BUNNY_NUM_TRIANGLES); + psb->m_cfg.kDF = 0.5; + psb->m_cfg.kMT = 0.05; + psb->m_cfg.piterations = 5; + psb->randomizeConstraints(); + psb->scale(btVector3(6,6,6)); + psb->setTotalMass(100,true); + psb->setPose(false,true); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + +} + +// +// 50Kg Torus +// +static void Init_Torus(SoftDemo* pdemo) +{ + //TRACEDEMO + btSoftBody* psb=btSoftBodyHelpers::CreateFromTriMesh( pdemo->m_softBodyWorldInfo, gVertices, + &gIndices[0][0], + NUM_TRIANGLES); + psb->generateBendingConstraints(2); + psb->m_cfg.piterations=2; + psb->randomizeConstraints(); + btMatrix3x3 m; + m.setEulerZYX(SIMD_PI/2,0,0); + psb->transform(btTransform(m,btVector3(0,4,0))); + psb->scale(btVector3(2,2,2)); + psb->setTotalMass(50,true); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + pdemo->m_cutting=true; + + +} + +// +// 50Kg Torus with pose matching +// +static void Init_TorusMatch(SoftDemo* pdemo) +{ + //TRACEDEMO + btSoftBody* psb=btSoftBodyHelpers::CreateFromTriMesh(pdemo->m_softBodyWorldInfo, gVertices, + &gIndices[0][0], + NUM_TRIANGLES); + psb->m_materials[0]->m_kLST = 0.1; + psb->m_cfg.kMT = 0.05; + psb->randomizeConstraints(); + btMatrix3x3 m; + m.setEulerZYX(SIMD_PI/2,0,0); + psb->transform(btTransform(m,btVector3(0,4,0))); + psb->scale(btVector3(2,2,2)); + psb->setTotalMass(50,true); + psb->setPose(false,true); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); +} + +// +// Cutting1 +// +static void Init_Cutting1(SoftDemo* pdemo) +{ + const btScalar s=6; + const btScalar h=2; + const int r=16; + const btVector3 p[]={ btVector3(+s,h,-s), + btVector3(-s,h,-s), + btVector3(+s,h,+s), + btVector3(-s,h,+s)}; + btSoftBody* psb=btSoftBodyHelpers::CreatePatch(pdemo->m_softBodyWorldInfo,p[0],p[1],p[2],p[3],r,r,1+2+4+8,true); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + psb->m_cfg.piterations=1; + pdemo->m_cutting=true; +} + +// +// Clusters +// + +// +static void Ctor_Gear(SoftDemo* pdemo,const btVector3& pos,btScalar speed) +{ + btTransform startTransform; + startTransform.setIdentity(); + startTransform.setOrigin(pos); + btCompoundShape* shape=new btCompoundShape(); +#if 1 + shape->addChildShape(btTransform(btQuaternion(0,0,0)),new btBoxShape(btVector3(5,1,6))); + shape->addChildShape(btTransform(btQuaternion(0,0,SIMD_HALF_PI)),new btBoxShape(btVector3(5,1,6))); +#else + shape->addChildShape(btTransform(btQuaternion(0,0,0)),new btCylinderShapeZ(btVector3(5,1,7))); + shape->addChildShape(btTransform(btQuaternion(0,0,SIMD_HALF_PI)),new btBoxShape(btVector3(4,1,8))); +#endif + btRigidBody* body=pdemo->createRigidBody(10,startTransform,shape); + body->setFriction(1); + btDynamicsWorld* world=pdemo->getDynamicsWorld(); + btHingeConstraint* hinge=new btHingeConstraint(*body,btTransform::getIdentity()); + if(speed!=0) hinge->enableAngularMotor(true,speed,3); + world->addConstraint(hinge); +} + +// +static btSoftBody* Ctor_ClusterBunny(SoftDemo* pdemo,const btVector3& x,const btVector3& a) +{ + btSoftBody* psb=btSoftBodyHelpers::CreateFromTriMesh(pdemo->m_softBodyWorldInfo,gVerticesBunny,&gIndicesBunny[0][0],BUNNY_NUM_TRIANGLES); + btSoftBody::Material* pm=psb->appendMaterial(); + pm->m_kLST = 1; + pm->m_flags -= btSoftBody::fMaterial::DebugDraw; + psb->generateBendingConstraints(2,pm); + psb->m_cfg.piterations = 2; + psb->m_cfg.kDF = 1; + psb->m_cfg.collisions = btSoftBody::fCollision::CL_SS+ + btSoftBody::fCollision::CL_RS; + psb->randomizeConstraints(); + btMatrix3x3 m; + m.setEulerZYX(a.x(),a.y(),a.z()); + psb->transform(btTransform(m,x)); + psb->scale(btVector3(8,8,8)); + psb->setTotalMass(150,true); + psb->generateClusters(1); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + return(psb); +} + +// +static btSoftBody* Ctor_ClusterTorus(SoftDemo* pdemo,const btVector3& x,const btVector3& a,const btVector3& s=btVector3(2,2,2)) +{ + btSoftBody* psb=btSoftBodyHelpers::CreateFromTriMesh(pdemo->m_softBodyWorldInfo,gVertices,&gIndices[0][0],NUM_TRIANGLES); + btSoftBody::Material* pm=psb->appendMaterial(); + pm->m_kLST = 1; + pm->m_flags -= btSoftBody::fMaterial::DebugDraw; + psb->generateBendingConstraints(2,pm); + psb->m_cfg.piterations = 2; + psb->m_cfg.collisions = btSoftBody::fCollision::CL_SS+ + btSoftBody::fCollision::CL_RS; + psb->randomizeConstraints(); + psb->scale(s); + psb->rotate(btQuaternion(a[0],a[1],a[2])); + psb->translate(x); + psb->setTotalMass(50,true); + psb->generateClusters(64); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + return(psb); +} + +// +static struct MotorControl : btSoftBody::AJoint::IControl +{ + MotorControl() + { + goal=0; + maxtorque=0; + } + btScalar Speed(btSoftBody::AJoint*,btScalar current) + { + return(current+btMin(maxtorque,btMax(-maxtorque,goal-current))); + } + btScalar goal; + btScalar maxtorque; +} motorcontrol; + +// +struct SteerControl : btSoftBody::AJoint::IControl +{ + SteerControl(btScalar s) + { + angle=0; + sign=s; + } + void Prepare(btSoftBody::AJoint* joint) + { + joint->m_refs[0][0]=btCos(angle*sign); + joint->m_refs[0][2]=btSin(angle*sign); + } + btScalar Speed(btSoftBody::AJoint* joint,btScalar current) + { + return(motorcontrol.Speed(joint,current)); + } + btScalar angle; + btScalar sign; +}; + +static SteerControl steercontrol_f(+1); +static SteerControl steercontrol_r(-1); + +// +static void Init_ClusterDeform(SoftDemo* pdemo) +{ + btSoftBody* psb=Ctor_ClusterTorus(pdemo,btVector3(0,0,0),btVector3(SIMD_PI/2,0,SIMD_HALF_PI)); + psb->generateClusters(8); + psb->m_cfg.kDF=1; +} + +// +static void Init_ClusterCollide1(SoftDemo* pdemo) +{ + const btScalar s=8; + btSoftBody* psb=btSoftBodyHelpers::CreatePatch( pdemo->m_softBodyWorldInfo,btVector3(-s,0,-s), + btVector3(+s,0,-s), + btVector3(-s,0,+s), + btVector3(+s,0,+s), + 17,17,//9,9,//31,31, + 1+2+4+8, + true); + btSoftBody::Material* pm=psb->appendMaterial(); + pm->m_kLST = 0.4; + pm->m_flags -= btSoftBody::fMaterial::DebugDraw; + psb->m_cfg.kDF = 1; + psb->m_cfg.kSRHR_CL = 1; + psb->m_cfg.kSR_SPLT_CL = 0; + psb->m_cfg.collisions = btSoftBody::fCollision::CL_SS+ + + btSoftBody::fCollision::CL_RS; + psb->generateBendingConstraints(2,pm); + + psb->getCollisionShape()->setMargin(0.05); + psb->setTotalMass(50); + + ///pass zero in generateClusters to create cluster for each tetrahedron or triangle + psb->generateClusters(0); + //psb->generateClusters(64); + + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + + Ctor_RbUpStack(pdemo,10); +} + +// +static void Init_ClusterCollide2(SoftDemo* pdemo) +{ + struct Functor + { + static btSoftBody* Create(SoftDemo* pdemo,const btVector3& x,const btVector3& a) + { + btSoftBody* psb=btSoftBodyHelpers::CreateFromTriMesh(pdemo->m_softBodyWorldInfo,gVertices, + &gIndices[0][0], + NUM_TRIANGLES); + btSoftBody::Material* pm=psb->appendMaterial(); + pm->m_flags -= btSoftBody::fMaterial::DebugDraw; + psb->generateBendingConstraints(2,pm); + psb->m_cfg.piterations=2; + psb->m_cfg.kDF =1; + psb->m_cfg.kSSHR_CL =1; + psb->m_cfg.kSS_SPLT_CL =0; + psb->m_cfg.kSKHR_CL =0.1f; + psb->m_cfg.kSK_SPLT_CL =1; + psb->m_cfg.collisions= btSoftBody::fCollision::CL_SS+ + btSoftBody::fCollision::CL_RS; + psb->randomizeConstraints(); + btMatrix3x3 m; + m.setEulerZYX(a.x(),a.y(),a.z()); + psb->transform(btTransform(m,x)); + psb->scale(btVector3(2,2,2)); + psb->setTotalMass(50,true); + psb->generateClusters(16); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + return(psb); + } + }; + for(int i=0;i<3;++i) + { + Functor::Create(pdemo,btVector3(3*i,2,0),btVector3(SIMD_PI/2*(1-(i&1)),SIMD_PI/2*(i&1),0)); + } +} + +// +static void Init_ClusterSocket(SoftDemo* pdemo) +{ + btSoftBody* psb=Ctor_ClusterTorus(pdemo,btVector3(0,0,0),btVector3(SIMD_PI/2,0,SIMD_HALF_PI)); + btRigidBody* prb=Ctor_BigPlate(pdemo,50,8); + psb->m_cfg.kDF=1; + btSoftBody::LJoint::Specs lj; + lj.position = btVector3(0,5,0); + psb->appendLinearJoint(lj,prb); +} + +// +static void Init_ClusterHinge(SoftDemo* pdemo) +{ + btSoftBody* psb=Ctor_ClusterTorus(pdemo,btVector3(0,0,0),btVector3(SIMD_PI/2,0,SIMD_HALF_PI)); + btRigidBody* prb=Ctor_BigPlate(pdemo,50,8); + psb->m_cfg.kDF=1; + btSoftBody::AJoint::Specs aj; + aj.axis = btVector3(0,0,1); + psb->appendAngularJoint(aj,prb); +} + +// +static void Init_ClusterCombine(SoftDemo* pdemo) +{ + const btVector3 sz(2,4,2); + btSoftBody* psb0=Ctor_ClusterTorus(pdemo,btVector3(0,8,0),btVector3(SIMD_PI/2,0,SIMD_HALF_PI),sz); + btSoftBody* psb1=Ctor_ClusterTorus(pdemo,btVector3(0,8,10),btVector3(SIMD_PI/2,0,SIMD_HALF_PI),sz); + btSoftBody* psbs[]={psb0,psb1}; + for(int j=0;j<2;++j) + { + psbs[j]->m_cfg.kDF=1; + psbs[j]->m_cfg.kDP=0; + psbs[j]->m_cfg.piterations=1; + psbs[j]->m_clusters[0]->m_matching = 0.05; + psbs[j]->m_clusters[0]->m_ndamping = 0.05; + } + btSoftBody::AJoint::Specs aj; + aj.axis = btVector3(0,0,1); + aj.icontrol = &motorcontrol; + psb0->appendAngularJoint(aj,psb1); + + btSoftBody::LJoint::Specs lj; + lj.position = btVector3(0,8,5); + psb0->appendLinearJoint(lj,psb1); +} + +// +static void Init_ClusterCar(SoftDemo* pdemo) +{ +// pdemo->setAzi(180); + const btVector3 origin(100,80,0); + const btQuaternion orientation(-SIMD_PI/2,0,0); + const btScalar widthf=8; + const btScalar widthr=9; + const btScalar length=8; + const btScalar height=4; + const btVector3 wheels[]= { + btVector3(+widthf,-height,+length), // Front left + btVector3(-widthf,-height,+length), // Front right + btVector3(+widthr,-height,-length), // Rear left + btVector3(-widthr,-height,-length), // Rear right + }; + btSoftBody* pa=Ctor_ClusterBunny(pdemo,btVector3(0,0,0),btVector3(0,0,0)); + btSoftBody* pfl=Ctor_ClusterTorus(pdemo,wheels[0],btVector3(0,0,SIMD_HALF_PI),btVector3(2,4,2)); + btSoftBody* pfr=Ctor_ClusterTorus(pdemo,wheels[1],btVector3(0,0,SIMD_HALF_PI),btVector3(2,4,2)); + btSoftBody* prl=Ctor_ClusterTorus(pdemo,wheels[2],btVector3(0,0,SIMD_HALF_PI),btVector3(2,5,2)); + btSoftBody* prr=Ctor_ClusterTorus(pdemo,wheels[3],btVector3(0,0,SIMD_HALF_PI),btVector3(2,5,2)); + + pfl->m_cfg.kDF = + pfr->m_cfg.kDF = + prl->m_cfg.kDF = + prr->m_cfg.kDF = 1; + + btSoftBody::LJoint::Specs lspecs; + lspecs.cfm = 1; + lspecs.erp = 1; + lspecs.position = btVector3(0,0,0); + + lspecs.position=wheels[0];pa->appendLinearJoint(lspecs,pfl); + lspecs.position=wheels[1];pa->appendLinearJoint(lspecs,pfr); + lspecs.position=wheels[2];pa->appendLinearJoint(lspecs,prl); + lspecs.position=wheels[3];pa->appendLinearJoint(lspecs,prr); + + btSoftBody::AJoint::Specs aspecs; + aspecs.cfm = 1; + aspecs.erp = 1; + aspecs.axis = btVector3(1,0,0); + + aspecs.icontrol = &steercontrol_f; + pa->appendAngularJoint(aspecs,pfl); + pa->appendAngularJoint(aspecs,pfr); + + aspecs.icontrol = &motorcontrol; + pa->appendAngularJoint(aspecs,prl); + pa->appendAngularJoint(aspecs,prr); + + pa->rotate(orientation); + pfl->rotate(orientation); + pfr->rotate(orientation); + prl->rotate(orientation); + prr->rotate(orientation); + pa->translate(origin); + pfl->translate(origin); + pfr->translate(origin); + prl->translate(origin); + prr->translate(origin); + pfl->m_cfg.piterations = + pfr->m_cfg.piterations = + prl->m_cfg.piterations = + prr->m_cfg.piterations = 1; + pfl->m_clusters[0]->m_matching = + pfr->m_clusters[0]->m_matching = + prl->m_clusters[0]->m_matching = + prr->m_clusters[0]->m_matching = 0.05; + pfl->m_clusters[0]->m_ndamping = + pfr->m_clusters[0]->m_ndamping = + prl->m_clusters[0]->m_ndamping = + prr->m_clusters[0]->m_ndamping = 0.05; + + Ctor_LinearStair(pdemo,btVector3(0,-8,0),btVector3(3,2,40),0,20); + Ctor_RbUpStack(pdemo,50); + pdemo->m_autocam=true; + +} + +// +static void Init_ClusterRobot(SoftDemo* pdemo) +{ + struct Functor + { + static btSoftBody* CreateBall(SoftDemo* pdemo,const btVector3& pos) + { + btSoftBody* psb=btSoftBodyHelpers::CreateEllipsoid(pdemo->m_softBodyWorldInfo,pos,btVector3(1,1,1)*3,512); + psb->m_materials[0]->m_kLST = 0.45; + psb->m_cfg.kVC = 20; + psb->setTotalMass(50,true); + psb->setPose(true,false); + psb->generateClusters(1); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + return(psb); + } + }; + const btVector3 base=btVector3(0,25,8); + btSoftBody* psb0=Functor::CreateBall(pdemo,base+btVector3(-8,0,0)); + btSoftBody* psb1=Functor::CreateBall(pdemo,base+btVector3(+8,0,0)); + btSoftBody* psb2=Functor::CreateBall(pdemo,base+btVector3(0,0,+8*btSqrt(2))); + const btVector3 ctr=(psb0->clusterCom(0)+psb1->clusterCom(0)+psb2->clusterCom(0))/3; + btCylinderShape* pshp=new btCylinderShape(btVector3(8,1,8)); + btRigidBody* prb=pdemo->createRigidBody(50,btTransform(btQuaternion(0,0,0),ctr+btVector3(0,5,0)),pshp); + btSoftBody::LJoint::Specs ls; + ls.erp=0.5f; + ls.position=psb0->clusterCom(0);psb0->appendLinearJoint(ls,prb); + ls.position=psb1->clusterCom(0);psb1->appendLinearJoint(ls,prb); + ls.position=psb2->clusterCom(0);psb2->appendLinearJoint(ls,prb); + + btBoxShape* pbox=new btBoxShape(btVector3(20,1,40)); + btRigidBody* pgrn=pdemo->createRigidBody(0,btTransform(btQuaternion(0,-SIMD_HALF_PI/2,0),btVector3(0,0,0)),pbox); + + pdemo->m_autocam=true; + +} + +// +static void Init_ClusterStackSoft(SoftDemo* pdemo) +{ + for(int i=0;i<10;++i) + { + btSoftBody* psb=Ctor_ClusterTorus(pdemo,btVector3(0,-9+8.25*i,0),btVector3(0,0,0)); + psb->m_cfg.kDF=1; + } +} + +// +static void Init_ClusterStackMixed(SoftDemo* pdemo) +{ + for(int i=0;i<10;++i) + { + if((i+1)&1) + { + Ctor_BigPlate(pdemo,50,-9+4.25*i); + } + else + { + btSoftBody* psb=Ctor_ClusterTorus(pdemo,btVector3(0,-9+4.25*i,0),btVector3(0,0,0)); + psb->m_cfg.kDF=1; + } + } +} + + +// +// TetraBunny +// +static void Init_TetraBunny(SoftDemo* pdemo) +{ + btSoftBody* psb=btSoftBodyHelpers::CreateFromTetGenData(pdemo->m_softBodyWorldInfo, + TetraBunny::getElements(), + 0, + TetraBunny::getNodes(), + false,true,true); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + psb->rotate(btQuaternion(SIMD_PI/2,0,0)); + psb->setVolumeMass(150); + psb->m_cfg.piterations=2; + //psb->m_cfg.piterations=1; + pdemo->m_cutting=false; + //psb->getCollisionShape()->setMargin(0.01); + psb->m_cfg.collisions = btSoftBody::fCollision::CL_SS+ btSoftBody::fCollision::CL_RS + //+ btSoftBody::fCollision::CL_SELF + ; + + ///pass zero in generateClusters to create cluster for each tetrahedron or triangle + psb->generateClusters(0); + //psb->m_materials[0]->m_kLST=.2; + psb->m_cfg.kDF = 10. ; + + +} + +// +// TetraCube +// +static void Init_TetraCube(SoftDemo* pdemo) +{ + btSoftBody* psb=btSoftBodyHelpers::CreateFromTetGenData(pdemo->m_softBodyWorldInfo, + TetraCube::getElements(), + 0, + TetraCube::getNodes(), + false,true,true); + pdemo->getSoftDynamicsWorld()->addSoftBody(psb); + psb->scale(btVector3(4,4,4)); + psb->translate(btVector3(0,5,0)); + psb->setVolumeMass(300); + + + ///fix one vertex + //psb->setMass(0,0); + //psb->setMass(10,0); + //psb->setMass(20,0); + psb->m_cfg.piterations=1; + //psb->generateClusters(128); + psb->generateClusters(16); + //psb->getCollisionShape()->setMargin(0.5); + + psb->getCollisionShape()->setMargin(0.01); + psb->m_cfg.collisions = btSoftBody::fCollision::CL_SS+ btSoftBody::fCollision::CL_RS + //+ btSoftBody::fCollision::CL_SELF + ; + psb->m_materials[0]->m_kLST=0.8; + pdemo->m_cutting=false; +} + + + + + + /* Init */ + void (*demofncs[])(SoftDemo*)= + { + Init_Cloth, + Init_Pressure, + Init_Volume, + Init_Ropes, + Init_RopeAttach, + Init_ClothAttach, + Init_Sticks, + Init_CapsuleCollision, + Init_Collide, + Init_Collide2, + Init_Collide3, + Init_Impact, + Init_Aero, + Init_Aero2, + Init_Friction, + Init_Torus, + Init_TorusMatch, + Init_Bunny, + Init_BunnyMatch, + Init_Cutting1, + Init_ClusterDeform, + Init_ClusterCollide1, + Init_ClusterCollide2, + Init_ClusterSocket, + Init_ClusterHinge, + Init_ClusterCombine, + Init_ClusterCar, + Init_ClusterRobot, + Init_ClusterStackSoft, + Init_ClusterStackMixed, + Init_TetraCube, + Init_TetraBunny, + }; + +#if 0 +void SoftDemo::clientResetScene() +{ + m_azi = 0; + m_cameraDistance = 30.f; + m_cameraTargetPosition.setValue(0,0,0); + + + /* Clean up */ + for(int i=m_dynamicsWorld->getNumCollisionObjects()-1;i>=0;i--) + { + btCollisionObject* obj=m_dynamicsWorld->getCollisionObjectArray()[i]; + btRigidBody* body=btRigidBody::upcast(obj); + if(body&&body->getMotionState()) + { + delete body->getMotionState(); + } + while(m_dynamicsWorld->getNumConstraints()) + { + btTypedConstraint* pc=m_dynamicsWorld->getConstraint(0); + m_dynamicsWorld->removeConstraint(pc); + delete pc; + } + btSoftBody* softBody = btSoftBody::upcast(obj); + if (softBody) + { + getSoftDynamicsWorld()->removeSoftBody(softBody); + } else + { + btRigidBody* body = btRigidBody::upcast(obj); + if (body) + m_dynamicsWorld->removeRigidBody(body); + else + m_dynamicsWorld->removeCollisionObject(obj); + } + delete obj; + } + + + +} + +#if 0 +void SoftDemo::clientMoveAndDisplay() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT|GL_STENCIL_BUFFER_BIT); + + + + + float ms = getDeltaTimeMicroseconds(); + float dt = ms / 1000000.f;//1.0/60.; + + + + if (m_dynamicsWorld) + { + + if (sDemoMode) + { + static float demoCounter = DEMO_MODE_TIMEOUT; + demoCounter-= dt; + if (demoCounter<0) + { + + demoCounter=DEMO_MODE_TIMEOUT; + current_demo++; + current_demo=current_demo%(sizeof(demofncs)/sizeof(demofncs[0])); + clientResetScene(); + } + } + + +//#define FIXED_STEP +#ifdef FIXED_STEP + m_dynamicsWorld->stepSimulation(dt=1.0f/60.f,0); + +#else + //during idle mode, just run 1 simulation step maximum, otherwise 4 at max + // int maxSimSubSteps = m_idle ? 1 : 4; + //if (m_idle) + // dt = 1.0/420.f; + + int numSimSteps; + numSimSteps = m_dynamicsWorld->stepSimulation(dt); + //numSimSteps = m_dynamicsWorld->stepSimulation(dt,10,1./240.f); + +#ifdef VERBOSE_TIMESTEPPING_CONSOLEOUTPUT + if (!numSimSteps) + printf("Interpolated transforms\n"); + else + { + if (numSimSteps > maxSimSubSteps) + { + //detect dropping frames + printf("Dropped (%i) simulation steps out of %i\n",numSimSteps - maxSimSubSteps,numSimSteps); + } else + { + printf("Simulated (%i) steps\n",numSimSteps); + } + } +#endif //VERBOSE_TIMESTEPPING_CONSOLEOUTPUT + +#endif + +#ifdef USE_AMD_OPENCL + if (g_openCLSIMDSolver) + g_openCLSIMDSolver->copyBackToSoftBodies(); +#endif //USE_AMD_OPENCL + + if(m_drag) + { + m_node->m_v*=0; + } + + m_softBodyWorldInfo.m_sparsesdf.GarbageCollect(); + + //optional but useful: debug drawing + + } + +#ifdef USE_QUICKPROF + btProfiler::beginBlock("render"); +#endif //USE_QUICKPROF + + renderme(); + + //render the graphics objects, with center of mass shift + + updateCamera(); + + + +#ifdef USE_QUICKPROF + btProfiler::endBlock("render"); +#endif + glFlush(); + //some additional debugging info +#ifdef PRINT_CONTACT_STATISTICS + printf("num manifolds: %i\n",gNumManifold); + printf("num gOverlappingPairs: %i\n",gOverlappingPairs); + +#endif //PRINT_CONTACT_STATISTICS + + + swapBuffers(); + +} +#endif + + +#if 0 +void SoftDemo::renderme() +{ + btIDebugDraw* idraw=m_dynamicsWorld->getDebugDrawer(); + + glDisable(GL_TEXTURE_2D); + glDisable(GL_LIGHTING); + m_dynamicsWorld->debugDrawWorld(); + + //int debugMode = m_dynamicsWorld->getDebugDrawer()? m_dynamicsWorld->getDebugDrawer()->getDebugMode() : -1; + + btSoftRigidDynamicsWorld* softWorld = (btSoftRigidDynamicsWorld*)m_dynamicsWorld; + //btIDebugDraw* sdraw = softWorld ->getDebugDrawer(); + + + for ( int i=0;igetSoftBodyArray().size();i++) + { + btSoftBody* psb=(btSoftBody*)softWorld->getSoftBodyArray()[i]; + if (softWorld->getDebugDrawer() && !(softWorld->getDebugDrawer()->getDebugMode() & (btIDebugDraw::DBG_DrawWireframe))) + { + btSoftBodyHelpers::DrawFrame(psb,softWorld->getDebugDrawer()); + btSoftBodyHelpers::Draw(psb,softWorld->getDebugDrawer(),softWorld->getDrawFlags()); + } + } + + /* Bodies */ + btVector3 ps(0,0,0); + int nps=0; + + btSoftBodyArray& sbs=getSoftDynamicsWorld()->getSoftBodyArray(); + for(int ib=0;ibm_nodes.size(); + for(int i=0;im_nodes.size();++i) + { + ps+=psb->m_nodes[i].m_x; + } + } + ps/=nps; + if(m_autocam) + m_cameraTargetPosition+=(ps-m_cameraTargetPosition)*0.05; + /* Anm */ + if(!isIdle()) + m_animtime=m_clock.getTimeMilliseconds()/1000.f; + /* Ray cast */ + if(m_raycast) + { + /* Prepare rays */ + const int res=64; + const btScalar fres=res-1; + const btScalar size=8; + const btScalar dist=10; + btTransform trs; + trs.setOrigin(ps); + btScalar rayLength = 1000.f; + + const btScalar angle=m_animtime*0.2; + trs.setRotation(btQuaternion(angle,SIMD_PI/4,0)); + btVector3 dir=trs.getBasis()*btVector3(0,-1,0); + trs.setOrigin(ps-dir*dist); + btAlignedObjectArray origins; + btAlignedObjectArray fractions; + origins.resize(res*res); + fractions.resize(res*res,1.f); + for(int y=0;yrayTest(rayFrom,rayTo,results)) + { + *fraction=results.fraction; + } + } + ++org;++fraction; + } + long ms=btMax(m_clock.getTimeMilliseconds(),1); + long rayperseconds=(1000*(origins.size()*sbs.size()))/ms; + printf("%d ms (%d rays/s)\r\n",int(ms),int(rayperseconds)); + } + } + /* Draw rays */ + const btVector3 c[]={ origins[0], + origins[res-1], + origins[res*(res-1)], + origins[res*(res-1)+res-1]}; + idraw->drawLine(c[0],c[1],btVector3(0,0,0)); + idraw->drawLine(c[1],c[3],btVector3(0,0,0)); + idraw->drawLine(c[3],c[2],btVector3(0,0,0)); + idraw->drawLine(c[2],c[0],btVector3(0,0,0)); + for(int i=0,ni=origins.size();idrawLine(org,org+dir*rayLength*fraction,btVector3(1,0,0)); + } + else + { + idraw->drawLine(org,org-dir*rayLength*0.1,btVector3(0,0,0)); + } + } +#undef RES + } + /* Water level */ + static const btVector3 axis[]={btVector3(1,0,0), + btVector3(0,1,0), + btVector3(0,0,1)}; + if(m_softBodyWorldInfo.water_density>0) + { + const btVector3 c= btVector3((btScalar)0.25,(btScalar)0.25,1); + const btScalar a= (btScalar)0.5; + const btVector3 n= m_softBodyWorldInfo.water_normal; + const btVector3 o= -n*m_softBodyWorldInfo.water_offset; + const btVector3 x= btCross(n,axis[n.minAxis()]).normalized(); + const btVector3 y= btCross(x,n).normalized(); + const btScalar s= 25; + idraw->drawTriangle(o-x*s-y*s,o+x*s-y*s,o+x*s+y*s,c,a); + idraw->drawTriangle(o-x*s-y*s,o+x*s+y*s,o-x*s+y*s,c,a); + } + // + + int lineWidth=280; + int xStart = m_glutScreenWidth - lineWidth; + int yStart = 20; + + if((getDebugMode() & btIDebugDraw::DBG_NoHelpText)==0) + { + setOrthographicProjection(); + glDisable(GL_LIGHTING); + glColor3f(0, 0, 0); + char buf[124]; + + glRasterPos3f(xStart, yStart, 0); + if (sDemoMode) + { + sprintf(buf,"d to toggle demo mode (on)"); + } else + { + sprintf(buf,"d to toggle demo mode (off)"); + } + GLDebugDrawString(xStart,20,buf); + glRasterPos3f(xStart, yStart, 0); + sprintf(buf,"] for next demo (%d)",current_demo); + yStart+=20; + GLDebugDrawString(xStart,yStart,buf); + glRasterPos3f(xStart, yStart, 0); + sprintf(buf,"c to visualize clusters"); + yStart+=20; + GLDebugDrawString(xStart,yStart,buf); + glRasterPos3f(xStart, yStart, 0); + sprintf(buf,"; to toggle camera mode"); + yStart+=20; + GLDebugDrawString(xStart,yStart,buf); + glRasterPos3f(xStart, yStart, 0); + sprintf(buf,"n,m,l,k for power and steering"); + yStart+=20; + GLDebugDrawString(xStart,yStart,buf); + + + resetPerspectiveProjection(); + glEnable(GL_LIGHTING); + } + + DemoApplication::renderme(); + +} +#endif +#endif + +void SoftDemo::setDrawClusters(bool drawClusters) +{ + if (drawClusters) + { + getSoftDynamicsWorld()->setDrawFlags(getSoftDynamicsWorld()->getDrawFlags()|fDrawFlags::Clusters); + } else + { + getSoftDynamicsWorld()->setDrawFlags(getSoftDynamicsWorld()->getDrawFlags()& (~fDrawFlags::Clusters)); + } +} + + +#if 0 +void SoftDemo::keyboardCallback(unsigned char key, int x, int y) +{ + switch(key) + { + case 'd': sDemoMode = !sDemoMode; break; + case 'n': motorcontrol.maxtorque=10;motorcontrol.goal+=1;break; + case 'm': motorcontrol.maxtorque=10;motorcontrol.goal-=1;break; + case 'l': steercontrol_f.angle+=0.1;steercontrol_r.angle+=0.1;break; + case 'k': steercontrol_f.angle-=0.1;steercontrol_r.angle-=0.1;break; + case ']': ++current_demo;clientResetScene();break; + case '[': --current_demo;clientResetScene();break; + case ',': m_raycast=!m_raycast;break; + case ';': m_autocam=!m_autocam;break; + case 'c': getSoftDynamicsWorld()->setDrawFlags(getSoftDynamicsWorld()->getDrawFlags()^fDrawFlags::Clusters);break; + case '`': + { + btSoftBodyArray& sbs=getSoftDynamicsWorld()->getSoftBodyArray(); + for(int ib=0;ibstaticSolve(128); + } + } + break; + default: DemoApplication::keyboardCallback(key,x,y); + } +} +#endif +// +void SoftDemo::mouseMotionFunc(int x,int y) +{ + if(m_node&&(m_results.fraction<1.f)) + { + if(!m_drag) + { +#define SQ(_x_) (_x_)*(_x_) + if((SQ(x-m_lastmousepos[0])+SQ(y-m_lastmousepos[1]))>6) + { + m_drag=true; + } +#undef SQ + } + if(m_drag) + { + m_lastmousepos[0] = x; + m_lastmousepos[1] = y; + } + } +} + +#if 0 +// +void SoftDemo::mouseFunc(int button, int state, int x, int y) +{ + if(button==0) + { + switch(state) + { + case 0: + { + m_results.fraction=1.f; + DemoApplication::mouseFunc(button,state,x,y); + if(!m_pickConstraint) + { + const btVector3 rayFrom=m_cameraPosition; + const btVector3 rayTo=getRayTo(x,y); + const btVector3 rayDir=(rayTo-rayFrom).normalized(); + btSoftBodyArray& sbs=getSoftDynamicsWorld()->getSoftBodyArray(); + for(int ib=0;ibrayTest(rayFrom,rayTo,res)) + { + m_results=res; + } + } + if(m_results.fraction<1.f) + { + m_impact = rayFrom+(rayTo-rayFrom)*m_results.fraction; + m_drag = m_cutting ? false : true; + m_lastmousepos[0] = x; + m_lastmousepos[1] = y; + m_node = 0; + switch(m_results.feature) + { + case btSoftBody::eFeature::Tetra: + { + btSoftBody::Tetra& tet=m_results.body->m_tetras[m_results.index]; + m_node=tet.m_n[0]; + for(int i=1;i<4;++i) + { + if( (m_node->m_x-m_impact).length2()> + (tet.m_n[i]->m_x-m_impact).length2()) + { + m_node=tet.m_n[i]; + } + } + break; + } + case btSoftBody::eFeature::Face: + { + btSoftBody::Face& f=m_results.body->m_faces[m_results.index]; + m_node=f.m_n[0]; + for(int i=1;i<3;++i) + { + if( (m_node->m_x-m_impact).length2()> + (f.m_n[i]->m_x-m_impact).length2()) + { + m_node=f.m_n[i]; + } + } + } + break; + } + if(m_node) m_goal=m_node->m_x; + return; + } + } + } + break; + case 1: + if((!m_drag)&&m_cutting&&(m_results.fraction<1.f)) + { + ImplicitSphere isphere(m_impact,1); + printf("Mass before: %f\r\n",m_results.body->getTotalMass()); + m_results.body->refine(&isphere,0.0001,true); + printf("Mass after: %f\r\n",m_results.body->getTotalMass()); + } + m_results.fraction=1.f; + m_drag=false; + DemoApplication::mouseFunc(button,state,x,y); + break; + } + } + else + { + DemoApplication::mouseFunc(button,state,x,y); + } +} +#endif + +void SoftDemo::initPhysics() +{ + ///create concave ground mesh + + +// m_azi = 0; + + //reset and disable motorcontrol at the start + motorcontrol.goal = 0; + motorcontrol.maxtorque = 0; + + btCollisionShape* groundShape = 0; + { + int i; + int j; + + const int NUM_VERTS_X = 30; + const int NUM_VERTS_Y = 30; + const int totalVerts = NUM_VERTS_X*NUM_VERTS_Y; + const int totalTriangles = 2*(NUM_VERTS_X-1)*(NUM_VERTS_Y-1); + + gGroundVertices = new btVector3[totalVerts]; + gGroundIndices = new int[totalTriangles*3]; + + btScalar offset(-50); + + for ( i=0;isetMargin(0.5); + } + + m_collisionShapes.push_back(groundShape); + + btCollisionShape* groundBox = new btBoxShape (btVector3(100,CUBE_HALF_EXTENTS,100)); + m_collisionShapes.push_back(groundBox); + + btCompoundShape* cylinderCompound = new btCompoundShape; + btCollisionShape* cylinderShape = new btCylinderShape (btVector3(CUBE_HALF_EXTENTS,CUBE_HALF_EXTENTS,CUBE_HALF_EXTENTS)); + btTransform localTransform; + localTransform.setIdentity(); + cylinderCompound->addChildShape(localTransform,cylinderShape); + btQuaternion orn(btVector3(0,1,0),SIMD_PI); + localTransform.setRotation(orn); + cylinderCompound->addChildShape(localTransform,cylinderShape); + + m_collisionShapes.push_back(cylinderCompound); + + + m_dispatcher=0; + + ///register some softbody collision algorithms on top of the default btDefaultCollisionConfiguration + m_collisionConfiguration = new btSoftBodyRigidBodyCollisionConfiguration(); + + + m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); + m_softBodyWorldInfo.m_dispatcher = m_dispatcher; + + //////////////////////////// + ///Register softbody versus softbody collision algorithm + + + ///Register softbody versus rigidbody collision algorithm + + + //////////////////////////// + + btVector3 worldAabbMin(-1000,-1000,-1000); + btVector3 worldAabbMax(1000,1000,1000); + + m_broadphase = new btAxisSweep3(worldAabbMin,worldAabbMax,maxProxies); + + m_softBodyWorldInfo.m_broadphase = m_broadphase; + + btSequentialImpulseConstraintSolver* solver = new btSequentialImpulseConstraintSolver(); + + m_solver = solver; + + btSoftBodySolver* softBodySolver = 0; +#ifdef USE_AMD_OPENCL + + static bool once = true; + if (once) + { + once=false; + initCL(0,0); + } + + if( g_openCLSIMDSolver ) + delete g_openCLSIMDSolver; + if( g_softBodyOutput ) + delete g_softBodyOutput; + + if (1) + { + g_openCLSIMDSolver = new btOpenCLSoftBodySolverSIMDAware( g_cqCommandQue, g_cxMainContext); + // g_openCLSIMDSolver = new btOpenCLSoftBodySolver( g_cqCommandQue, g_cxMainContext); + g_openCLSIMDSolver->setCLFunctions(new CachingCLFunctions(g_cqCommandQue, g_cxMainContext)); + } + + + + softBodySolver = g_openCLSIMDSolver; + g_softBodyOutput = new btSoftBodySolverOutputCLtoCPU; +#endif //USE_AMD_OPENCL + + btDiscreteDynamicsWorld* world = new btSoftRigidDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration,softBodySolver); + m_dynamicsWorld = world; + m_dynamicsWorld->setInternalTickCallback(pickingPreTickCallback,this,true); + + + m_dynamicsWorld->getDispatchInfo().m_enableSPU = true; + m_dynamicsWorld->setGravity(btVector3(0,-10,0)); + m_softBodyWorldInfo.m_gravity.setValue(0,-10,0); + m_guiHelper->createPhysicsDebugDrawer(world); + // clientResetScene(); + + m_softBodyWorldInfo.m_sparsesdf.Initialize(); +// clientResetScene(); + + //create ground object + btTransform tr; + tr.setIdentity(); + tr.setOrigin(btVector3(0,-12,0)); + + btCollisionObject* newOb = new btCollisionObject(); + newOb->setWorldTransform(tr); + newOb->setInterpolationWorldTransform( tr); + int lastDemo = (sizeof(demofncs)/sizeof(demofncs[0]))-1; + + if (current_demo<0) + current_demo = lastDemo; + if (current_demo > lastDemo) + current_demo =0; + + + if (current_demo>19) + { + newOb->setCollisionShape(m_collisionShapes[0]); + } else + { + newOb->setCollisionShape(m_collisionShapes[1]); + } + + m_dynamicsWorld->addCollisionObject(newOb); + + m_softBodyWorldInfo.m_sparsesdf.Reset(); + + + + + + + + motorcontrol.goal = 0; + motorcontrol.maxtorque = 0; + + + + m_softBodyWorldInfo.air_density = (btScalar)1.2; + m_softBodyWorldInfo.water_density = 0; + m_softBodyWorldInfo.water_offset = 0; + m_softBodyWorldInfo.water_normal = btVector3(0,0,0); + m_softBodyWorldInfo.m_gravity.setValue(0,-10,0); + + + m_autocam = false; + m_raycast = false; + m_cutting = false; + m_results.fraction = 1.f; + + demofncs[current_demo](this); + + m_guiHelper->autogenerateGraphicsObjects(m_dynamicsWorld); +} + + + + + + +void SoftDemo::exitPhysics() +{ + + //cleanup in the reverse order of creation/initialization + + //remove the rigidbodies from the dynamics world and delete them + int i; + for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--) + { + btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i]; + btRigidBody* body = btRigidBody::upcast(obj); + if (body && body->getMotionState()) + { + delete body->getMotionState(); + } + m_dynamicsWorld->removeCollisionObject( obj ); + delete obj; + } + + //delete collision shapes + for (int j=0;jShow(); if ( m_ToggleButton ) m_ToggleButton->SetToggleState( true ); Invalidate(); - m_TreeControl->ForceUpdateScrollBars(); + if (m_TreeControl) + m_TreeControl->ForceUpdateScrollBars(); } void TreeNode::Close() @@ -153,7 +154,8 @@ void TreeNode::Close() if ( m_ToggleButton ) m_ToggleButton->SetToggleState( false ); Invalidate(); - m_TreeControl->ForceUpdateScrollBars(); + if (m_TreeControl) + m_TreeControl->ForceUpdateScrollBars(); } void TreeNode::ExpandAll() diff --git a/examples/VoronoiFracture/VoronoiFractureDemo.cpp b/examples/VoronoiFracture/VoronoiFractureDemo.cpp new file mode 100644 index 000000000..547686f42 --- /dev/null +++ b/examples/VoronoiFracture/VoronoiFractureDemo.cpp @@ -0,0 +1,819 @@ +/* +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. +*/ +/* +Voronoi fracture and shatter code and demo copyright (c) 2011 Alain Ducharme + - Reset scene (press spacebar) to generate new random voronoi shattered cuboids + - Check console for total time required to: compute and mesh all 3D shards, calculate volumes and centers of mass and create rigid bodies + - Modify VORONOIPOINTS define below to change number of potential voronoi shards + - Note that demo's visual cracks between voronoi shards are NOT present in the internally generated voronoi mesh! +*/ + +//Number of random voronoi points to generate for shattering +#define VORONOIPOINTS 100 + +//maximum number of objects (and allow user to shoot additional boxes) +#define MAX_PROXIES (2048) +#define BREAKING_THRESHOLD 3 +#define CONVEX_MARGIN 0.04 +static int useMpr = 0; + +#include "VoronoiFractureDemo.h" + +///btBulletDynamicsCommon.h is the main Bullet include file, contains most common include files. +#include "btBulletDynamicsCommon.h" +#include //printf debugging + + +static bool useGenericConstraint = false; + +#include "btConvexConvexMprAlgorithm.h" + + +#include "LinearMath/btAlignedObjectArray.h" +#include "LinearMath/btConvexHullComputer.h" +#include "LinearMath/btQuaternion.h" +#include +#include + +class btBroadphaseInterface; +class btCollisionShape; +class btOverlappingPairCache; +class btCollisionDispatcher; +class btConstraintSolver; +struct btCollisionAlgorithmCreateFunc; +class btDefaultCollisionConfiguration; + +#include "../CommonInterfaces/CommonRigidBodyBase.h" + + +class VoronoiFractureDemo : public CommonRigidBodyBase +{ + //keep the collision shapes, for deletion/cleanup + btAlignedObjectArray m_collisionShapes; + + btBroadphaseInterface* m_broadphase; + + btCollisionDispatcher* m_dispatcher; + + btConstraintSolver* m_solver; + + btDefaultCollisionConfiguration* m_collisionConfiguration; + + btClock m_perfmTimer; + + public: + + VoronoiFractureDemo(struct GUIHelperInterface* helper) + :CommonRigidBodyBase(helper) + { + srand((unsigned)time(NULL)); // Seed it... + } + virtual ~VoronoiFractureDemo() + { + btAssert(m_dynamicsWorld==0); + } + void initPhysics(); + + void exitPhysics(); + + //virtual void renderme(); + + void getVerticesInsidePlanes(const btAlignedObjectArray& planes, btAlignedObjectArray& verticesOut, std::set& planeIndicesOut); + void voronoiBBShatter(const btAlignedObjectArray& points, const btVector3& bbmin, const btVector3& bbmax, const btQuaternion& bbq, const btVector3& bbt, btScalar matDensity); + void voronoiConvexHullShatter(const btAlignedObjectArray& points, const btAlignedObjectArray& verts, const btQuaternion& bbq, const btVector3& bbt, btScalar matDensity); + + //virtual void clientMoveAndDisplay(); + + //virtual void displayCallback(); + //virtual void clientResetScene(); + + //virtual void keyboardCallback(unsigned char key, int x, int y); + + void attachFixedConstraints(); + + + + +}; + +void VoronoiFractureDemo::attachFixedConstraints() +{ + btAlignedObjectArray bodies; + + int numManifolds = m_dynamicsWorld->getDispatcher()->getNumManifolds(); + + for (int i=0;igetDispatcher()->getManifoldByIndexInternal(i); + if (!manifold->getNumContacts()) + continue; + + btScalar minDist = 1e30f; + int minIndex = -1; + for (int v=0;vgetNumContacts();v++) + { + if (minDist >manifold->getContactPoint(v).getDistance()) + { + minDist = manifold->getContactPoint(v).getDistance(); + minIndex = v; + } + } + if (minDist>0.) + continue; + + btCollisionObject* colObj0 = (btCollisionObject*)manifold->getBody0(); + btCollisionObject* colObj1 = (btCollisionObject*)manifold->getBody1(); + // int tag0 = (colObj0)->getIslandTag(); +// int tag1 = (colObj1)->getIslandTag(); + btRigidBody* body0 = btRigidBody::upcast(colObj0); + btRigidBody* body1 = btRigidBody::upcast(colObj1); + if (bodies.findLinearSearch(body0)==bodies.size()) + bodies.push_back(body0); + if (bodies.findLinearSearch(body1)==bodies.size()) + bodies.push_back(body1); + + if (body0 && body1) + { + if (!colObj0->isStaticOrKinematicObject() && !colObj1->isStaticOrKinematicObject()) + { + if (body0->checkCollideWithOverride(body1)) + { + { + btTransform trA,trB; + trA.setIdentity(); + trB.setIdentity(); + btVector3 contactPosWorld = manifold->getContactPoint(minIndex).m_positionWorldOnA; + btTransform globalFrame; + globalFrame.setIdentity(); + globalFrame.setOrigin(contactPosWorld); + + trA = body0->getWorldTransform().inverse()*globalFrame; + trB = body1->getWorldTransform().inverse()*globalFrame; + float totalMass = 1.f/body0->getInvMass() + 1.f/body1->getInvMass(); + + + if (useGenericConstraint) + { + btGeneric6DofConstraint* dof6 = new btGeneric6DofConstraint(*body0,*body1,trA,trB,true); + dof6->setOverrideNumSolverIterations(30); + + + dof6->setBreakingImpulseThreshold(BREAKING_THRESHOLD*totalMass); + + for (int i=0;i<6;i++) + dof6->setLimit(i,0,0); + m_dynamicsWorld->addConstraint(dof6,true); + + } else + { + btFixedConstraint* fixed = new btFixedConstraint(*body0,*body1,trA,trB); + fixed->setBreakingImpulseThreshold(BREAKING_THRESHOLD*totalMass); + fixed ->setOverrideNumSolverIterations(30); + m_dynamicsWorld->addConstraint(fixed,true); + + } + + } + } + } + } + + } + + for (int i=0;iremoveRigidBody(bodies[i]); + m_dynamicsWorld->addRigidBody(bodies[i]); + } +} +/* +void VoronoiFractureDemo::keyboardCallback(unsigned char key, int x, int y) +{ + if (key == 'g') + { + attachFixedConstraints(); + }else + { + PlatformDemoApplication::keyboardCallback(key,x,y); + } +} +*/ + +void VoronoiFractureDemo::getVerticesInsidePlanes(const btAlignedObjectArray& planes, btAlignedObjectArray& verticesOut, std::set& planeIndicesOut) +{ + // Based on btGeometryUtil.cpp (Gino van den Bergen / Erwin Coumans) + verticesOut.resize(0); + planeIndicesOut.clear(); + const int numPlanes = planes.size(); + int i, j, k, l; + for (i=0;i btScalar(0.0001)) + { + for (k=j+1;k btScalar(0.0001)) && (n3n1.length2() > btScalar(0.0001) )) + { + btScalar quotient = (N1.dot(n2n3)); + if (btFabs(quotient) > btScalar(0.0001)) + { + btVector3 potentialVertex = (n2n3 * N1[3] + n3n1 * N2[3] + n1n2 * N3[3]) * (btScalar(-1.) / quotient); + for (l=0; l btScalar(0.000001)) + break; + } + if (l == numPlanes) + { + // vertex (three plane intersection) inside all planes + verticesOut.push_back(potentialVertex); + planeIndicesOut.insert(i); + planeIndicesOut.insert(j); + planeIndicesOut.insert(k); + } + } + } + } + } + } + } +} + +static btVector3 curVoronoiPoint; + +struct pointCmp +{ + bool operator()(const btVector3& p1, const btVector3& p2) const + { + float v1 = (p1-curVoronoiPoint).length2(); + float v2 = (p2-curVoronoiPoint).length2(); + bool result0 = v1 < v2; + //bool result1 = ((btScalar)(p1-curVoronoiPoint).length2()) < ((btScalar)(p2-curVoronoiPoint).length2()); + //apparently result0 is not always result1, because extended precision used in registered is different from precision when values are stored in memory + return result0; + } +}; + +void VoronoiFractureDemo::voronoiBBShatter(const btAlignedObjectArray& points, const btVector3& bbmin, const btVector3& bbmax, const btQuaternion& bbq, const btVector3& bbt, btScalar matDensity) { + // points define voronoi cells in world space (avoid duplicates) + // bbmin & bbmax = bounding box min and max in local space + // bbq & bbt = bounding box quaternion rotation and translation + // matDensity = Material density for voronoi shard mass calculation + btVector3 bbvx = quatRotate(bbq, btVector3(1.0, 0.0, 0.0)); + btVector3 bbvy = quatRotate(bbq, btVector3(0.0, 1.0, 0.0)); + btVector3 bbvz = quatRotate(bbq, btVector3(0.0, 0.0, 1.0)); + btQuaternion bbiq = bbq.inverse(); + btConvexHullComputer* convexHC = new btConvexHullComputer(); + btAlignedObjectArray vertices; + btVector3 rbb, nrbb; + btScalar nlength, maxDistance, distance; + btAlignedObjectArray sortedVoronoiPoints; + sortedVoronoiPoints.copyFromArray(points); + btVector3 normal, plane; + btAlignedObjectArray planes; + std::set planeIndices; + std::set::iterator planeIndicesIter; + int numplaneIndices; + int cellnum = 0; + int i, j, k; + + int numpoints = points.size(); + for (i=0; i < numpoints ;i++) { + curVoronoiPoint = points[i]; + btVector3 icp = quatRotate(bbiq, curVoronoiPoint - bbt); + rbb = icp - bbmax; + nrbb = bbmin - icp; + planes.resize(6); + planes[0] = bbvx; planes[0][3] = rbb.x(); + planes[1] = bbvy; planes[1][3] = rbb.y(); + planes[2] = bbvz; planes[2][3] = rbb.z(); + planes[3] = -bbvx; planes[3][3] = nrbb.x(); + planes[4] = -bbvy; planes[4][3] = nrbb.y(); + planes[5] = -bbvz; planes[5][3] = nrbb.z(); + maxDistance = SIMD_INFINITY; + sortedVoronoiPoints.heapSort(pointCmp()); + for (j=1; j < numpoints; j++) { + normal = sortedVoronoiPoints[j] - curVoronoiPoint; + nlength = normal.length(); + if (nlength > maxDistance) + break; + plane = normal.normalized(); + plane[3] = -nlength / btScalar(2.); + planes.push_back(plane); + getVerticesInsidePlanes(planes, vertices, planeIndices); + if (vertices.size() == 0) + break; + numplaneIndices = planeIndices.size(); + if (numplaneIndices != planes.size()) { + planeIndicesIter = planeIndices.begin(); + for (k=0; k < numplaneIndices; k++) { + if (k != *planeIndicesIter) + planes[k] = planes[*planeIndicesIter]; + planeIndicesIter++; + } + planes.resize(numplaneIndices); + } + maxDistance = vertices[0].length(); + for (k=1; k < vertices.size(); k++) { + distance = vertices[k].length(); + if (maxDistance < distance) + maxDistance = distance; + } + maxDistance *= btScalar(2.); + } + if (vertices.size() == 0) + continue; + + // Clean-up voronoi convex shard vertices and generate edges & faces + convexHC->compute(&vertices[0].getX(), sizeof(btVector3), vertices.size(),CONVEX_MARGIN,0.0); + + // At this point we have a complete 3D voronoi shard mesh contained in convexHC + + // Calculate volume and center of mass (Stan Melax volume integration) + int numFaces = convexHC->faces.size(); + int v0, v1, v2; // Triangle vertices + btScalar volume = btScalar(0.); + btVector3 com(0., 0., 0.); + for (j=0; j < numFaces; j++) { + const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[j]]; + v0 = edge->getSourceVertex(); + v1 = edge->getTargetVertex(); + edge = edge->getNextEdgeOfFace(); + v2 = edge->getTargetVertex(); + while (v2 != v0) { + // Counter-clockwise triangulated voronoi shard mesh faces (v0-v1-v2) and edges here... + btScalar vol = convexHC->vertices[v0].triple(convexHC->vertices[v1], convexHC->vertices[v2]); + volume += vol; + com += vol * (convexHC->vertices[v0] + convexHC->vertices[v1] + convexHC->vertices[v2]); + edge = edge->getNextEdgeOfFace(); + v1 = v2; + v2 = edge->getTargetVertex(); + } + } + com /= volume * btScalar(4.); + volume /= btScalar(6.); + + // Shift all vertices relative to center of mass + int numVerts = convexHC->vertices.size(); + for (j=0; j < numVerts; j++) + { + convexHC->vertices[j] -= com; + } + + // Note: + // At this point convex hulls contained in convexHC should be accurate (line up flush with other pieces, no cracks), + // ...however Bullet Physics rigid bodies demo visualizations appear to produce some visible cracks. + // Use the mesh in convexHC for visual display or to perform boolean operations with. + + // Create Bullet Physics rigid body shards + btCollisionShape* shardShape = new btConvexHullShape(&(convexHC->vertices[0].getX()), convexHC->vertices.size()); + shardShape->setMargin(CONVEX_MARGIN); // for this demo; note convexHC has optional margin parameter for this + m_collisionShapes.push_back(shardShape); + btTransform shardTransform; + shardTransform.setIdentity(); + shardTransform.setOrigin(curVoronoiPoint + com); // Shard's adjusted location + btDefaultMotionState* shardMotionState = new btDefaultMotionState(shardTransform); + btScalar shardMass(volume * matDensity); + btVector3 shardInertia(0.,0.,0.); + shardShape->calculateLocalInertia(shardMass, shardInertia); + btRigidBody::btRigidBodyConstructionInfo shardRBInfo(shardMass, shardMotionState, shardShape, shardInertia); + btRigidBody* shardBody = new btRigidBody(shardRBInfo); + m_dynamicsWorld->addRigidBody(shardBody); + + cellnum ++; + + } + printf("Generated %d voronoi btRigidBody shards\n", cellnum); +} + +void VoronoiFractureDemo::voronoiConvexHullShatter(const btAlignedObjectArray& points, const btAlignedObjectArray& verts, const btQuaternion& bbq, const btVector3& bbt, btScalar matDensity) { + // points define voronoi cells in world space (avoid duplicates) + // verts = source (convex hull) mesh vertices in local space + // bbq & bbt = source (convex hull) mesh quaternion rotation and translation + // matDensity = Material density for voronoi shard mass calculation + btConvexHullComputer* convexHC = new btConvexHullComputer(); + btAlignedObjectArray vertices, chverts; + btVector3 rbb, nrbb; + btScalar nlength, maxDistance, distance; + btAlignedObjectArray sortedVoronoiPoints; + sortedVoronoiPoints.copyFromArray(points); + btVector3 normal, plane; + btAlignedObjectArray planes, convexPlanes; + std::set planeIndices; + std::set::iterator planeIndicesIter; + int numplaneIndices; + int cellnum = 0; + int i, j, k; + + // Convert verts to world space and get convexPlanes + int numverts = verts.size(); + chverts.resize(verts.size()); + for (i=0; i < numverts ;i++) { + chverts[i] = quatRotate(bbq, verts[i]) + bbt; + } + //btGeometryUtil::getPlaneEquationsFromVertices(chverts, convexPlanes); + // Using convexHullComputer faster than getPlaneEquationsFromVertices for large meshes... + convexHC->compute(&chverts[0].getX(), sizeof(btVector3), numverts, 0.0, 0.0); + int numFaces = convexHC->faces.size(); + int v0, v1, v2; // vertices + for (i=0; i < numFaces; i++) { + const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[i]]; + v0 = edge->getSourceVertex(); + v1 = edge->getTargetVertex(); + edge = edge->getNextEdgeOfFace(); + v2 = edge->getTargetVertex(); + plane = (convexHC->vertices[v1]-convexHC->vertices[v0]).cross(convexHC->vertices[v2]-convexHC->vertices[v0]).normalize(); + plane[3] = -plane.dot(convexHC->vertices[v0]); + convexPlanes.push_back(plane); + } + const int numconvexPlanes = convexPlanes.size(); + + int numpoints = points.size(); + for (i=0; i < numpoints ;i++) { + curVoronoiPoint = points[i]; + planes.copyFromArray(convexPlanes); + for (j=0; j < numconvexPlanes ;j++) { + planes[j][3] += planes[j].dot(curVoronoiPoint); + } + maxDistance = SIMD_INFINITY; + sortedVoronoiPoints.heapSort(pointCmp()); + for (j=1; j < numpoints; j++) { + normal = sortedVoronoiPoints[j] - curVoronoiPoint; + nlength = normal.length(); + if (nlength > maxDistance) + break; + plane = normal.normalized(); + plane[3] = -nlength / btScalar(2.); + planes.push_back(plane); + getVerticesInsidePlanes(planes, vertices, planeIndices); + if (vertices.size() == 0) + break; + numplaneIndices = planeIndices.size(); + if (numplaneIndices != planes.size()) { + planeIndicesIter = planeIndices.begin(); + for (k=0; k < numplaneIndices; k++) { + if (k != *planeIndicesIter) + planes[k] = planes[*planeIndicesIter]; + planeIndicesIter++; + } + planes.resize(numplaneIndices); + } + maxDistance = vertices[0].length(); + for (k=1; k < vertices.size(); k++) { + distance = vertices[k].length(); + if (maxDistance < distance) + maxDistance = distance; + } + maxDistance *= btScalar(2.); + } + if (vertices.size() == 0) + continue; + + // Clean-up voronoi convex shard vertices and generate edges & faces + convexHC->compute(&vertices[0].getX(), sizeof(btVector3), vertices.size(),0.0,0.0); + + // At this point we have a complete 3D voronoi shard mesh contained in convexHC + + // Calculate volume and center of mass (Stan Melax volume integration) + numFaces = convexHC->faces.size(); + btScalar volume = btScalar(0.); + btVector3 com(0., 0., 0.); + for (j=0; j < numFaces; j++) { + const btConvexHullComputer::Edge* edge = &convexHC->edges[convexHC->faces[j]]; + v0 = edge->getSourceVertex(); + v1 = edge->getTargetVertex(); + edge = edge->getNextEdgeOfFace(); + v2 = edge->getTargetVertex(); + while (v2 != v0) { + // Counter-clockwise triangulated voronoi shard mesh faces (v0-v1-v2) and edges here... + btScalar vol = convexHC->vertices[v0].triple(convexHC->vertices[v1], convexHC->vertices[v2]); + volume += vol; + com += vol * (convexHC->vertices[v0] + convexHC->vertices[v1] + convexHC->vertices[v2]); + edge = edge->getNextEdgeOfFace(); + v1 = v2; + v2 = edge->getTargetVertex(); + } + } + com /= volume * btScalar(4.); + volume /= btScalar(6.); + + // Shift all vertices relative to center of mass + int numVerts = convexHC->vertices.size(); + for (j=0; j < numVerts; j++) + { + convexHC->vertices[j] -= com; + } + + // Note: + // At this point convex hulls contained in convexHC should be accurate (line up flush with other pieces, no cracks), + // ...however Bullet Physics rigid bodies demo visualizations appear to produce some visible cracks. + // Use the mesh in convexHC for visual display or to perform boolean operations with. + + // Create Bullet Physics rigid body shards + btCollisionShape* shardShape = new btConvexHullShape(&(convexHC->vertices[0].getX()), convexHC->vertices.size()); + shardShape->setMargin(CONVEX_MARGIN); // for this demo; note convexHC has optional margin parameter for this + m_collisionShapes.push_back(shardShape); + btTransform shardTransform; + shardTransform.setIdentity(); + shardTransform.setOrigin(curVoronoiPoint + com); // Shard's adjusted location + btDefaultMotionState* shardMotionState = new btDefaultMotionState(shardTransform); + btScalar shardMass(volume * matDensity); + btVector3 shardInertia(0.,0.,0.); + shardShape->calculateLocalInertia(shardMass, shardInertia); + btRigidBody::btRigidBodyConstructionInfo shardRBInfo(shardMass, shardMotionState, shardShape, shardInertia); + btRigidBody* shardBody = new btRigidBody(shardRBInfo); + m_dynamicsWorld->addRigidBody(shardBody); + + cellnum ++; + + } + printf("Generated %d voronoi btRigidBody shards\n", cellnum); +} + +/* +void VoronoiFractureDemo::clientMoveAndDisplay() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + //simple dynamics world doesn't handle fixed-time-stepping + float ms = getDeltaTimeMicroseconds(); + + ///step the simulation + if (m_dynamicsWorld) + { + m_dynamicsWorld->stepSimulation(1. / 60., 0);// ms / 1000000.f); + //optional but useful: debug drawing + m_dynamicsWorld->debugDrawWorld(); + } + + renderme(); + + glFlush(); + + swapBuffers(); +} +*/ +/* +void VoronoiFractureDemo::displayCallback(void) { + + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + renderme(); + + //optional but useful: debug drawing to detect problems + if (m_dynamicsWorld) + m_dynamicsWorld->debugDrawWorld(); + + glFlush(); + swapBuffers(); +} +*/ +/* +void VoronoiFractureDemo::renderme() +{ + DemoApplication::renderme(); + char buf[124]; + + int lineWidth = 200; + int xStart = m_glutScreenWidth - lineWidth; + + if (useMpr) + { + sprintf(buf, "Using GJK+MPR"); + } + else + { + sprintf(buf, "Using GJK+EPA"); + } + GLDebugDrawString(xStart, 20, buf); + +} +*/ + +void VoronoiFractureDemo::initPhysics() +{ + srand(13); + useGenericConstraint = !useGenericConstraint; + printf("useGenericConstraint = %d\n", useGenericConstraint); + + + + ///collision configuration contains default setup for memory, collision setup + m_collisionConfiguration = new btDefaultCollisionConfiguration(); + //m_collisionConfiguration->setConvexConvexMultipointIterations(); + + ///use the default collision dispatcher. For parallel processing you can use a diffent dispatcher (see Extras/BulletMultiThreaded) + m_dispatcher = new btCollisionDispatcher(m_collisionConfiguration); + + useMpr = 1 - useMpr; + + if (useMpr) + { + printf("using GJK+MPR convex-convex collision detection\n"); + btConvexConvexMprAlgorithm::CreateFunc* cf = new btConvexConvexMprAlgorithm::CreateFunc; + m_dispatcher->registerCollisionCreateFunc(CONVEX_HULL_SHAPE_PROXYTYPE, CONVEX_HULL_SHAPE_PROXYTYPE, cf); + m_dispatcher->registerCollisionCreateFunc(CONVEX_HULL_SHAPE_PROXYTYPE, BOX_SHAPE_PROXYTYPE, cf); + m_dispatcher->registerCollisionCreateFunc(BOX_SHAPE_PROXYTYPE, CONVEX_HULL_SHAPE_PROXYTYPE, cf); + } + else + { + printf("using default (GJK+EPA) convex-convex collision detection\n"); + } + + m_broadphase = new btDbvtBroadphase(); + + ///the default constraint solver. For parallel processing you can use a different solver (see Extras/BulletMultiThreaded) + btSequentialImpulseConstraintSolver* sol = new btSequentialImpulseConstraintSolver; + m_solver = sol; + + m_dynamicsWorld = new btDiscreteDynamicsWorld(m_dispatcher,m_broadphase,m_solver,m_collisionConfiguration); + m_dynamicsWorld->getSolverInfo().m_splitImpulse = true; + + m_guiHelper->createPhysicsDebugDrawer(m_dynamicsWorld); + + + m_dynamicsWorld->setGravity(btVector3(0,-10,0)); + + ///create a few basic rigid bodies + btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(50.),btScalar(50.),btScalar(50.))); +// btCollisionShape* groundShape = new btStaticPlaneShape(btVector3(0,1,0),50); + + m_collisionShapes.push_back(groundShape); + + btTransform groundTransform; + groundTransform.setIdentity(); + groundTransform.setOrigin(btVector3(0,-50,0)); + + //We can also use DemoApplication::localCreateRigidBody, but for clarity it is provided here: + { + btScalar mass(0.); + + //rigidbody is dynamic if and only if mass is non zero, otherwise static + bool isDynamic = (mass != 0.f); + + btVector3 localInertia(0,0,0); + if (isDynamic) + groundShape->calculateLocalInertia(mass,localInertia); + + //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects + btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform); + btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia); + btRigidBody* body = new btRigidBody(rbInfo); + + //add the body to the dynamics world + m_dynamicsWorld->addRigidBody(body); + } + + { + btCollisionShape* groundShape = new btBoxShape(btVector3(btScalar(10.),btScalar(8.),btScalar(1.))); + btScalar mass(0.); + + //rigidbody is dynamic if and only if mass is non zero, otherwise static + bool isDynamic = (mass != 0.f); + + btVector3 localInertia(0,0,0); + if (isDynamic) + groundShape->calculateLocalInertia(mass,localInertia); + groundTransform.setOrigin(btVector3(0,0,0)); + //using motionstate is recommended, it provides interpolation capabilities, and only synchronizes 'active' objects + btDefaultMotionState* myMotionState = new btDefaultMotionState(groundTransform); + btRigidBody::btRigidBodyConstructionInfo rbInfo(mass,myMotionState,groundShape,localInertia); + btRigidBody* body = new btRigidBody(rbInfo); + + //add the body to the dynamics world + m_dynamicsWorld->addRigidBody(body); + } + + // ==> Voronoi Shatter Basic Demo: Random Cuboid + + // Random size cuboid (defined by bounding box max and min) + btVector3 bbmax(btScalar(rand() / btScalar(RAND_MAX)) * 12. +0.5, btScalar(rand() / btScalar(RAND_MAX)) * 1. +0.5, btScalar(rand() / btScalar(RAND_MAX)) * 1. +0.5); + btVector3 bbmin = -bbmax; + // Place it 10 units above ground + btVector3 bbt(0,15,0); + // Use an arbitrary material density for shards (should be consitent/relative with/to rest of RBs in world) + btScalar matDensity = 1; + // Using random rotation + btQuaternion bbq(btScalar(rand() / btScalar(RAND_MAX)) * 2. -1.,btScalar(rand() / btScalar(RAND_MAX)) * 2. -1.,btScalar(rand() / btScalar(RAND_MAX)) * 2. -1.,btScalar(rand() / btScalar(RAND_MAX)) * 2. -1.); + bbq.normalize(); + // Generate random points for voronoi cells + btAlignedObjectArray points; + btVector3 point; + btVector3 diff = bbmax - bbmin; + for (int i=0; i < VORONOIPOINTS; i++) { + // Place points within box area (points are in world coordinates) + point = quatRotate(bbq, btVector3(btScalar(rand() / btScalar(RAND_MAX)) * diff.x() -diff.x()/2., btScalar(rand() / btScalar(RAND_MAX)) * diff.y() -diff.y()/2., btScalar(rand() / btScalar(RAND_MAX)) * diff.z() -diff.z()/2.)) + bbt; + points.push_back(point); + } + m_perfmTimer.reset(); + voronoiBBShatter(points, bbmin, bbmax, bbq, bbt, matDensity); + printf("Total Time: %f seconds\n", m_perfmTimer.getTimeMilliseconds()/1000.); + + for (int i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--) + { + btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i]; + obj->getCollisionShape()->setMargin(CONVEX_MARGIN+0.01); + } + m_dynamicsWorld->performDiscreteCollisionDetection(); + + for (int i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--) + { + btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i]; + obj->getCollisionShape()->setMargin(CONVEX_MARGIN); + } + + attachFixedConstraints(); + + m_guiHelper->autogenerateGraphicsObjects(m_dynamicsWorld); +} + + +void VoronoiFractureDemo::exitPhysics() +{ + + //cleanup in the reverse order of creation/initialization + + int i; + //remove all constraints + for (i=m_dynamicsWorld->getNumConstraints()-1;i>=0;i--) + { + btTypedConstraint* constraint = m_dynamicsWorld->getConstraint(i); + m_dynamicsWorld->removeConstraint(constraint); + delete constraint; + } + + //remove the rigidbodies from the dynamics world and delete them + + for (i=m_dynamicsWorld->getNumCollisionObjects()-1; i>=0 ;i--) + { + btCollisionObject* obj = m_dynamicsWorld->getCollisionObjectArray()[i]; + btRigidBody* body = btRigidBody::upcast(obj); + if (body && body->getMotionState()) + { + delete body->getMotionState(); + } + m_dynamicsWorld->removeCollisionObject( obj ); + delete obj; + } + + //delete collision shapes + for (int j=0;jmyinit(); + demo->initPhysics(); + return demo; + } + +*/ + +ExampleInterface* VoronoiFractureCreateFunc(PhysicsInterface* pint, GUIHelperInterface* helper, int option) +{ + return new VoronoiFractureDemo(helper); +} diff --git a/examples/VoronoiFracture/VoronoiFractureDemo.h b/examples/VoronoiFracture/VoronoiFractureDemo.h new file mode 100644 index 000000000..e4ac01db1 --- /dev/null +++ b/examples/VoronoiFracture/VoronoiFractureDemo.h @@ -0,0 +1,21 @@ +/* +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 VORONOI_FRACTURE_DEMO_H +#define VORONOI_FRACTURE_DEMO_H + +class ExampleInterface* VoronoiFractureCreateFunc(struct PhysicsInterface* pint, struct GUIHelperInterface* helper, int option); + +#endif //VORONOI_FRACTURE_DEMO_H + diff --git a/examples/VoronoiFracture/btConvexConvexMprAlgorithm.cpp b/examples/VoronoiFracture/btConvexConvexMprAlgorithm.cpp new file mode 100644 index 000000000..e14a0e67d --- /dev/null +++ b/examples/VoronoiFracture/btConvexConvexMprAlgorithm.cpp @@ -0,0 +1,288 @@ +/* +Bullet Continuous Collision Detection and Physics Library +Copyright (c) 2003-2014 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 "btConvexConvexMprAlgorithm.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/btTriangleShape.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" +#include "BulletCollision/NarrowPhaseCollision/btPolyhedralContactClipping.h" +#include "BulletCollision/CollisionDispatch/btCollisionObjectWrapper.h" + +#include "BulletCollision/NarrowPhaseCollision/btComputeGjkEpaPenetration.h" +#include "BulletCollision/NarrowPhaseCollision/btGjkEpa3.h" +#include "BulletCollision/NarrowPhaseCollision/btMprPenetration.h" + +//this is just an internal debug variable to switch between GJK+MPR or GJK+EPA +bool gUseMprCollisionFunction = true; + +btConvexConvexMprAlgorithm::CreateFunc::CreateFunc() +{ + +} + +btConvexConvexMprAlgorithm::CreateFunc::~CreateFunc() +{ +} + +btConvexConvexMprAlgorithm::btConvexConvexMprAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap) +: btActivatingCollisionAlgorithm(ci,body0Wrap,body1Wrap), +m_ownManifold (false), +m_manifoldPtr(mf) +{ + (void)body0Wrap; + (void)body1Wrap; +} + + + + +btConvexConvexMprAlgorithm::~btConvexConvexMprAlgorithm() +{ + if (m_ownManifold) + { + if (m_manifoldPtr) + m_dispatcher->releaseManifold(m_manifoldPtr); + } +} + + +btVector3 btBulletShapeSupportFunc(const void* shapeAptr, const btVector3& dir, bool includeMargin) +{ + btConvexShape* shape = (btConvexShape*) shapeAptr; + if (includeMargin) + { + return shape->localGetSupportingVertex(dir); + } + + return shape->localGetSupportingVertexWithoutMargin(dir); +} + +btVector3 btBulletShapeCenterFunc(const void* shapeAptr) +{ + return btVector3(0,0,0); +} + + +struct btMprConvexWrap +{ + const btConvexShape* m_convex; + btTransform m_worldTrans; + inline btScalar getMargin() const + { + return m_convex->getMargin(); + } + inline btVector3 getObjectCenterInWorld() const + { + return m_worldTrans.getOrigin(); + } + inline const btTransform& getWorldTransform() const + { + return m_worldTrans; + } + inline btVector3 getLocalSupportWithMargin(const btVector3& dir) const + { + return m_convex->localGetSupportingVertex(dir); + } + inline btVector3 getLocalSupportWithoutMargin(const btVector3& dir) const + { + return m_convex->localGetSupportingVertexWithoutMargin(dir); + } +}; + +struct btMyDistanceInfo +{ + btVector3 m_pointOnA; + btVector3 m_pointOnB; + btVector3 m_normalBtoA; + btScalar m_distance; +}; + +// +// Convex-Convex collision algorithm +// +void btConvexConvexMprAlgorithm ::processCollision (const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) +{ + + if (!m_manifoldPtr) + { + //swapped? + m_manifoldPtr = m_dispatcher->getNewManifold(body0Wrap->getCollisionObject(),body1Wrap->getCollisionObject()); + m_ownManifold = true; + } + resultOut->setPersistentManifold(m_manifoldPtr); + + //comment-out next line to test multi-contact generation + //resultOut->getPersistentManifold()->clearManifold(); + + + const btConvexShape* min0 = static_cast(body0Wrap->getCollisionShape()); + const btConvexShape* min1 = static_cast(body1Wrap->getCollisionShape()); + + btVector3 normalOnB; + btVector3 pointOnBWorld; + + btGjkPairDetector::ClosestPointInput input; + + btVoronoiSimplexSolver vs; + btGjkEpaPenetrationDepthSolver epa; + + + if (gUseMprCollisionFunction) + { + + btMprConvexWrap a,b; + a.m_worldTrans = body0Wrap->getWorldTransform(); + b.m_worldTrans = body1Wrap->getWorldTransform(); + a.m_convex = (const btConvexShape*)body0Wrap->getCollisionShape(); + b.m_convex = (const btConvexShape*)body1Wrap->getCollisionShape(); + btVoronoiSimplexSolver simplexSolver; + simplexSolver.reset(); + btGjkCollisionDescription colDesc; + btMyDistanceInfo distInfo; + int res = btComputeGjkDistance(a,b,colDesc,&distInfo); + if (res==0) + { + //printf("use GJK results in distance %f\n",distInfo.m_distance); + } else + { + btMprCollisionDescription mprDesc; + res = btComputeMprPenetration(a,b,mprDesc, &distInfo); + + //printf("use MPR results in distance %f\n",distInfo.m_distance); + + } + if (res == 0) + { +#if 0 + printf("Dist=%f,normalOnB[%f,%f,%f],pA=[%f,%f,%f],pB[%f,%f,%f]\n", + distInfo.m_distance, distInfo.m_normalBtoA[0], distInfo.m_normalBtoA[1], distInfo.m_normalBtoA[2], + distInfo.m_pointOnA[0], distInfo.m_pointOnA[1], distInfo.m_pointOnA[2], + distInfo.m_pointOnB[0], distInfo.m_pointOnB[1], distInfo.m_pointOnB[2]); +#endif + + if (distInfo.m_distance<=0) + { + resultOut->addContactPoint(distInfo.m_normalBtoA, distInfo.m_pointOnB, distInfo.m_distance); + } + //ASSERT_EQ(0,result); + //ASSERT_NEAR(btFabs(btScalar(i-z))-btScalar(j)-ssd.m_radiusB, distInfo.m_distance, abs_error); + //btVector3 computedA = distInfo.m_pointOnB+distInfo.m_distance*distInfo.m_normalBtoA; + //ASSERT_NEAR(computedA.x(),distInfo.m_pointOnA.x(),abs_error); + //ASSERT_NEAR(computedA.y(),distInfo.m_pointOnA.y(),abs_error); + //ASSERT_NEAR(computedA.z(),distInfo.m_pointOnA.z(),abs_error); + } + + +#if 0 + btCollisionDescription colDesc; + colDesc.m_objA = min0; + colDesc.m_objB = min1; + colDesc.m_localSupportFuncA = &btBulletShapeSupportFunc; + colDesc.m_localSupportFuncB = &btBulletShapeSupportFunc; + colDesc.m_localOriginFuncA = &btBulletShapeCenterFunc; + colDesc.m_localOriginFuncB = &btBulletShapeCenterFunc; + + colDesc.m_transformA = body0Wrap->getWorldTransform(); + colDesc.m_transformB = body1Wrap->getWorldTransform(); + colDesc.m_marginA = body0Wrap->getCollisionShape()->getMargin(); + colDesc.m_marginB = body1Wrap->getCollisionShape()->getMargin(); + btDistanceInfo distInfo; + //int result = btComputeGjkEpaPenetration(colDesc, &distInfo); + //int result = btComputeGjkEpaPenetration2(colDesc, &distInfo); + int result = btComputeMprPenetration(colDesc, &distInfo); + + if (result==0) + { + resultOut->addContactPoint(distInfo.m_normalBtoA,distInfo.m_pointOnB,distInfo.m_distance); + } + + //bool res = b3MprPenetration(pairIndex,bodyIndexA,bodyIndexB,cpuBodyBuf,convexData,collidable2,cpuVertices,sepAxis,hasSepAxis,depthOut,dirOut,posOut); + + /*btCollisionDescription colDesc; + btDistanceInfo distInfo; + int btComputeGjkEpaPenetration(min0, min1, &colDesc, &distInfo); + */ +#endif + } else + { + + btGjkPairDetector gjkPairDetector(min0,min1,&vs,&epa);//m_simplexSolver,m_pdSolver); + //TODO: if (dispatchInfo.m_useContinuous) + gjkPairDetector.setMinkowskiA(min0); + gjkPairDetector.setMinkowskiB(min1); + + { + //if (dispatchInfo.m_convexMaxDistanceUseCPT) + //{ + // input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactProcessingThreshold(); + //} else + //{ + input.m_maximumDistanceSquared = min0->getMargin() + min1->getMargin() + m_manifoldPtr->getContactBreakingThreshold(); + // } + + input.m_maximumDistanceSquared*= input.m_maximumDistanceSquared; + } + + input.m_transformA = body0Wrap->getWorldTransform(); + input.m_transformB = body1Wrap->getWorldTransform(); + + + gjkPairDetector.getClosestPoints(input,*resultOut,dispatchInfo.m_debugDraw); + } + if (m_ownManifold) + { + resultOut->refreshContactPoints(); + } + +} + + +btScalar btConvexConvexMprAlgorithm::calculateTimeOfImpact(btCollisionObject* col0,btCollisionObject* col1,const btDispatcherInfo& dispatchInfo,btManifoldResult* resultOut) +{ + (void)resultOut; + (void)dispatchInfo; + btAssert(0); + return 0; +} + diff --git a/examples/VoronoiFracture/btConvexConvexMprAlgorithm.h b/examples/VoronoiFracture/btConvexConvexMprAlgorithm.h new file mode 100644 index 000000000..6edbdccae --- /dev/null +++ b/examples/VoronoiFracture/btConvexConvexMprAlgorithm.h @@ -0,0 +1,87 @@ +/* +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_CONVEX_CONVEX_MPR_ALGORITHM_H +#define BT_CONVEX_CONVEX_MPR_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; + +///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 + +///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 btConvexConvexMprAlgorithm : public btActivatingCollisionAlgorithm +{ + + + bool m_ownManifold; + btPersistentManifold* m_manifoldPtr; + ///cache separating vector to speedup collision detection + +public: + + btConvexConvexMprAlgorithm(btPersistentManifold* mf,const btCollisionAlgorithmConstructionInfo& ci,const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap); + + virtual ~btConvexConvexMprAlgorithm(); + + virtual void processCollision (const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap,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); + } + +const btPersistentManifold* getManifold() + { + return m_manifoldPtr; + } + + struct CreateFunc :public btCollisionAlgorithmCreateFunc + { + + + + CreateFunc(); + + virtual ~CreateFunc(); + + virtual btCollisionAlgorithm* CreateCollisionAlgorithm(btCollisionAlgorithmConstructionInfo& ci, const btCollisionObjectWrapper* body0Wrap,const btCollisionObjectWrapper* body1Wrap) + { + void* mem = ci.m_dispatcher1->allocateCollisionAlgorithm(sizeof(btConvexConvexMprAlgorithm)); + return new(mem) btConvexConvexMprAlgorithm(ci.m_manifold,ci,body0Wrap,body1Wrap); + } + }; + + +}; + +#endif //BT_CONVEX_CONVEX_MPR_ALGORITHM_H diff --git a/test/GwenOpenGLTest/Button.cpp b/test/GwenOpenGLTest/Button.cpp new file mode 100644 index 000000000..727670ed2 --- /dev/null +++ b/test/GwenOpenGLTest/Button.cpp @@ -0,0 +1,75 @@ +#include "UnitTest.h" + +using namespace Gwen; + +class Button : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( Button, GUnit ) + { + // Normal button + Controls::Button* pButtonA = new Controls::Button( this ); + pButtonA->SetText( L"Event Tester" ); + pButtonA->onPress.Add( this, &Button::onButtonA ); + + { + Controls::Button* pButtonA = new Controls::Button( this ); + pButtonA->SetBounds( 200, 30, 300, 200 ); + pButtonA->SetText( L"Event Tester" ); + pButtonA->onPress.Add( this, &Button::onButtonA ); + } + + // Unicode test + Controls::Button* pButtonB = new Controls::Button( this ); + pButtonB->SetText( L"\u0417\u0430\u043C\u0435\u0436\u043D\u0430\u044F \u043C\u043E\u0432\u0430" ); + Gwen::Align::PlaceBelow( pButtonB, pButtonA, 10 ); + + // Image with text + Controls::Button* pButtonC = new Controls::Button( this ); + pButtonC->SetText( L"Image Button" ); + pButtonC->SetImage( L"test16.png" ); + Gwen::Align::PlaceBelow( pButtonC, pButtonB, 10 ); + + // Just image + Controls::Button* pButtonD = new Controls::Button( this ); + pButtonD->SetText( L"" ); + pButtonD->SetImage( L"test16.png" ); + pButtonD->SetSize( 20, 20 ); + Gwen::Align::PlaceBelow( pButtonD, pButtonC, 10 ); + + // Toggle button + Controls::Button* pButtonE = new Controls::Button( this ); + pButtonE->SetText( L"Toggle Me" ); + pButtonE->SetIsToggle( true ); + pButtonE->onToggle.Add( this, &Button::OnToggle ); + pButtonE->onToggleOn.Add( this, &Button::OnToggleOn ); + pButtonE->onToggleOff.Add( this, &Button::OnToggleOff ); + Gwen::Align::PlaceBelow( pButtonE, pButtonD, 10 ); + } + + void onButtonA( Controls::Base* pControl ) + { + UnitPrint( L"Button Pressed (using 'OnPress' event)" ); + } + + void OnToggle( Controls::Base* pControl ) + { + UnitPrint( L"Button Toggled (using 'OnToggle' event)" ); + } + + void OnToggleOn( Controls::Base* pControl ) + { + UnitPrint( L"Button Toggled ON (using 'OnToggleOn' event)" ); + } + + void OnToggleOff( Controls::Base* pControl ) + { + UnitPrint( L"Button Toggled Off (using 'OnToggleOff' event)" ); + } + +}; + + + +DEFINE_UNIT_TEST( Button, L"Button" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/Checkbox.cpp b/test/GwenOpenGLTest/Checkbox.cpp new file mode 100644 index 000000000..b46a84b37 --- /dev/null +++ b/test/GwenOpenGLTest/Checkbox.cpp @@ -0,0 +1,48 @@ +#include "UnitTest.h" +#include "Gwen/Controls/CheckBox.h" + +using namespace Gwen; + +class Checkbox : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( Checkbox, GUnit ) + { + Gwen::Controls::CheckBox* check = new Gwen::Controls::CheckBox( this ); + check->SetPos( 10, 10 ); + check->onChecked.Add( this, &Checkbox::OnChecked ); + check->onUnChecked.Add( this, &Checkbox::OnUnchecked ); + check->onCheckChanged.Add( this, &Checkbox::OnCheckChanged ); + + + Gwen::Controls::CheckBoxWithLabel* labeled = new Gwen::Controls::CheckBoxWithLabel( this ); + labeled->SetPos( 10, 10 ); + labeled->Label()->SetText( "Labeled CheckBox" ); + labeled->Checkbox()->onChecked.Add( this, &Checkbox::OnChecked ); + labeled->Checkbox()->onUnChecked.Add( this, &Checkbox::OnUnchecked ); + labeled->Checkbox()->onCheckChanged.Add( this, &Checkbox::OnCheckChanged ); + Gwen::Align::PlaceBelow( labeled, check, 10 ); + + } + + void OnChecked( Controls::Base* pControl ) + { + UnitPrint( L"Checkbox Checked (using 'OnChecked' event)" ); + } + + void OnUnchecked( Controls::Base* pControl ) + { + UnitPrint( L"Checkbox Unchecked (using 'OnUnchecked' event)" ); + } + + void OnCheckChanged( Controls::Base* pControl ) + { + UnitPrint( L"Checkbox CheckChanged (using 'OnCheckChanged' event)" ); + } + +}; + + + +DEFINE_UNIT_TEST( Checkbox, L"Checkbox" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/ComboBox.cpp b/test/GwenOpenGLTest/ComboBox.cpp new file mode 100644 index 000000000..3ae13cb09 --- /dev/null +++ b/test/GwenOpenGLTest/ComboBox.cpp @@ -0,0 +1,58 @@ +#include "UnitTest.h" +#include "Gwen/Controls/ComboBox.h" + +using namespace Gwen; + +class ComboBox : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( ComboBox, GUnit ) + { + + { + Gwen::Controls::ComboBox* combo = new Gwen::Controls::ComboBox( this ); + combo->SetKeyboardInputEnabled(true); + combo->SetPos( 50, 50 ); + combo->SetWidth( 200 ); + + + combo->AddItem( L"Option One", "one" ); + combo->AddItem( L"Number Two", "two" ); + combo->AddItem( L"Door Three", "three" ); + combo->AddItem( L"Four Legs", "four" ); + combo->AddItem( L"Five Birds", "five" ); + + combo->onSelection.Add( this, &ComboBox::OnComboSelect ); + } + + { + // Empty.. + Gwen::Controls::ComboBox* combo = new Gwen::Controls::ComboBox( this ); + combo->SetPos( 50, 80 ); + combo->SetWidth( 200 ); + } + + { + // Empty.. + Gwen::Controls::ComboBox* combo = new Gwen::Controls::ComboBox( this ); + combo->SetPos( 50, 110 ); + combo->SetWidth( 200 ); + + for (int i=0; i<500; i++ ) + combo->AddItem( L"Lots Of Options" ); + } + + } + + void OnComboSelect( Gwen::Controls::Base* pControl ) + { + Gwen::Controls::ComboBox* combo = (Gwen::Controls::ComboBox*)pControl; + + UnitPrint( Utility::Format( L"Combo Changed: %s", combo->GetSelectedItem()->GetText().c_str() ) ); + } +}; + + + +DEFINE_UNIT_TEST( ComboBox, L"ComboBox" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/CrossSplitter.cpp b/test/GwenOpenGLTest/CrossSplitter.cpp new file mode 100644 index 000000000..dea72d466 --- /dev/null +++ b/test/GwenOpenGLTest/CrossSplitter.cpp @@ -0,0 +1,115 @@ +#include "UnitTest.h" +#include "Gwen/Controls/CrossSplitter.h" +#include "Gwen/Controls/StatusBar.h" +#include "Gwen/Controls/Button.h" + +using namespace Gwen; + +class CrossSplitter : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( CrossSplitter, GUnit ) + { + + m_bSplittersVisible = false; + m_iCurZoom = 0; + + m_Splitter = new Gwen::Controls::CrossSplitter( this ); + m_Splitter->SetPos(0, 0); + m_Splitter->Dock( Pos::Fill ); + + { + Gwen::Controls::Button* testButton = new Gwen::Controls::Button( m_Splitter ); + testButton->SetText( "TOPLEFT"); + m_Splitter->SetPanel( 0, testButton ); + } + + { + Gwen::Controls::Button* testButton = new Gwen::Controls::Button( m_Splitter ); + testButton->SetText( "TOPRIGHT"); + m_Splitter->SetPanel( 1, testButton ); + } + + { + Gwen::Controls::Button* testButton = new Gwen::Controls::Button( m_Splitter ); + testButton->SetText( "BOTTOMRIGHT"); + m_Splitter->SetPanel( 2, testButton ); + } + + { + Gwen::Controls::Button* testButton = new Gwen::Controls::Button( m_Splitter ); + testButton->SetText( "BOTTOMLEFT"); + m_Splitter->SetPanel( 3, testButton ); + } + + + //Status bar to hold unit testing buttons + Gwen::Controls::StatusBar* pStatus = new Gwen::Controls::StatusBar( this ); + pStatus->Dock( Pos::Bottom ); + + + { + Gwen::Controls::Button* pButton = new Gwen::Controls::Button( pStatus ); + pButton->SetText( "Zoom" ); + pButton->onPress.Add( this, &CrossSplitter::ZoomTest ); + pStatus->AddControl( pButton, false ); + } + + { + Gwen::Controls::Button* pButton = new Gwen::Controls::Button( pStatus ); + pButton->SetText( "UnZoom" ); + pButton->onPress.Add( this, &CrossSplitter::UnZoomTest ); + pStatus->AddControl( pButton, false ); + } + + { + Gwen::Controls::Button* pButton = new Gwen::Controls::Button( pStatus ); + pButton->SetText( "CenterPanels" ); + pButton->onPress.Add( this, &CrossSplitter::CenterPanels ); + pStatus->AddControl( pButton, true ); + } + + { + Gwen::Controls::Button* pButton = new Gwen::Controls::Button( pStatus ); + pButton->SetText( "Splitters" ); + pButton->onPress.Add( this, &CrossSplitter::ToggleSplitters ); + pStatus->AddControl( pButton, true ); + } + } + + void ZoomTest( Gwen::Controls::Base* pFromPanel ) + { + m_Splitter->Zoom(m_iCurZoom); + m_iCurZoom++; + if (m_iCurZoom == 4) + m_iCurZoom = 0; + } + + void UnZoomTest( Gwen::Controls::Base* pFromPanel ) + { + m_Splitter->UnZoom(); + } + + void CenterPanels( Gwen::Controls::Base* pFromPanel ) + { + m_Splitter->CenterPanels(); + m_Splitter->UnZoom(); + } + + void ToggleSplitters( Gwen::Controls::Base* pFromPanel ) + { + m_Splitter->SetSplittersVisible( !m_bSplittersVisible ); + m_bSplittersVisible = !m_bSplittersVisible; + } + + + bool m_bSplittersVisible; + int m_iCurZoom; + Controls::CrossSplitter* m_Splitter; + +}; + + + +DEFINE_UNIT_TEST( CrossSplitter, L"CrossSplitter" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/GroupBox.cpp b/test/GwenOpenGLTest/GroupBox.cpp new file mode 100644 index 000000000..f0a490162 --- /dev/null +++ b/test/GwenOpenGLTest/GroupBox.cpp @@ -0,0 +1,21 @@ +#include "UnitTest.h" +#include "Gwen/Controls/GroupBox.h" + +using namespace Gwen; + +class GroupBox2 : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( GroupBox2, GUnit ) + { + Gwen::Controls::GroupBox* pGroup = new Gwen::Controls::GroupBox( this ); + pGroup->Dock( Pos::Fill ); + pGroup->SetText( "Group Box" ); + } +}; + + + + +DEFINE_UNIT_TEST( GroupBox2, L"GroupBox" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/ImagePanel.cpp b/test/GwenOpenGLTest/ImagePanel.cpp new file mode 100644 index 000000000..015cfb307 --- /dev/null +++ b/test/GwenOpenGLTest/ImagePanel.cpp @@ -0,0 +1,32 @@ +#include "UnitTest.h" +#include "Gwen/Controls/ImagePanel.h" + +using namespace Gwen; + +class ImagePanel : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( ImagePanel, GUnit ) + { + // Normal + { + Controls::ImagePanel* img = new Controls::ImagePanel( this ); + img->SetImage( L"gwen.png" ); + img->SetBounds( 10, 10, 100, 100 ); + } + + // Missing + { + Controls::ImagePanel* img = new Controls::ImagePanel( this ); + img->SetImage( L"missingimage.png" ); + img->SetBounds( 120, 10, 100, 100 ); + } + + } + +}; + + + +DEFINE_UNIT_TEST( ImagePanel, L"ImagePanel" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/Label.cpp b/test/GwenOpenGLTest/Label.cpp new file mode 100644 index 000000000..a2301f1f2 --- /dev/null +++ b/test/GwenOpenGLTest/Label.cpp @@ -0,0 +1,99 @@ +#include "UnitTest.h" +#include "Gwen/Controls/Label.h" + +using namespace Gwen; + +class Label : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( Label, GUnit ) + { + { + Gwen::Controls::Label* label = new Gwen::Controls::Label( this ); + label->SetText( "Garry's Normal Label" ); + label->SizeToContents(); + label->SetPos( 10, 10 ); + } + + { + Gwen::Controls::Label* label = new Gwen::Controls::Label( this ); + label->SetText( L"Chinese: \u4E45\u6709\u5F52\u5929\u613F \u7EC8\u8FC7\u9B3C\u95E8\u5173" ); + label->SizeToContents(); + label->SetPos( 10, 30 ); + } + + { + Gwen::Controls::Label* label = new Gwen::Controls::Label( this ); + label->SetText( L"Japanese: \u751F\u3080\u304E\u3000\u751F\u3054\u3081\u3000\u751F\u305F\u307E\u3054" ); + label->SizeToContents(); + label->SetPos( 10, 50 ); + } + + { + Gwen::Controls::Label* label = new Gwen::Controls::Label( this ); + label->SetText( L"Korean: \uADF9\uC9C0\uD0D0\uD5D8\u3000\uD611\uD68C\uACB0\uC131\u3000\uCCB4\uACC4\uC801\u3000\uC5F0\uAD6C" ); + label->SizeToContents(); + label->SetPos( 10, 70 ); + } + + { + Gwen::Controls::Label* label = new Gwen::Controls::Label( this ); + label->SetText( L"Hindi: \u092F\u0947 \u0905\u0928\u0941\u091A\u094D\u091B\u0947\u0926 \u0939\u093F\u0928\u094D\u0926\u0940 \u092E\u0947\u0902 \u0939\u0948\u0964" ); + label->SizeToContents(); + label->SetPos( 10, 90 ); + } + + { + Gwen::Controls::Label* label = new Gwen::Controls::Label( this ); + label->SetText( L"Arabic: \u0627\u0644\u0622\u0646 \u0644\u062D\u0636\u0648\u0631 \u0627\u0644\u0645\u0624\u062A\u0645\u0631 \u0627\u0644\u062F\u0648\u0644\u064A" ); + label->SizeToContents(); + label->SetPos( 10, 110 ); + } + + { + Gwen::Controls::Label* label = new Gwen::Controls::Label( this ); + label->SetText( L"Wow, Coloured Text" ); + label->SetTextColor( Gwen::Color( 0, 0, 255, 255 ) ); + label->SizeToContents(); + label->SetPos( 10, 130 ); + } + + { + Gwen::Controls::Label* label = new Gwen::Controls::Label( this ); + label->SetText( L"Coloured Text With Alpha" ); + label->SetTextColor( Gwen::Color( 0, 0, 255, 100 ) ); + label->SizeToContents(); + label->SetPos( 10, 150 ); + } + + { + // + // Note that when using a custom font, this font object has to stick around + // for the lifetime of the label. Rethink, or is that ideal? + // + m_Font.facename = L"Comic Sans MS"; + m_Font.size = 25; + + Gwen::Controls::Label* label = new Gwen::Controls::Label( this ); + label->SetText( L"Custom Font (Comic Sans 25)" ); + label->SetFont( &m_Font ); + label->SizeToContents(); + label->SetPos( 10, 170 ); + } + + { + Gwen::Controls::Label* label = new Gwen::Controls::Label( this ); + label->SetText( L"Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.\n\nLorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua." ); + label->SizeToContents(); + label->SetBounds( 300, 10, 150, 500 ); + } + + } + + Gwen::Font m_Font; +}; + + + +DEFINE_UNIT_TEST( Label, L"Label" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/ListBox.cpp b/test/GwenOpenGLTest/ListBox.cpp new file mode 100644 index 000000000..7072f89b2 --- /dev/null +++ b/test/GwenOpenGLTest/ListBox.cpp @@ -0,0 +1,71 @@ +#include "UnitTest.h" +#include "Gwen/Controls/ListBox.h" + +using namespace Gwen; + +class ListBox : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( ListBox, GUnit ) + { + { + Gwen::Controls::ListBox* ctrl = new Gwen::Controls::ListBox( this ); + ctrl->SetBounds( 10, 10, 100, 200 ); + + ctrl->AddItem( L"First" ); + ctrl->AddItem( L"Blue" ); + ctrl->AddItem( L"Yellow" ); + ctrl->AddItem( L"Orange" ); + ctrl->AddItem( L"Brown" ); + ctrl->AddItem( L"Green" ); + ctrl->AddItem( L"Dog" ); + ctrl->AddItem( L"Cat" ); + ctrl->AddItem( L"Shoes" ); + ctrl->AddItem( L"Chair" ); + ctrl->AddItem( L"Last" ); + + ctrl->onRowSelected.Add( this, &ThisClass::RowSelected ); + } + + { + Gwen::Controls::ListBox* ctrl = new Gwen::Controls::ListBox( this ); + ctrl->SetBounds( 120, 10, 200, 200 ); + ctrl->SetColumnCount( 3 ); + ctrl->SetAllowMultiSelect( true ); + ctrl->onRowSelected.Add( this, &ThisClass::RowSelected ); + + + { + Gwen::Controls::Layout::TableRow* pRow = ctrl->AddItem( L"Baked Beans" ); + pRow->SetCellText( 1, L"Heinz" ); + pRow->SetCellText( 2, L"£3.50" ); + } + + { + Gwen::Controls::Layout::TableRow* pRow = ctrl->AddItem( L"Bananas" ); + pRow->SetCellText( 1, L"Trees" ); + pRow->SetCellText( 2, L"£1.27" ); + } + + { + Gwen::Controls::Layout::TableRow* pRow = ctrl->AddItem( L"Chicken" ); + pRow->SetCellText( 1, L"\u5355\u5143\u6D4B\u8BD5" ); + pRow->SetCellText( 2, L"£8.95" ); + } + } + } + + void RowSelected( Gwen::Controls::Base* pControl ) + { + Gwen::Controls::ListBox* ctrl = (Gwen::Controls::ListBox*)pControl; + + UnitPrint( Utility::Format( L"Listbox Item Selected: %s", ctrl->GetSelectedRow()->GetText( 0 ).c_str() ) ); + } + + Gwen::Font m_Font; +}; + + + +DEFINE_UNIT_TEST( ListBox, L"ListBox" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/MenuStrip.cpp b/test/GwenOpenGLTest/MenuStrip.cpp new file mode 100644 index 000000000..14a8a1457 --- /dev/null +++ b/test/GwenOpenGLTest/MenuStrip.cpp @@ -0,0 +1,105 @@ +#include "UnitTest.h" +#include "Gwen/Controls/MenuStrip.h" + +using namespace Gwen; + +class MenuStrip : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( MenuStrip, GUnit ) + { + Gwen::Controls::MenuStrip* menu = new Gwen::Controls::MenuStrip( this ); + + { + Gwen::Controls::MenuItem* pRoot = menu->AddItem( L"File" ); + pRoot->GetMenu()->AddItem( L"New", L"test16.png", GWEN_MCALL( ThisClass::MenuItemSelect ) ); + pRoot->GetMenu()->AddItem( L"Load", L"test16.png", GWEN_MCALL( ThisClass::MenuItemSelect ) ); + pRoot->GetMenu()->AddItem( L"Save", GWEN_MCALL( ThisClass::MenuItemSelect ) ); + pRoot->GetMenu()->AddItem( L"Save As..", GWEN_MCALL( ThisClass::MenuItemSelect ) ); + pRoot->GetMenu()->AddItem( L"Quit", GWEN_MCALL( ThisClass::MenuItemSelect ) ); + } + + { + Gwen::Controls::MenuItem* pRoot = menu->AddItem( L"\u043F\u0438\u0440\u0430\u0442\u0441\u0442\u0432\u043E" ); + pRoot->GetMenu()->AddItem( L"\u5355\u5143\u6D4B\u8BD5", GWEN_MCALL( ThisClass::MenuItemSelect ) ); + pRoot->GetMenu()->AddItem( L"\u0111\u01A1n v\u1ECB th\u1EED nghi\u1EC7m", L"test16.png", GWEN_MCALL( ThisClass::MenuItemSelect ) ); + } + + { + Gwen::Controls::MenuItem* pRoot = menu->AddItem( L"Submenu" ); + + pRoot->GetMenu()->AddItem( "One" )->SetCheckable( true ); + + { + Gwen::Controls::MenuItem* pRootB = pRoot->GetMenu()->AddItem( "Two" ); + pRootB->GetMenu()->AddItem( "Two.One" ); + pRootB->GetMenu()->AddItem( "Two.Two" ); + pRootB->GetMenu()->AddItem( "Two.Three" ); + pRootB->GetMenu()->AddItem( "Two.Four" ); + pRootB->GetMenu()->AddItem( "Two.Five" ); + pRootB->GetMenu()->AddItem( "Two.Six" ); + pRootB->GetMenu()->AddItem( "Two.Seven" ); + pRootB->GetMenu()->AddItem( "Two.Eight" ); + pRootB->GetMenu()->AddItem( "Two.Nine", "test16.png" ); + } + + pRoot->GetMenu()->AddItem( "Three" ); + pRoot->GetMenu()->AddItem( "Four" ); + pRoot->GetMenu()->AddItem( "Five" ); + + { + Gwen::Controls::MenuItem* pRootB = pRoot->GetMenu()->AddItem( "Six" ); + pRootB->GetMenu()->AddItem( "Six.One" ); + pRootB->GetMenu()->AddItem( "Six.Two" ); + pRootB->GetMenu()->AddItem( "Six.Three" ); + pRootB->GetMenu()->AddItem( "Six.Four" ); + pRootB->GetMenu()->AddItem( "Six.Five", "test16.png" ); + + { + Gwen::Controls::MenuItem* pRootC = pRootB->GetMenu()->AddItem( "Six.Six" ); + pRootC->GetMenu()->AddItem( "Sheep" ); + pRootC->GetMenu()->AddItem( "Goose" ); + { + Gwen::Controls::MenuItem* pRootD = pRootC->GetMenu()->AddItem( "Camel" ); + pRootD->GetMenu()->AddItem( "Eyes" ); + pRootD->GetMenu()->AddItem( "Nose" ); + { + Gwen::Controls::MenuItem* pRootE = pRootD->GetMenu()->AddItem( "Hair" ); + pRootE->GetMenu()->AddItem( "Blonde" ); + pRootE->GetMenu()->AddItem( "Black" ); + { + Gwen::Controls::MenuItem* pRootF = pRootE->GetMenu()->AddItem( "Red" ); + pRootF->GetMenu()->AddItem( "Light" ); + pRootF->GetMenu()->AddItem( "Medium" ); + pRootF->GetMenu()->AddItem( "Dark" ); + } + pRootE->GetMenu()->AddItem( "Brown" ); + } + pRootD->GetMenu()->AddItem( "Ears" ); + } + pRootC->GetMenu()->AddItem( "Duck" ); + } + + pRootB->GetMenu()->AddItem( "Six.Seven" ); + pRootB->GetMenu()->AddItem( "Six.Eight" ); + pRootB->GetMenu()->AddItem( "Six.Nine" ); + } + + pRoot->GetMenu()->AddItem( "Seven" ); + + } + } + + void MenuItemSelect( Base* pControl ) + { + Gwen::Controls::MenuItem* pMenuItem = (Gwen::Controls::MenuItem*)pControl; + + UnitPrint( Utility::Format( L"Menu Selected: %s", pMenuItem->GetText().c_str() ) ); + } + +}; + + + +DEFINE_UNIT_TEST( MenuStrip, L"MenuStrip" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/Numeric.cpp b/test/GwenOpenGLTest/Numeric.cpp new file mode 100644 index 000000000..f7a1c85eb --- /dev/null +++ b/test/GwenOpenGLTest/Numeric.cpp @@ -0,0 +1,31 @@ +#include "UnitTest.h" +#include "Gwen/Controls/NumericUpDown.h" + +using namespace Gwen; + +class Numeric : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( Numeric, GUnit ) + { + + Controls::NumericUpDown* pCtrl = new Controls::NumericUpDown( this ); + pCtrl->SetBounds( 10, 10, 50, 20 ); + pCtrl->SetValue( 50 ); + pCtrl->SetMax( 1000 ); + pCtrl->SetMin( -1000 ); + + // pCtrl->onPress.Add( this, &ThisClass::onButtonA ); + } + + void onButtonA( Controls::Base* pControl ) + { + // UnitPrint( L"Button Pressed (using 'OnPress' event)" ); + } + +}; + + + +DEFINE_UNIT_TEST( Numeric, L"Numeric" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/OpenGLSample.cpp b/test/GwenOpenGLTest/OpenGLSample.cpp new file mode 100644 index 000000000..a669b1652 --- /dev/null +++ b/test/GwenOpenGLTest/OpenGLSample.cpp @@ -0,0 +1,534 @@ + + +#include "Gwen/Gwen.h" +#include "Gwen/Skins/Simple.h" + +#include "UnitTest.h" + +extern unsigned char OpenSansData[]; + +#include "Gwen/Renderers/OpenGL_DebugFont.h" +#ifdef __APPLE__ +#include "OpenGLWindow/MacOpenGLWindow.h" +#else + +#include "CustomGL/glew.h" +#ifdef _WIN32 +#include "OpenGLWindow/Win32OpenGLWindow.h" +#else +//let's cross the fingers it is Linux/X11 +#include "OpenGLWindow/X11OpenGLWindow.h" +#endif //_WIN32 +#endif//__APPLE__ + +#include "OpenGLWindow/opengl_fontstashcallbacks.h" + +#include "OpenGLWindow/GwenOpenGL3CoreRenderer.h" +#include "OpenGLWindow/GLPrimitiveRenderer.h" +#include + +Gwen::Controls::Canvas* pCanvas = NULL; +Gwen::Skin::Simple skin; + +void MyMouseMoveCallback( float x, float y) +{ + //b3DefaultMouseCallback(button,state,x,y); + + static int m_lastmousepos[2] = {0,0}; + static bool isInitialized = false; + if (pCanvas) + { + if (!isInitialized) + { + isInitialized = true; + m_lastmousepos[0] = x+1; + m_lastmousepos[1] = y+1; + } + bool handled = pCanvas->InputMouseMoved(x,y,m_lastmousepos[0],m_lastmousepos[1]); + } +} + +void MyMouseButtonCallback(int button, int state, float x, float y) +{ + //b3DefaultMouseCallback(button,state,x,y); + + if (pCanvas) + { + bool handled = pCanvas->InputMouseMoved(x,y,x, y); + + if (button>=0) + { + handled = pCanvas->InputMouseButton(button,state); + if (handled) + { + if (!state) + return; + } + } + } +} + +int sWidth = 800;//1050; +int sHeight = 600;//768; +GLPrimitiveRenderer* primRenderer=0; +//GwenOpenGL3CoreRenderer* gwenRenderer=0; +Gwen::Renderer::Base* gwenRenderer =0; + +static void MyResizeCallback( float width, float height) +{ + sWidth = width; + sHeight = height; +// printf("resize(%d,%d)\n",sWidth,sHeight); + if (primRenderer) + { + primRenderer->setScreenSize(width,height); + } + if (gwenRenderer) + { + gwenRenderer->Resize(width,height); + } + if (pCanvas) + { + pCanvas->SetSize( sWidth, sHeight); + } + +} + + + int droidRegular;//, droidItalic, droidBold, droidJapanese, dejavu; + +sth_stash* initFont(GLPrimitiveRenderer* primRenderer) +{ + GLint err; + + struct sth_stash* stash = 0; + OpenGL2RenderCallbacks* renderCallbacks = new OpenGL2RenderCallbacks(primRenderer); + + stash = sth_create(512,512,renderCallbacks);//256,256);//,1024);//512,512); + err = glGetError(); + assert(err==GL_NO_ERROR); + + if (!stash) + { + fprintf(stderr, "Could not create stash.\n"); + return 0; + } + + +#ifdef LOAD_FONTS_FROM_FILE + int datasize; + unsigned char* data; + float sx,sy,dx,dy,lh; + GLuint texture; + + + + const char* fontPaths[]={ + "./", + "../../bin/", + "../bin/", + "bin/" + }; + + int numPaths=sizeof(fontPaths)/sizeof(char*); + + // Load the first truetype font from memory (just because we can). + + FILE* fp = 0; + const char* fontPath ="./"; + char fullFontFileName[1024]; + + for (int i=0;iInputKey(key,value==1); + + + int gwenKey = -1; + + switch (key) + { + case B3G_LEFT_ARROW: + { + gwenKey = Gwen::Key::Left; + break; + } + case B3G_RIGHT_ARROW: + { + gwenKey = Gwen::Key::Right; + break; + } + case B3G_UP_ARROW: + { + gwenKey = Gwen::Key::Up; + break; + } + case B3G_DOWN_ARROW: + { + gwenKey = Gwen::Key::Down; + break; + } + case B3G_BACKSPACE: + { + gwenKey = Gwen::Key::Backspace; + break; + } + case B3G_DELETE: + { + gwenKey = Gwen::Key::Delete; + break; + } + case B3G_HOME: + { + gwenKey = Gwen::Key::Home; + break; + } + case B3G_END: + { + gwenKey = Gwen::Key::End; + break; + } + case B3G_SHIFT: + { + gwenKey = Gwen::Key::Shift; + break; + } + case B3G_CONTROL: + { + gwenKey = Gwen::Key::Control; + break; + } + + + + default: + { + + } + }; + + if (gwenKey>=0) + { + pCanvas->InputKey(gwenKey,value==1); + } else + { + if (key<256 && value) + { + Gwen::UnicodeChar c = ( Gwen::UnicodeChar ) key; + pCanvas->InputCharacter(c); + } + } +} + +extern int avoidUpdate; + +int main() +{ + + b3gDefaultOpenGLWindow* window = new b3gDefaultOpenGLWindow(); + window->setKeyboardCallback(keyCallback); + b3gWindowConstructionInfo wci; + wci.m_openglVersion = 2; + wci.m_width = sWidth; + wci.m_height = sHeight; + // wci.m_resizeCallback = MyResizeCallback; + + window->createWindow(wci); + window->setResizeCallback(MyResizeCallback); + + + int majorGlVersion, minorGlVersion; + + if (!sscanf((const char*)glGetString(GL_VERSION), "%d.%d", &majorGlVersion, &minorGlVersion)==2) + { + printf("Exit: Error cannot extract OpenGL version from GL_VERSION string\n"); + exit(0); + } + char title[1024]; + if (wci.m_openglVersion>2) + { + sprintf(title,"Gwen with OpenGL %d.%d\n",majorGlVersion,minorGlVersion); + } else + { + sprintf(title,"Gwen with OpenGL %d\n",wci.m_openglVersion); + } + window->setWindowTitle(title); + + if (majorGlVersion>=3 && wci.m_openglVersion>=3) + { + float retinaScale = 1.f; + +#ifndef __APPLE__ +#ifndef _WIN32 + //we need glewExperimental on Linux + glewExperimental = GL_TRUE; +#endif // _WIN32 + glewInit(); +#endif + + //we ned to call glGetError twice, because of some Ubuntu/Intel/OpenGL issue + + GLuint err = glGetError(); + err = glGetError(); + assert(err==GL_NO_ERROR); + + + retinaScale = window->getRetinaScale(); + + primRenderer = new GLPrimitiveRenderer(sWidth,sHeight); + + sth_stash* font = initFont(primRenderer ); + + + gwenRenderer = new GwenOpenGL3CoreRenderer(primRenderer,font,sWidth,sHeight,retinaScale); + + } else + { + //OpenGL 2.x + gwenRenderer = new Gwen::Renderer::OpenGL_DebugFont(); + + + skin.SetRender( gwenRenderer ); + + + + glClearColor(1,0,0,1); + + } + + + + // + // Create a GWEN OpenGL Renderer + // +// Gwen::Renderer::OpenGL_DebugFont * pRenderer = new Gwen::Renderer::OpenGL_DebugFont(); + + // + // Create a GWEN skin + // + + +#ifdef USE_TEXTURED_SKIN + Gwen::Skin::TexturedBase skin; + skin.SetRender( pRenderer ); + skin.Init("DefaultSkin.png"); +#else + skin.SetRender( gwenRenderer ); +#endif + + + // + // Create a Canvas (it's root, on which all other GWEN panels are created) + // + pCanvas = new Gwen::Controls::Canvas( &skin ); + pCanvas->SetSize( sWidth, sHeight); + pCanvas->SetDrawBackground( true ); + pCanvas->SetBackgroundColor( Gwen::Color( 150, 170, 170, 255 ) ); + + window->setMouseButtonCallback(MyMouseButtonCallback); + window->setMouseMoveCallback(MyMouseMoveCallback); + + + // + // Create our unittest control (which is a Window with controls in it) + // + UnitTest* pUnit = new UnitTest( pCanvas ); + pUnit->SetPos( 10, 10 ); + + // + // Create a Windows Control helper + // (Processes Windows MSG's and fires input at GWEN) + // + //Gwen::Input::Windows GwenInput; + //GwenInput.Initialize( pCanvas ); + + // + // Begin the main game loop + // +// MSG msg; + while( !window->requestedExit() ) + { + if (majorGlVersion<3 || wci.m_openglVersion<3) + { + saveOpenGLState(sWidth,sHeight); + } + + // Skip out if the window is closed + //if ( !IsWindowVisible( g_pHWND ) ) + //break; + + // If we have a message from windows.. + // if ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) ) + { + + // .. give it to the input handler to process + // GwenInput.ProcessMessage( msg ); + + // if it's QUIT then quit.. + // if ( msg.message == WM_QUIT ) + // break; + + // Handle the regular window stuff.. + // TranslateMessage(&msg); + // DispatchMessage(&msg); + + } + + window->startRendering(); + + // Main OpenGL Render Loop + { + glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT ); + + glEnable(GL_BLEND); + GLint err = glGetError(); + assert(err==GL_NO_ERROR); + + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + err = glGetError(); + assert(err==GL_NO_ERROR); + + err = glGetError(); + assert(err==GL_NO_ERROR); + + glDisable(GL_DEPTH_TEST); + err = glGetError(); + assert(err==GL_NO_ERROR); + + //glColor4ub(255,0,0,255); + + err = glGetError(); + assert(err==GL_NO_ERROR); + + + err = glGetError(); + assert(err==GL_NO_ERROR); + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + + // saveOpenGLState(width,height);//m_glutScreenWidth,m_glutScreenHeight); + + err = glGetError(); + assert(err==GL_NO_ERROR); + + + err = glGetError(); + assert(err==GL_NO_ERROR); + + glDisable(GL_CULL_FACE); + + glDisable(GL_DEPTH_TEST); + err = glGetError(); + assert(err==GL_NO_ERROR); + + err = glGetError(); + assert(err==GL_NO_ERROR); + + glEnable(GL_BLEND); + + + err = glGetError(); + assert(err==GL_NO_ERROR); + + + + pCanvas->RenderCanvas(); + + if (avoidUpdate<=0) + avoidUpdate++; + + // SwapBuffers( GetDC( g_pHWND ) ); + } + window->endRendering(); + + if (majorGlVersion<3 || wci.m_openglVersion<3) + { + restoreOpenGLState(); + } + } + + window->closeWindow(); + delete window; + + +} diff --git a/test/GwenOpenGLTest/PanelListPanel.cpp b/test/GwenOpenGLTest/PanelListPanel.cpp new file mode 100644 index 000000000..fcf1ae316 --- /dev/null +++ b/test/GwenOpenGLTest/PanelListPanel.cpp @@ -0,0 +1,61 @@ +#include "UnitTest.h" +#include "Gwen/Controls/PanelListPanel.h" +#include "Gwen/Controls/StatusBar.h" +#include "Gwen/Utility.h" + +using namespace Gwen; + +class PanelListPanel : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( PanelListPanel, GUnit ) + { + m_PLP = new Gwen::Controls::PanelListPanel( this ); + m_PLP->Dock( Pos::Fill ); + m_PLP->SetPadding( Gwen::Padding( 10, 10 )); + m_PLP->SetVertical(); + m_PLP->SetSizeToChildren( false ); + + for ( int i = 0; i < 16; i++) + { + Gwen::String testName = "TEST" + Utility::ToString( i ); + Gwen::Controls::Button* testButton = new Gwen::Controls::Button( m_PLP ); + testButton->SetText( testName ); + } + + Gwen::Controls::StatusBar* pStatus = new Gwen::Controls::StatusBar( this ); + pStatus->Dock( Pos::Bottom ); + + { + Gwen::Controls::Button* pButton = new Gwen::Controls::Button( pStatus ); + pButton->SetText( "Horizontal" ); + pButton->onPress.Add( this, &PanelListPanel::GoHorizontal ); + pStatus->AddControl( pButton, false ); + } + + { + Gwen::Controls::Button* pButton = new Gwen::Controls::Button( pStatus ); + pButton->SetText( "Vertical" ); + pButton->onPress.Add( this, &PanelListPanel::GoVertical ); + pStatus->AddControl( pButton, true ); + } + } + + + void GoVertical( Gwen::Controls::Base* pFromPanel ) + { + m_PLP->SetVertical(); + } + + void GoHorizontal( Gwen::Controls::Base* pFromPanel ) + { + m_PLP->SetHorizontal(); + } + + Gwen::Controls::PanelListPanel* m_PLP; +}; + + + +DEFINE_UNIT_TEST( PanelListPanel, L"PanelListPanel" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/ProgressBar.cpp b/test/GwenOpenGLTest/ProgressBar.cpp new file mode 100644 index 000000000..ed72c3e19 --- /dev/null +++ b/test/GwenOpenGLTest/ProgressBar.cpp @@ -0,0 +1,93 @@ +#include "UnitTest.h" +#include "Gwen/Controls/RadioButtonController.h" +#include "Gwen/Controls/ProgressBar.h" + +using namespace Gwen; + +class ProgressBar : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( ProgressBar, GUnit ) + { + + { + Gwen::Controls::ProgressBar* pb = new Gwen::Controls::ProgressBar( this ); + pb->SetBounds( Gwen::Rect( 110, 20, 200, 20 ) ); + pb->SetValue( 0.27f ); + } + + { + Gwen::Controls::ProgressBar* pb = new Gwen::Controls::ProgressBar( this ); + pb->SetBounds( Gwen::Rect( 110, 50, 200, 20 ) ); + pb->SetValue( 0.66f ); + pb->SetAlignment( Pos::Right | Pos::CenterV ); + } + + { + Gwen::Controls::ProgressBar* pb = new Gwen::Controls::ProgressBar( this ); + pb->SetBounds( Gwen::Rect( 110, 80, 200, 20 ) ); + pb->SetValue( 0.88f ); + pb->SetAlignment( Pos::Left | Pos::CenterV ); + } + + { + Gwen::Controls::ProgressBar* pb = new Gwen::Controls::ProgressBar( this ); + pb->SetBounds( Gwen::Rect( 110, 110, 200, 20 ) ); + pb->SetAutoLabel( false ); + pb->SetValue( 0.20f ); + pb->SetAlignment( Pos::Right | Pos::CenterV ); + pb->SetText( L"40,245 MB" ); + } + + { + Gwen::Controls::ProgressBar* pb = new Gwen::Controls::ProgressBar( this ); + pb->SetBounds( Gwen::Rect( 110, 140, 200, 20 ) ); + pb->SetAutoLabel( false ); + pb->SetValue( 1.00f ); + } + + { + Gwen::Controls::ProgressBar* pb = new Gwen::Controls::ProgressBar( this ); + pb->SetBounds( Gwen::Rect( 110, 170, 200, 20 ) ); + pb->SetAutoLabel( false ); + pb->SetValue( 0.00f ); + } + + { + Gwen::Controls::ProgressBar* pb = new Gwen::Controls::ProgressBar( this ); + pb->SetBounds( Gwen::Rect( 110, 200, 200, 20 ) ); + pb->SetAutoLabel( false ); + pb->SetValue( 0.50f ); + } + + { + Gwen::Controls::ProgressBar* pb = new Gwen::Controls::ProgressBar( this ); + pb->SetBounds( Gwen::Rect( 20, 20, 25, 200 ) ); + pb->SetVertical(); + pb->SetValue( 0.25f ); + pb->SetAlignment( Pos::Top | Pos::CenterH ); + } + + { + Gwen::Controls::ProgressBar* pb = new Gwen::Controls::ProgressBar( this ); + pb->SetBounds( Gwen::Rect( 50, 20, 25, 200 ) ); + pb->SetVertical(); + pb->SetValue( 0.40f ); + } + + { + Gwen::Controls::ProgressBar* pb = new Gwen::Controls::ProgressBar( this ); + pb->SetBounds( Gwen::Rect( 80, 20, 25, 200 ) ); + pb->SetVertical(); + pb->SetAlignment( Pos::Bottom | Pos::CenterH ); + pb->SetValue( 0.65f ); + } + + } + +}; + + + +DEFINE_UNIT_TEST( ProgressBar, L"ProgressBar" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/Properties.cpp b/test/GwenOpenGLTest/Properties.cpp new file mode 100644 index 000000000..c909db388 --- /dev/null +++ b/test/GwenOpenGLTest/Properties.cpp @@ -0,0 +1,63 @@ +#include "UnitTest.h" +#include "Gwen/Controls/Properties.h" +#include "Gwen/Controls/PropertyTree.h" + +using namespace Gwen; + +class Properties2 : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( Properties2, GUnit ) + { + { + Gwen::Controls::Properties* props = new Gwen::Controls::Properties( this ); + + props->SetBounds( 10, 10, 150, 300 ); + + { + { + Gwen::Controls::PropertyRow* pRow = props->Add( L"First Name" ); + pRow->onChange.Add( this, &Properties2::OnFirstNameChanged ); + } + + props->Add( L"Middle Name" ); + props->Add( L"Last Name" ); + } + + } + + { + Gwen::Controls::PropertyTree* ptree = new Gwen::Controls::PropertyTree( this ); + ptree->SetBounds( 200, 10, 200, 200 ); + + { + Gwen::Controls::Properties* props = ptree->Add( L"Item One" ); + props->Add( L"Middle Name" ); + props->Add( L"Last Name" ); + props->Add( L"Four" ); + } + + { + Gwen::Controls::Properties* props = ptree->Add( L"Item Two" ); + props->Add( L"More Items" ); + props->Add( L"To Fill" ); + props->Add( L"Out Here" ); + } + + ptree->ExpandAll(); + + } + } + + void OnFirstNameChanged( Controls::Base* pControl ) + { + Gwen::Controls::PropertyRow* pRow = (Gwen::Controls::PropertyRow*) pControl; + UnitPrint( Utility::Format( L"First Name Changed: %s", pRow->GetProperty()->GetPropertyValue().c_str() ) ); + } + +}; + + + +DEFINE_UNIT_TEST( Properties2, L"Properties" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/RadioButton.cpp b/test/GwenOpenGLTest/RadioButton.cpp new file mode 100644 index 000000000..5d4948dd0 --- /dev/null +++ b/test/GwenOpenGLTest/RadioButton.cpp @@ -0,0 +1,38 @@ +#include "UnitTest.h" +#include "Gwen/Controls/RadioButtonController.h" + +using namespace Gwen; + +class RadioButton2 : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( RadioButton2, GUnit ) + { + + Gwen::Controls::RadioButtonController* rc = new Gwen::Controls::RadioButtonController( this ); + + rc->AddOption( "Option 1" ); + rc->AddOption( "Option 2" ); + rc->AddOption( "Option 3" ); + rc->AddOption( L"\u0627\u0644\u0622\u0646 \u0644\u062D\u0636\u0648\u0631" ); + + rc->SetBounds( 30, 30, 200, 200 ); + + rc->onSelectionChange.Add( this, &RadioButton2::OnChange ); + + + } + + void OnChange( Controls::Base* pControl ) + { + Gwen::Controls::RadioButtonController* rc = (Gwen::Controls::RadioButtonController*) pControl; + Gwen::Controls::LabeledRadioButton* pSelected = rc->GetSelected(); + + UnitPrint( Utility::Format( L"RadioButton changed (using 'OnChange' event)\n Chosen Item: '%s'", pSelected->GetLabel()->GetText().c_str() ) ); + } +}; + + + +DEFINE_UNIT_TEST( RadioButton2, L"RadioButton" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/ScrollControl.cpp b/test/GwenOpenGLTest/ScrollControl.cpp new file mode 100644 index 000000000..c21a2080a --- /dev/null +++ b/test/GwenOpenGLTest/ScrollControl.cpp @@ -0,0 +1,138 @@ +#include "UnitTest.h" +#include "Gwen/Controls/ScrollControl.h" + +using namespace Gwen; + +class ScrollControl : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( ScrollControl, GUnit ) + { + + { + Gwen::Controls::ScrollControl* pCtrl = new Gwen::Controls::ScrollControl( this ); + pCtrl->SetBounds( 10, 10, 100, 100 ); + + Controls::Button* pTestButton = new Controls::Button( pCtrl ); + pTestButton->SetText( L"Twice As Big" ); + pTestButton->SetBounds( 0, 0, 200, 200 ); + } + + { + Gwen::Controls::ScrollControl* pCtrl = new Gwen::Controls::ScrollControl( this ); + pCtrl->SetBounds( 110, 10, 100, 100 ); + + Controls::Button* pTestButton = new Controls::Button( pCtrl ); + pTestButton->SetText( L"Same Size" ); + pTestButton->SetBounds( 0, 0, 100, 100 ); + } + + { + Gwen::Controls::ScrollControl* pCtrl = new Gwen::Controls::ScrollControl( this ); + pCtrl->SetBounds( 210, 10, 100, 100 ); + + Controls::Button* pTestButton = new Controls::Button( pCtrl ); + pTestButton->SetText( L"Wide" ); + pTestButton->SetBounds( 0, 0, 200, 50 ); + } + + { + Gwen::Controls::ScrollControl* pCtrl = new Gwen::Controls::ScrollControl( this ); + pCtrl->SetBounds( 310, 10, 100, 100 ); + + Controls::Button* pTestButton = new Controls::Button( pCtrl ); + pTestButton->SetText( L"Tall" ); + pTestButton->SetBounds( 0, 0, 50, 200 ); + } + + { + Gwen::Controls::ScrollControl* pCtrl = new Gwen::Controls::ScrollControl( this ); + pCtrl->SetBounds( 410, 10, 100, 100 ); + pCtrl->SetScroll( false, true ); + + Controls::Button* pTestButton = new Controls::Button( pCtrl ); + pTestButton->SetText( L"Vertical" ); + pTestButton->SetBounds( 0, 0, 200, 200 ); + } + + { + Gwen::Controls::ScrollControl* pCtrl = new Gwen::Controls::ScrollControl( this ); + pCtrl->SetBounds( 510, 10, 100, 100 ); + pCtrl->SetScroll( true, false ); + + Controls::Button* pTestButton = new Controls::Button( pCtrl ); + pTestButton->SetText( L"Horinzontal" ); + pTestButton->SetBounds( 0, 0, 200, 200 ); + } + + // Bottom Row + + { + Gwen::Controls::ScrollControl* pCtrl = new Gwen::Controls::ScrollControl( this ); + pCtrl->SetBounds( 10, 110, 100, 100 ); + pCtrl->SetAutoHideBars( true ); + + Controls::Button* pTestButton = new Controls::Button( pCtrl ); + pTestButton->SetText( L"Twice As Big" ); + pTestButton->SetBounds( 0, 0, 200, 200 ); + } + + { + Gwen::Controls::ScrollControl* pCtrl = new Gwen::Controls::ScrollControl( this ); + pCtrl->SetBounds( 110, 110, 100, 100 ); + pCtrl->SetAutoHideBars( true ); + + Controls::Button* pTestButton = new Controls::Button( pCtrl ); + pTestButton->SetText( L"Same Size" ); + pTestButton->SetBounds( 0, 0, 100, 100 ); + } + + { + Gwen::Controls::ScrollControl* pCtrl = new Gwen::Controls::ScrollControl( this ); + pCtrl->SetBounds( 210, 110, 100, 100 ); + pCtrl->SetAutoHideBars( true ); + + Controls::Button* pTestButton = new Controls::Button( pCtrl ); + pTestButton->SetText( L"Wide" ); + pTestButton->SetBounds( 0, 0, 200, 50 ); + } + + { + Gwen::Controls::ScrollControl* pCtrl = new Gwen::Controls::ScrollControl( this ); + pCtrl->SetBounds( 310, 110, 100, 100 ); + pCtrl->SetAutoHideBars( true ); + + Controls::Button* pTestButton = new Controls::Button( pCtrl ); + pTestButton->SetText( L"Tall" ); + pTestButton->SetBounds( 0, 0, 50, 200 ); + } + + { + Gwen::Controls::ScrollControl* pCtrl = new Gwen::Controls::ScrollControl( this ); + pCtrl->SetBounds( 410, 110, 100, 100 ); + pCtrl->SetAutoHideBars( true ); + pCtrl->SetScroll( false, true ); + + Controls::Button* pTestButton = new Controls::Button( pCtrl ); + pTestButton->SetText( L"Vertical" ); + pTestButton->SetBounds( 0, 0, 200, 200 ); + } + + { + Gwen::Controls::ScrollControl* pCtrl = new Gwen::Controls::ScrollControl( this ); + pCtrl->SetBounds( 510, 110, 100, 100 ); + pCtrl->SetAutoHideBars( true ); + pCtrl->SetScroll( true, false ); + + Controls::Button* pTestButton = new Controls::Button( pCtrl ); + pTestButton->SetText( L"Horinzontal" ); + pTestButton->SetBounds( 0, 0, 200, 200 ); + } + } + +}; + + + +DEFINE_UNIT_TEST( ScrollControl, L"Scroll" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/Slider.cpp b/test/GwenOpenGLTest/Slider.cpp new file mode 100644 index 000000000..cf002fa86 --- /dev/null +++ b/test/GwenOpenGLTest/Slider.cpp @@ -0,0 +1,66 @@ +#include "UnitTest.h" +#include "Gwen/Controls/RadioButtonController.h" +#include "Gwen/Controls/VerticalSlider.h" +#include "Gwen/Controls/HorizontalSlider.h" + +using namespace Gwen; + +class Slider : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( Slider, GUnit ) + { + { + Gwen::Controls::HorizontalSlider* pSlider = new Gwen::Controls::HorizontalSlider( this ); + pSlider->SetPos( 10, 10 ); + pSlider->SetSize( 150, 20 ); + pSlider->SetRange( 0, 100 ); + pSlider->SetValue( 25 ); + pSlider->onValueChanged.Add( this, &Slider::SliderMoved ); + } + + { + Gwen::Controls::HorizontalSlider* pSlider = new Gwen::Controls::HorizontalSlider( this ); + pSlider->SetPos( 10, 40 ); + pSlider->SetSize( 150, 20 ); + pSlider->SetRange( 0, 100 ); + pSlider->SetValue( 25 ); + pSlider->SetNotchCount( 10 ); + pSlider->SetClampToNotches( true ); + pSlider->onValueChanged.Add( this, &Slider::SliderMoved ); + } + + { + Gwen::Controls::VerticalSlider* pSlider = new Gwen::Controls::VerticalSlider( this ); + pSlider->SetPos( 160, 10 ); + pSlider->SetSize( 20, 200 ); + pSlider->SetRange( 0, 100 ); + pSlider->SetValue( 25 ); + pSlider->onValueChanged.Add( this, &Slider::SliderMoved ); + } + + { + Gwen::Controls::VerticalSlider* pSlider = new Gwen::Controls::VerticalSlider( this ); + pSlider->SetPos( 190, 10 ); + pSlider->SetSize( 20, 200 ); + pSlider->SetRange( 0, 100 ); + pSlider->SetValue( 25 ); + pSlider->SetNotchCount( 10 ); + pSlider->SetClampToNotches( true ); + pSlider->onValueChanged.Add( this, &Slider::SliderMoved ); + } + } + + void SliderMoved( Base* pControl ) + { + Gwen::Controls::Slider* pSlider = (Gwen::Controls::Slider*)pControl; + + UnitPrint( Utility::Format( L"Slider Value: %.2f", pSlider->GetValue() ) ); + } + +}; + + + +DEFINE_UNIT_TEST( Slider, L"Slider" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/StatusBar.cpp b/test/GwenOpenGLTest/StatusBar.cpp new file mode 100644 index 000000000..902553739 --- /dev/null +++ b/test/GwenOpenGLTest/StatusBar.cpp @@ -0,0 +1,28 @@ +#include "UnitTest.h" +#include "Gwen/Controls/StatusBar.h" +#include "Gwen/Controls/Label.h" + +using namespace Gwen; + +class StatusBar : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( StatusBar, GUnit ) + { + Gwen::Controls::StatusBar* pStatus = new Gwen::Controls::StatusBar( this ); + pStatus->Dock( Pos::Bottom ); + + Gwen::Controls::Label* pLeft = new Gwen::Controls::Label( pStatus ); + pLeft->SetText(L"Label Added to left"); + pStatus->AddControl( pLeft, false ); + + Gwen::Controls::Label* pRight = new Gwen::Controls::Label( pStatus ); + pRight->SetText(L"Label Added to Right"); + pStatus->AddControl( pRight, true ); + } +}; + + + +DEFINE_UNIT_TEST( StatusBar, L"StatusBar" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/TabControl.cpp b/test/GwenOpenGLTest/TabControl.cpp new file mode 100644 index 000000000..8ed2b2ba6 --- /dev/null +++ b/test/GwenOpenGLTest/TabControl.cpp @@ -0,0 +1,71 @@ +#include "UnitTest.h" +#include "Gwen/Controls/TabControl.h" +#include "Gwen/Controls/RadioButtonController.h" + +using namespace Gwen; + +class TabControl2 : public GUnit +{ + public: + + Controls::TabControl* m_pDockControlLeft; + + GWEN_CONTROL_INLINE( TabControl2, GUnit ) + { + { + m_pDockControlLeft = new Controls::TabControl( this ); + m_pDockControlLeft->SetBounds( 10, 10, 200, 200 ); + + { + Controls::TabButton* pButton = m_pDockControlLeft->AddPage( L"Controls" ); + Base* pPage = pButton->GetPage(); + + { + Controls::RadioButtonController* pRadio = new Controls::RadioButtonController( pPage ); + pRadio->SetBounds( 10, 10, 100, 100 ); + + pRadio->AddOption( "Top" )->Select(); + pRadio->AddOption( "Bottom" ); + pRadio->AddOption( "Left" ); + pRadio->AddOption( "Right" ); + + pRadio->onSelectionChange.Add( this, &ThisClass::OnDockChange ); + + } + } + + m_pDockControlLeft->AddPage( L"Red" ); + m_pDockControlLeft->AddPage( L"Green" ); + m_pDockControlLeft->AddPage( L"Blue" ); + } + + { + Controls::TabControl* pDragMe = new Controls::TabControl( this ); + pDragMe->SetBounds( 220, 10, 200, 200 ); + + pDragMe->AddPage( L"You" ); + pDragMe->AddPage( L"Can" ); + pDragMe->AddPage( L"Reorder" )->SetImage( L"test16.png" ); + pDragMe->AddPage( L"These" ); + pDragMe->AddPage( L"Tabs" ); + + pDragMe->SetAllowReorder( true ); + } + } + + void OnDockChange( Gwen::Controls::Base* pControl ) + { + Gwen::Controls::RadioButtonController* rc = (Gwen::Controls::RadioButtonController*) pControl; + + if ( rc->GetSelectedLabel() == L"Top" ) m_pDockControlLeft->SetTabStripPosition( Pos::Top ); + if ( rc->GetSelectedLabel() == L"Bottom" ) m_pDockControlLeft->SetTabStripPosition( Pos::Bottom ); + if ( rc->GetSelectedLabel() == L"Left" ) m_pDockControlLeft->SetTabStripPosition( Pos::Left ); + if ( rc->GetSelectedLabel() == L"Right" ) m_pDockControlLeft->SetTabStripPosition( Pos::Right ); + } + + Gwen::Font m_Font; +}; + + + +DEFINE_UNIT_TEST( TabControl2, L"TabControl" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/TextBox.cpp b/test/GwenOpenGLTest/TextBox.cpp new file mode 100644 index 000000000..72b49adc9 --- /dev/null +++ b/test/GwenOpenGLTest/TextBox.cpp @@ -0,0 +1,79 @@ +#include "UnitTest.h" +#include "Gwen/Controls/TextBox.h" + +using namespace Gwen; + +class TextBox : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( TextBox, GUnit ) + { + { + Gwen::Controls::TextBox* label = new Gwen::Controls::TextBox( this ); + label->SetText( "" ); + label->SetPos( 10, 10 ); + label->onTextChanged.Add( this, &ThisClass::OnEdit ); + label->onReturnPressed.Add( this, &ThisClass::OnSubmit ); + + } + + { + Gwen::Controls::TextBox* label = new Gwen::Controls::TextBox( this ); + label->SetText( "Normal Everyday Label" ); + label->SetPos( 10, 10 + 25 ); + } + + { + Gwen::Controls::TextBox* label = new Gwen::Controls::TextBox( this ); + label->SetText( "Select All Text On Focus" ); + label->SetPos( 10, 10 + 25 * 2 ); + label->SetSelectAllOnFocus( true ); + } + + { + Gwen::Controls::TextBox* label = new Gwen::Controls::TextBox( this ); + label->SetText( L"Different Coloured Text, for some reason" ); + label->SetTextColor( Gwen::Color( 255, 0, 255, 255 ) ); + label->SetPos( 10, 10 + 25 * 3 ); + } + + { + Gwen::Controls::TextBoxNumeric* label = new Gwen::Controls::TextBoxNumeric( this ); + label->SetText( L"2004" ); + label->SetTextColor( Gwen::Color( 255, 0, 255, 255 ) ); + label->SetPos( 10, 10 + 25 * 4 ); + } + + { + m_Font.facename = L"Impact"; + m_Font.size = 50; + + Gwen::Controls::TextBox* label = new Gwen::Controls::TextBox( this ); + label->SetText( L"Different Font" ); + label->SetPos( 10, 10 + 25 * 5 ); + label->SetFont( &m_Font ); + label->SetSize( 200, 55 ); + } + + + } + + void OnEdit( Gwen::Controls::Base* pControl ) + { + Gwen::Controls::TextBox* textbox = (Gwen::Controls::TextBox*) (pControl); + UnitPrint( Utility::Format( L"Textbox Edit: [%s]\n", textbox->GetText().c_str() ) ); + } + + void OnSubmit( Gwen::Controls::Base* pControl ) + { + Gwen::Controls::TextBox* textbox = (Gwen::Controls::TextBox*) (pControl); + UnitPrint( Utility::Format( L"Textbox Submit: [%s]\n", textbox->GetText().c_str() ) ); + } + + Gwen::Font m_Font; +}; + + + +DEFINE_UNIT_TEST( TextBox, L"TextBox" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/TreeControl.cpp b/test/GwenOpenGLTest/TreeControl.cpp new file mode 100644 index 000000000..87924ce7e --- /dev/null +++ b/test/GwenOpenGLTest/TreeControl.cpp @@ -0,0 +1,61 @@ +#include "UnitTest.h" +#include "Gwen/Controls/TreeControl.h" + +using namespace Gwen; + +using namespace Gwen::Controls; + + +class TreeControl2 : public GUnit +{ + public: + + GWEN_CONTROL_INLINE( TreeControl2, GUnit ) + { + { + Gwen::Controls::TreeControl* ctrl = new Gwen::Controls::TreeControl( this ); + + ctrl->SetKeyboardInputEnabled(true); + ctrl->AddNode( L"Node One" ); + Gwen::Controls::TreeNode* pNode = ctrl->AddNode( L"Node Two" ); + pNode->AddNode( L"Node Two Inside" ); + pNode->AddNode( L"Eyes" ); + pNode->SetSelected(true); + + pNode->AddNode( L"Brown" )->AddNode( L"Node Two Inside" )->AddNode( L"Eyes" )->AddNode( L"Brown" ); + ctrl->AddNode( L"Node Three" ); + ctrl->Focus(); + ctrl->SetKeyboardInputEnabled(true); + + ctrl->SetBounds( 30, 30, 200, 200 ); + ctrl->ExpandAll(); + } + + { + Gwen::Controls::TreeControl* ctrl = new Gwen::Controls::TreeControl( this ); + + ctrl->AllowMultiSelect( true ); + + ctrl->AddNode( L"Node One" ); + Gwen::Controls::TreeNode* pNode = ctrl->AddNode( L"Node Two" ); + pNode->AddNode( L"Node Two Inside" ); + pNode->AddNode( L"Eyes" ); + Gwen::Controls::TreeNode* pNodeTwo = pNode->AddNode( L"Brown" )->AddNode( L"Node Two Inside" )->AddNode( L"Eyes" ); + pNodeTwo->AddNode( L"Brown" ); + pNodeTwo->AddNode( L"Green" ); + pNodeTwo->AddNode( L"Slime" ); + pNodeTwo->AddNode( L"Grass" ); + pNodeTwo->AddNode( L"Pipe" ); + + ctrl->AddNode( L"Node Three" ); + + ctrl->SetBounds( 240, 30, 200, 200 ); + ctrl->ExpandAll(); + } + } + +}; + + + +DEFINE_UNIT_TEST( TreeControl2, L"TreeControl" ); \ No newline at end of file diff --git a/test/GwenOpenGLTest/UnitTest.cpp b/test/GwenOpenGLTest/UnitTest.cpp new file mode 100644 index 000000000..9886c6eb3 --- /dev/null +++ b/test/GwenOpenGLTest/UnitTest.cpp @@ -0,0 +1,179 @@ +/* + GWEN + Copyright (c) 2010 Facepunch Studios + See license in Gwen.h +*/ + +#include "UnitTest.h" +#include "Gwen/Platform.h" +#include "Gwen/Controls/TreeControl.h" + +using namespace Gwen; + +#define ADD_UNIT_TEST( name )\ + GUnit* RegisterUnitTest_##name( Gwen::Controls::TabControl* tab );\ + RegisterUnitTest_##name( m_TabControl )->SetUnitTest( this ); + +GWEN_CONTROL_CONSTRUCTOR( UnitTest ) +{ + SetTitle( L"GWEN Unit Test" ); + + SetSize( 600, 450 ); + + + m_TabControl = new Controls::TabControl( this ); + m_TabControl->Dock( Pos::Fill ); + m_TabControl->SetMargin( Margin( 2, 2, 2, 2 ) ); + + m_TextOutput = new Controls::ListBox( this ); + m_TextOutput->Dock( Pos::Bottom ); + m_TextOutput->SetHeight( 100 ); + + + ADD_UNIT_TEST( ImagePanel ); + + //ADD_UNIT_TEST( MenuStrip ); + + Gwen::UnicodeString str1(L"testje"); + Gwen::Controls::TabButton* tab = m_TabControl->AddPage(str1); + + Gwen::Controls::TreeControl* ctrl=0; + + { + ctrl = new Gwen::Controls::TreeControl(tab->GetPage()); + + ctrl->SetKeyboardInputEnabled(true); + ctrl->AddNode( L"Node One" ); + { + Gwen::Controls::TreeNode* pNode = ctrl->AddNode( L"Node Two" ); + pNode->AddNode( L"Node Two Inside" ); + pNode->AddNode( L"Eyes" ); + + } + { + Gwen::Controls::TreeNode* pNode = ctrl->AddNode( L"Node Two" ); + pNode->AddNode( L"Node Two Inside" ); + pNode->AddNode( L"Eyes" ); + + } + { + Gwen::Controls::TreeNode* pNode = ctrl->AddNode( L"Node Two" ); + pNode->AddNode( L"Node Two Inside" ); + pNode->AddNode( L"Eyes" ); + + } + { + Gwen::Controls::TreeNode* pNode = ctrl->AddNode( L"Node Two" ); + pNode->AddNode( L"Node Two Inside" ); + pNode->AddNode( L"Eyes" ); + + } + { + Gwen::Controls::TreeNode* pNode = ctrl->AddNode( L"Node Two" ); + pNode->AddNode( L"Node Two Inside" ); + pNode->AddNode( L"Eyes" ); + + } + { + Gwen::Controls::TreeNode* pNode = ctrl->AddNode( L"Node Two" ); + pNode->AddNode( L"Node Two Inside" ); + pNode->AddNode( L"Eyes" ); + pNode->SetSelected(true); + + + pNode->AddNode( L"Brown" )->AddNode( L"Node Two Inside" )->AddNode( L"Eyes" )->AddNode( L"Brown" ); + } + ctrl->AddNode( L"Node Three" ); + ctrl->Focus(); + ctrl->SetKeyboardInputEnabled(true); + + ctrl->SetBounds( 30, 30, 200, 30+16*10 ); + //ctrl->ExpandAll(); + ctrl->ForceUpdateScrollBars(); + ctrl->OnKeyDown(true); + + + } + + + //GUnit* u = new TreeControl2(m_TabControl);..Gwen::Controls::TreeControl2( m_TabControl ); + //GUnit* RegisterUnitTest_TreeControl2( Gwen::Controls::TabControl* tab );\ + //RegisterUnitTest_TreeControl2( m_TabControl )->SetUnitTest( this ); + + + //#define DEFINE_UNIT_TEST( name, displayname ) + //GUnit* RegisterUnitTest_TreeControl2( Gwen::Controls::TabControl* tab ) + //{ + // GUnit* u = new TreeControl2( tab ); + // tab->AddPage( displayname, u ); + // return u; + //} + + //ADD_UNIT_TEST( TreeControl2 ); + + ADD_UNIT_TEST( Properties2 ); + + + ADD_UNIT_TEST( TabControl2 ); + ADD_UNIT_TEST( ScrollControl ); + ADD_UNIT_TEST( MenuStrip ); + ADD_UNIT_TEST( Numeric ); + ADD_UNIT_TEST( ComboBox ); + ADD_UNIT_TEST( TextBox ); + ADD_UNIT_TEST( ListBox ); + ADD_UNIT_TEST( Slider ); + ADD_UNIT_TEST( ProgressBar ); + ADD_UNIT_TEST( RadioButton2 ); + + ADD_UNIT_TEST( Label ); + ADD_UNIT_TEST( Checkbox ); + ADD_UNIT_TEST( Button ); + + ADD_UNIT_TEST( CrossSplitter ); + + ADD_UNIT_TEST( PanelListPanel ); + ADD_UNIT_TEST( GroupBox2 ); + + ADD_UNIT_TEST( StatusBar ); + + + ctrl->Focus(); + PrintText( L"Unit Test Started.\n" ); + + m_fLastSecond = Gwen::Platform::GetTimeInSeconds(); + m_iFrames = 0; +} + + +void UnitTest::PrintText( const Gwen::UnicodeString& str ) +{ + m_TextOutput->AddItem( str ); + m_TextOutput->Scroller()->ScrollToBottom(); +} + +void UnitTest::Render( Gwen::Skin::Base* skin ) +{ + m_iFrames++; + + if ( m_fLastSecond < Gwen::Platform::GetTimeInSeconds() ) + { + SetTitle( Gwen::Utility::Format( L"GWEN Unit Test - %i fps", m_iFrames ) ); + + m_fLastSecond = Gwen::Platform::GetTimeInSeconds() + 1.0f; + m_iFrames = 0; + } + + BaseClass::Render( skin ); + +} + +void GUnit::UnitPrint( const Gwen::UnicodeString& str ) +{ + m_pUnitTest->PrintText( str ); +} + +void GUnit::UnitPrint( const Gwen::String& str ) +{ + UnitPrint( Utility::StringToUnicode( str ) ); +} + diff --git a/test/GwenOpenGLTest/UnitTest.h b/test/GwenOpenGLTest/UnitTest.h new file mode 100644 index 000000000..7d8f76f7f --- /dev/null +++ b/test/GwenOpenGLTest/UnitTest.h @@ -0,0 +1,64 @@ +/* + GWEN + Copyright (c) 2011 Facepunch Studios + See license in Gwen.h +*/ + + +#pragma once +#ifndef GWEN_UNITTEST_UNITTEST_H +#define GWEN_UNITTEST_UNITTEST_H + +#include "Gwen/Gwen.h" +#include "Gwen/Align.h" +#include "Gwen/Utility.h" +#include "Gwen/Controls/WindowControl.h" +#include "Gwen/Controls/TabControl.h" +#include "Gwen/Controls/ListBox.h" + +class UnitTest; + + + +class GUnit : public Gwen::Controls::Base +{ + public: + + GWEN_CONTROL_INLINE( GUnit, Gwen::Controls::Base ) + { + m_pUnitTest = NULL; + } + + void SetUnitTest( UnitTest* u ){ m_pUnitTest = u; } + + void UnitPrint( const Gwen::UnicodeString& str ); + void UnitPrint( const Gwen::String& str ); + + + + + UnitTest* m_pUnitTest; +}; + +class UnitTest : public Gwen::Controls::WindowControl +{ + public: + + GWEN_CONTROL( UnitTest, Gwen::Controls::WindowControl ); + + void PrintText( const Gwen::UnicodeString& str ); + + void Render( Gwen::Skin::Base* skin ); + + + private: + + Gwen::Controls::TabControl* m_TabControl; + Gwen::Controls::ListBox* m_TextOutput; + unsigned int m_iFrames; + float m_fLastSecond; + +}; + +#define DEFINE_UNIT_TEST( name, displayname ) GUnit* RegisterUnitTest_##name( Gwen::Controls::TabControl* tab ){ GUnit* u = new name( tab ); tab->AddPage( displayname, u ); return u; } +#endif diff --git a/test/GwenOpenGLTest/premake4.lua b/test/GwenOpenGLTest/premake4.lua new file mode 100644 index 000000000..11cf86dc5 --- /dev/null +++ b/test/GwenOpenGLTest/premake4.lua @@ -0,0 +1,68 @@ + + project "Test_Gwen_OpenGL" + + kind "ConsoleApp" + flags {"Unicode"} + + defines { "GWEN_COMPILE_STATIC" , "_HAS_EXCEPTIONS=0", "_STATIC_CPPLIB" } + defines { "DONT_USE_GLUT"} + + targetdir "../../bin" + + includedirs + { + + "../../examples/ThirdPartLibs/Gwen", + ".", + } + + initOpenGL() + initGlew() + + links { + "gwen", + } + + + files { + "../../examples/OpenGLWindow/OpenSans.cpp", + "../../examples/OpenGLWindow/TwFonts.cpp", + "../../examples/OpenGLWindow/TwFonts.h", + "../../examples/OpenGLWindow/LoadShader.cpp", + "../../examples/OpenGLWindow/LoadShader.h", + "../../examples/OpenGLWindow/GLPrimitiveRenderer.cpp", + "../../examples/OpenGLWindow/GLPrimitiveRenderer.h", + "../../examples/OpenGLWindow/GwenOpenGL3CoreRenderer.h", + "../../examples/OpenGLWindow/fontstash.cpp", + "../../examples/OpenGLWindow/fontstash.h", + "../../examples/OpenGLWindow/opengl_fontstashcallbacks.cpp", + "../../examples/OpenGLWindow/opengl_fontstashcallbacks.h", + "../../examples/Utils/b3Clock.cpp", + "../../examples/Utils/b3Clock.h", + "**.cpp", + "**.h", + } + if os.is("Windows") then + files { + "../../examples/OpenGLWindow/Win32OpenGLWindow.cpp", + "../../examples/OpenGLWindow/Win32OpenGLWindow.h", + "../../examples/OpenGLWindow/Win32Window.cpp", + "../../examples/OpenGLWindow/Win32Window.h", + } + end + if os.is("Linux") then + initX11() + files{ + "../../examples/OpenGLWindow/X11OpenGLWindow.h", + "../../examples/OpenGLWindow/X11OpenGLWindow.cpp" + } + links{"pthread"} + end + if os.is("MacOSX") then + links{"Cocoa.framework"} +print("hello!") + files{ + "../../examples/OpenGLWindow/MacOpenGLWindow.mm", + "../../examples/OpenGLWindow/MacOpenGLWindow.h", + } + end