// Dynamic texturing demo // // Feel free to use this for anything you want (Wumpus, OGRE Team 2004). This file is public domain. // Uses the Grey-Scott diffusion reaction process, a nice overview of the parameter space can be seen at // http://www.cacr.caltech.edu/ismap/image.html // // Some very cool effects can be reached with some combinations of parameters, varying the parameters // during growth gives even more curious things. // // Use 1-8 to change parameters, and 0 to reset to initial conditions #include "ExampleApplication.h" #include #include #include #include #include TexturePtr ptex; HardwarePixelBufferSharedPtr buffer; Overlay* overlay; static const int reactorExtent = 130; // must be 2^N + 2 uint32 clut[1024]; AnimationState *swim; // Nano fixed point library #define FROMFLOAT(X) ((int)((X)*((float)(1<<16)))) #define TOFLOAT(X) ((float)((X)/((float)(1<<16)))) #define MULT(X,Y) (((X)*(Y))>>16) ColourValue HSVtoRGB( float h, float s, float v ) { int i; ColourValue rv(0.0f, 0.0f, 0.0f, 1.0f); float f, p, q, t; h = fmodf(h, 360.0f); h /= 60.0f; // sector 0 to 5 i = (int)floor( h ); f = h - i; // factorial part of h p = v * ( 1.0f - s ); q = v * ( 1.0f - s * f ); t = v * ( 1.0f - s * ( 1.0f - f ) ); switch( i ) { case 0: rv.r = v; rv.g = t; rv.b = p; break; case 1: rv.r = q; rv.g = v; rv.b = p; break; case 2: rv.r = p; rv.g = v; rv.b = t; break; case 3: rv.r = p; rv.g = q; rv.b = v; break; case 4: rv.r = t; rv.g = p; rv.b = v; break; default: rv.r = v; rv.g = p; rv.b = q; break; } return rv; } class DynTexFrameListener : public ExampleFrameListener { private: static float fDefDim; static float fDefVel; float tim; int *chemical[2]; int *delta[2]; size_t mSize; int dt,hdiv0,hdiv1; // diffusion parameters int F,k; // reaction parameters bool rpressed; public: DynTexFrameListener(RenderWindow* win, Camera* cam) : ExampleFrameListener( win, cam ) { tim = 0; rpressed = false; // Create colour lookup for(unsigned int col=0; col<1024; col++) { ColourValue c; c = HSVtoRGB((1.0f-col/1024.0f)*90.0f+225.0f, 0.9f, 0.75f+0.25f*(1.0f-col/1024.0f)); c.a = 1.0f - col/1024.0f; PixelUtil::packColour(c, PF_A8R8G8B8, &clut[col]); } // Setup LogManager::getSingleton().logMessage("Creating chemical containment"); mSize = reactorExtent*reactorExtent; chemical[0] = new int [mSize]; chemical[1] = new int [mSize]; delta[0] = new int [mSize]; delta[1] = new int [mSize]; dt = FROMFLOAT(2.0f); hdiv0 = FROMFLOAT(2.0E-5f/(2.0f*0.01f*0.01f)); // a / (2.0f*h*h); -- really diffusion rate hdiv1 = FROMFLOAT(1.0E-5f/(2.0f*0.01f*0.01f)); // a / (2.0f*h*h); -- really diffusion rate //k = FROMFLOAT(0.056f); //F = FROMFLOAT(0.020f); k = FROMFLOAT(0.0619f); F = FROMFLOAT(0.0316f); resetReactor(); fireUpReactor(); updateInfoParamF(); updateInfoParamK(); updateInfoParamA0(); updateInfoParamA1(); LogManager::getSingleton().logMessage("Cthulhu dawn"); } void resetReactor() { LogManager::getSingleton().logMessage("Facilitating neutral start up conditions"); for(unsigned int x=0; xlock(HardwareBuffer::HBL_DISCARD); const PixelBox &pb = buffer->getCurrentLock(); unsigned int idx = reactorExtent+1; for(unsigned int y=0; y<(reactorExtent-2); y++) { uint32 *data = static_cast(pb.data) + y*pb.rowPitch; int *chem = &chemical[0][idx]; for(unsigned int x=0; x<(reactorExtent-2); x++) { data[x] = clut[(chem[x]>>6)&1023]; } idx += reactorExtent; } buffer->unlock(); } // GUI updaters void updateInfoParamK() { OverlayManager::getSingleton().getOverlayElement("Example/DynTex/Param_K") \ ->setCaption("[1/2]k: "+StringConverter::toString(TOFLOAT(k))); } void updateInfoParamF() { OverlayManager::getSingleton().getOverlayElement("Example/DynTex/Param_F") \ ->setCaption("[3/4]F: "+StringConverter::toString(TOFLOAT(F))); } void updateInfoParamA0() { // Diffusion rate for chemical 1 OverlayManager::getSingleton().getOverlayElement("Example/DynTex/Param_A0") \ ->setCaption("[5/6]Diffusion 1: "+StringConverter::toString(TOFLOAT(hdiv0))); } void updateInfoParamA1() { // Diffusion rate for chemical 2 OverlayManager::getSingleton().getOverlayElement("Example/DynTex/Param_A1") \ ->setCaption("[7/8]Diffusion 2: "+StringConverter::toString(TOFLOAT(hdiv1))); } bool frameStarted( const FrameEvent& evt ) { using namespace OIS; if( ExampleFrameListener::frameStarted( evt ) == false ) return false; if( mKeyboard->isKeyDown( KC_1 ) ) { k -= FROMFLOAT(0.005f*evt.timeSinceLastFrame); updateInfoParamK(); } if( mKeyboard->isKeyDown( KC_2 ) ) { k += FROMFLOAT(0.005f*evt.timeSinceLastFrame); updateInfoParamK(); } if( mKeyboard->isKeyDown( KC_3 ) ) { F -= FROMFLOAT(0.005f*evt.timeSinceLastFrame); updateInfoParamF(); } if( mKeyboard->isKeyDown( KC_4 ) ) { F += FROMFLOAT(0.005f*evt.timeSinceLastFrame); updateInfoParamF(); } if( mKeyboard->isKeyDown( KC_5 ) ) { hdiv0 -= FROMFLOAT(0.005f*evt.timeSinceLastFrame); updateInfoParamA0(); } if( mKeyboard->isKeyDown( KC_6 ) ) { hdiv0 += FROMFLOAT(0.005f*evt.timeSinceLastFrame); updateInfoParamA0(); } if( mKeyboard->isKeyDown( KC_7 ) ) { hdiv1 -= FROMFLOAT(0.005f*evt.timeSinceLastFrame); updateInfoParamA1(); } if( mKeyboard->isKeyDown( KC_8 ) ) { hdiv1 += FROMFLOAT(0.005f*evt.timeSinceLastFrame); updateInfoParamA1(); } if( mKeyboard->isKeyDown( KC_0 ) && !rpressed ) { // Reset 0 resetReactor(); fireUpReactor(); rpressed = true; } else { rpressed = false; } for(int x=0; x<10; x++) runStep(); buildTexture(); swim->addTime(evt.timeSinceLastFrame); return true; } virtual ~DynTexFrameListener(void) { delete [] chemical[0]; delete [] chemical[1]; delete [] delta[0]; delete [] delta[1]; } }; float DynTexFrameListener::fDefDim = 25.0f; float DynTexFrameListener::fDefVel = 50.0f; class DynTexApplication : public ExampleApplication { public: DynTexApplication() {} protected: virtual void createFrameListener(void) { mFrameListener= new DynTexFrameListener(mWindow, mCamera); mFrameListener->showDebugOverlay(true); mRoot->addFrameListener(mFrameListener); } virtual void createViewports(void) { // Create one viewport, entire window Viewport* vp = mWindow->addViewport(mCamera); vp->setBackgroundColour(ColourValue(0,0,0)); // Alter the camera aspect ratio to match the viewport mCamera->setAspectRatio( Real(vp->getActualWidth()) / Real(vp->getActualHeight())); } // Just override the mandatory create scene method void createScene(void) { // Create dynamic texture ptex = TextureManager::getSingleton().createManual( "DynaTex","General", TEX_TYPE_2D, reactorExtent-2, reactorExtent-2, 0, PF_A8R8G8B8, TU_DYNAMIC_WRITE_ONLY); buffer = ptex->getBuffer(0, 0); // Set ambient light mSceneMgr->setAmbientLight(ColourValue(0.6, 0.6, 0.6)); mSceneMgr->setSkyBox(true, "Examples/SpaceSkyBox", 50 ); //mRoot->getRenderSystem()->clearFrameBuffer(FBT_COLOUR, ColourValue(255,255,255,0)); // Create a light Light* l = mSceneMgr->createLight("MainLight"); l->setDiffuseColour(0.75, 0.75, 0.80); l->setSpecularColour(0.9, 0.9, 1); l->setPosition(-100,80,50); mSceneMgr->getRootSceneNode()->attachObject(l); Entity *planeEnt = mSceneMgr->createEntity("TexPlane1", Ogre::SceneManager::PT_PLANE); // Give the plane a texture planeEnt->setMaterialName("Examples/DynaTest"); SceneNode* node = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-100,-40,-100)); node->attachObject(planeEnt); node->setScale(3.0f, 3.0f, 3.0f); // Create objects SceneNode *blaNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-200,0,50)); Entity *ent2 = mSceneMgr->createEntity( "knot", "knot.mesh" ); ent2->setMaterialName("Examples/DynaTest4"); blaNode->attachObject( ent2 ); blaNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(200,-90,50)); ent2 = mSceneMgr->createEntity( "knot2", "knot.mesh" ); ent2->setMaterialName("Examples/DynaTest2"); blaNode->attachObject( ent2 ); blaNode = mSceneMgr->getRootSceneNode()->createChildSceneNode(Vector3(-110,200,50)); // Cloaked fish ent2 = mSceneMgr->createEntity( "knot3", "fish.mesh" ); ent2->setMaterialName("Examples/DynaTest3"); swim = ent2->getAnimationState("swim"); swim->setEnabled(true); blaNode->attachObject( ent2 ); blaNode->setScale(50.0f, 50.0f, 50.0f); //TextureManager::getSingleton().getByName("RustySteel.jpg"); std::stringstream d; d << "HardwarePixelBuffer " << buffer->getWidth() << " " << buffer->getHeight() << " " << buffer->getDepth(); LogManager::getSingleton().logMessage(d.str()); buffer->lock(HardwareBuffer::HBL_NORMAL); const PixelBox &pb = buffer->getCurrentLock(); d.str(""); d << "PixelBox " << pb.getWidth() << " " << pb.getHeight() << " " << pb.getDepth() << " " << pb.rowPitch << " " << pb.slicePitch << " " << pb.data << " " << PixelUtil::getFormatName(pb.format); LogManager::getSingleton().logMessage(d.str()); buffer->unlock(); // show GUI overlay = OverlayManager::getSingleton().getByName("Example/DynTexOverlay"); overlay->show(); } void destroyScene(void) { // Free resource pointers before shutdown ptex.setNull(); buffer.setNull(); } }; #ifdef __cplusplus extern "C" { #endif #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 #define WIN32_LEAN_AND_MEAN #include "windows.h" INT WINAPI WinMain( HINSTANCE hInst, HINSTANCE, LPSTR strCmdLine, INT ) #else int main(int argc, char *argv[]) #endif { // Create application object DynTexApplication app; try { app.go(); } catch( Ogre::Exception& e ) { #if OGRE_PLATFORM == OGRE_PLATFORM_WIN32 MessageBox( NULL, e.getFullDescription().c_str(), "An exception has occured!", MB_OK | MB_ICONERROR | MB_TASKMODAL); #else std::cerr << "An exception has occured: " << e.getFullDescription().c_str() << std::endl; #endif } return 0; } #ifdef __cplusplus } #endif