From f1ee78503912e7083267d0c70452495e22641bd6 Mon Sep 17 00:00:00 2001 From: cutealien Date: Wed, 12 Apr 2017 15:33:31 +0000 Subject: [PATCH] Merge revisions r5337:r5415 from trunk to ogl-es. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@5416 dfc29bdd-3216-0410-991c-e03cc46cb475 --- changes.txt | 26 +- examples/07.Collision/main.cpp | 93 +++-- include/ESceneNodeTypes.h | 3 + include/IBillboardTextSceneNode.h | 18 +- include/IOSOperator.h | 6 +- include/ISceneCollisionManager.h | 87 +++- include/ISceneManager.h | 52 ++- include/ITextSceneNode.h | 18 + include/ITriangleSelector.h | 104 ++++- include/Keycodes.h | 5 +- include/SMaterialLayer.h | 3 +- include/SMesh.h | 23 +- include/fast_atof.h | 18 +- include/irrMath.h | 111 +++-- include/irrString.h | 44 +- include/irrXML.h | 28 +- include/line2d.h | 82 +++- include/matrix4.h | 11 +- include/quaternion.h | 80 +++- include/vector2d.h | 71 +++- source/Irrlicht/CCSMLoader.cpp | 2 +- source/Irrlicht/CD3D9Driver.cpp | 41 ++ source/Irrlicht/CD3D9Driver.h | 3 + source/Irrlicht/CDefaultSceneNodeFactory.cpp | 4 + source/Irrlicht/CFileSystem.cpp | 2 +- source/Irrlicht/CGUIContextMenu.cpp | 31 +- source/Irrlicht/CImageLoaderJPG.cpp | 2 +- source/Irrlicht/CIrrDeviceLinux.cpp | 5 + source/Irrlicht/CIrrDeviceOSX.mm | 4 + source/Irrlicht/CIrrDeviceWin32.cpp | 25 +- source/Irrlicht/CIrrDeviceWin32.h | 21 +- source/Irrlicht/CMS3DMeshFileLoader.cpp | 2 +- source/Irrlicht/CMetaTriangleSelector.cpp | 55 ++- source/Irrlicht/CMetaTriangleSelector.h | 9 +- source/Irrlicht/COBJMeshFileLoader.cpp | 2 + source/Irrlicht/COSOperator.cpp | 36 +- source/Irrlicht/COctreeTriangleSelector.cpp | 73 +++- source/Irrlicht/COctreeTriangleSelector.h | 9 +- source/Irrlicht/COpenGLCacheHandler.cpp | 2 - source/Irrlicht/COpenGLDriver.cpp | 387 ++++++++++-------- source/Irrlicht/COpenGLDriver.h | 3 + source/Irrlicht/COpenGLMaterialRenderer.h | 273 ++++++------ source/Irrlicht/CPLYMeshFileLoader.cpp | 4 +- source/Irrlicht/CSceneCollisionManager.cpp | 107 +++-- source/Irrlicht/CSceneCollisionManager.h | 25 +- source/Irrlicht/CSceneManager.cpp | 26 +- source/Irrlicht/CSceneManager.h | 11 +- .../CSceneNodeAnimatorCollisionResponse.cpp | 3 +- source/Irrlicht/CTerrainTriangleSelector.cpp | 37 +- source/Irrlicht/CTerrainTriangleSelector.h | 11 +- source/Irrlicht/CTextSceneNode.cpp | 41 +- source/Irrlicht/CTextSceneNode.h | 22 +- source/Irrlicht/CTriangleBBSelector.cpp | 76 ++-- source/Irrlicht/CTriangleBBSelector.h | 12 +- source/Irrlicht/CTriangleSelector.cpp | 241 +++++++++-- source/Irrlicht/CTriangleSelector.h | 33 +- source/Irrlicht/CWriteFile.cpp | 2 +- source/Irrlicht/CXMLReader.cpp | 2 +- source/Irrlicht/CXMLReaderImpl.h | 16 +- source/Irrlicht/Irrlicht14.0.vcxproj | 1 + source/Irrlicht/aesGladman/fileenc.cpp | 4 +- tests/Makefile | 8 +- tests/fast_atof.cpp | 2 + tests/irrArray.cpp | 51 +++ tests/line2d.cpp | 79 ++++ tests/main.cpp | 1 + tests/testUtils.cpp | 10 +- tests/tests.cbp | 1 + tests/tests_vc10.vcxproj | 1 + tests/tests_vc11.vcxproj | 1 + tests/tests_vc12.vcxproj | 1 + tests/tests_vc14.vcxproj | 1 + tools/IrrFontTool/newFontTool/CFontTool.cpp | 10 +- tools/IrrFontTool/newFontTool/main.cpp | 2 +- 74 files changed, 2003 insertions(+), 713 deletions(-) create mode 100644 tests/line2d.cpp diff --git a/changes.txt b/changes.txt index 6bdd925d..dd8a14d6 100644 --- a/changes.txt +++ b/changes.txt @@ -9,6 +9,19 @@ Changes in ogl-es (not yet released - will be merged with trunk at some point) -------------------------- Changes in 1.9 (not yet released) +- Improve speed of draw3DBox (OpenGL and D3D9). Thanks @zerochen for patch (https://sourceforge.net/p/irrlicht/patches/256) +- Support more keys on OSX "[]\". Thanks @neoascetic for patch (#313). +- Fix IBillboardTextSceneNode::setTextColor which did nothing in the past. It now maps to setColor instead. +- Add access functions to IBillboardTextSceneNode (getText, getFont). +- Add access functions to ITextSceneNode (getText, getTextColor, setFont, getFont). +- Try harder to move Window to custom WindowPosition set in SIrrlichtCreationParameters on X11. Thx@ Hernan Ezequiel Di Giorgi for the patch (#304). +- Fix bug in virtual filessystem which prevented createFileList from working. Thx @Cube for reporting a problem. +- ITriangleSelector now can also return meshbuffer collision information. +- core::string::split now adds delimiter to token before delimiter when keepSeparators is true. That way we never end up with 2 tokens for an original string with a single character. +- Bugfix: SMesh::recalculateBoundingBox() does now ignore empty boundingboxes of meshbuffers instead of adding them. +- IIrrXMLReader::getAttributeValueAsInt and IIrrXMLReader::getAttributeValueAsFloat can now return a custom default-value when the attribute is not found. +- core::string::split now handles ignoreEmptyTokens=false correct. Thanks @manni63 for bugreport: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=51551&p=299375#p299375 +- Bugfix: Previously when some material had a texture matrix and another didn't those materials were still considered identical. Which had prevented correct switching between materials with and without texture matrices. - IWriteFile::write now returning size_t (like fwrite in c-lib). Also sizeToWrite parameter changed from u32 to size_t. - IReadFile::read now returning size_t (like fread in c-lib). Also sizeToRead parameter changed from u32 to size_t. - add clear function to strings. @@ -160,6 +173,17 @@ should now be fps independentn -------------------------- Changes in 1.8.5 + - Fix bug in cursor positions when compiled with newer Windows SDK's (v110 in VS2012) and running on Systems >= Windows Vista in windowed mode. + Thanks @Mustapha Tachouct for the bugreport and patch proposal. Also thanks @BakeMyCake for an earlier report. + - IOSOperator::getSysteMemory() no longer returns incorrect values with >2GB. Thanks @Eduline - human development for report and patch. + - Increase KEY_KEY_CODES_COUNT to fix problem with laptop keyboards which return the keycode 0xff for the function key. Thx @Klokancz for bugreport and patch. + - Fix bug when calling activateJoysticks on windows several times. It had appened joystick information instead of replacing it, thereby increasing joystick number on each call. + Only happened compiling with _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ (which is the default). Linux and SDL implementation not affected. + Thx @Andrea Demetrio for the bugreport. + - Fix bug in fast_atof when reading floating point numbers with more than 16 digits past the dot. Those produced completely wrong results (sometimes even causing INF numbers). + This bug also did cause many meshloaders to have problems with certain meshes (basically all text-based formats are affected). + - Accuracy of fast_atof is back to older Irrlicht versions (fixes test warnings, usually not a noticable problem). + - Fix crash in eventhandling when calling remove() on a contextmenu while it has focus. - CImageLoaderJPG::isALoadableFileFormat uses a test which allows to load more jpg formats (for example uncompressed jpg's). Thx @Yaron Cohen-Tal for report, test-image and his help with the patch. -------------------------- @@ -255,7 +279,7 @@ Changes in 1.8 (7.11.2012) - quaternion conversions to and from matrix4 no longer invert rotations. To test if your code was affected by this you can set IRR_TEST_BROKEN_QUATERNION_USE in quaternion.h and try to compile your application. - Then on all compile-errors when you pass the matrix to the quaternion you can replace the matrix transposed matrix. + Then on all compile-errors when you pass the matrix to the quaternion you can replace the matrix with the transposed matrix. For all errors you get on getMatrix() you can use quaternion::getMatrix_transposed instead. - CGUIEnvironment::loadGui - loading a gui into a target-element no longer messes up when the gui-file contained guienvironment serialization. diff --git a/examples/07.Collision/main.cpp b/examples/07.Collision/main.cpp index 842a0f09..8a705316 100644 --- a/examples/07.Collision/main.cpp +++ b/examples/07.Collision/main.cpp @@ -36,6 +36,13 @@ enum IDFlag_IsHighlightable = 1 << 1 }; +/* + Some triangle selectors allow to get collisions either per mesh or per meshbuffer. + Getting them per mesh can be faster. But if you need information about the hit + material you have to get the meshbuffer information as well. +*/ +const bool separateMeshBuffers = true; + int main() { // ask user for driver @@ -86,8 +93,34 @@ int main() { q3node->setPosition(core::vector3df(-1350,-130,-1400)); - selector = smgr->createOctreeTriangleSelector( - q3node->getMesh(), q3node, 128); + /* + There is currently no way to split an octree by material. + So if we need that we have to create one octree per meshbuffer + and put them together in a MetaTriangleSelector. + */ + if ( separateMeshBuffers && q3node->getMesh()->getMeshBufferCount() > 1) + { + scene::IMetaTriangleSelector * metaSelector = smgr->createMetaTriangleSelector(); + for ( irr::u32 m=0; m < q3node->getMesh()->getMeshBufferCount(); ++m ) + { + scene::ITriangleSelector* + bufferSelector = smgr->createOctreeTriangleSelector( + q3node->getMesh()->getMeshBuffer(m), m, q3node); + if ( bufferSelector ) + { + metaSelector->addTriangleSelector( bufferSelector ); + bufferSelector->drop(); + } + } + selector = metaSelector; + } + else + { + // Just one octree for the whole mesh. + // Can't get information which material got hit, but for many situations that's enough. + selector = smgr->createOctreeTriangleSelector( + q3node->getMesh(), q3node, 128); + } q3node->setTriangleSelector(selector); // We're not done with this selector yet, so don't drop it. } @@ -138,7 +171,7 @@ int main() if (selector) { - scene::ISceneNodeAnimator* anim = smgr->createCollisionResponseAnimator( + scene::ISceneNodeAnimatorCollisionResponse * anim = smgr->createCollisionResponseAnimator( selector, camera, core::vector3df(30,50,30), core::vector3df(0,-1000,0), core::vector3df(0,30,0)); selector->drop(); // As soon as we're done with the selector, drop it. @@ -183,7 +216,7 @@ int main() // Now create a triangle selector for it. The selector will know that it // is associated with an animated node, and will update itself as necessary. - selector = smgr->createTriangleSelector(node); + selector = smgr->createTriangleSelector(node, separateMeshBuffers); node->setTriangleSelector(selector); selector->drop(); // We're done with this selector, so drop it now. @@ -197,7 +230,7 @@ int main() node->getMaterial(0).NormalizeNormals = true; node->getMaterial(0).Lighting = true; // Just do the same as we did above. - selector = smgr->createTriangleSelector(node); + selector = smgr->createTriangleSelector(node, separateMeshBuffers); node->setTriangleSelector(selector); selector->drop(); @@ -208,11 +241,10 @@ int main() node->setRotation(core::vector3df(0,-90,0)); // And turn it towards the camera. node->setAnimationSpeed(20.f); node->getMaterial(0).Lighting = true; - selector = smgr->createTriangleSelector(node); + selector = smgr->createTriangleSelector(node, separateMeshBuffers); node->setTriangleSelector(selector); selector->drop(); - // And this mdl file uses skinned skeletal animation. node = smgr->addAnimatedMeshSceneNode(smgr->getMesh(mediaPath + "yodan.mdl"), 0, IDFlag_IsPickable | IDFlag_IsHighlightable); @@ -222,7 +254,7 @@ int main() node->setAnimationSpeed(20.f); // Just do the same as we did above. - selector = smgr->createTriangleSelector(node); + selector = smgr->createTriangleSelector(node, separateMeshBuffers); node->setTriangleSelector(selector); selector->drop(); @@ -237,7 +269,6 @@ int main() // Remember which scene node is highlighted scene::ISceneNode* highlightedSceneNode = 0; scene::ISceneCollisionManager* collMan = smgr->getSceneCollisionManager(); - int lastFPS = -1; // draw the selection triangle only as wireframe material.Wireframe=true; @@ -263,10 +294,6 @@ int main() ray.start = camera->getPosition(); ray.end = ray.start + (camera->getTarget() - ray.start).normalize() * 1000.0f; - // Tracks the current intersection point with the level or a mesh - core::vector3df intersection; - // Used to show with triangle has been hit - core::triangle3df hitTriangle; // This call is all you need to perform ray/triangle collision on every scene node // that has a triangle selector, including the Quake level mesh. It finds the nearest @@ -274,25 +301,27 @@ int main() // Irrlicht provides other types of selection, including ray/triangle selector, // ray/box and ellipse/triangle selector, plus associated helpers. // See the methods of ISceneCollisionManager - scene::ISceneNode * selectedSceneNode = - collMan->getSceneNodeAndCollisionPointFromRay( + + irr::io::SNamedPath hitTextureName; + scene::SCollisionHit hitResult; + scene::ISceneNode * selectedSceneNode =collMan->getSceneNodeAndCollisionPointFromRay( + hitResult, // Returns all kind of info about the collision ray, - intersection, // This will be the position of the collision - hitTriangle, // This will be the triangle hit in the collision IDFlag_IsPickable, // This ensures that only nodes that we have // set up to be pickable are considered 0); // Check the entire scene (this is actually the implicit default) + // If the ray hit anything, move the billboard to the collision position // and draw the triangle that was hit. if(selectedSceneNode) { - bill->setPosition(intersection); + bill->setPosition(hitResult.Intersection); // Show the current intersection point with the level or a mesh // We need to reset the transform before doing our own rendering. driver->setTransform(video::ETS_WORLD, core::matrix4()); driver->setMaterial(material); - driver->draw3DTriangle(hitTriangle, video::SColor(0,255,0,0)); + driver->draw3DTriangle(hitResult.Triangle, video::SColor(0,255,0,0)); // Show which triangle has been hit // We can check the flags for the scene node that was hit to see if it should be // highlighted. The animated nodes can be highlighted, but not the Quake level mesh @@ -304,23 +333,31 @@ int main() // which means that it will be drawn with full brightness. highlightedSceneNode->setMaterialFlag(video::EMF_LIGHTING, false); } + + if ( hitResult.MeshBuffer && hitResult.Node && hitResult.Node->getMaterial(hitResult.MaterialIndex).TextureLayer[0].Texture ) + { + // Note we are interested in the node material and not in the meshbuffer material. + // Otherwise we wouldn't get the fairy2 texture which is only set on the node. + hitTextureName = hitResult.Node->getMaterial(hitResult.MaterialIndex).TextureLayer[0].Texture->getName(); + } } // We're all done drawing, so end the scene. driver->endScene(); + // Show some info in title-bar int fps = driver->getFPS(); - - if (lastFPS != fps) + core::stringw str = L"Collision detection example - Irrlicht Engine ["; + str += driver->getName(); + str += "] FPS:"; + str += fps; + if ( !hitTextureName.getInternalName().empty() ) { - core::stringw str = L"Collision detection example - Irrlicht Engine ["; - str += driver->getName(); - str += "] FPS:"; - str += fps; - - device->setWindowCaption(str.c_str()); - lastFPS = fps; + str += " "; + irr::io::path texName(hitTextureName.getInternalName()); + str += core::deletePathFromFilename(texName); } + device->setWindowCaption(str.c_str()); } device->drop(); diff --git a/include/ESceneNodeTypes.h b/include/ESceneNodeTypes.h index 0e055e2f..0eeab92a 100644 --- a/include/ESceneNodeTypes.h +++ b/include/ESceneNodeTypes.h @@ -30,6 +30,9 @@ namespace scene //! Text Scene Node ESNT_TEXT = MAKE_IRR_ID('t','e','x','t'), + //! Billboard text scene node + ESNT_BILLBOARD_TEXT = MAKE_IRR_ID('b','t','x','t'), + //! Water Surface Scene Node ESNT_WATER_SURFACE = MAKE_IRR_ID('w','a','t','r'), diff --git a/include/IBillboardTextSceneNode.h b/include/IBillboardTextSceneNode.h index b7f2359f..0526b63f 100644 --- a/include/IBillboardTextSceneNode.h +++ b/include/IBillboardTextSceneNode.h @@ -9,6 +9,12 @@ namespace irr { + +namespace gui +{ + class IGUIFont; +} + namespace scene { @@ -50,8 +56,18 @@ public: //! sets the text string virtual void setText(const wchar_t* text) = 0; + //! get the text string + virtual const wchar_t* getText() const = 0; + //! sets the color of the text - virtual void setTextColor(video::SColor color) = 0; + //! You can use setColor instead which does the same + virtual void setTextColor(video::SColor color) + { + setColor(color); + } + + //! Get the font used to draw the text + virtual gui::IGUIFont* getFont() const = 0; }; } // end namespace scene diff --git a/include/IOSOperator.h b/include/IOSOperator.h index 2ba04172..eeb1856d 100644 --- a/include/IOSOperator.h +++ b/include/IOSOperator.h @@ -38,10 +38,10 @@ public: virtual bool getProcessorSpeedMHz(u32* MHz) const = 0; //! Get the total and available system RAM - /** \param Total: will contain the total system memory - \param Avail: will contain the available memory + /** \param totalBytes: will contain the total system memory in bytes + \param availableBytes: will contain the available memory in bytes \return True if successful, false if not */ - virtual bool getSystemMemory(u32* Total, u32* Avail) const = 0; + virtual bool getSystemMemory(u32* totalBytes, u32* availableBytes) const = 0; }; diff --git a/include/ISceneCollisionManager.h b/include/ISceneCollisionManager.h index e43f1381..ccfe8639 100644 --- a/include/ISceneCollisionManager.h +++ b/include/ISceneCollisionManager.h @@ -19,12 +19,45 @@ namespace scene class ISceneNode; class ICameraSceneNode; class ITriangleSelector; + class IMeshBuffer; + + struct SCollisionHit + { + //! Point of collision + core::vector3df Intersection; + + //! Triangle with which we collided + core::triangle3df Triangle; + + //! Triangle selector which contained the colliding triangle (useful when having MetaTriangleSelector) + ITriangleSelector* TriangleSelector; + + //! Node which contained the triangle (is 0 when selector doesn't have that information) + ISceneNode* Node; + + //! Meshbuffer which contained the triangle (is 0 when the selector doesn't have that information, only works when selectors are created per meshbuffer) + const IMeshBuffer* MeshBuffer; + + //! Index of selected material of the triangle in the SceneNode. Usually only valid when MeshBuffer is also set, otherwise always 0 + irr::u32 MaterialIndex; + + SCollisionHit() : TriangleSelector(0), Node(0), MeshBuffer(0), MaterialIndex(0) + {} + }; //! The Scene Collision Manager provides methods for performing collision tests and picking on scene nodes. class ISceneCollisionManager : public virtual IReferenceCounted { public: + //! Finds the nearest collision point of a line and lots of triangles, if there is one. + /** \param hitResult: Contains collision result when there was a collision detected. + \param ray: Line with which collisions are tested. + \param selector: TriangleSelector to be used for the collision check. + \return true if a collision was detected and false if not. */ + virtual bool getCollisionPoint(SCollisionHit& hitResult, const core::line3d& ray, + ITriangleSelector* selector) = 0; + //! Finds the nearest collision point of a line and lots of triangles, if there is one. /** \param ray: Line with which collisions are tested. \param selector: TriangleSelector containing the triangles. It @@ -40,7 +73,18 @@ namespace scene \return True if a collision was detected and false if not. */ virtual bool getCollisionPoint(const core::line3d& ray, ITriangleSelector* selector, core::vector3df& outCollisionPoint, - core::triangle3df& outTriangle, ISceneNode*& outNode) =0; + core::triangle3df& outTriangle, ISceneNode*& outNode) + { + SCollisionHit hitResult; + if ( getCollisionPoint(hitResult, ray, selector) ) + { + outCollisionPoint = hitResult.Intersection; + outTriangle = hitResult.Triangle; + outNode = hitResult.Node; + return true; + } + return false; + } //! Collides a moving ellipsoid with a 3d world with gravity and returns the resulting new position of the ellipsoid. /** This can be used for moving a character in a 3d world: The @@ -161,6 +205,7 @@ namespace scene virtual ISceneNode* getSceneNodeFromCameraBB(const ICameraSceneNode* camera, s32 idBitMask=0, bool bNoDebugObjects = false) = 0; + //! Perform a ray/box and ray/triangle collision check on a hierarchy of scene nodes. /** This checks all scene nodes under the specified one, first by ray/bounding box, and then by accurate ray/triangle collision, finding the nearest collision, @@ -173,6 +218,31 @@ namespace scene You do not have to build a meta triangle selector; the individual triangle selectors of each candidate scene node are used automatically. + \param ray: Line with which collisions are tested. + \param outCollisionPoint: If a collision is detected, this will contain the + position of the nearest collision. + \param outTriangle: If a collision is detected, this will contain the triangle + with which the ray collided. + \param idBitMask: Only scene nodes with an id which matches at least one of the + bits contained in this mask will be tested. However, if this parameter is 0, then + all nodes are checked. + \param collisionRootNode: the scene node at which to begin checking. Only this + node and its children will be checked. If you want to check the entire scene, + pass 0, and the root scene node will be used (this is the default). + \param noDebugObjects: when true, debug objects are not considered viable targets. + Debug objects are scene nodes with IsDebugObject() = true. + \return Returns the scene node containing the hit triangle nearest to ray.start. + If no collision is detected, then 0 is returned. */ + virtual ISceneNode* getSceneNodeAndCollisionPointFromRay( + SCollisionHit& hitResult, + const core::line3df& ray, + s32 idBitMask = 0, + ISceneNode * collisionRootNode = 0, + bool noDebugObjects = false) = 0; + + //! Perform a ray/box and ray/triangle collision check on a hierarchy of scene nodes. + /** Works same as other getSceneNodeAndCollisionPointFromRay but returns less information. + (was written before the other getSceneNodeAndCollisionPointFromRay implementation). \param ray: Line with which collisions are tested. \param outCollisionPoint: If a collision is detected, this will contain the position of the nearest collision. @@ -194,12 +264,21 @@ namespace scene core::triangle3df& outTriangle, s32 idBitMask = 0, ISceneNode * collisionRootNode = 0, - bool noDebugObjects = false) = 0; - }; + bool noDebugObjects = false) + { + SCollisionHit hitResult; + ISceneNode* node = getSceneNodeAndCollisionPointFromRay(hitResult, ray, idBitMask, collisionRootNode, noDebugObjects); + if ( node ) + { + outCollisionPoint = hitResult.Intersection; + outTriangle = hitResult.Triangle; + } + return node; + } + }; } // end namespace scene } // end namespace irr #endif - diff --git a/include/ISceneManager.h b/include/ISceneManager.h index e94f915e..2a105c55 100644 --- a/include/ISceneManager.h +++ b/include/ISceneManager.h @@ -322,7 +322,7 @@ namespace scene * files thanks to
the importer created by Jonas * Petersen. * Notes for
this version of the loader:
- * - It does not recognise/support user data in the + * - It does not recognize/support user data in the * *.lmts files.
* - The TGAs generated by LMTools don't work in * Irrlicht for some reason (the textures are upside @@ -1271,19 +1271,30 @@ namespace scene s->drop(); \endcode \param mesh: Mesh of which the triangles are taken. - \param node: Scene node of which visibility and transformation is used. + \param node: Scene node of which transformation is used. + \param separateMeshbuffers: When true it's possible to get information which meshbuffer + got hit in collision tests. But has a slight speed cost. \return The selector, or null if not successful. If you no longer need the selector, you should call ITriangleSelector::drop(). See IReferenceCounted::drop() for more information. */ - virtual ITriangleSelector* createTriangleSelector(IMesh* mesh, ISceneNode* node) = 0; + virtual ITriangleSelector* createTriangleSelector(IMesh* mesh, ISceneNode* node, bool separateMeshbuffers=false) = 0; + + //! Creates a simple ITriangleSelector, based on a meshbuffer. + /** + This is a static selector which won't update when the mesh changes. + \param meshBuffer Triangles of that meshbuffer are used + \param materialIndex If you pass a material index that index can be returned by the triangle selector. + \para node: Scene node of which transformation is used. + */ + virtual ITriangleSelector* createTriangleSelector(const IMeshBuffer* meshBuffer, irr::u32 materialIndex, ISceneNode* node) = 0; //! Creates a simple ITriangleSelector, based on an animated mesh scene node. /** Details of the mesh associated with the node will be extracted internally. - Call ITriangleSelector::update() to have the triangle selector updated based - on the current frame of the animated mesh scene node. \param node The animated mesh scene node from which to build the selector + \param separateMeshbuffers: When true it's possible to get information which meshbuffer + got hit in collision tests. But has a slight speed cost. */ - virtual ITriangleSelector* createTriangleSelector(IAnimatedMeshSceneNode* node) = 0; + virtual ITriangleSelector* createTriangleSelector(IAnimatedMeshSceneNode* node, bool separateMeshbuffers=false) = 0; //! Creates a simple dynamic ITriangleSelector, based on a axis aligned bounding box. @@ -1323,6 +1334,33 @@ namespace scene virtual ITriangleSelector* createOctreeTriangleSelector(IMesh* mesh, ISceneNode* node, s32 minimalPolysPerNode=32) = 0; + //! Creates a Triangle Selector for a single meshbuffer, optimized by an octree. + /** Triangle selectors + can be used for doing collision detection. This triangle selector is + optimized for huge amounts of triangle, it organizes them in an octree. + Please note that the created triangle selector is not automatically attached + to the scene node. You will have to call ISceneNode::setTriangleSelector() + for this. To create and attach a triangle selector is done like this: + \code + ITriangleSelector* s = sceneManager->createOctreeTriangleSelector(yourMesh, + yourSceneNode); + yourSceneNode->setTriangleSelector(s); + s->drop(); + \endcode + For more information and examples on this, take a look at the collision + tutorial in the SDK. + \param meshBuffer: Meshbuffer of which the triangles are taken. + \param materialIndex: Setting this value allows the triangle selector to return the material index + \param node: Scene node of which visibility and transformation is used. + \param minimalPolysPerNode: Specifies the minimal polygons contained a octree node. + If a node gets less polys than this value, it will not be split into + smaller nodes. + \return The selector, or null if not successful. + If you no longer need the selector, you should call ITriangleSelector::drop(). + See IReferenceCounted::drop() for more information. */ + virtual ITriangleSelector* createOctreeTriangleSelector(IMeshBuffer* meshBuffer, irr::u32 materialIndex, + ISceneNode* node, s32 minimalPolysPerNode=32) = 0; + //! //! Creates a Triangle Selector, optimized by an octree. /** \deprecated Use createOctreeTriangleSelector instead. This method may be removed by Irrlicht 1.9. */ _IRR_DEPRECATED_ ITriangleSelector* createOctTreeTriangleSelector(IMesh* mesh, @@ -1589,7 +1627,7 @@ namespace scene using ISceneManager::saveScene(). \param file File where the scene is loaded from. \param userDataSerializer If you want to load user data - possibily saved in that file for some scene nodes in the file, + saved in that file for some scene nodes in the file, implement the ISceneUserDataSerializer interface and provide it as parameter here. Otherwise, simply specify 0 as this parameter. diff --git a/include/ITextSceneNode.h b/include/ITextSceneNode.h index 540d7b7b..2e12379f 100644 --- a/include/ITextSceneNode.h +++ b/include/ITextSceneNode.h @@ -9,6 +9,12 @@ namespace irr { + +namespace gui +{ + class IGUIFont; +} + namespace scene { @@ -25,8 +31,20 @@ public: //! sets the text string virtual void setText(const wchar_t* text) = 0; + //! get the text string + virtual const wchar_t* getText() const = 0; + //! sets the color of the text virtual void setTextColor(video::SColor color) = 0; + + //! get the color of the text + virtual video::SColor getTextColor() const = 0; + + //! set the font used to draw the text + virtual void setFont(gui::IGUIFont* font) = 0; + + //! Get the font used to draw the text + virtual gui::IGUIFont* getFont() const = 0; }; } // end namespace scene diff --git a/include/ITriangleSelector.h b/include/ITriangleSelector.h index ecd4088e..1d5985c7 100644 --- a/include/ITriangleSelector.h +++ b/include/ITriangleSelector.h @@ -10,6 +10,7 @@ #include "aabbox3d.h" #include "matrix4.h" #include "line3d.h" +#include "irrArray.h" namespace irr { @@ -17,6 +18,49 @@ namespace scene { class ISceneNode; +class ITriangleSelector; +class IMeshBuffer; + +//! Additional information about the triangle arrays returned by ITriangleSelector::getTriangles +/** ITriangleSelector are free to fill out this information fully, partly or ignore it. + Usually they will try to fill it when they can and set values to 0 otherwise. +*/ +struct SCollisionTriangleRange +{ + SCollisionTriangleRange() + : RangeStart(0), RangeSize(0) + , Selector(0), SceneNode(0) + , MeshBuffer(0), MaterialIndex(0) + {} + + //! Check if this triangle index inside the range + /** + \param triangleIndex Index to an element inside the array of triangles returned by ITriangleSelector::getTriangles + */ + bool isIndexInRange(irr::u32 triangleIndex) const + { + return triangleIndex >= RangeStart && triangleIndex < RangeStart+RangeSize; + } + + //! First index in the array for which this struct is valid + irr::u32 RangeStart; + + //! Number of elements in the array for which this struct is valid (starting with RangeStart) + irr::u32 RangeSize; + + //! Real selector which contained those triangles (useful when working with MetaTriangleSelector) + ITriangleSelector* Selector; + + //! SceneNode from which the triangles are from + ISceneNode* SceneNode; + + //! Meshbuffer from which the triangles are from + //! Is 0 when the ITriangleSelector doesn't support meshbuffer selection + const IMeshBuffer* MeshBuffer; + + //! Index of selected material in the SceneNode. Usually only valid when MeshBuffer is also set, otherwise always 0 + irr::u32 MaterialIndex; +}; //! Interface to return triangles with specific properties. /** Every ISceneNode may have a triangle selector, available with @@ -45,10 +89,18 @@ public: into the array. \param transform Pointer to matrix for transforming the triangles before they are returned. Useful for example to scale all triangles - down into an ellipsoid space. If this pointer is null, no - transformation will be done. */ + down into an ellipsoid space. + \param useNodeTransform When the selector has a node then transform the + triangles by that node's transformation matrix. + \param outTriangleInfo When a pointer to an array is passed then that + array is filled with additional information about the returned triangles. + One element of SCollisionTriangleRange added for each range of triangles which + has distinguishable information. For example one range per meshbuffer. + */ virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, - s32& outTriangleCount, const core::matrix4* transform=0) const = 0; + s32& outTriangleCount, const core::matrix4* transform=0, + bool useNodeTransform=true, + irr::core::array* outTriangleInfo=0) const = 0; //! Gets the triangles for one associated node which may lie within a specific bounding box. /** @@ -68,11 +120,17 @@ public: will be written into the array. \param transform Pointer to matrix for transforming the triangles before they are returned. Useful for example to scale all triangles - down into an ellipsoid space. If this pointer is null, no - transformation will be done. */ + down into an ellipsoid space. + \param useNodeTransform When the selector has a node then transform the + triangles by that node's transformation matrix. + \param outTriangleInfo When a pointer to an array is passed then that + array is filled with additional information about the returned triangles. + One element of SCollisionTriangleRange added for each range of triangles which + has distinguishable information. For example one range per meshbuffer. */ virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, const core::aabbox3d& box, - const core::matrix4* transform=0) const = 0; + const core::matrix4* transform=0, bool useNodeTransform=true, + irr::core::array* outTriangleInfo=0) const = 0; //! Gets the triangles for one associated node which have or may have contact with a 3d line. /** @@ -92,22 +150,17 @@ public: will be written into the array. \param transform Pointer to matrix for transforming the triangles before they are returned. Useful for example to scale all triangles - down into an ellipsoid space. If this pointer is null, no - transformation will be done. */ + down into an ellipsoid space. + \param useNodeTransform When the selector has a node then transform the + triangles by that node's transformation matrix. + \param outTriangleInfo When a pointer to an array is passed then that + array is filled with additional information about the returned triangles. + One element of SCollisionTriangleRange added for each range of triangles which + has distinguishable information. For example one range per meshbuffer. */ virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, const core::line3d& line, - const core::matrix4* transform=0) const = 0; - - //! Get scene node associated with a given triangle. - /** - This allows to find which scene node (potentially of several) is - associated with a specific triangle. - - \param triangleIndex: the index of the triangle for which you want to find - the associated scene node. - \return The scene node associated with that triangle. - */ - virtual ISceneNode* getSceneNodeForTriangle(u32 triangleIndex) const = 0; + const core::matrix4* transform=0, bool useNodeTransform=true, + irr::core::array* outTriangleInfo=0) const = 0; //! Get number of TriangleSelectors that are part of this one /** Only useful for MetaTriangleSelector, others return 1 @@ -123,6 +176,17 @@ public: /** Only useful for MetaTriangleSelector, others return 'this' or 0 */ virtual const ITriangleSelector* getSelector(u32 index) const = 0; + + //! Get scene node associated with a given triangle. + /** With CMetaTriangleSelector-selectors it's possible to find out a node + belonging to a certain triangle index. + NOTE: triangleIndex has nothing to do with the order of triangles returned by getTriangles functions! + So you can _not_ use this function to find out anything about to which node returned triangles belong. + Use STriangleCollisionInfo struct for that. + \param triangleIndex: the index of the triangle for which you want to find. + \return The scene node associated with that triangle. + */ + virtual ISceneNode* getSceneNodeForTriangle(u32 triangleIndex) const = 0; }; } // end namespace scene diff --git a/include/Keycodes.h b/include/Keycodes.h index 19be5b12..8fb85942 100644 --- a/include/Keycodes.h +++ b/include/Keycodes.h @@ -177,9 +177,10 @@ namespace irr KEY_PLAY = 0xFA, // Play key KEY_ZOOM = 0xFB, // Zoom key KEY_PA1 = 0xFD, // PA1 key - KEY_OEM_CLEAR = 0xFE, // Clear key + KEY_OEM_CLEAR = 0xFE, // Clear key + KEY_NONE = 0xFF, // usually no key mapping, but some laptops use it for fn key - KEY_KEY_CODES_COUNT = 0xFF // this is not a key, but the amount of keycodes there are. + KEY_KEY_CODES_COUNT = 0x100 // this is not a key, but the amount of keycodes there are. }; } // end namespace irr diff --git a/include/SMaterialLayer.h b/include/SMaterialLayer.h index 5724d7d2..c19f4481 100644 --- a/include/SMaterialLayer.h +++ b/include/SMaterialLayer.h @@ -165,8 +165,7 @@ namespace video return true; else different |= (TextureMatrix != b.TextureMatrix) && - TextureMatrix && b.TextureMatrix && - (*TextureMatrix != *(b.TextureMatrix)); + (!TextureMatrix || !b.TextureMatrix || (*TextureMatrix != *(b.TextureMatrix))); return different; } diff --git a/include/SMesh.h b/include/SMesh.h index 77a695db..91151c99 100644 --- a/include/SMesh.h +++ b/include/SMesh.h @@ -83,13 +83,26 @@ namespace scene //! recalculates the bounding box void recalculateBoundingBox() { - if (MeshBuffers.size()) + bool hasMeshBufferBBox = false; + for (u32 i=0; igetBoundingBox(); - for (u32 i=1; igetBoundingBox()); + const core::aabbox3df& bb = MeshBuffers[i]->getBoundingBox(); + if ( !bb.isEmpty() ) + { + if ( !hasMeshBufferBBox ) + { + hasMeshBufferBBox = true; + BoundingBox = bb; + } + else + { + BoundingBox.addInternalBox(bb); + } + + } } - else + + if ( !hasMeshBufferBBox ) BoundingBox.reset(0.0f, 0.0f, 0.0f); } diff --git a/include/fast_atof.h b/include/fast_atof.h index 22b333fa..2e894353 100644 --- a/include/fast_atof.h +++ b/include/fast_atof.h @@ -17,7 +17,8 @@ namespace core // the float-to-string code used there has to be rewritten first. IRRLICHT_API extern irr::core::stringc LOCALE_DECIMAL_POINTS; -// we write [17] here instead of [] to work around a swig bug +#define IRR_ATOF_TABLE_SIZE 17 +// we write [IRR_ATOF_TABLE_SIZE] here instead of [] to work around a swig bug const float fast_atof_table[17] = { 0.f, 0.1f, @@ -323,8 +324,16 @@ inline const char* fast_atof_move(const char* in, f32& result) if ( LOCALE_DECIMAL_POINTS.findFirst(*in) >= 0 ) { const char* afterDecimal = ++in; - const f32 decimal = strtof10(in, &afterDecimal); - value += decimal * fast_atof_table[afterDecimal - in]; + f32 decimal = strtof10(in, &afterDecimal); + size_t numDecimals = afterDecimal - in; + if (numDecimals < IRR_ATOF_TABLE_SIZE) + { + value += decimal * fast_atof_table[numDecimals]; + } + else + { + value += decimal * (f32)pow(10.f, -(float)numDecimals); + } in = afterDecimal; } @@ -334,7 +343,8 @@ inline const char* fast_atof_move(const char* in, f32& result) // Assume that the exponent is a whole number. // strtol10() will deal with both + and - signs, // but calculate as f32 to prevent overflow at FLT_MAX - value *= powf(10.f, (f32)strtol10(in, &in)); + // Using pow with float cast instead of powf as otherwise accuracy decreases. + value *= (f32)pow(10.f, (f32)strtol10(in, &in)); } result = negative?-value:value; diff --git a/include/irrMath.h b/include/irrMath.h index 612fe632..99341721 100644 --- a/include/irrMath.h +++ b/include/irrMath.h @@ -43,6 +43,7 @@ namespace core //! Rounding error constant often used when comparing f32 values. const s32 ROUNDING_ERROR_S32 = 0; + #ifdef __IRR_HAS_S64 const s64 ROUNDING_ERROR_S64 = 0; #endif @@ -181,16 +182,85 @@ namespace core b = c; } + template + inline T roundingError(); + + template <> + inline f32 roundingError() + { + return ROUNDING_ERROR_f32; + } + + template <> + inline f64 roundingError() + { + return ROUNDING_ERROR_f64; + } + + template <> + inline s32 roundingError() + { + return ROUNDING_ERROR_S32; + } + + template <> + inline u32 roundingError() + { + return ROUNDING_ERROR_S32; + } + +#ifdef __IRR_HAS_S64 + template <> + inline s64 roundingError() + { + return ROUNDING_ERROR_S64; + } + + template <> + inline u64 roundingError() + { + return ROUNDING_ERROR_S64; + } +#endif + + template + inline T relativeErrorFactor() + { + return 1; + } + + template <> + inline f32 relativeErrorFactor() + { + return 4; + } + + template <> + inline f64 relativeErrorFactor() + { + return 8; + } + //! returns if a equals b, taking possible rounding errors into account - inline bool equals(const f64 a, const f64 b, const f64 tolerance = ROUNDING_ERROR_f64) + template + inline T equals(const T a, const T b, const T tolerance = roundingError()) { return (a + tolerance >= b) && (a - tolerance <= b); } - //! returns if a equals b, taking possible rounding errors into account - inline bool equals(const f32 a, const f32 b, const f32 tolerance = ROUNDING_ERROR_f32) + + //! returns if a equals b, taking relative error in form of factor + //! this particular function does not involve any division. + template + inline bool equalsRelative( const T a, const T b, const T factor = relativeErrorFactor()) { - return (a + tolerance >= b) && (a - tolerance <= b); + //https://eagergames.wordpress.com/2017/04/01/fast-parallel-lines-and-vectors-test/ + + const T maxi = max_( a, b); + const T mini = min_( a, b); + const T maxMagnitude = max_( maxi, -mini); + + return (maxMagnitude*factor + maxi) == (maxMagnitude*factor + mini); // MAD Wise } union FloatIntUnion32 @@ -233,39 +303,6 @@ namespace core return false; } -#if 0 - //! returns if a equals b, not using any rounding tolerance - inline bool equals(const s32 a, const s32 b) - { - return (a == b); - } - - //! returns if a equals b, not using any rounding tolerance - inline bool equals(const u32 a, const u32 b) - { - return (a == b); - } -#endif - //! returns if a equals b, taking an explicit rounding tolerance into account - inline bool equals(const s32 a, const s32 b, const s32 tolerance = ROUNDING_ERROR_S32) - { - return (a + tolerance >= b) && (a - tolerance <= b); - } - - //! returns if a equals b, taking an explicit rounding tolerance into account - inline bool equals(const u32 a, const u32 b, const s32 tolerance = ROUNDING_ERROR_S32) - { - return (a + tolerance >= b) && (a - tolerance <= b); - } - -#ifdef __IRR_HAS_S64 - //! returns if a equals b, taking an explicit rounding tolerance into account - inline bool equals(const s64 a, const s64 b, const s64 tolerance = ROUNDING_ERROR_S64) - { - return (a + tolerance >= b) && (a - tolerance <= b); - } -#endif - //! returns if a equals zero, taking rounding errors into account inline bool iszero(const f64 a, const f64 tolerance = ROUNDING_ERROR_f64) { diff --git a/include/irrString.h b/include/irrString.h index 737fe3d0..abf92370 100644 --- a/include/irrString.h +++ b/include/irrString.h @@ -1306,14 +1306,14 @@ public: return used > 1 ? array[used-2] : 0; } - //! split string into parts. + //! Split string into parts (tokens). /** This method will split a string at certain delimiter characters into the container passed in as reference. The type of the container has to be given as template parameter. It must provide a push_back and a size method. - \param ret The result container - \param c C-style string of delimiter characters - \param count Number of delimiter characters + \param ret The result container. Tokens are added, the container is not cleared. + \param delimiter C-style string of delimiter characters + \param countDelimiters Number of delimiter characters \param ignoreEmptyTokens Flag to avoid empty substrings in the result container. If two delimiters occur without a character in between, an empty substring would be placed in the result. If this flag is set, @@ -1325,33 +1325,39 @@ public: \return The number of resulting substrings */ template - u32 split(container& ret, const T* const c, u32 count=1, bool ignoreEmptyTokens=true, bool keepSeparators=false) const + u32 split(container& ret, const T* const delimiter, u32 countDelimiters=1, bool ignoreEmptyTokens=true, bool keepSeparators=false) const { - if (!c) + if (!delimiter) return 0; const u32 oldSize=ret.size(); - u32 lastpos = 0; - bool lastWasSeparator = false; + + u32 tokenStartIdx = 0; for (u32 i=0; i(&array[lastpos], i - lastpos)); - foundSeparator = true; - lastpos = (keepSeparators ? i : i + 1); + if ( keepSeparators ) + { + ret.push_back(string(&array[tokenStartIdx], i+1 - tokenStartIdx)); + } + else + { + if (i - tokenStartIdx > 0) + ret.push_back(string(&array[tokenStartIdx], i - tokenStartIdx)); + else if ( !ignoreEmptyTokens ) + ret.push_back(string()); + } + tokenStartIdx = i+1; break; } } - lastWasSeparator = foundSeparator; } - if ((used - 1) > lastpos) - ret.push_back(string(&array[lastpos], (used - 1) - lastpos)); + if ((used - 1) > tokenStartIdx) + ret.push_back(string(&array[tokenStartIdx], (used - 1) - tokenStartIdx)); + return ret.size()-oldSize; } diff --git a/include/irrXML.h b/include/irrXML.h index 5b4b7afe..cc65bd15 100644 --- a/include/irrXML.h +++ b/include/irrXML.h @@ -316,27 +316,31 @@ namespace io //! Returns the value of an attribute as integer. /** \param name Name of the attribute. - \return Value of the attribute as integer, and 0 if an attribute with this name does not exist or - the value could not be interpreted as integer. */ - virtual int getAttributeValueAsInt(const char_type* name) const = 0; + \param defaultNotFound Value returned when name does not exist + \return Value of the attribute as integer or value of defaultNotFound + when name was not found or 0 when value could not be interpreted as integer */ + virtual int getAttributeValueAsInt(const char_type* name, int defaultNotFound=0) const = 0; //! Returns the value of an attribute as integer. /** \param idx: Zero based index, should be something between 0 and getAttributeCount()-1. - \return Value of the attribute as integer, and 0 if an attribute with this index does not exist or - the value could not be interpreted as integer. */ - virtual int getAttributeValueAsInt(int idx) const = 0; + \param defaultNotFound Value returned when index does not exist. + \return Value of the attribute as integer or value of defaultNotFound parameter for invalid index + or 0 when value could not be interpreted as integer */ + virtual int getAttributeValueAsInt(int idx, int defaultNotFound=0) const = 0; //! Returns the value of an attribute as float. /** \param name: Name of the attribute. - \return Value of the attribute as float, and 0 if an attribute with this name does not exist or - the value could not be interpreted as float. */ - virtual float getAttributeValueAsFloat(const char_type* name) const = 0; + \param defaultNotFound Value returned when name does not exist. + \return Value of the attribute as float or value of defaultNotFound parameter on failure + or 0 when value could not be interpreted as float. */ + virtual float getAttributeValueAsFloat(const char_type* name, float defaultNotFound=0.f) const = 0; //! Returns the value of an attribute as float. /** \param idx: Zero based index, should be something between 0 and getAttributeCount()-1. - \return Value of the attribute as float, and 0 if an attribute with this index does not exist or - the value could not be interpreted as float. */ - virtual float getAttributeValueAsFloat(int idx) const = 0; + \param defaultNotFound Value returned when index does not exist. + \return Value of the attribute as float or value of defaultNotFound parameter on failure + or 0 when value could not be interpreted as float. */ + virtual float getAttributeValueAsFloat(int idx, float defaultNotFound=0.f) const = 0; //! Returns the name of the current node. /** Only valid, if the node type is EXN_ELEMENT. diff --git a/include/line2d.h b/include/line2d.h index 6037bb1d..b5a47555 100644 --- a/include/line2d.h +++ b/include/line2d.h @@ -65,7 +65,85 @@ class line2d //! Get the vector of the line. /** \return The vector of the line. */ - vector2d getVector() const { return vector2d(end.X - start.X, end.Y - start.Y); } + vector2d getVector() const { return vector2d( end.X - start.X, end.Y - start.Y); } + + /*! Check if this segment intersects another segment, + or if segments are coincindent (colinear). */ + bool intersectAsSegments( const line2d& other) const + { + // Taken from: + // http://www.geeksforgeeks.org/check-if-two-given-line-segments-intersect/ + + // Find the four orientations needed for general and + // special cases + s32 o1 = start.checkOrientation( end, other.start); + s32 o2 = start.checkOrientation( end, other.end); + s32 o3 = other.start.checkOrientation( other.end, start); + s32 o4 = other.start.checkOrientation( other.end, end); + + // General case + if (o1 != o2 && o3 != o4) + return true; + + // Special Cases to check if segments are coolinear + if (o1 == 0 && other.start.isBetweenPoints( start, end)) return true; + if (o2 == 0 && other.end.isBetweenPoints( start, end)) return true; + if (o3 == 0 && start.isBetweenPoints( other.start, other.end)) return true; + if (o4 == 0 && end.isBetweenPoints( other.start, other.end)) return true; + + return false; // Doesn't fall in any of the above cases + } + + /*! Check if 2 segments are incident (intersects in exactly 1 point).*/ + bool incidentSegments( const line2d& other) const + { + return + start.checkOrientation( end, other.start) != start.checkOrientation( end, other.end) + && other.start.checkOrientation( other.end, start) != other.start.checkOrientation( other.end, end); + } + + /*! Check if 2 lines/segments are parallel or nearly parallel.*/ + bool nearlyParallel( const line2d& line, const T factor = relativeErrorFactor()) const + { + const vector2d a = getVector(); + const vector2d b = line.getVector(); + + return a.nearlyParallel( b, factor); + } + + /*! returns a intersection point of 2 lines (if lines are not parallel). Behaviour + undefined if lines are parallel or coincident.*/ + vector2d fastLinesIntersection( const line2d& l) const + { + const f32 commonDenominator = (f32)((l.end.Y - l.start.Y)*(end.X - start.X) - + (l.end.X - l.start.X)*(end.Y - start.Y)); + + const f32 numeratorA = (f32)((l.end.X - l.start.X)*(start.Y - l.start.Y) - + (l.end.Y - l.start.Y)*(start.X - l.start.X)); + + const f32 numeratorB = (f32)((end.X - start.X)*(start.Y - l.start.Y) - + (end.Y - start.Y)*(start.X - l.start.X)); + + const f32 uA = numeratorA / commonDenominator; + const f32 uB = numeratorB / commonDenominator; + + // Calculate the intersection point. + return vector2d ( + (T)(start.X + uA * (end.X - start.X)), + (T)(start.Y + uA * (end.Y - start.Y)) + ); + } + + /*! Check if this line intersect a segment. The eventual intersection point is returned in "out".*/ + bool lineIntersectSegment( const line2d& segment, vector2d & out) const + { + if (nearlyParallel( segment)) + return false; + + out = fastLinesIntersection( segment); + + return out.isBetweenPoints( segment.start, segment.end); + } //! Tests if this line intersects with another line. /** \param l: Other line to test intersection with. @@ -209,7 +287,7 @@ class line2d /** Assumes that the point is already somewhere on the line. */ bool isPointBetweenStartAndEnd(const vector2d& point) const { - return point.isBetweenPoints(start, end); + return point.isBetweenPoints(start, end); } //! Get the closest point on this line to a point diff --git a/include/matrix4.h b/include/matrix4.h index 9d37f7ad..3498ab10 100644 --- a/include/matrix4.h +++ b/include/matrix4.h @@ -221,18 +221,25 @@ namespace core void rotateVect(T *out,const core::vector3df &in) const; //! Transforms the vector by this matrix + /** This operation is performed as if the vector was 4d with the 4th component =1 */ void transformVect( vector3df& vect) const; //! Transforms input vector by this matrix and stores result in output vector + /** This operation is performed as if the vector was 4d with the 4th component =1 */ void transformVect( vector3df& out, const vector3df& in ) const; //! An alternate transform vector method, writing into an array of 4 floats + /** This operation is performed as if the vector was 4d with the 4th component =1. + NOTE: out[3] will be written to (4th vector component)*/ void transformVect(T *out,const core::vector3df &in) const; //! An alternate transform vector method, reading from and writing to an array of 3 floats + /** This operation is performed as if the vector was 4d with the 4th component =1 + NOTE: out[3] will be written to (4th vector component)*/ void transformVec3(T *out, const T * in) const; //! Translate a vector by the translation part of this matrix. + /** This operation is performed as if the vector was 4d with the 4th component =1 */ void translateVect( vector3df& vect ) const; //! Transforms a plane by this matrix @@ -247,7 +254,7 @@ namespace core void transformBox(core::aabbox3d& box) const; //! Transforms a axis aligned bounding box - /** The result box of this operation should by accurate, but this operation + /** The result box of this operation should be accurate, but this operation is slower than transformBox(). */ void transformBoxEx(core::aabbox3d& box) const; @@ -2233,6 +2240,8 @@ namespace core { #if defined ( USE_MATRIX_TEST ) definitelyIdentityMatrix = isDefinitelyIdentityMatrix; +#else + (void)isDefinitelyIdentityMatrix; // prevent compiler warning #endif } diff --git a/include/quaternion.h b/include/quaternion.h index 6435a85a..1fcbb06b 100644 --- a/include/quaternion.h +++ b/include/quaternion.h @@ -108,6 +108,8 @@ class quaternion //! Creates a matrix from this quaternion matrix4 getMatrix() const; #endif + //! Faster method to create a rotation matrix, you should normalize the quaternion before! + void getMatrixFast(matrix4 &dest) const; //! Creates a matrix from this quaternion void getMatrix( matrix4 &dest, const core::vector3df &translation=core::vector3df() ) const; @@ -349,12 +351,51 @@ inline matrix4 quaternion::getMatrix() const } #endif +//! Faster method to create a rotation matrix, you should normalize the quaternion before! +inline void quaternion::getMatrixFast( matrix4 &dest) const +{ + // TODO: + // gpu quaternion skinning => fast Bones transform chain O_O YEAH! + // http://www.mrelusive.com/publications/papers/SIMD-From-Quaternion-to-Matrix-and-Back.pdf + dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z; + dest[1] = 2.0f*X*Y + 2.0f*Z*W; + dest[2] = 2.0f*X*Z - 2.0f*Y*W; + dest[3] = 0.0f; + + dest[4] = 2.0f*X*Y - 2.0f*Z*W; + dest[5] = 1.0f - 2.0f*X*X - 2.0f*Z*Z; + dest[6] = 2.0f*Z*Y + 2.0f*X*W; + dest[7] = 0.0f; + + dest[8] = 2.0f*X*Z + 2.0f*Y*W; + dest[9] = 2.0f*Z*Y - 2.0f*X*W; + dest[10] = 1.0f - 2.0f*X*X - 2.0f*Y*Y; + dest[11] = 0.0f; + + dest[12] = 0.f; + dest[13] = 0.f; + dest[14] = 0.f; + dest[15] = 1.f; + + dest.setDefinitelyIdentityMatrix(false); +} + /*! Creates a matrix from this quaternion */ inline void quaternion::getMatrix(matrix4 &dest, const core::vector3df ¢er) const { + // ok creating a copy may be slower, but at least avoid internal + // state chance (also because otherwise we cannot keep this method "const"). + + quaternion q( *this); + q.normalize(); + f32 X = q.X; + f32 Y = q.Y; + f32 Z = q.Z; + f32 W = q.W; + dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z; dest[1] = 2.0f*X*Y + 2.0f*Z*W; dest[2] = 2.0f*X*Z - 2.0f*Y*W; @@ -395,6 +436,13 @@ inline void quaternion::getMatrixCenter(matrix4 &dest, const core::vector3df ¢er, const core::vector3df &translation) const { + quaternion q(*this); + q.normalize(); + f32 X = q.X; + f32 Y = q.Y; + f32 Z = q.Z; + f32 W = q.W; + dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z; dest[1] = 2.0f*X*Y + 2.0f*Z*W; dest[2] = 2.0f*X*Z - 2.0f*Y*W; @@ -416,6 +464,13 @@ inline void quaternion::getMatrixCenter(matrix4 &dest, // Creates a matrix from this quaternion inline void quaternion::getMatrix_transposed(matrix4 &dest) const { + quaternion q(*this); + q.normalize(); + f32 X = q.X; + f32 Y = q.Y; + f32 Z = q.Z; + f32 W = q.W; + dest[0] = 1.0f - 2.0f*Y*Y - 2.0f*Z*Z; dest[4] = 2.0f*X*Y + 2.0f*Z*W; dest[8] = 2.0f*X*Z - 2.0f*Y*W; @@ -492,7 +547,7 @@ inline quaternion& quaternion::set(f32 x, f32 y, f32 z) // sets new quaternion based on Euler angles inline quaternion& quaternion::set(const core::vector3df& vec) { - return set(vec.X, vec.Y, vec.Z); + return set( vec.X, vec.Y, vec.Z); } // sets new quaternion based on other quaternion @@ -505,28 +560,23 @@ inline quaternion& quaternion::set(const core::quaternion& quat) //! returns if this quaternion equals the other one, taking floating point rounding errors into account inline bool quaternion::equals(const quaternion& other, const f32 tolerance) const { - return core::equals(X, other.X, tolerance) && - core::equals(Y, other.Y, tolerance) && - core::equals(Z, other.Z, tolerance) && - core::equals(W, other.W, tolerance); + return core::equals( X, other.X, tolerance) && + core::equals( Y, other.Y, tolerance) && + core::equals( Z, other.Z, tolerance) && + core::equals( W, other.W, tolerance); } // normalizes the quaternion inline quaternion& quaternion::normalize() { - const f32 n = X*X + Y*Y + Z*Z + W*W; - - if (n == 1) - return *this; - - //n = 1.0f / sqrtf(n); - return (*this *= reciprocal_squareroot ( n )); + // removed conditional branch since it may slow down and anyway the condition was + // false even after normalization in some cases. + return (*this *= reciprocal_squareroot ( X*X + Y*Y + Z*Z + W*W )); } - // set this quaternion to the result of the linear interpolation between two quaternions -inline quaternion& quaternion::lerp(quaternion q1, quaternion q2, f32 time) +inline quaternion& quaternion::lerp( quaternion q1, quaternion q2, f32 time) { const f32 scale = 1.0f - time; return (*this = (q1*scale) + (q2*time)); @@ -534,7 +584,7 @@ inline quaternion& quaternion::lerp(quaternion q1, quaternion q2, f32 time) // set this quaternion to the result of the interpolation between two quaternions -inline quaternion& quaternion::slerp(quaternion q1, quaternion q2, f32 time, f32 threshold) +inline quaternion& quaternion::slerp( quaternion q1, quaternion q2, f32 time, f32 threshold) { f32 angle = q1.dotProduct(q2); diff --git a/include/vector2d.h b/include/vector2d.h index 1e597f3c..b8eaf70b 100644 --- a/include/vector2d.h +++ b/include/vector2d.h @@ -127,6 +127,20 @@ public: return X*other.X + Y*other.Y; } + //! check if this vector is parallel to another vector + bool nearlyParallel( const vector2d & other, const T factor = relativeErrorFactor()) const + { + // https://eagergames.wordpress.com/2017/04/01/fast-parallel-lines-and-vectors-test/ + // if a || b then a.x/a.y = b.x/b.y (similiar triangles) + // if a || b then either both x are 0 or both y are 0. + + return equalsRelative( X*other.Y, other.X* Y, factor) + && // a bit counterintuitive, but makes sure that + // only y or only x are 0, and at same time deals + // with the case where one vector is zero vector. + (X*other.X + Y*other.Y) != 0; + } + //! Gets distance from another point. /** Here, the vector is interpreted as a point in 2-dimensional space. \param other Other vector to measure from. @@ -259,15 +273,24 @@ public: \return True if this vector is between begin and end, false if not. */ bool isBetweenPoints(const vector2d& begin, const vector2d& end) const { + // . end + // / + // / + // / + // . begin + // - + // - + // . this point (am I inside or outside)? + // if (begin.X != end.X) { return ((begin.X <= X && X <= end.X) || - (begin.X >= X && X >= end.X)); + (begin.X >= X && X >= end.X)); } else { return ((begin.Y <= Y && Y <= end.Y) || - (begin.Y >= Y && Y >= end.Y)); + (begin.Y >= Y && Y >= end.Y)); } } @@ -300,13 +323,55 @@ public: (T)(Y * mul0 + v2.Y * mul1 + v3.Y * mul2)); } + /*! Test if this point and another 2 poitns taken as triplet + are colinear, clockwise, anticlockwise. This can be used also + to check winding order in triangles for 2D meshes. + \return 0 if points are colinear, 1 if clockwise, 2 if anticlockwise + */ + s32 checkOrientation( const vector2d & b, const vector2d & c) const + { + // Example of clockwise points + // + // ^ Y + // | A + // | . . + // | . . + // | C.....B + // +---------------> X + + T val = (b.Y - Y) * (c.X - b.X) - + (b.X - X) * (c.Y - b.Y); + + if (val == 0) return 0; // colinear + + return (val > 0) ? 1 : 2; // clock or counterclock wise + } + + /*! Returns true if points (a,b,c) are clockwise on the X,Y plane*/ + inline bool areClockwise( const vector2d & b, const vector2d & c) const + { + T val = (b.Y - Y) * (c.X - b.X) - + (b.X - X) * (c.Y - b.Y); + + return val > 0; + } + + /*! Returns true if points (a,b,c) are counterclockwise on the X,Y plane*/ + inline bool areCounterClockwise( const vector2d & b, const vector2d & c) const + { + T val = (b.Y - Y) * (c.X - b.X) - + (b.X - X) * (c.Y - b.Y); + + return val < 0; + } + //! Sets this vector to the linearly interpolated vector between a and b. /** \param a first vector to interpolate with, maximum at 1.0f \param b second vector to interpolate with, maximum at 0.0f \param d Interpolation value between 0.0f (all vector b) and 1.0f (all vector a) Note that this is the opposite direction of interpolation to getInterpolated_quadratic() */ - vector2d& interpolate(const vector2d& a, const vector2d& b, f64 d) + vector2d& interpolate( const vector2d& a, const vector2d& b, f64 d) { X = (T)((f64)b.X + ( ( a.X - b.X ) * d )); Y = (T)((f64)b.Y + ( ( a.Y - b.Y ) * d )); diff --git a/source/Irrlicht/CCSMLoader.cpp b/source/Irrlicht/CCSMLoader.cpp index a93c5a31..d560311c 100644 --- a/source/Irrlicht/CCSMLoader.cpp +++ b/source/Irrlicht/CCSMLoader.cpp @@ -50,7 +50,7 @@ namespace scene { BinaryFileReader(io::IReadFile* pFile) : file(pFile) { } - s32 readBuffer(void* buffer, s32 len) + size_t readBuffer(void* buffer, s32 len) { return file->read(buffer,len); } diff --git a/source/Irrlicht/CD3D9Driver.cpp b/source/Irrlicht/CD3D9Driver.cpp index 220ab2a3..33627ac1 100644 --- a/source/Irrlicht/CD3D9Driver.cpp +++ b/source/Irrlicht/CD3D9Driver.cpp @@ -2830,6 +2830,47 @@ void CD3D9Driver::draw3DLine(const core::vector3df& start, pID3DDevice->DrawPrimitiveUP(D3DPT_LINELIST, 1, v, sizeof(S3DVertex)); } +void CD3D9Driver::draw3DBox( const core::aabbox3d& box, SColor color) +{ + core::vector3df edges[8]; + box.getEdges(edges); + + setVertexShader(EVT_STANDARD); + setRenderStates3DMode(); + + video::S3DVertex v[24]; + + for(u32 i = 0; i < 24; i++) + v[i].Color = color; + + v[0].Pos = edges[5]; + v[1].Pos = edges[1]; + v[2].Pos = edges[1]; + v[3].Pos = edges[3]; + v[4].Pos = edges[3]; + v[5].Pos = edges[7]; + v[6].Pos = edges[7]; + v[7].Pos = edges[5]; + v[8].Pos = edges[0]; + v[9].Pos = edges[2]; + v[10].Pos = edges[2]; + v[11].Pos = edges[6]; + v[12].Pos = edges[6]; + v[13].Pos = edges[4]; + v[14].Pos = edges[4]; + v[15].Pos = edges[0]; + v[16].Pos = edges[1]; + v[17].Pos = edges[0]; + v[18].Pos = edges[3]; + v[19].Pos = edges[2]; + v[20].Pos = edges[7]; + v[21].Pos = edges[6]; + v[22].Pos = edges[5]; + v[23].Pos = edges[4]; + + pID3DDevice->DrawPrimitiveUP(D3DPT_LINELIST, 12, v, sizeof(S3DVertex)); +} + //! resets the device bool CD3D9Driver::reset() diff --git a/source/Irrlicht/CD3D9Driver.h b/source/Irrlicht/CD3D9Driver.h index 2387362e..51015fa4 100644 --- a/source/Irrlicht/CD3D9Driver.h +++ b/source/Irrlicht/CD3D9Driver.h @@ -170,6 +170,9 @@ namespace video virtual void draw3DLine(const core::vector3df& start, const core::vector3df& end, SColor color = SColor(255,255,255,255)) _IRR_OVERRIDE_; + //! Draws a 3d box. + virtual void draw3DBox( const core::aabbox3d& box, SColor color = SColor(255,255,255,255 ) ) _IRR_OVERRIDE_; + //! initialises the Direct3D API bool initDriver(HWND hwnd, bool pureSoftware); diff --git a/source/Irrlicht/CDefaultSceneNodeFactory.cpp b/source/Irrlicht/CDefaultSceneNodeFactory.cpp index bf7e9bcb..2902501a 100644 --- a/source/Irrlicht/CDefaultSceneNodeFactory.cpp +++ b/source/Irrlicht/CDefaultSceneNodeFactory.cpp @@ -5,6 +5,7 @@ #include "CDefaultSceneNodeFactory.h" #include "ISceneManager.h" #include "ITextSceneNode.h" +#include "IBillboardTextSceneNode.h" #include "ITerrainSceneNode.h" #include "IDummyTransformationSceneNode.h" #include "ICameraSceneNode.h" @@ -33,6 +34,7 @@ CDefaultSceneNodeFactory::CDefaultSceneNodeFactory(ISceneManager* mgr) SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_CUBE, "cube")); SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_SPHERE, "sphere")); SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_TEXT, "text")); + SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_BILLBOARD_TEXT, "billboardText")); SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_WATER_SURFACE, "waterSurface")); SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_TERRAIN, "terrain")); SupportedSceneNodeTypes.push_back(SSceneNodeTypePair(ESNT_SKY_BOX, "skyBox")); @@ -70,6 +72,8 @@ ISceneNode* CDefaultSceneNodeFactory::addSceneNode(ESCENE_NODE_TYPE type, IScene return Manager->addSphereSceneNode(5, 16, parent); case ESNT_TEXT: return Manager->addTextSceneNode(0, L"example"); + case ESNT_BILLBOARD_TEXT: + return Manager->addBillboardTextSceneNode(0, L"example"); case ESNT_WATER_SURFACE: return Manager->addWaterSurfaceSceneNode(0, 2.0f, 300.0f, 10.0f, parent); case ESNT_TERRAIN: diff --git a/source/Irrlicht/CFileSystem.cpp b/source/Irrlicht/CFileSystem.cpp index 60420d28..ffe631ee 100644 --- a/source/Irrlicht/CFileSystem.cpp +++ b/source/Irrlicht/CFileSystem.cpp @@ -826,7 +826,7 @@ IFileList* CFileSystem::createFileList() CFileList* r = 0; io::path Path = getWorkingDirectory(); Path.replace('\\', '/'); - if (Path.lastChar() != '/') + if (!Path.empty() && Path.lastChar() != '/') Path.append('/'); //! Construct from native filesystem diff --git a/source/Irrlicht/CGUIContextMenu.cpp b/source/Irrlicht/CGUIContextMenu.cpp index c46838cd..b7452db3 100644 --- a/source/Irrlicht/CGUIContextMenu.cpp +++ b/source/Irrlicht/CGUIContextMenu.cpp @@ -285,22 +285,25 @@ bool CGUIContextMenu::OnEvent(const SEvent& event) { // set event parent of submenus IGUIElement * p = EventParent ? EventParent : Parent; - setEventParent(p); - - SEvent event; - event.EventType = EET_GUI_EVENT; - event.GUIEvent.Caller = this; - event.GUIEvent.Element = 0; - event.GUIEvent.EventType = EGET_ELEMENT_CLOSED; - if ( !p->OnEvent(event) ) + if ( p ) // can be 0 when element got removed already { - if ( CloseHandling & ECMC_HIDE ) + setEventParent(p); + + SEvent event; + event.EventType = EET_GUI_EVENT; + event.GUIEvent.Caller = this; + event.GUIEvent.Element = 0; + event.GUIEvent.EventType = EGET_ELEMENT_CLOSED; + if ( !p->OnEvent(event) ) { - setVisible(false); - } - if ( CloseHandling & ECMC_REMOVE ) - { - remove(); + if ( CloseHandling & ECMC_HIDE ) + { + setVisible(false); + } + if ( CloseHandling & ECMC_REMOVE ) + { + remove(); + } } } diff --git a/source/Irrlicht/CImageLoaderJPG.cpp b/source/Irrlicht/CImageLoaderJPG.cpp index 6ebe4fc1..6b51bd98 100644 --- a/source/Irrlicht/CImageLoaderJPG.cpp +++ b/source/Irrlicht/CImageLoaderJPG.cpp @@ -128,7 +128,7 @@ bool CImageLoaderJPG::isALoadableFileFormat(io::IReadFile* file) const if (!(file && file->seek(0))) return false; unsigned char header[3]; - int headerLen = file->read(header, sizeof(header)); + size_t headerLen = file->read(header, sizeof(header)); return headerLen >= 3 && !memcmp(header, "\xFF\xD8\xFF", 3); #endif } diff --git a/source/Irrlicht/CIrrDeviceLinux.cpp b/source/Irrlicht/CIrrDeviceLinux.cpp index 1f5190ce..ca3c6307 100644 --- a/source/Irrlicht/CIrrDeviceLinux.cpp +++ b/source/Irrlicht/CIrrDeviceLinux.cpp @@ -498,6 +498,11 @@ bool CIrrDeviceLinux::createWindow() IrrPrintXGrabError(grabPointer, "XGrabPointer"); XWarpPointer(XDisplay, None, XWindow, 0, 0, 0, 0, 0, 0); } + else if (CreationParams.WindowPosition.X >= 0 || CreationParams.WindowPosition.Y >= 0) // default is -1, -1 + { + // Window managers are free to ignore positions above, so give it another shot + XMoveWindow(XDisplay,XWindow,x,y); + } } else { diff --git a/source/Irrlicht/CIrrDeviceOSX.mm b/source/Irrlicht/CIrrDeviceOSX.mm index c7d7a1b9..39842820 100644 --- a/source/Irrlicht/CIrrDeviceOSX.mm +++ b/source/Irrlicht/CIrrDeviceOSX.mm @@ -1395,6 +1395,10 @@ void CIrrDeviceMacOSX::initKeycodes() KeyCodes[kVK_ANSI_KeypadDivide] = irr::KEY_DIVIDE; KeyCodes[kVK_ANSI_KeypadEnter] = irr::KEY_RETURN; KeyCodes[kVK_ANSI_KeypadMinus] = irr::KEY_SUBTRACT; + + KeyCodes[kVK_ANSI_LeftBracket] = irr::KEY_OEM_4; + KeyCodes[kVK_ANSI_Backslash] = irr::KEY_OEM_5; + KeyCodes[kVK_ANSI_RightBracket] = irr::KEY_OEM_6; } diff --git a/source/Irrlicht/CIrrDeviceWin32.cpp b/source/Irrlicht/CIrrDeviceWin32.cpp index 1fd84b4c..b2ad55ed 100644 --- a/source/Irrlicht/CIrrDeviceWin32.cpp +++ b/source/Irrlicht/CIrrDeviceWin32.cpp @@ -455,6 +455,8 @@ irr::core::stringc SJoystickWin32Control::findJoystickName(int index, const JOYC bool SJoystickWin32Control::activateJoysticks(core::array & joystickInfo) { #if defined _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ + joystickInfo.clear(); + ActiveJoysticks.clear(); #ifdef _IRR_COMPILE_WITH_DIRECTINPUT_JOYSTICK_ if (!DirectInputDevice || (DirectInputDevice->EnumDevices(DI8DEVCLASS_GAMECTRL, SJoystickWin32Control::EnumJoysticks, this, DIEDFL_ATTACHEDONLY ))) { @@ -475,9 +477,6 @@ bool SJoystickWin32Control::activateJoysticks(core::array & joyst } return true; #else - joystickInfo.clear(); - ActiveJoysticks.clear(); - const u32 numberOfJoysticks = ::joyGetNumDevs(); JOYINFOEX info; info.dwSize = sizeof(info); @@ -2002,6 +2001,26 @@ void CIrrDeviceWin32::ReportLastWinApiError() } } +// Same function Windows offers in VersionHelpers.h, but we can't use that as it's not available in older sdk's (minimum is SDK 8.1) +bool CIrrDeviceWin32::isWindowsVistaOrGreater() +{ +#if (_WIN32_WINNT >= 0x0500) + OSVERSIONINFOEX osvi; + ZeroMemory(&osvi, sizeof(OSVERSIONINFOEX)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); + osvi.dwMajorVersion = 6; // Windows Vista + + if ( !GetVersionEx((OSVERSIONINFO*)&osvi) ) + { + return false; + } + + return VerifyVersionInfo(&osvi, VER_MAJORVERSION, VerSetConditionMask(0, VER_MAJORVERSION, VER_GREATER_EQUAL)); +#else + return false; +#endif +} + // Convert an Irrlicht texture to a Windows cursor // Based on http://www.codeguru.com/cpp/w-p/win32/cursors/article.php/c4529/ HCURSOR CIrrDeviceWin32::TextureToCursor(HWND hwnd, irr::video::ITexture * tex, const core::rect& sourceRect, const core::position2d &hotspot) diff --git a/source/Irrlicht/CIrrDeviceWin32.h b/source/Irrlicht/CIrrDeviceWin32.h index e231d26e..02e7a6e9 100644 --- a/source/Irrlicht/CIrrDeviceWin32.h +++ b/source/Irrlicht/CIrrDeviceWin32.h @@ -118,13 +118,16 @@ namespace irr return CIrrDeviceStub::checkSuccessiveClicks(mouseX, mouseY, inputEvent ); } - //! switchs to fullscreen + //! Switch to fullscreen bool switchToFullScreen(bool reset=false); //! Check for and show last Windows API error to help internal debugging. - //! Does call GetLastError and on errors formats the errortext and displays it in a messagebox. + //! Does call GetLastError and on errors formats the error text and displays it in a messagebox. static void ReportLastWinApiError(); + //! Same function Windows offers in VersionHelpers.h, but we can't use that as it's not available before SDK 8.1 + static bool isWindowsVistaOrGreater(); + // convert an Irrlicht texture to a windows cursor HCURSOR TextureToCursor(HWND hwnd, irr::video::ITexture * tex, const core::rect& sourceRect, const core::position2d &hotspot); @@ -282,15 +285,21 @@ namespace irr { if (!fullscreen) { + s32 paddingBorder = 0; + #if defined (SM_CXPADDEDBORDER) + if (CIrrDeviceWin32::isWindowsVistaOrGreater()) + paddingBorder = GetSystemMetrics(SM_CXPADDEDBORDER); + #endif + if (resizable) { - BorderX = GetSystemMetrics(SM_CXSIZEFRAME); - BorderY = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYSIZEFRAME); + BorderX = GetSystemMetrics(SM_CXSIZEFRAME) + paddingBorder; + BorderY = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYSIZEFRAME) + paddingBorder; } else { - BorderX = GetSystemMetrics(SM_CXDLGFRAME); - BorderY = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYDLGFRAME); + BorderX = GetSystemMetrics(SM_CXDLGFRAME) + paddingBorder; + BorderY = GetSystemMetrics(SM_CYCAPTION) + GetSystemMetrics(SM_CYDLGFRAME) + paddingBorder; } } else diff --git a/source/Irrlicht/CMS3DMeshFileLoader.cpp b/source/Irrlicht/CMS3DMeshFileLoader.cpp index a3919fe1..ed7d9cec 100644 --- a/source/Irrlicht/CMS3DMeshFileLoader.cpp +++ b/source/Irrlicht/CMS3DMeshFileLoader.cpp @@ -159,7 +159,7 @@ bool CMS3DMeshFileLoader::load(io::IReadFile* file) // read whole file u8* buffer = new u8[fileSize]; - s32 read = file->read(buffer, fileSize); + long read = (long)file->read(buffer, fileSize); if (read != fileSize) { delete [] buffer; diff --git a/source/Irrlicht/CMetaTriangleSelector.cpp b/source/Irrlicht/CMetaTriangleSelector.cpp index 206be192..9675268b 100644 --- a/source/Irrlicht/CMetaTriangleSelector.cpp +++ b/source/Irrlicht/CMetaTriangleSelector.cpp @@ -38,14 +38,27 @@ s32 CMetaTriangleSelector::getTriangleCount() const //! Gets all triangles. void CMetaTriangleSelector::getTriangles(core::triangle3df* triangles, s32 arraySize, - s32& outTriangleCount, const core::matrix4* transform) const + s32& outTriangleCount, const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const { s32 outWritten = 0; + irr::u32 outTriangleInfoSize = outTriangleInfo ? outTriangleInfo->size() : 0; for (u32 i=0; igetTriangles(triangles + outWritten, - arraySize - outWritten, t, transform); + arraySize - outWritten, t, transform, useNodeTransform, outTriangleInfo); + + if ( outTriangleInfo ) + { + irr::u32 newTriangleInfoSize = outTriangleInfo->size(); + for ( u32 ti=outTriangleInfoSize; ti& box, - const core::matrix4* transform) const + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const { s32 outWritten = 0; + irr::u32 outTriangleInfoSize = outTriangleInfo ? outTriangleInfo->size() : 0; for (u32 i=0; igetTriangles(triangles + outWritten, - arraySize - outWritten, t, box, transform); + arraySize - outWritten, t, box, transform, useNodeTransform, outTriangleInfo); + + if ( outTriangleInfo ) + { + irr::u32 newTriangleInfoSize = outTriangleInfo->size(); + for ( u32 ti=outTriangleInfoSize; ti& line, - const core::matrix4* transform) const + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const { s32 outWritten = 0; + irr::u32 outTriangleInfoSize = outTriangleInfo ? outTriangleInfo->size() : 0; for (u32 i=0; igetTriangles(triangles + outWritten, - arraySize - outWritten, t, line, transform); + arraySize - outWritten, t, line, transform, useNodeTransform, outTriangleInfo); + + if ( outTriangleInfo ) + { + irr::u32 newTriangleInfoSize = outTriangleInfo->size(); + for ( u32 ti=outTriangleInfoSize; tigetSceneNodeForTriangle(0); } - // For lack of anything more sensible, return the first selector. - return TriangleSelectors[0]->getSceneNodeForTriangle(0); + return 0; } - /* Return the number of TriangleSelectors that are inside this one, Only useful for MetaTriangleSelector others return 1 */ diff --git a/source/Irrlicht/CMetaTriangleSelector.h b/source/Irrlicht/CMetaTriangleSelector.h index f8b8f523..b5202621 100644 --- a/source/Irrlicht/CMetaTriangleSelector.h +++ b/source/Irrlicht/CMetaTriangleSelector.h @@ -29,17 +29,20 @@ public: //! Gets all triangles. virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, - s32& outTriangleCount, const core::matrix4* transform=0) const _IRR_OVERRIDE_; + s32& outTriangleCount, const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; //! Gets all triangles which lie within a specific bounding box. virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, const core::aabbox3d& box, - const core::matrix4* transform=0) const _IRR_OVERRIDE_; + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; //! Gets all triangles which have or may have contact with a 3d line. virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, const core::line3d& line, - const core::matrix4* transform=0) const _IRR_OVERRIDE_; + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; //! Adds a triangle selector to the collection of triangle selectors //! in this metaTriangleSelector. diff --git a/source/Irrlicht/COBJMeshFileLoader.cpp b/source/Irrlicht/COBJMeshFileLoader.cpp index 22ab12e0..fe89af96 100644 --- a/source/Irrlicht/COBJMeshFileLoader.cpp +++ b/source/Irrlicht/COBJMeshFileLoader.cpp @@ -100,6 +100,7 @@ IAnimatedMesh* COBJMeshFileLoader::createMesh(io::IReadFile* file) bool mtlChanged=false; bool useGroups = !SceneManager->getParameters()->getAttributeAsBool(OBJ_LOADER_IGNORE_GROUPS); bool useMaterials = !SceneManager->getParameters()->getAttributeAsBool(OBJ_LOADER_IGNORE_MATERIAL_FILES); + irr::u32 lineNr = 1; // only counts non-empty lines, still useful in debugging to locate errors while(bufPtr != bufEnd) { switch(bufPtr[0]) @@ -289,6 +290,7 @@ IAnimatedMesh* COBJMeshFileLoader::createMesh(io::IReadFile* file) } // end switch(bufPtr[0]) // eat up rest of line bufPtr = goNextLine(bufPtr, bufEnd); + ++lineNr; } // end while(bufPtr && (bufPtr-buf #include -#ifndef _IRR_SOLARIS_PLATFORM_ #ifndef _IRR_ANDROID_PLATFORM_ #include +#ifdef _IRR_OSX_PLATFORM_ #include #endif #endif @@ -84,7 +84,7 @@ void COSOperator::copyToClipboard(const c8* text) const #elif defined(_IRR_COMPILE_WITH_OSX_DEVICE_) NSString *str = nil; NSPasteboard *board = nil; - + if ((text != NULL) && (strlen(text) > 0)) { str = [NSString stringWithCString:text encoding:NSWindowsCP1252StringEncoding]; @@ -92,7 +92,7 @@ void COSOperator::copyToClipboard(const c8* text) const [board declareTypes:[NSArray arrayWithObject:NSStringPboardType] owner:NSApp]; [board setString:str forType:NSStringPboardType]; } - + #elif defined(_IRR_COMPILE_WITH_X11_DEVICE_) if ( IrrDeviceLinux ) IrrDeviceLinux->copyToClipboard(text); @@ -127,10 +127,10 @@ const c8* COSOperator::getTextFromClipboard() const board = [NSPasteboard generalPasteboard]; str = [board stringForType:NSStringPboardType]; - + if (str != nil) result = (char*)[str cStringUsingEncoding:NSWindowsCP1252StringEncoding]; - + return (result); #elif defined(_IRR_COMPILE_WITH_X11_DEVICE_) @@ -208,18 +208,32 @@ bool COSOperator::getProcessorSpeedMHz(u32* MHz) const bool COSOperator::getSystemMemory(u32* Total, u32* Avail) const { #if defined(_IRR_WINDOWS_API_) && !defined (_IRR_XBOX_PLATFORM_) + + #if (_WIN32_WINNT >= 0x0500) + MEMORYSTATUSEX MemoryStatusEx; + MemoryStatusEx.dwLength = sizeof(MEMORYSTATUSEX); + + // cannot fail + GlobalMemoryStatusEx(&MemoryStatusEx); + + if (Total) + *Total = (u32)(MemoryStatusEx.ullTotalPhys>>10); + if (Avail) + *Avail = (u32)(MemoryStatusEx.ullAvailPhys>>10); + return true; + #else MEMORYSTATUS MemoryStatus; MemoryStatus.dwLength = sizeof(MEMORYSTATUS); - // cannot fail + // cannot fail GlobalMemoryStatus(&MemoryStatus); - if (Total) + if (Total) *Total = (u32)(MemoryStatus.dwTotalPhys>>10); - if (Avail) + if (Avail) *Avail = (u32)(MemoryStatus.dwAvailPhys>>10); - - return true; + return true; + #endif #elif defined(_IRR_POSIX_API_) && !defined(__FreeBSD__) #if defined(_SC_PHYS_PAGES) && defined(_SC_AVPHYS_PAGES) @@ -236,7 +250,7 @@ bool COSOperator::getSystemMemory(u32* Total, u32* Avail) const *Avail = (u32)((ps*(long long)ap)>>10); return true; #else - // TODO: implement for non-availablity of symbols/features + // TODO: implement for non-availability of symbols/features return false; #endif #elif defined(_IRR_OSX_PLATFORM_) diff --git a/source/Irrlicht/COctreeTriangleSelector.cpp b/source/Irrlicht/COctreeTriangleSelector.cpp index 806fd769..c8f62a65 100644 --- a/source/Irrlicht/COctreeTriangleSelector.cpp +++ b/source/Irrlicht/COctreeTriangleSelector.cpp @@ -15,8 +15,9 @@ namespace scene //! constructor COctreeTriangleSelector::COctreeTriangleSelector(const IMesh* mesh, ISceneNode* node, s32 minimalPolysPerNode) - : CTriangleSelector(mesh, node), Root(0), NodeCount(0), - MinimalPolysPerNode(minimalPolysPerNode) + : CTriangleSelector(mesh, node, false) + , Root(0), NodeCount(0) + , MinimalPolysPerNode(minimalPolysPerNode) { #ifdef _DEBUG setDebugName("COctreeTriangleSelector"); @@ -38,6 +39,30 @@ COctreeTriangleSelector::COctreeTriangleSelector(const IMesh* mesh, } } +COctreeTriangleSelector::COctreeTriangleSelector(const IMeshBuffer* meshBuffer, irr::u32 materialIndex, ISceneNode* node, s32 minimalPolysPerNode) + : CTriangleSelector(meshBuffer, materialIndex, node) + , Root(0), NodeCount(0) + , MinimalPolysPerNode(minimalPolysPerNode) +{ + #ifdef _DEBUG + setDebugName("COctreeTriangleSelector"); + #endif + + if (!Triangles.empty()) + { + const u32 start = os::Timer::getRealTime(); + + // create the triangle octree + Root = new SOctreeNode(); + Root->Triangles = Triangles; + constructOctree(Root); + + c8 tmp[256]; + sprintf(tmp, "Needed %ums to create OctreeTriangleSelector.(%d nodes, %u polys)", + os::Timer::getRealTime() - start, NodeCount, Triangles.size()); + os::Printer::log(tmp, ELL_INFORMATION); + } +} //! destructor COctreeTriangleSelector::~COctreeTriangleSelector() @@ -111,15 +136,19 @@ void COctreeTriangleSelector::constructOctree(SOctreeNode* node) void COctreeTriangleSelector::getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, const core::aabbox3d& box, - const core::matrix4* transform) const + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const { core::matrix4 mat(core::matrix4::EM4CONST_NOTHING); core::aabbox3d invbox = box; - if (SceneNode) + if (SceneNode && useNodeTransform) { - SceneNode->getAbsoluteTransformation().getInverse(mat); - mat.transformBoxEx(invbox); + if ( SceneNode->getAbsoluteTransformation().getInverse(mat) ) + mat.transformBoxEx(invbox); + else + // TODO: case not handled well, we can only return all triangles + return CTriangleSelector::getTriangles(triangles, arraySize, outTriangleCount, transform, useNodeTransform, outTriangleInfo); } if (transform) @@ -127,7 +156,7 @@ void COctreeTriangleSelector::getTriangles(core::triangle3df* triangles, else mat.makeIdentity(); - if (SceneNode) + if (SceneNode && useNodeTransform) mat *= SceneNode->getAbsoluteTransformation(); s32 trianglesWritten = 0; @@ -136,6 +165,17 @@ void COctreeTriangleSelector::getTriangles(core::triangle3df* triangles, getTrianglesFromOctree(Root, trianglesWritten, arraySize, invbox, &mat, triangles); + if ( outTriangleInfo ) + { + SCollisionTriangleRange triRange; + triRange.RangeSize = trianglesWritten; + triRange.Selector = const_cast(this); + triRange.SceneNode = SceneNode; + triRange.MeshBuffer = MeshBuffer; + triRange.MaterialIndex = MaterialIndex; + outTriangleInfo->push_back(triRange); + } + outTriangleCount = trianglesWritten; } @@ -180,7 +220,8 @@ void COctreeTriangleSelector::getTrianglesFromOctree( // new version: from user Piraaate void COctreeTriangleSelector::getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, const core::line3d& line, - const core::matrix4* transform) const + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const { #if 0 core::aabbox3d box(line.start); @@ -194,7 +235,7 @@ void COctreeTriangleSelector::getTriangles(core::triangle3df* triangles, s32 arr core::matrix4 mat ( core::matrix4::EM4CONST_NOTHING ); core::vector3df vectStartInv ( line.start ), vectEndInv ( line.end ); - if (SceneNode) + if (SceneNode && useNodeTransform) { mat = SceneNode->getAbsoluteTransformation(); mat.makeInverse(); @@ -208,7 +249,7 @@ void COctreeTriangleSelector::getTriangles(core::triangle3df* triangles, s32 arr if (transform) mat = (*transform); - if (SceneNode) + if (SceneNode && useNodeTransform) mat *= SceneNode->getAbsoluteTransformation(); s32 trianglesWritten = 0; @@ -216,6 +257,17 @@ void COctreeTriangleSelector::getTriangles(core::triangle3df* triangles, s32 arr if (Root) getTrianglesFromOctree(Root, trianglesWritten, arraySize, invline, &mat, triangles); + if ( outTriangleInfo ) + { + SCollisionTriangleRange triRange; + triRange.RangeSize = trianglesWritten; + triRange.Selector = const_cast(this); + triRange.SceneNode = SceneNode; + triRange.MeshBuffer = MeshBuffer; + triRange.MaterialIndex = MaterialIndex; + outTriangleInfo->push_back(triRange); + } + outTriangleCount = trianglesWritten; #endif } @@ -262,4 +314,3 @@ void COctreeTriangleSelector::getTrianglesFromOctree(SOctreeNode* node, } // end namespace scene } // end namespace irr - diff --git a/source/Irrlicht/COctreeTriangleSelector.h b/source/Irrlicht/COctreeTriangleSelector.h index 76b6b63d..b022b2ab 100644 --- a/source/Irrlicht/COctreeTriangleSelector.h +++ b/source/Irrlicht/COctreeTriangleSelector.h @@ -22,16 +22,21 @@ public: //! Constructs a selector based on a mesh COctreeTriangleSelector(const IMesh* mesh, ISceneNode* node, s32 minimalPolysPerNode); + //! Constructs a selector based on a meshbuffer + COctreeTriangleSelector(const IMeshBuffer* meshBuffer, irr::u32 materialIndex, ISceneNode* node, s32 minimalPolysPerNode); + virtual ~COctreeTriangleSelector(); //! Gets all triangles which lie within a specific bounding box. virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, - const core::aabbox3d& box, const core::matrix4* transform=0) const _IRR_OVERRIDE_; + const core::aabbox3d& box, const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; //! Gets all triangles which have or may have contact with a 3d line. virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, const core::line3d& line, - const core::matrix4* transform=0) const _IRR_OVERRIDE_; + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; private: diff --git a/source/Irrlicht/COpenGLCacheHandler.cpp b/source/Irrlicht/COpenGLCacheHandler.cpp index ed4831f2..a8cab54c 100644 --- a/source/Irrlicht/COpenGLCacheHandler.cpp +++ b/source/Irrlicht/COpenGLCacheHandler.cpp @@ -25,8 +25,6 @@ COpenGLCacheHandler::COpenGLCacheHandler(COpenGLDriver* driver) : glAlphaFunc(AlphaMode, AlphaRef); glDisable(GL_ALPHA_TEST); - - glMatrixMode(MatrixMode); Driver->irrGlClientActiveTexture(ClientActiveTexture); diff --git a/source/Irrlicht/COpenGLDriver.cpp b/source/Irrlicht/COpenGLDriver.cpp index 31931c00..3a11002b 100644 --- a/source/Irrlicht/COpenGLDriver.cpp +++ b/source/Irrlicht/COpenGLDriver.cpp @@ -1087,14 +1087,19 @@ void COpenGLDriver::renderArray(const void* indexList, u32 primitiveCount, glPointSize(particleSize); #ifdef GL_ARB_point_sprite - if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite]) - glTexEnvf(GL_POINT_SPRITE_ARB,GL_COORD_REPLACE, GL_TRUE); + if (pType == scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite]) + { + CacheHandler->setActiveTexture(GL_TEXTURE0_ARB); + glTexEnvf(GL_POINT_SPRITE_ARB, GL_COORD_REPLACE, GL_TRUE); + } #endif glDrawArrays(GL_POINTS, 0, primitiveCount); #ifdef GL_ARB_point_sprite if (pType==scene::EPT_POINT_SPRITES && FeatureAvailable[IRR_ARB_point_sprite]) { glDisable(GL_POINT_SPRITE_ARB); + + CacheHandler->setActiveTexture(GL_TEXTURE0_ARB); glTexEnvf(GL_POINT_SPRITE_ARB,GL_COORD_REPLACE, GL_FALSE); } #endif @@ -2098,8 +2103,6 @@ void COpenGLDriver::setMaterial(const SMaterial& material) CacheHandler->getTextureCache().set(i, material.getTexture(i)); setTransform((E_TRANSFORMATION_STATE)(ETS_TEXTURE_0 + i), material.getTextureMatrix(i)); } - - CacheHandler->setActiveTexture(GL_TEXTURE0_ARB); } @@ -2148,6 +2151,8 @@ void COpenGLDriver::setRenderStates3DMode() CacheHandler->setBlend(false); CacheHandler->setAlphaTest(false); CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + CacheHandler->setActiveTexture(GL_TEXTURE0_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); // switch back the matrices CacheHandler->setMatrixMode(GL_MODELVIEW); @@ -2747,7 +2752,7 @@ void COpenGLDriver::setTextureRenderStates(const SMaterial& material, bool reset { // Set textures to TU/TIU and apply filters to them - for (s32 i = Feature.TextureUnit - 1; i>= 0; --i) + for (s32 i = Feature.TextureUnit - 1; i >= 0; --i) { bool fixedPipeline = false; @@ -2756,149 +2761,146 @@ void COpenGLDriver::setTextureRenderStates(const SMaterial& material, bool reset const COpenGLTexture* tmpTexture = CacheHandler->getTextureCache().get(i); - if (!tmpTexture) - continue; - - CacheHandler->setActiveTexture(GL_TEXTURE0 + i); - - if (fixedPipeline) + if (tmpTexture) { - const bool isRTT = tmpTexture->isRenderTarget(); + CacheHandler->setActiveTexture(GL_TEXTURE0 + i); - CacheHandler->setMatrixMode(GL_TEXTURE); - - if (!isRTT && Matrices[ETS_TEXTURE_0 + i].isIdentity()) - glLoadIdentity(); - else + if (fixedPipeline) { - GLfloat glmat[16]; - if (isRTT) - getGLTextureMatrix(glmat, Matrices[ETS_TEXTURE_0 + i] * TextureFlipMatrix); + const bool isRTT = tmpTexture->isRenderTarget(); + + CacheHandler->setMatrixMode(GL_TEXTURE); + + if (!isRTT && Matrices[ETS_TEXTURE_0 + i].isIdentity()) + glLoadIdentity(); else - getGLTextureMatrix(glmat, Matrices[ETS_TEXTURE_0 + i]); - glLoadMatrixf(glmat); + { + GLfloat glmat[16]; + if (isRTT) + getGLTextureMatrix(glmat, Matrices[ETS_TEXTURE_0 + i] * TextureFlipMatrix); + else + getGLTextureMatrix(glmat, Matrices[ETS_TEXTURE_0 + i]); + glLoadMatrixf(glmat); + } } - } - const GLenum tmpType = tmpTexture->getOpenGLTextureType(); + const GLenum tmpType = tmpTexture->getOpenGLTextureType(); - COpenGLTexture::SStatesCache& statesCache = tmpTexture->getStatesCache(); + COpenGLTexture::SStatesCache& statesCache = tmpTexture->getStatesCache(); - if (resetAllRenderstates) - statesCache.IsCached = false; + if (resetAllRenderstates) + statesCache.IsCached = false; #ifdef GL_VERSION_2_1 - if (Version>=210) - { - if (!statesCache.IsCached || material.TextureLayer[i].LODBias != statesCache.LODBias) + if (Version >= 210) + { + if (!statesCache.IsCached || material.TextureLayer[i].LODBias != statesCache.LODBias) + { + if (material.TextureLayer[i].LODBias) + { + const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias); + glTexParameterf(tmpType, GL_TEXTURE_LOD_BIAS, tmp); + } + else + glTexParameterf(tmpType, GL_TEXTURE_LOD_BIAS, 0.f); + + statesCache.LODBias = material.TextureLayer[i].LODBias; + } + } + else if (FeatureAvailable[IRR_EXT_texture_lod_bias]) { if (material.TextureLayer[i].LODBias) { const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias); - glTexParameterf(tmpType, GL_TEXTURE_LOD_BIAS, tmp); + glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, tmp); } else - glTexParameterf(tmpType, GL_TEXTURE_LOD_BIAS, 0.f); - - statesCache.LODBias = material.TextureLayer[i].LODBias; + glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.f); } - } - else if (FeatureAvailable[IRR_EXT_texture_lod_bias]) - { - if (material.TextureLayer[i].LODBias) - { - const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias); - glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, tmp); - } - else - glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.f); - } #elif defined(GL_EXT_texture_lod_bias) - if (FeatureAvailable[IRR_EXT_texture_lod_bias]) - { - if (material.TextureLayer[i].LODBias) + if (FeatureAvailable[IRR_EXT_texture_lod_bias]) { - const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias); - glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, tmp); + if (material.TextureLayer[i].LODBias) + { + const float tmp = core::clamp(material.TextureLayer[i].LODBias * 0.125f, -MaxTextureLODBias, MaxTextureLODBias); + glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, tmp); + } + else + glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.f); } - else - glTexEnvf(GL_TEXTURE_FILTER_CONTROL_EXT, GL_TEXTURE_LOD_BIAS_EXT, 0.f); - } #endif - if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter || - material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter) - { - glTexParameteri(tmpType, GL_TEXTURE_MAG_FILTER, - (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); - - statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter; - statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter; - } - - if (material.UseMipMaps && tmpTexture->hasMipMaps()) - { if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter || - material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter || !statesCache.MipMapStatus) + material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter) { - glTexParameteri(tmpType, GL_TEXTURE_MIN_FILTER, - material.TextureLayer[i].TrilinearFilter ? GL_LINEAR_MIPMAP_LINEAR : - material.TextureLayer[i].BilinearFilter ? GL_LINEAR_MIPMAP_NEAREST : - GL_NEAREST_MIPMAP_NEAREST); - - statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter; - statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter; - statesCache.MipMapStatus = true; - } - } - else - { - if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter || - material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter || statesCache.MipMapStatus) - { - glTexParameteri(tmpType, GL_TEXTURE_MIN_FILTER, + glTexParameteri(tmpType, GL_TEXTURE_MAG_FILTER, (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter; statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter; - statesCache.MipMapStatus = false; } - } + + if (material.UseMipMaps && tmpTexture->hasMipMaps()) + { + if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter || + material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter || !statesCache.MipMapStatus) + { + glTexParameteri(tmpType, GL_TEXTURE_MIN_FILTER, + material.TextureLayer[i].TrilinearFilter ? GL_LINEAR_MIPMAP_LINEAR : + material.TextureLayer[i].BilinearFilter ? GL_LINEAR_MIPMAP_NEAREST : + GL_NEAREST_MIPMAP_NEAREST); + + statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter; + statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter; + statesCache.MipMapStatus = true; + } + } + else + { + if (!statesCache.IsCached || material.TextureLayer[i].BilinearFilter != statesCache.BilinearFilter || + material.TextureLayer[i].TrilinearFilter != statesCache.TrilinearFilter || statesCache.MipMapStatus) + { + glTexParameteri(tmpType, GL_TEXTURE_MIN_FILTER, + (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); + + statesCache.BilinearFilter = material.TextureLayer[i].BilinearFilter; + statesCache.TrilinearFilter = material.TextureLayer[i].TrilinearFilter; + statesCache.MipMapStatus = false; + } + } #ifdef GL_EXT_texture_filter_anisotropic - if (FeatureAvailable[IRR_EXT_texture_filter_anisotropic] && - (!statesCache.IsCached || material.TextureLayer[i].AnisotropicFilter != statesCache.AnisotropicFilter)) - { - glTexParameteri(tmpType, GL_TEXTURE_MAX_ANISOTROPY_EXT, - material.TextureLayer[i].AnisotropicFilter>1 ? core::min_(MaxAnisotropy, material.TextureLayer[i].AnisotropicFilter) : 1); + if (FeatureAvailable[IRR_EXT_texture_filter_anisotropic] && + (!statesCache.IsCached || material.TextureLayer[i].AnisotropicFilter != statesCache.AnisotropicFilter)) + { + glTexParameteri(tmpType, GL_TEXTURE_MAX_ANISOTROPY_EXT, + material.TextureLayer[i].AnisotropicFilter > 1 ? core::min_(MaxAnisotropy, material.TextureLayer[i].AnisotropicFilter) : 1); - statesCache.AnisotropicFilter = material.TextureLayer[i].AnisotropicFilter; - } + statesCache.AnisotropicFilter = material.TextureLayer[i].AnisotropicFilter; + } #endif - if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapU != statesCache.WrapU) - { - glTexParameteri(tmpType, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayer[i].TextureWrapU)); - statesCache.WrapU = material.TextureLayer[i].TextureWrapU; - } + if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapU != statesCache.WrapU) + { + glTexParameteri(tmpType, GL_TEXTURE_WRAP_S, getTextureWrapMode(material.TextureLayer[i].TextureWrapU)); + statesCache.WrapU = material.TextureLayer[i].TextureWrapU; + } - if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapV != statesCache.WrapV) - { - glTexParameteri(tmpType, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayer[i].TextureWrapV)); - statesCache.WrapV = material.TextureLayer[i].TextureWrapV; - } + if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapV != statesCache.WrapV) + { + glTexParameteri(tmpType, GL_TEXTURE_WRAP_T, getTextureWrapMode(material.TextureLayer[i].TextureWrapV)); + statesCache.WrapV = material.TextureLayer[i].TextureWrapV; + } - if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapW != statesCache.WrapW) - { - glTexParameteri(tmpType, GL_TEXTURE_WRAP_R, getTextureWrapMode(material.TextureLayer[i].TextureWrapW)); - statesCache.WrapW = material.TextureLayer[i].TextureWrapW; - } + if (!statesCache.IsCached || material.TextureLayer[i].TextureWrapW != statesCache.WrapW) + { + glTexParameteri(tmpType, GL_TEXTURE_WRAP_R, getTextureWrapMode(material.TextureLayer[i].TextureWrapW)); + statesCache.WrapW = material.TextureLayer[i].TextureWrapW; + } - statesCache.IsCached = true; + statesCache.IsCached = true; + } } - - // be sure to leave in texture stage 0 - CacheHandler->setActiveTexture(GL_TEXTURE0); } @@ -2920,6 +2922,8 @@ void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaCh else FixedPipelineState = COpenGLDriver::EOFPS_ENABLE; + bool resetAllRenderStates = false; + if (CurrentRenderMode != ERM_2D || Transformation3DChanged) { // unset last 3d material @@ -2928,6 +2932,7 @@ void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaCh if (static_cast(LastMaterial.MaterialType) < MaterialRenderers.size()) MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); } + if (Transformation3DChanged) { CacheHandler->setMatrixMode(GL_PROJECTION); @@ -2940,32 +2945,40 @@ void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaCh CacheHandler->setMatrixMode(GL_MODELVIEW); glLoadIdentity(); - glTranslatef(0.375f, 0.375f, 0.0f); - // Make sure we set first texture matrix - CacheHandler->setActiveTexture(GL_TEXTURE0); - Transformation3DChanged = false; } - if (!OverrideMaterial2DEnabled) - { - setBasicRenderStates(InitMaterial2D, LastMaterial, true); - LastMaterial = InitMaterial2D; - } + CacheHandler->setBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + #ifdef GL_EXT_clip_volume_hint if (FeatureAvailable[IRR_EXT_clip_volume_hint]) glHint(GL_CLIP_VOLUME_CLIPPING_HINT_EXT, GL_FASTEST); #endif + resetAllRenderStates = true; } - if (OverrideMaterial2DEnabled) + + SMaterial currentMaterial = (!OverrideMaterial2DEnabled) ? InitMaterial2D : OverrideMaterial2D; + currentMaterial.Lighting = false; + + if (texture) { - OverrideMaterial2D.Lighting=false; - setBasicRenderStates(OverrideMaterial2D, LastMaterial, false); - LastMaterial = OverrideMaterial2D; + setTransform(ETS_TEXTURE_0, core::IdentityMatrix); + + // Due to the transformation change, the previous line would call a reset each frame + // but we can safely reset the variable as it was false before + Transformation3DChanged = false; } + else + { + CacheHandler->getTextureCache().set(0, 0); + } + + setBasicRenderStates(currentMaterial, LastMaterial, resetAllRenderStates); + + LastMaterial = currentMaterial; // no alphaChannel without texture alphaChannel &= texture; @@ -2984,23 +2997,14 @@ void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaCh if (texture) { - if (OverrideMaterial2DEnabled) - setTextureRenderStates(OverrideMaterial2D, false); - else - setTextureRenderStates(InitMaterial2D, false); - - Material.setTexture(0, const_cast(CacheHandler->getTextureCache()[0])); - setTransform(ETS_TEXTURE_0, core::IdentityMatrix); - // Due to the transformation change, the previous line would call a reset each frame - // but we can safely reset the variable as it was false before - Transformation3DChanged=false; + CacheHandler->setActiveTexture(GL_TEXTURE0_ARB); if (alphaChannel) { // if alpha and alpha texture just modulate, otherwise use only the alpha channel if (alpha) { - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } else { @@ -3008,26 +3012,26 @@ void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaCh if (FeatureAvailable[IRR_ARB_texture_env_combine]||FeatureAvailable[IRR_EXT_texture_env_combine]) { #ifdef GL_ARB_texture_env_combine - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); // rgb always modulates - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB); #else - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE); // rgb always modulates - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); #endif } else #endif - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } } else @@ -3038,21 +3042,21 @@ void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaCh if (FeatureAvailable[IRR_ARB_texture_env_combine]||FeatureAvailable[IRR_EXT_texture_env_combine]) { #ifdef GL_ARB_texture_env_combine - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); // rgb always modulates - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PRIMARY_COLOR_ARB); #else - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); // rgb always modulates - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PRIMARY_COLOR_EXT); #endif } else @@ -3532,6 +3536,67 @@ void COpenGLDriver::setFog(SColor c, E_FOG_TYPE fogType, f32 start, glFogfv(GL_FOG_COLOR, data); } +//! Draws a 3d box. +void COpenGLDriver::draw3DBox( const core::aabbox3d& box, SColor color ) +{ + core::vector3df edges[8]; + box.getEdges(edges); + + setRenderStates3DMode(); + + video::S3DVertex v[24]; + + for(u32 i = 0; i < 24; i++) + v[i].Color = color; + + v[0].Pos = edges[5]; + v[1].Pos = edges[1]; + v[2].Pos = edges[1]; + v[3].Pos = edges[3]; + v[4].Pos = edges[3]; + v[5].Pos = edges[7]; + v[6].Pos = edges[7]; + v[7].Pos = edges[5]; + v[8].Pos = edges[0]; + v[9].Pos = edges[2]; + v[10].Pos = edges[2]; + v[11].Pos = edges[6]; + v[12].Pos = edges[6]; + v[13].Pos = edges[4]; + v[14].Pos = edges[4]; + v[15].Pos = edges[0]; + v[16].Pos = edges[1]; + v[17].Pos = edges[0]; + v[18].Pos = edges[3]; + v[19].Pos = edges[2]; + v[20].Pos = edges[7]; + v[21].Pos = edges[6]; + v[22].Pos = edges[5]; + v[23].Pos = edges[4]; + + if (!FeatureAvailable[IRR_ARB_vertex_array_bgra] && !FeatureAvailable[IRR_EXT_vertex_array_bgra]) + getColorBuffer(v, 24, EVT_STANDARD); + + CacheHandler->setClientState(true, false, true, false); + + glVertexPointer(3, GL_FLOAT, sizeof(S3DVertex), &(static_cast(v))[0].Pos); + +#ifdef GL_BGRA + const GLint colorSize=(FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra])?GL_BGRA:4; +#else + const GLint colorSize=4; +#endif + if (FeatureAvailable[IRR_ARB_vertex_array_bgra] || FeatureAvailable[IRR_EXT_vertex_array_bgra]) + glColorPointer(colorSize, GL_UNSIGNED_BYTE, sizeof(S3DVertex), &(static_cast(v))[0].Color); + else + { + _IRR_DEBUG_BREAK_IF(ColorBuffer.size()==0); + glColorPointer(colorSize, GL_UNSIGNED_BYTE, 0, &ColorBuffer[0]); + } + + glDrawArrays(GL_LINES, 0, 24); +} + //! Draws a 3d line. void COpenGLDriver::draw3DLine(const core::vector3df& start, @@ -4287,7 +4352,7 @@ void COpenGLDriver::getColorFormatParameters(ECOLOR_FORMAT format, GLint& intern case ECF_G32R32F: if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_rg)) { - internalFormat = GL_RG32F; + internalFormat = GL_RG32F; pixelFormat = GL_RG; pixelType = GL_FLOAT; } @@ -4297,7 +4362,7 @@ void COpenGLDriver::getColorFormatParameters(ECOLOR_FORMAT format, GLint& intern case ECF_A32B32G32R32F: if (queryOpenGLFeature(COpenGLExtensionHandler::IRR_ARB_texture_float)) { - internalFormat = GL_RGBA32F_ARB; + internalFormat = GL_RGBA32F_ARB; pixelFormat = GL_RGBA; pixelType = GL_FLOAT; } diff --git a/source/Irrlicht/COpenGLDriver.h b/source/Irrlicht/COpenGLDriver.h index 9cbc2806..192bd12a 100644 --- a/source/Irrlicht/COpenGLDriver.h +++ b/source/Irrlicht/COpenGLDriver.h @@ -198,6 +198,9 @@ namespace video //! Draws a single pixel virtual void drawPixel(u32 x, u32 y, const SColor & color) _IRR_OVERRIDE_; + //! Draws a 3d box + virtual void draw3DBox( const core::aabbox3d& box, SColor color = SColor(255,255,255,255 ) ) _IRR_OVERRIDE_; + //! Draws a 3d line. virtual void draw3DLine(const core::vector3df& start, const core::vector3df& end, diff --git a/source/Irrlicht/COpenGLMaterialRenderer.h b/source/Irrlicht/COpenGLMaterialRenderer.h index e3f225fc..115d161d 100644 --- a/source/Irrlicht/COpenGLMaterialRenderer.h +++ b/source/Irrlicht/COpenGLMaterialRenderer.h @@ -35,13 +35,6 @@ public: Driver->disableTextures(1); Driver->setBasicRenderStates(material, lastMaterial, resetAllRenderstates); - - if (resetAllRenderstates || (material.MaterialType != lastMaterial.MaterialType)) - { - // thanks to Murphy, the following line removed some - // bugs with several OpenGL implementations. - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - } } protected: @@ -89,17 +82,19 @@ public: Driver->getCacheHandler()->setBlendFunc(Driver->getGLBlend(srcRGBFact), Driver->getGLBlend(dstRGBFact)); } + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + #ifdef GL_ARB_texture_env_combine - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, (f32) modulate ); #else - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, (f32) modulate ); #endif @@ -109,33 +104,33 @@ public: if (alphaSource==EAS_VERTEX_COLOR) { #ifdef GL_ARB_texture_env_combine - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); #else - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); #endif } else if (alphaSource==EAS_TEXTURE) { #ifdef GL_ARB_texture_env_combine - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); #else - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE); #endif } else { #ifdef GL_ARB_texture_env_combine - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_TEXTURE); #else - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_TEXTURE); #endif } } @@ -144,15 +139,18 @@ public: virtual void OnUnsetMaterial() _IRR_OVERRIDE_ { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + #ifdef GL_ARB_texture_env_combine - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.f ); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); #else - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE); glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.f ); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); #endif Driver->getCacheHandler()->setBlend(false); @@ -195,23 +193,23 @@ public: { Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1_ARB); #ifdef GL_ARB_texture_env_combine - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_PRIMARY_COLOR); - glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_INTERPOLATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_ARB, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_ALPHA); #else - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_INTERPOLATE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_PRIMARY_COLOR); - glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_INTERPOLATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE2_RGB_EXT, GL_PRIMARY_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_ALPHA); #endif } } @@ -222,13 +220,14 @@ public: if (Driver->queryFeature(EVDF_MULTITEXTURE)) { Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + #ifdef GL_ARB_texture_env_combine - glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_ARB, GL_SRC_COLOR); #else - glTexEnvf(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); + glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND2_RGB_EXT, GL_SRC_COLOR); #endif - Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); } } @@ -258,9 +257,6 @@ public: Driver->getCacheHandler()->setBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_COLOR); Driver->getCacheHandler()->setBlend(true); - - if ((material.MaterialType != lastMaterial.MaterialType) || resetAllRenderstates) - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } virtual void OnUnsetMaterial() _IRR_OVERRIDE_ @@ -303,35 +299,39 @@ public: if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + #ifdef GL_ARB_texture_env_combine - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PRIMARY_COLOR_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); #else - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT ); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PRIMARY_COLOR_EXT ); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); #endif } } virtual void OnUnsetMaterial() _IRR_OVERRIDE_ { - // default values + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); #ifdef GL_ARB_texture_env_combine - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE ); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE ); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE ); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE ); #else - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE ); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE ); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE ); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE ); #endif + Driver->getCacheHandler()->setBlend(false); } @@ -370,34 +370,37 @@ public: Driver->getCacheHandler()->setAlphaTest(true); Driver->getCacheHandler()->setAlphaFunc(GL_GREATER, material.MaterialTypeParam); - if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates - || material.MaterialTypeParam != lastMaterial.MaterialTypeParam ) + if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates || material.MaterialTypeParam != lastMaterial.MaterialTypeParam ) { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + #ifdef GL_ARB_texture_env_combine - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); #else - glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); - glTexEnvf(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE); #endif } } virtual void OnUnsetMaterial() _IRR_OVERRIDE_ { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); #ifdef GL_ARB_texture_env_combine - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE ); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE ); #else - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE ); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE ); #endif Driver->getCacheHandler()->setAlphaTest(false); Driver->getCacheHandler()->setBlend(false); @@ -437,7 +440,6 @@ public: { Driver->getCacheHandler()->setAlphaTest(true); Driver->getCacheHandler()->setAlphaFunc(GL_GREATER, 0.5f); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } } @@ -478,6 +480,8 @@ public: if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + // diffuse map switch (material.MaterialType) @@ -511,7 +515,7 @@ public: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_ARB, GL_PREVIOUS_ARB); #else @@ -524,7 +528,7 @@ public: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); - glTexEnvf(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_MODULATE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_ALPHA_EXT, GL_PREVIOUS_EXT); #endif @@ -554,7 +558,6 @@ public: glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.0f); #endif } - Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); } } } @@ -564,15 +567,17 @@ public: if (Driver->queryFeature(EVDF_MULTITEXTURE)) { Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1_ARB); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); #ifdef GL_ARB_texture_env_combine glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_ARB, 1.f ); #else glTexEnvf(GL_TEXTURE_ENV, GL_RGB_SCALE_EXT, 1.f ); #endif - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } + + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); } protected: @@ -602,12 +607,11 @@ public: if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) { - // diffuse map is default modulated - // detail map on second layer if (Driver->queryFeature(EVDF_MULTITEXTURE)) { Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1_ARB); + #ifdef GL_ARB_texture_env_combine glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_ADD_SIGNED_ARB); @@ -628,8 +632,8 @@ public: if (Driver->queryFeature(EVDF_MULTITEXTURE)) { Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); } } @@ -663,6 +667,8 @@ public: if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); @@ -673,6 +679,8 @@ public: virtual void OnUnsetMaterial() _IRR_OVERRIDE_ { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + glDisable(GL_TEXTURE_GEN_S); glDisable(GL_TEXTURE_GEN_T); } @@ -706,6 +714,7 @@ public: if (Driver->queryFeature(EVDF_MULTITEXTURE)) { Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1_ARB); + #ifdef GL_ARB_texture_env_combine glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); @@ -717,11 +726,12 @@ public: glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); #endif + + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); } - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); } } @@ -730,13 +740,10 @@ public: if (Driver->queryFeature(EVDF_MULTITEXTURE)) { Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); - } - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - if (Driver->queryFeature(EVDF_MULTITEXTURE)) - { - Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); } } @@ -769,20 +776,22 @@ public: if (material.MaterialType != lastMaterial.MaterialType || resetAllRenderstates) { + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + #ifdef GL_ARB_texture_env_combine - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_ARB, GL_PREVIOUS_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_PREVIOUS_ARB); #else - glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); - glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); - glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PREVIOUS_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_EXT, GL_MODULATE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_EXT, GL_TEXTURE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE1_RGB_EXT, GL_PREVIOUS_EXT); + glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); + glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PREVIOUS_ARB); #endif if (Driver->queryFeature(EVDF_MULTITEXTURE)) { @@ -802,11 +811,12 @@ public: glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_EXT, GL_REPLACE); glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_EXT, GL_PREVIOUS_ARB); #endif + + glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); + glEnable(GL_TEXTURE_GEN_S); + glEnable(GL_TEXTURE_GEN_T); } - glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); - glEnable(GL_TEXTURE_GEN_S); - glEnable(GL_TEXTURE_GEN_T); } } @@ -815,14 +825,17 @@ public: if (Driver->queryFeature(EVDF_MULTITEXTURE)) { Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE1_ARB); + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + + glDisable(GL_TEXTURE_GEN_S); + glDisable(GL_TEXTURE_GEN_T); } - glDisable(GL_TEXTURE_GEN_S); - glDisable(GL_TEXTURE_GEN_T); - if (Driver->queryFeature(EVDF_MULTITEXTURE)) - { - Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); - } + + Driver->getCacheHandler()->setActiveTexture(GL_TEXTURE0_ARB); + + glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + Driver->getCacheHandler()->setBlend(false); } diff --git a/source/Irrlicht/CPLYMeshFileLoader.cpp b/source/Irrlicht/CPLYMeshFileLoader.cpp index 1ef49461..290e704a 100644 --- a/source/Irrlicht/CPLYMeshFileLoader.cpp +++ b/source/Irrlicht/CPLYMeshFileLoader.cpp @@ -469,7 +469,7 @@ void CPLYMeshFileLoader::fillBuffer() if (EndOfFile) return; - u32 length = (u32)(EndPointer - StartPointer); + size_t length = (size_t)(EndPointer - StartPointer); if (length && StartPointer != Buffer) { // copy the remaining data to the start of the buffer @@ -486,7 +486,7 @@ void CPLYMeshFileLoader::fillBuffer() else { // read data from the file - u32 count = File->read(EndPointer, PLY_INPUT_BUFFER_SIZE - length); + size_t count = File->read(EndPointer, PLY_INPUT_BUFFER_SIZE - length); // increment the end pointer by the number of bytes read EndPointer = EndPointer + count; diff --git a/source/Irrlicht/CSceneCollisionManager.cpp b/source/Irrlicht/CSceneCollisionManager.cpp index 41424761..78ba1318 100644 --- a/source/Irrlicht/CSceneCollisionManager.cpp +++ b/source/Irrlicht/CSceneCollisionManager.cpp @@ -225,16 +225,12 @@ void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root, ISceneNode* CSceneCollisionManager::getSceneNodeAndCollisionPointFromRay( + SCollisionHit& hitResult, const core::line3df& ray, - core::vector3df & outCollisionPoint, - core::triangle3df & outTriangle, s32 idBitMask, ISceneNode * collisionRootNode, bool noDebugObjects) { - ISceneNode* bestNode = 0; - f32 bestDistanceSquared = FLT_MAX; - if(0 == collisionRootNode) collisionRootNode = SceneManager->getRootSceneNode(); @@ -261,23 +257,21 @@ ISceneNode* CSceneCollisionManager::getSceneNodeAndCollisionPointFromRay( // node in order to find the nearest collision point, so sorting them by // bounding box would be pointless. + f32 bestDistanceSquared = FLT_MAX; core::line3df rayRest(ray); - getPickedNodeFromBBAndSelector(collisionRootNode, rayRest, idBitMask, - noDebugObjects, bestDistanceSquared, bestNode, - outCollisionPoint, outTriangle); - return bestNode; + getPickedNodeFromBBAndSelector(hitResult, collisionRootNode, rayRest, idBitMask, + noDebugObjects, bestDistanceSquared); + return hitResult.Node; } void CSceneCollisionManager::getPickedNodeFromBBAndSelector( + SCollisionHit& hitResult, ISceneNode * root, core::line3df & ray, s32 bits, bool noDebugObjects, - f32 & outBestDistanceSquared, - ISceneNode * & outBestNode, - core::vector3df & outBestCollisionPoint, - core::triangle3df & outBestTriangle) + f32 & outBestDistanceSquared) { const ISceneNodeList& children = root->getChildren(); @@ -303,31 +297,26 @@ void CSceneCollisionManager::getPickedNodeFromBBAndSelector( const core::aabbox3df& box = current->getBoundingBox(); - core::vector3df candidateCollisionPoint; - core::triangle3df candidateTriangle; + SCollisionHit candidateHitResult; // do intersection test in object space - ISceneNode * hitNode = 0; if (box.intersectsWithLine(line) && - getCollisionPoint(ray, selector, candidateCollisionPoint, candidateTriangle, hitNode)) + getCollisionPoint(candidateHitResult, ray, selector)) { - const f32 distanceSquared = (candidateCollisionPoint - ray.start).getLengthSQ(); + const f32 distanceSquared = (candidateHitResult.Intersection - ray.start).getLengthSQ(); if(distanceSquared < outBestDistanceSquared) { outBestDistanceSquared = distanceSquared; - outBestNode = current; - outBestCollisionPoint = candidateCollisionPoint; - outBestTriangle = candidateTriangle; + hitResult = candidateHitResult; const core::vector3df rayVector = ray.getVector().normalize(); ray.end = ray.start + (rayVector * sqrtf(distanceSquared)); } } } - getPickedNodeFromBBAndSelector(current, ray, bits, noDebugObjects, - outBestDistanceSquared, outBestNode, - outBestCollisionPoint, outBestTriangle); + getPickedNodeFromBBAndSelector(hitResult, current, ray, bits, noDebugObjects, + outBestDistanceSquared); } } @@ -348,12 +337,7 @@ ISceneNode* CSceneCollisionManager::getSceneNodeFromCameraBB( return getSceneNodeFromRayBB(core::line3d(start, end), idBitMask, noDebugObjects); } - -//! Finds the collision point of a line and lots of triangles, if there is one. -bool CSceneCollisionManager::getCollisionPoint(const core::line3d& ray, - ITriangleSelector* selector, core::vector3df& outIntersection, - core::triangle3df& outTriangle, - ISceneNode*& outNode) +bool CSceneCollisionManager::getCollisionPoint(SCollisionHit& hitResult, const core::line3d& ray, ITriangleSelector* selector) { if (!selector) { @@ -367,12 +351,13 @@ bool CSceneCollisionManager::getCollisionPoint(const core::line3d& ray, Triangles.set_used(totalcnt); s32 cnt = 0; - selector->getTriangles(Triangles.pointer(), totalcnt, cnt, ray); + irr::core::array outTriangleInfo; + selector->getTriangles(Triangles.pointer(), totalcnt, cnt, ray, 0, true, &outTriangleInfo); const core::vector3df linevect = ray.getVector().normalize(); core::vector3df intersection; f32 nearest = FLT_MAX; - bool found = false; + irr::s32 foundIndex = -1; const f32 raylength = ray.getLengthSQ(); const f32 minX = core::min_(ray.start.X, ray.end.X); @@ -407,17 +392,34 @@ bool CSceneCollisionManager::getCollisionPoint(const core::line3d& ray, if (tmp < raylength && tmp2 < raylength && tmp < nearest) { nearest = tmp; - outTriangle = triangle; - outIntersection = intersection; - outNode = selector->getSceneNodeForTriangle(i); - found = true; + + hitResult.Triangle = triangle; + hitResult.Intersection = intersection; + foundIndex = i; } } } - return found; -} + if ( foundIndex >= 0 ) + { + for ( irr::u32 t=0; ttriangleHits; + // distance to collision is t f32 distToCollision = t*colData->velocity.getLength(); @@ -677,7 +681,6 @@ bool CSceneCollisionManager::testTriangleIntersection(SCollisionData* colData, colData->intersectionPoint = collisionPoint; colData->foundCollision = true; colData->intersectionTriangle = triangle; - ++colData->triangleHits; return true; } }// end found collision @@ -712,7 +715,7 @@ core::vector3df CSceneCollisionManager::collideEllipsoidWithWorld( colData.selector = selector; colData.slidingSpeed = slidingSpeed; colData.triangleHits = 0; - colData.triangleIndex = -1; + colData.node = 0; core::vector3df eSpacePosition = colData.R3Position / colData.eRadius; core::vector3df eSpaceVelocity = colData.R3Velocity / colData.eRadius; @@ -746,7 +749,7 @@ core::vector3df CSceneCollisionManager::collideEllipsoidWithWorld( triout.pointA *= colData.eRadius; triout.pointB *= colData.eRadius; triout.pointC *= colData.eRadius; - outNode = selector->getSceneNodeForTriangle(colData.triangleIndex); + outNode = colData.node; } finalPos *= colData.eRadius; @@ -787,12 +790,30 @@ core::vector3df CSceneCollisionManager::collideWithWorld(s32 recursionDepth, 1.0f / colData.eRadius.Y, 1.0f / colData.eRadius.Z)); + irr::core::array outTriangleInfo; s32 triangleCnt = 0; - colData.selector->getTriangles(Triangles.pointer(), totalTriangleCnt, triangleCnt, box, &scaleMatrix); + colData.selector->getTriangles(Triangles.pointer(), totalTriangleCnt, triangleCnt, box, &scaleMatrix, true, &outTriangleInfo); + // Find closest intersection + irr::s32 nearestTriangleIndex = -1; for (s32 i=0; i= 0 ) + { + for ( irr::u32 t=0; t& ray, - ITriangleSelector* selector, core::vector3df& outCollisionPoint, - core::triangle3df& outTriangle, - ISceneNode* & outNode) _IRR_OVERRIDE_; + //! Finds the nearest collision point of a line and lots of triangles, if there is one. + virtual bool getCollisionPoint(SCollisionHit& hitResult, const core::line3d& ray, + ITriangleSelector* selector) _IRR_OVERRIDE_; //! Collides a moving ellipsoid with a 3d world with gravity and returns //! the resulting new position of the ellipsoid. @@ -72,13 +70,11 @@ namespace scene //! Gets the scene node and nearest collision point for a ray based on //! the nodes' id bitmasks, bounding boxes and triangle selectors. virtual ISceneNode* getSceneNodeAndCollisionPointFromRay( + SCollisionHit& hitResult, const core::line3df& ray, - core::vector3df& outCollisionPoint, - core::triangle3df& outTriangle, s32 idBitMask = 0, ISceneNode * collisionRootNode = 0, - bool noDebugObjects = false) _IRR_OVERRIDE_; - + bool noDebugObjects = false) _IRR_OVERRIDE_; private: @@ -88,14 +84,13 @@ namespace scene f32& outbestdistance, ISceneNode*& outbestnode); //! recursive method for going through all scene nodes - void getPickedNodeFromBBAndSelector(ISceneNode * root, + void getPickedNodeFromBBAndSelector( + SCollisionHit& hitResult, + ISceneNode * root, core::line3df & ray, s32 bits, bool noDebugObjects, - f32 & outBestDistanceSquared, - ISceneNode * & outBestNode, - core::vector3df & outBestCollisionPoint, - core::triangle3df & outBestTriangle); + f32 & outBestDistanceSquared); struct SCollisionData @@ -114,7 +109,7 @@ namespace scene core::vector3df intersectionPoint; core::triangle3df intersectionTriangle; - s32 triangleIndex; + irr::scene::ISceneNode* node; s32 triangleHits; f32 slidingSpeed; diff --git a/source/Irrlicht/CSceneManager.cpp b/source/Irrlicht/CSceneManager.cpp index 939d2bd3..17977ec5 100644 --- a/source/Irrlicht/CSceneManager.cpp +++ b/source/Irrlicht/CSceneManager.cpp @@ -1847,23 +1847,29 @@ IMeshManipulator* CSceneManager::getMeshManipulator() //! Creates a simple ITriangleSelector, based on a mesh. -ITriangleSelector* CSceneManager::createTriangleSelector(IMesh* mesh, ISceneNode* node) +ITriangleSelector* CSceneManager::createTriangleSelector(IMesh* mesh, ISceneNode* node, bool separateMeshbuffers) { if (!mesh) return 0; - return new CTriangleSelector(mesh, node); + return new CTriangleSelector(mesh, node, separateMeshbuffers); +} + +ITriangleSelector* CSceneManager::createTriangleSelector(const IMeshBuffer* meshBuffer, irr::u32 materialIndex, ISceneNode* node) +{ + if ( !meshBuffer) + return 0; + return new CTriangleSelector(meshBuffer, materialIndex, node); } -//! Creates a simple and updatable ITriangleSelector, based on a the mesh owned by an -//! animated scene node -ITriangleSelector* CSceneManager::createTriangleSelector(IAnimatedMeshSceneNode* node) +//! Creates a ITriangleSelector, based on a the mesh owned by an animated scene node +ITriangleSelector* CSceneManager::createTriangleSelector(IAnimatedMeshSceneNode* node, bool separateMeshbuffers) { if (!node || !node->getMesh()) return 0; - return new CTriangleSelector(node); + return new CTriangleSelector(node, separateMeshbuffers); } @@ -1887,6 +1893,14 @@ ITriangleSelector* CSceneManager::createOctreeTriangleSelector(IMesh* mesh, return new COctreeTriangleSelector(mesh, node, minimalPolysPerNode); } +ITriangleSelector* CSceneManager::createOctreeTriangleSelector(IMeshBuffer* meshBuffer, irr::u32 materialIndex, + ISceneNode* node, s32 minimalPolysPerNode) +{ + if ( !meshBuffer) + return 0; + + return new COctreeTriangleSelector(meshBuffer, materialIndex, node, minimalPolysPerNode); +} //! Creates a meta triangle selector. IMetaTriangleSelector* CSceneManager::createMetaTriangleSelector() diff --git a/source/Irrlicht/CSceneManager.h b/source/Irrlicht/CSceneManager.h index 6d2f3373..4944894c 100644 --- a/source/Irrlicht/CSceneManager.h +++ b/source/Irrlicht/CSceneManager.h @@ -343,19 +343,26 @@ namespace scene //! Creates a simple ITriangleSelector, based on a mesh. - virtual ITriangleSelector* createTriangleSelector(IMesh* mesh, ISceneNode* node) _IRR_OVERRIDE_; + virtual ITriangleSelector* createTriangleSelector(IMesh* mesh, ISceneNode* node, bool separateMeshbuffers) _IRR_OVERRIDE_; + + //! Creates a simple ITriangleSelector, based on a meshbuffer. + virtual ITriangleSelector* createTriangleSelector(const IMeshBuffer* meshBuffer, irr::u32 materialIndex, ISceneNode* node) _IRR_OVERRIDE_; //! Creates a simple ITriangleSelector, based on an animated mesh scene node. //! Details of the mesh associated with the node will be extracted internally. //! Call ITriangleSelector::update() to have the triangle selector updated based //! on the current frame of the animated mesh scene node. //! \param: The animated mesh scene node from which to build the selector - virtual ITriangleSelector* createTriangleSelector(IAnimatedMeshSceneNode* node) _IRR_OVERRIDE_; + virtual ITriangleSelector* createTriangleSelector(IAnimatedMeshSceneNode* node, bool separateMeshbuffers) _IRR_OVERRIDE_; //! Creates a simple ITriangleSelector, based on a mesh. virtual ITriangleSelector* createOctreeTriangleSelector(IMesh* mesh, ISceneNode* node, s32 minimalPolysPerNode) _IRR_OVERRIDE_; + //! Creates a simple ITriangleSelector, based on a meshbuffer. + virtual ITriangleSelector* createOctreeTriangleSelector(IMeshBuffer* meshBuffer, irr::u32 materialIndex, + ISceneNode* node, s32 minimalPolysPerNode=32) _IRR_OVERRIDE_; + //! Creates a simple dynamic ITriangleSelector, based on a axis aligned bounding box. virtual ITriangleSelector* createTriangleSelectorFromBoundingBox( ISceneNode* node) _IRR_OVERRIDE_; diff --git a/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.cpp b/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.cpp index d02c2b18..8d5b1701 100644 --- a/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.cpp +++ b/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.cpp @@ -202,7 +202,8 @@ void CSceneNodeAnimatorCollisionResponse::animateNode(ISceneNode* node, u32 time } else { - Falling = false; + if ( CollisionOccurred ) // f can also happen to be false when FallingVelocity was already 0 (p.e. at top of a jump) + Falling = false; FallingVelocity.set(0, 0, 0); } } diff --git a/source/Irrlicht/CTerrainTriangleSelector.cpp b/source/Irrlicht/CTerrainTriangleSelector.cpp index 91820ce2..459a62a3 100644 --- a/source/Irrlicht/CTerrainTriangleSelector.cpp +++ b/source/Irrlicht/CTerrainTriangleSelector.cpp @@ -77,7 +77,8 @@ void CTerrainTriangleSelector::setTriangleData(ITerrainSceneNode* node, s32 LOD) //! Gets all triangles. void CTerrainTriangleSelector::getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, - const core::matrix4* transform) const + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const { s32 count = TrianglePatches.TotalTriangles; @@ -106,6 +107,15 @@ void CTerrainTriangleSelector::getTriangles(core::triangle3df* triangles, } } + if ( outTriangleInfo ) + { + SCollisionTriangleRange triRange; + triRange.RangeSize = tIndex; + triRange.Selector = const_cast(this); + triRange.SceneNode = SceneNode; + outTriangleInfo->push_back(triRange); + } + outTriangleCount = tIndex; } @@ -113,7 +123,9 @@ void CTerrainTriangleSelector::getTriangles(core::triangle3df* triangles, //! Gets all triangles which lie within a specific bounding box. void CTerrainTriangleSelector::getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, - const core::aabbox3d& box, const core::matrix4* transform) const + const core::aabbox3d& box, + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const { s32 count = TrianglePatches.TotalTriangles; @@ -143,6 +155,15 @@ void CTerrainTriangleSelector::getTriangles(core::triangle3df* triangles, } } + if ( outTriangleInfo ) + { + SCollisionTriangleRange triRange; + triRange.RangeSize = tIndex; + triRange.Selector = const_cast(this); + triRange.SceneNode = SceneNode; + outTriangleInfo->push_back(triRange); + } + outTriangleCount = tIndex; } @@ -150,7 +171,8 @@ void CTerrainTriangleSelector::getTriangles(core::triangle3df* triangles, //! Gets all triangles which have or may have contact with a 3d line. void CTerrainTriangleSelector::getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, const core::line3d& line, - const core::matrix4* transform) const + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const { const s32 count = core::min_((s32)TrianglePatches.TotalTriangles, arraySize); @@ -179,6 +201,15 @@ void CTerrainTriangleSelector::getTriangles(core::triangle3df* triangles, } } + if ( outTriangleInfo ) + { + SCollisionTriangleRange triRange; + triRange.RangeSize = tIndex; + triRange.Selector = const_cast(this); + triRange.SceneNode = SceneNode; + outTriangleInfo->push_back(triRange); + } + outTriangleCount = tIndex; } diff --git a/source/Irrlicht/CTerrainTriangleSelector.h b/source/Irrlicht/CTerrainTriangleSelector.h index 0dbad833..eee29772 100644 --- a/source/Irrlicht/CTerrainTriangleSelector.h +++ b/source/Irrlicht/CTerrainTriangleSelector.h @@ -22,7 +22,7 @@ class ITerrainSceneNode; //! Triangle Selector for the TerrainSceneNode /** The code for the TerrainTriangleSelector is based on the GeoMipMapSelector developed by Spintz. He made it available for Irrlicht and allowed it to be -distributed under this licence. I only modified some parts. A lot of thanks go +distributed under this license. I only modified some parts. A lot of thanks go to him. */ class CTerrainTriangleSelector : public ITriangleSelector @@ -40,16 +40,19 @@ public: //! Gets all triangles. void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, - const core::matrix4* transform=0) const _IRR_OVERRIDE_; + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; //! Gets all triangles which lie within a specific bounding box. void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, - const core::aabbox3d& box, const core::matrix4* transform=0) const _IRR_OVERRIDE_; + const core::aabbox3d& box, const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; //! Gets all triangles which have or may have contact with a 3d line. virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, const core::line3d& line, - const core::matrix4* transform=0) const _IRR_OVERRIDE_; + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; //! Returns amount of all available triangles in this selector virtual s32 getTriangleCount() const _IRR_OVERRIDE_; diff --git a/source/Irrlicht/CTextSceneNode.cpp b/source/Irrlicht/CTextSceneNode.cpp index b90d7991..d263a855 100644 --- a/source/Irrlicht/CTextSceneNode.cpp +++ b/source/Irrlicht/CTextSceneNode.cpp @@ -77,6 +77,11 @@ void CTextSceneNode::setText(const wchar_t* text) Text = text; } +//! get the text string +const wchar_t* CTextSceneNode::getText() const +{ + return Text.c_str(); +} //! sets the color of the text void CTextSceneNode::setTextColor(video::SColor color) @@ -84,6 +89,30 @@ void CTextSceneNode::setTextColor(video::SColor color) Color = color; } +//! get the color of the text +video::SColor CTextSceneNode::getTextColor() const +{ + return Color; +} + +void CTextSceneNode::setFont(gui::IGUIFont* font) +{ + if ( font != Font ) + { + if ( font ) + font->grab(); + if ( Font ) + Font->drop(); + Font = font; + } +} + +//! Get the font used to draw the text +gui::IGUIFont* CTextSceneNode::getFont() const +{ + return Font; +} + //!--------------------------------- CBillboardTextSceneNode ---------------------------------------------- @@ -234,6 +263,11 @@ void CBillboardTextSceneNode::setText(const wchar_t* text) } } +//! get the text string +const wchar_t* CBillboardTextSceneNode::getText() const +{ + return Text.c_str(); +} //! pre render event void CBillboardTextSceneNode::OnAnimate(u32 timeMs) @@ -408,11 +442,10 @@ const core::dimension2d& CBillboardTextSceneNode::getSize() const return Size; } - -//! sets the color of the text -void CBillboardTextSceneNode::setTextColor(video::SColor color) +//! Get the font used to draw the text +gui::IGUIFont* CBillboardTextSceneNode::getFont() const { - Color = color; + return Font; } //! Set the color of all vertices of the billboard diff --git a/source/Irrlicht/CTextSceneNode.h b/source/Irrlicht/CTextSceneNode.h index a9622a06..3e20e941 100644 --- a/source/Irrlicht/CTextSceneNode.h +++ b/source/Irrlicht/CTextSceneNode.h @@ -41,9 +41,21 @@ namespace scene //! sets the text string virtual void setText(const wchar_t* text) _IRR_OVERRIDE_; + //! get the text string + virtual const wchar_t* getText() const _IRR_OVERRIDE_; + //! sets the color of the text virtual void setTextColor(video::SColor color) _IRR_OVERRIDE_; + //! get the color of the text + virtual video::SColor getTextColor() const _IRR_OVERRIDE_; + + //! set the font used to draw the text + virtual void setFont(gui::IGUIFont* font) _IRR_OVERRIDE_; + + //! Get the font used to draw the text + virtual gui::IGUIFont* getFont() const _IRR_OVERRIDE_; + //! Returns type of the scene node virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_TEXT; } @@ -83,8 +95,11 @@ namespace scene //! sets the text string virtual void setText(const wchar_t* text) _IRR_OVERRIDE_; - //! sets the color of the text - virtual void setTextColor(video::SColor color) _IRR_OVERRIDE_; + //! get the text string + virtual const wchar_t* getText() const _IRR_OVERRIDE_; + + //! Get the font used to draw the text + virtual gui::IGUIFont* getFont() const _IRR_OVERRIDE_; //! sets the size of the billboard virtual void setSize(const core::dimension2d& size) _IRR_OVERRIDE_; @@ -98,7 +113,7 @@ namespace scene virtual u32 getMaterialCount() const _IRR_OVERRIDE_; //! Returns type of the scene node - virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_TEXT; } + virtual ESCENE_NODE_TYPE getType() const _IRR_OVERRIDE_ { return ESNT_BILLBOARD_TEXT; } //! Set the color of all vertices of the billboard //! \param overallColor: the color to set @@ -129,7 +144,6 @@ namespace scene private: core::stringw Text; - video::SColor Color; gui::IGUIFontBitmap* Font; core::dimension2d Size; diff --git a/source/Irrlicht/CTriangleBBSelector.cpp b/source/Irrlicht/CTriangleBBSelector.cpp index 547b2495..d752a044 100644 --- a/source/Irrlicht/CTriangleBBSelector.cpp +++ b/source/Irrlicht/CTriangleBBSelector.cpp @@ -21,60 +21,68 @@ CTriangleBBSelector::CTriangleBBSelector(ISceneNode* node) Triangles.set_used(12); // a box has 12 triangles. } - - //! Gets all triangles. void CTriangleBBSelector::getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, - const core::matrix4* transform) const + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const { - if (!SceneNode) - return; - - // construct triangles - const core::aabbox3d& box = SceneNode->getBoundingBox(); - core::vector3df edges[8]; - box.getEdges(edges); - - Triangles[0].set( edges[3], edges[0], edges[2]); - Triangles[1].set( edges[3], edges[1], edges[0]); - - Triangles[2].set( edges[3], edges[2], edges[7]); - Triangles[3].set( edges[7], edges[2], edges[6]); - - Triangles[4].set( edges[7], edges[6], edges[4]); - Triangles[5].set( edges[5], edges[7], edges[4]); - - Triangles[6].set( edges[5], edges[4], edges[0]); - Triangles[7].set( edges[5], edges[0], edges[1]); - - Triangles[8].set( edges[1], edges[3], edges[7]); - Triangles[9].set( edges[1], edges[7], edges[5]); - - Triangles[10].set(edges[0], edges[6], edges[2]); - Triangles[11].set(edges[0], edges[4], edges[6]); + fillTriangles(); // call parent - CTriangleSelector::getTriangles(triangles, arraySize, outTriangleCount, transform); + CTriangleSelector::getTriangles(triangles, arraySize, outTriangleCount, transform, useNodeTransform, outTriangleInfo); } void CTriangleBBSelector::getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, const core::aabbox3d& box, - const core::matrix4* transform) const + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const { - return getTriangles(triangles, arraySize, outTriangleCount, transform); + fillTriangles(); + return CTriangleSelector::getTriangles(triangles, arraySize, outTriangleCount, box, transform, useNodeTransform, outTriangleInfo); } void CTriangleBBSelector::getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, const core::line3d& line, - const core::matrix4* transform) const + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const { - return getTriangles(triangles, arraySize, outTriangleCount, transform); + fillTriangles(); + return CTriangleSelector::getTriangles(triangles, arraySize, outTriangleCount, line, transform, useNodeTransform, outTriangleInfo); +} + +void CTriangleBBSelector::fillTriangles() const +{ + if (SceneNode) + { + // construct triangles + const core::aabbox3d& box = SceneNode->getBoundingBox(); + core::vector3df edges[8]; + box.getEdges(edges); + + // yeah, not really const... Triangles are mutable + Triangles[0].set( edges[3], edges[0], edges[2]); + Triangles[1].set( edges[3], edges[1], edges[0]); + + Triangles[2].set( edges[3], edges[2], edges[7]); + Triangles[3].set( edges[7], edges[2], edges[6]); + + Triangles[4].set( edges[7], edges[6], edges[4]); + Triangles[5].set( edges[5], edges[7], edges[4]); + + Triangles[6].set( edges[5], edges[4], edges[0]); + Triangles[7].set( edges[5], edges[0], edges[1]); + + Triangles[8].set( edges[1], edges[3], edges[7]); + Triangles[9].set( edges[1], edges[7], edges[5]); + + Triangles[10].set(edges[0], edges[6], edges[2]); + Triangles[11].set(edges[0], edges[4], edges[6]); + } } } // end namespace scene } // end namespace irr - diff --git a/source/Irrlicht/CTriangleBBSelector.h b/source/Irrlicht/CTriangleBBSelector.h index 5e09c312..b4444a33 100644 --- a/source/Irrlicht/CTriangleBBSelector.h +++ b/source/Irrlicht/CTriangleBBSelector.h @@ -22,16 +22,22 @@ public: //! Gets all triangles. virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, - const core::matrix4* transform=0) const _IRR_OVERRIDE_; + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; //! Gets all triangles which lie within a specific bounding box. virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, - const core::aabbox3d& box, const core::matrix4* transform=0) const _IRR_OVERRIDE_; + const core::aabbox3d& box, const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; //! Gets all triangles which have or may have contact with a 3d line. virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, const core::line3d& line, - const core::matrix4* transform=0) const _IRR_OVERRIDE_; + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; + +protected: + void fillTriangles() const; }; diff --git a/source/Irrlicht/CTriangleSelector.cpp b/source/Irrlicht/CTriangleSelector.cpp index 8b9b948b..0342b349 100644 --- a/source/Irrlicht/CTriangleSelector.cpp +++ b/source/Irrlicht/CTriangleSelector.cpp @@ -15,7 +15,7 @@ namespace scene //! constructor CTriangleSelector::CTriangleSelector(ISceneNode* node) -: SceneNode(node), AnimatedNode(0), LastMeshFrame(0) +: SceneNode(node), MeshBuffer(0), MaterialIndex(0), AnimatedNode(0), LastMeshFrame(0) { #ifdef _DEBUG setDebugName("CTriangleSelector"); @@ -27,7 +27,7 @@ CTriangleSelector::CTriangleSelector(ISceneNode* node) //! constructor CTriangleSelector::CTriangleSelector(const core::aabbox3d& box, ISceneNode* node) -: SceneNode(node), AnimatedNode(0), LastMeshFrame(0) +: SceneNode(node), MeshBuffer(0), MaterialIndex(0), AnimatedNode(0), LastMeshFrame(0) { #ifdef _DEBUG setDebugName("CTriangleSelector"); @@ -39,18 +39,27 @@ CTriangleSelector::CTriangleSelector(const core::aabbox3d& box, ISceneNode* //! constructor -CTriangleSelector::CTriangleSelector(const IMesh* mesh, ISceneNode* node) -: SceneNode(node), AnimatedNode(0), LastMeshFrame(0) +CTriangleSelector::CTriangleSelector(const IMesh* mesh, ISceneNode* node, bool separateMeshbuffers) +: SceneNode(node), MeshBuffer(0), MaterialIndex(0), AnimatedNode(0), LastMeshFrame(0) { #ifdef _DEBUG setDebugName("CTriangleSelector"); #endif - createFromMesh(mesh); + createFromMesh(mesh, separateMeshbuffers); } +CTriangleSelector::CTriangleSelector(const IMeshBuffer* meshBuffer, irr::u32 materialIndex, ISceneNode* node) + : SceneNode(node), MeshBuffer(meshBuffer), MaterialIndex(materialIndex), AnimatedNode(0), LastMeshFrame(0) +{ + #ifdef _DEBUG + setDebugName("CTriangleSelector"); + #endif -CTriangleSelector::CTriangleSelector(IAnimatedMeshSceneNode* node) + createFromMeshBuffer(meshBuffer); +} + +CTriangleSelector::CTriangleSelector(IAnimatedMeshSceneNode* node, bool separateMeshbuffers) : SceneNode(node), AnimatedNode(node), LastMeshFrame(0) { #ifdef _DEBUG @@ -68,22 +77,51 @@ CTriangleSelector::CTriangleSelector(IAnimatedMeshSceneNode* node) IMesh* mesh = animatedMesh->getMesh(LastMeshFrame); if (mesh) - createFromMesh(mesh); + createFromMesh(mesh, separateMeshbuffers); } -void CTriangleSelector::createFromMesh(const IMesh* mesh) +void CTriangleSelector::createFromMesh(const IMesh* mesh, bool createBufferRanges) { + BufferRanges.clear(); + Triangles.clear(); + const u32 cnt = mesh->getMeshBufferCount(); u32 totalFaceCount = 0; for (u32 j=0; jgetMeshBuffer(j)->getIndexCount(); - totalFaceCount /= 3; + { + SCollisionTriangleRange range; + range.MeshBuffer = mesh->getMeshBuffer(j); + range.MaterialIndex = j; + range.RangeSize = range.MeshBuffer->getIndexCount() / 3; + + if ( createBufferRanges ) + { + range.RangeStart = totalFaceCount; + + BufferRanges.push_back(range); + } + + totalFaceCount += range.RangeSize; + } Triangles.set_used(totalFaceCount); updateFromMesh(mesh); } +void CTriangleSelector::createFromMeshBuffer(const IMeshBuffer* meshBuffer) +{ + BufferRanges.clear(); + Triangles.clear(); + + if ( meshBuffer ) + { + Triangles.set_used(meshBuffer->getIndexCount() / 3); + } + + updateFromMeshBuffer(meshBuffer); +} + template static void updateTriangles(u32& triangleCount, core::array& triangles, u32 idxCnt, const TIndex* indices, const u8* vertices, u32 vertexPitch, const core::matrix4* bufferTransform) { @@ -151,10 +189,41 @@ void CTriangleSelector::updateFromMesh(const IMesh* mesh) const } // Update bounding box - if ( triangleCount ) + updateBoundingBox(); +} + +void CTriangleSelector::updateFromMeshBuffer(const IMeshBuffer* meshBuffer) const +{ + if ( !meshBuffer ) + return; + + u32 idxCnt = meshBuffer->getIndexCount(); + u32 vertexPitch = getVertexPitchFromType(meshBuffer->getVertexType()); + u8* vertices = (u8*)meshBuffer->getVertices(); + u32 triangleCount = 0; + switch ( meshBuffer->getIndexType() ) + { + case video::EIT_16BIT: + { + const u16* indices = meshBuffer->getIndices(); + updateTriangles(triangleCount, Triangles, idxCnt, indices, vertices, vertexPitch, 0); + } + break; + case video::EIT_32BIT: + { + const u32* indices = (u32*)meshBuffer->getIndices(); + updateTriangles(triangleCount, Triangles, idxCnt, indices, vertices, vertexPitch, 0); + } + break; + } +} + +void CTriangleSelector::updateBoundingBox() const +{ + if ( !Triangles.empty() ) { BoundingBox.reset( Triangles[0].pointA ); - for (u32 i=0; i < triangleCount; ++i) + for (u32 i=0; i < Triangles.size(); ++i) { const core::triangle3df& tri = Triangles[i]; BoundingBox.addInternalPoint(tri.pointA); @@ -168,7 +237,6 @@ void CTriangleSelector::updateFromMesh(const IMesh* mesh) const } } - void CTriangleSelector::update(void) const { if (!AnimatedNode) @@ -194,7 +262,8 @@ void CTriangleSelector::update(void) const //! Gets all triangles. void CTriangleSelector::getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, - const core::matrix4* transform) const + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const { // Update my triangles if necessary update(); @@ -206,7 +275,7 @@ void CTriangleSelector::getTriangles(core::triangle3df* triangles, core::matrix4 mat; if (transform) mat = *transform; - if (SceneNode) + if (SceneNode&&useNodeTransform) mat *= SceneNode->getAbsoluteTransformation(); for (u32 i=0; i(this); + triRange.SceneNode = SceneNode; + triRange.MeshBuffer = MeshBuffer; + triRange.MaterialIndex = MaterialIndex; + outTriangleInfo->push_back(triRange); + } + else + { + irr::u32 rangeIndex = 0; + for (u32 i=0; i= (BufferRanges[rangeIndex].RangeStart + BufferRanges[rangeIndex].RangeSize) ) + ++rangeIndex; + + SCollisionTriangleRange triRange; + + triRange.MaterialIndex = BufferRanges[rangeIndex].MaterialIndex; + triRange.MeshBuffer = BufferRanges[rangeIndex].MeshBuffer; + triRange.RangeStart = BufferRanges[rangeIndex].RangeStart; + triRange.RangeSize = core::min_( cnt-BufferRanges[rangeIndex].RangeStart, BufferRanges[rangeIndex].RangeSize); + triRange.Selector = const_cast(this); + triRange.SceneNode = SceneNode; + outTriangleInfo->push_back(triRange); + + i += triRange.RangeSize; + } + } + } + outTriangleCount = cnt; } @@ -224,7 +330,8 @@ void CTriangleSelector::getTriangles(core::triangle3df* triangles, void CTriangleSelector::getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, const core::aabbox3d& box, - const core::matrix4* transform) const + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const { // Update my triangles if necessary update(); @@ -232,16 +339,23 @@ void CTriangleSelector::getTriangles(core::triangle3df* triangles, core::matrix4 mat(core::matrix4::EM4CONST_NOTHING); core::aabbox3df tBox(box); - if (SceneNode) + if (SceneNode && useNodeTransform) { - SceneNode->getAbsoluteTransformation().getInverse(mat); - mat.transformBoxEx(tBox); + if ( SceneNode->getAbsoluteTransformation().getInverse(mat) ) + mat.transformBoxEx(tBox); + else + { + // TODO: else is not yet handled optimally. + // If a node has an axis scaled to 0 we return all triangles without any check + return getTriangles(triangles, arraySize, outTriangleCount, + transform, useNodeTransform, outTriangleInfo ); + } } if (transform) mat = *transform; else mat.makeIdentity(); - if (SceneNode) + if (SceneNode && useNodeTransform) mat *= SceneNode->getAbsoluteTransformation(); outTriangleCount = 0; @@ -251,22 +365,80 @@ void CTriangleSelector::getTriangles(core::triangle3df* triangles, s32 triangleCount = 0; const u32 cnt = Triangles.size(); - for (u32 i=0; i(this); + triRange.SceneNode = SceneNode; + triRange.RangeStart = triangleCount; + triRange.MeshBuffer = BufferRanges[activeRange].MeshBuffer; + triRange.MaterialIndex = BufferRanges[activeRange].MaterialIndex; - triangles[triangleCount] = Triangles[i]; - mat.transformVect(triangles[triangleCount].pointA); - mat.transformVect(triangles[triangleCount].pointB); - mat.transformVect(triangles[triangleCount].pointC); + for (u32 i=0; i= BufferRanges[activeRange].RangeStart + BufferRanges[activeRange].RangeSize ) + { + triRange.RangeSize = triangleCount-triRange.RangeStart; + if ( triRange.RangeSize > 0 ) + outTriangleInfo->push_back(triRange); - if (triangleCount == arraySize) - break; + ++activeRange; + triRange.RangeStart = triangleCount; + triRange.MeshBuffer = BufferRanges[activeRange].MeshBuffer; + triRange.MaterialIndex = BufferRanges[activeRange].MaterialIndex; + } + + triangles[triangleCount] = Triangles[i]; + mat.transformVect(triangles[triangleCount].pointA); + mat.transformVect(triangles[triangleCount].pointB); + mat.transformVect(triangles[triangleCount].pointC); + + ++triangleCount; + + if (triangleCount == arraySize) + break; + } + triRange.RangeSize = triangleCount-triRange.RangeStart; + if ( triRange.RangeSize > 0 ) + outTriangleInfo->push_back(triRange); + } + else + { + for (u32 i=0; i(this); + triRange.SceneNode = SceneNode; + triRange.MeshBuffer = MeshBuffer; + triRange.MaterialIndex = MaterialIndex; + outTriangleInfo->push_back(triRange); + } } outTriangleCount = triangleCount; @@ -277,7 +449,8 @@ void CTriangleSelector::getTriangles(core::triangle3df* triangles, void CTriangleSelector::getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, const core::line3d& line, - const core::matrix4* transform) const + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const { // Update my triangles if necessary update(); @@ -287,7 +460,7 @@ void CTriangleSelector::getTriangles(core::triangle3df* triangles, // TODO: Could be optimized for line a little bit more. getTriangles(triangles, arraySize, outTriangleCount, - box, transform); + box, transform, useNodeTransform, outTriangleInfo); } diff --git a/source/Irrlicht/CTriangleSelector.h b/source/Irrlicht/CTriangleSelector.h index 7ec93b1b..01acacff 100644 --- a/source/Irrlicht/CTriangleSelector.h +++ b/source/Irrlicht/CTriangleSelector.h @@ -27,27 +27,33 @@ public: CTriangleSelector(ISceneNode* node); //! Constructs a selector based on a mesh - CTriangleSelector(const IMesh* mesh, ISceneNode* node); + CTriangleSelector(const IMesh* mesh, ISceneNode* node, bool separateMeshbuffers); + + //! Constructs a selector based on a meshbuffer + CTriangleSelector(const IMeshBuffer* meshBuffer, irr::u32 materialIndex, ISceneNode* node); //! Constructs a selector based on an animated mesh scene node //!\param node An animated mesh scene node, which must have a valid mesh - CTriangleSelector(IAnimatedMeshSceneNode* node); + CTriangleSelector(IAnimatedMeshSceneNode* node, bool separateMeshbuffers); //! Constructs a selector based on a bounding box CTriangleSelector(const core::aabbox3d& box, ISceneNode* node); //! Gets all triangles. virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, - const core::matrix4* transform=0) const _IRR_OVERRIDE_; + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; //! Gets all triangles which lie within a specific bounding box. virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, - const core::aabbox3d& box, const core::matrix4* transform=0) const _IRR_OVERRIDE_; + const core::aabbox3d& box, const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; //! Gets all triangles which have or may have contact with a 3d line. virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, const core::line3d& line, - const core::matrix4* transform=0) const _IRR_OVERRIDE_; + const core::matrix4* transform, bool useNodeTransform, + irr::core::array* outTriangleInfo) const _IRR_OVERRIDE_; //! Returns amount of all available triangles in this selector virtual s32 getTriangleCount() const _IRR_OVERRIDE_; @@ -66,20 +72,33 @@ public: protected: //! Create from a mesh - virtual void createFromMesh(const IMesh* mesh); + virtual void createFromMesh(const IMesh* mesh, bool createBufferRanges); + + //! Create from a meshbuffer + virtual void createFromMeshBuffer(const IMeshBuffer* meshBuffer); //! Update when the mesh has changed virtual void updateFromMesh(const IMesh* mesh) const; + //! Update when the meshbuffer has changed + virtual void updateFromMeshBuffer(const IMeshBuffer* meshBuffer) const; + + //! Update bounding box from triangles + void updateBoundingBox() const; + //! Update the triangle selector, which will only have an effect if it //! was built from an animated mesh and that mesh's frame has changed //! since the last time it was updated. virtual void update(void) const; + irr::core::array BufferRanges; + ISceneNode* SceneNode; mutable core::array Triangles; // (mutable for CTriangleBBSelector) mutable core::aabbox3df BoundingBox; // Allows for trivial rejection + const IMeshBuffer* MeshBuffer; // non-zero when the selector is for a single meshbuffer + irr::u32 MaterialIndex; // Only set when MeshBuffer is non-zero IAnimatedMeshSceneNode* AnimatedNode; mutable u32 LastMeshFrame; }; @@ -87,6 +106,4 @@ protected: } // end namespace scene } // end namespace irr - #endif - diff --git a/source/Irrlicht/CWriteFile.cpp b/source/Irrlicht/CWriteFile.cpp index 657825e2..ef816b6b 100644 --- a/source/Irrlicht/CWriteFile.cpp +++ b/source/Irrlicht/CWriteFile.cpp @@ -111,7 +111,7 @@ bool CWriteFile::flush() if (!isOpen()) return false; - return !(bool) fflush(File); + return fflush(File) == 0; // 0 indicates success, otherwise EOF and errno is set } IWriteFile* CWriteFile::createWriteFile(const io::path& fileName, bool append) diff --git a/source/Irrlicht/CXMLReader.cpp b/source/Irrlicht/CXMLReader.cpp index cc9f3e08..b6aa3187 100644 --- a/source/Irrlicht/CXMLReader.cpp +++ b/source/Irrlicht/CXMLReader.cpp @@ -33,7 +33,7 @@ namespace io //! Reads an amount of bytes from the file. virtual int read(void* buffer, int sizeToRead) { - return ReadFile->read(buffer, sizeToRead); + return (int)ReadFile->read(buffer, sizeToRead); } //! Returns size of file in bytes diff --git a/source/Irrlicht/CXMLReaderImpl.h b/source/Irrlicht/CXMLReaderImpl.h index d7021484..42a138be 100644 --- a/source/Irrlicht/CXMLReaderImpl.h +++ b/source/Irrlicht/CXMLReaderImpl.h @@ -136,11 +136,11 @@ public: //! Returns the value of an attribute as integer. - virtual int getAttributeValueAsInt(const char_type* name) const _IRR_OVERRIDE_ + virtual int getAttributeValueAsInt(const char_type* name, int defaultNotFound) const _IRR_OVERRIDE_ { const SAttribute* attr = getAttributeByName(name); if (!attr) - return 0; + return defaultNotFound; core::stringc c(attr->Value.c_str()); return core::strtol10(c.c_str()); @@ -148,11 +148,11 @@ public: //! Returns the value of an attribute as integer. - virtual int getAttributeValueAsInt(int idx) const _IRR_OVERRIDE_ + virtual int getAttributeValueAsInt(int idx, int defaultNotFound) const _IRR_OVERRIDE_ { const char_type* attrvalue = getAttributeValue(idx); if (!attrvalue) - return 0; + return defaultNotFound; core::stringc c(attrvalue); return core::strtol10(c.c_str()); @@ -160,11 +160,11 @@ public: //! Returns the value of an attribute as float. - virtual float getAttributeValueAsFloat(const char_type* name) const _IRR_OVERRIDE_ + virtual float getAttributeValueAsFloat(const char_type* name, float defaultNotFound) const _IRR_OVERRIDE_ { const SAttribute* attr = getAttributeByName(name); if (!attr) - return 0; + return defaultNotFound; core::stringc c = attr->Value.c_str(); return core::fast_atof(c.c_str()); @@ -172,11 +172,11 @@ public: //! Returns the value of an attribute as float. - virtual float getAttributeValueAsFloat(int idx) const _IRR_OVERRIDE_ + virtual float getAttributeValueAsFloat(int idx, float defaultNotFound) const _IRR_OVERRIDE_ { const char_type* attrvalue = getAttributeValue(idx); if (!attrvalue) - return 0; + return defaultNotFound; core::stringc c = attrvalue; return core::fast_atof(c.c_str()); diff --git a/source/Irrlicht/Irrlicht14.0.vcxproj b/source/Irrlicht/Irrlicht14.0.vcxproj index 3cf8129c..24247ea1 100644 --- a/source/Irrlicht/Irrlicht14.0.vcxproj +++ b/source/Irrlicht/Irrlicht14.0.vcxproj @@ -62,6 +62,7 @@ Irrlicht {E08E042A-6C45-411B-92BE-3CC31331019F} Irrlicht + 8.1 diff --git a/source/Irrlicht/aesGladman/fileenc.cpp b/source/Irrlicht/aesGladman/fileenc.cpp index 4e76c775..982d9c4e 100644 --- a/source/Irrlicht/aesGladman/fileenc.cpp +++ b/source/Irrlicht/aesGladman/fileenc.cpp @@ -131,10 +131,8 @@ void fcrypt_decrypt(unsigned char data[], unsigned int data_len, fcrypt_ctx cx[1 int fcrypt_end(unsigned char mac[], fcrypt_ctx cx[1]) { - unsigned int res = cx->mode; - hmac_sha_end(mac, MAC_LENGTH(cx->mode), cx->auth_ctx); memset(cx, 0, sizeof(fcrypt_ctx)); /* clear the encryption context */ - return MAC_LENGTH(res); /* return MAC length in bytes */ + return MAC_LENGTH(cx->mode); /* return MAC length in bytes */ } diff --git a/tests/Makefile b/tests/Makefile index 193434dc..83b4b26b 100644 --- a/tests/Makefile +++ b/tests/Makefile @@ -3,8 +3,12 @@ Target = tests Sources = $(wildcard *.cpp) CPPFLAGS = -I../include -I/usr/X11R6/include -pipe -# CXXFLAGS += -O3 -CXXFLAGS += -Wall -ansi -pedantic -O0 -g -D_DEBUG -fno-exceptions +CXXFLAGS += -Wall -ansi -pedantic -fno-exceptions +ifndef NDEBUG +CXXFLAGS += -O0 -g -D_DEBUG +else +CXXFLAGS += -fexpensive-optimizations -O3 +endif ifeq ($(HOSTTYPE), x86_64) LIBSELECT=64 diff --git a/tests/fast_atof.cpp b/tests/fast_atof.cpp index 01599dda..46ecb573 100644 --- a/tests/fast_atof.cpp +++ b/tests/fast_atof.cpp @@ -148,6 +148,8 @@ bool test_fast_atof(void) accurate &= testCalculation_atof("0000123456.789"); accurate &= testCalculation_atof("-0000123456.789"); accurate &= testCalculation_atof("-0.0690462109446526"); + accurate &= testCalculation_atof("0.11999999731779099"); // more numbers past dot than in lookup table + accurate &= testCalculation_atof("0.119999997317790999"); if (!accurate) { diff --git a/tests/irrArray.cpp b/tests/irrArray.cpp index 674489c8..12d46b32 100644 --- a/tests/irrArray.cpp +++ b/tests/irrArray.cpp @@ -113,6 +113,56 @@ static bool testSwap() return result; } +// add numbers to the array going down from size to 1 +static void addInvNumbers(irr::core::array& arr, irr::u32 size) +{ + for ( irr::u32 i=0; i& arr) +{ + for ( irr::u32 i=1; i< arr.size(); ++ i) + { + if ( arr[i-1] > arr[i] ) + return false; + } + + return true; +} + +static bool testSort() +{ + irr::core::array arr; + for ( irr::u32 i=0; i<1000; ++i ) + { + arr.clear(); + addInvNumbers(arr, i); + arr.sort(); + if ( !validateSortedAscending(arr) ) + { + return false; + } + } + + for ( irr::u32 i=0; i<1000; ++i ) + { + arr.clear(); + addInvNumbers(arr, i); + addInvNumbers(arr, i); + arr.sort(); + if ( !validateSortedAscending(arr) ) + { + return false; + } + } + + return true; +} + // Test the functionality of core::array bool testIrrArray(void) { @@ -123,6 +173,7 @@ bool testIrrArray(void) allExpected &= testSelfAssignment(); allExpected &= testSwap(); allExpected &= testErase(); + allExpected &= testSort(); if(allExpected) logTestString("\nAll tests passed\n"); diff --git a/tests/line2d.cpp b/tests/line2d.cpp new file mode 100644 index 00000000..eda2d543 --- /dev/null +++ b/tests/line2d.cpp @@ -0,0 +1,79 @@ +// Copyright (C) 2017 Dario Oliveri +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" + +#include + +using namespace irr; +using namespace irr::core; + +#define EXPECT( condition, value, name) if( condition != value) \ + { std::cout<< name << ": test failed"<< std::endl; return false;} + +//! Tests the basic functionality of the software device. +bool line2DTest(void) +{ + { + line2d< f32> a(0, 0, 0, 1); + line2d< f32> b(2, 0, 2, 1); + line2d< f32> c(2, 0, 2, 1 + 0.00001f); + + EXPECT( a.nearlyParallel( b), true, "parallel Lines are parallel"); + EXPECT( a.nearlyParallel( c, (f32)32), true, "nearly parallel lines are parallel"); + } + + { + line2d< f32> a( 0, 0, 0, 1); + line2d< f32> b( 0, 2, 2, 1); + EXPECT( a.nearlyParallel( b, 1), false, "orthogonal lines are NOT parallel"); + } + + { + line2d< f32> a( 0, 0, 100, 100); + line2d< f32> b( 100, 0, 0, 100); + + EXPECT( a.nearlyParallel( b, 1), false, "orthogonal lines are NOT parallel 2"); + + vector2df t = a.fastLinesIntersection( b); + vector2df u = vector2df( 50.0f, 50.0f); + + EXPECT( t.equals( u, roundingError() ), true, "fast intersection in known point"); + + EXPECT( a .intersectAsSegments(b), true, "intersect as Segments"); + + EXPECT( a.incidentSegments(b), true, "incidentSegments"); + + vector2df out; + EXPECT( a.lineIntersectSegment( b, out), true, "lineIntersectSegment"); + EXPECT( t.equals( out), true, "line intersect segment in known point"); + + EXPECT( a.isPointBetweenStartAndEnd( out), true, "point isBetween StartEnd of first line"); + EXPECT( b.isPointBetweenStartAndEnd( out), true, "point isBetween StartEnd of second line"); + + EXPECT( a.isPointOnLine( out), true, "is point on first line"); + EXPECT( b.isPointOnLine( out), true, "is point on second line"); + + EXPECT( out.isBetweenPoints( a.start, a.end), true, "test point is on segment with first line"); + EXPECT( out.isBetweenPoints( b.start, b.end), true, "test point is on segment with first line"); + } + + { + vector2df a( 0, 0); + vector2df b( 10, 0); + vector2df c( 0, 10); + vector2df d( 0, 40); + + EXPECT( a.areClockwise( c, b), true, "test if points are clockwise"); + EXPECT( a.areClockwise( b, c), false, "test if points are NOT clockwise"); + EXPECT( a.areCounterClockwise( b, c), true, "test if points are counter clockwise"); + EXPECT( a.areCounterClockwise( c, b), false, "test if points are NOT counter clockwise"); + + EXPECT( a.checkOrientation( c, b), 1, "test if orientation is clockwise"); + EXPECT( a.checkOrientation( b, c), 2, "test if orientation is anticlockwise"); + EXPECT( a.checkOrientation( c, d), 0, "test if orientation is colinear"); + EXPECT( a.checkOrientation( d, c), 0, "test if orientation is colinear 2"); + } + + return true; +} diff --git a/tests/main.cpp b/tests/main.cpp index 30323ee8..83cdcf70 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -129,6 +129,7 @@ int main(int argumentCount, char * arguments[]) TEST(terrainSceneNode); TEST(lightMaps); TEST(triangleSelector); + TEST(line2DTest); unsigned int numberOfTests = tests.size(); unsigned int testToRun = 0; diff --git a/tests/testUtils.cpp b/tests/testUtils.cpp index a77f5876..a34c947f 100644 --- a/tests/testUtils.cpp +++ b/tests/testUtils.cpp @@ -1,20 +1,16 @@ // Copyright (C) 2008-2012 Colin MacDonald // No rights reserved: this software is in the public domain. -#if defined(_MSC_VER) -#define _CRT_SECURE_NO_WARNINGS 1 -#define TESTING_ON_WINDOWS -#endif // _MSC_VER - #include "testUtils.h" #include #include #include #include -#if defined(TESTING_ON_WINDOWS) +#if defined(_MSC_VER) || defined(_IRR_WINDOWS_API_) +#define _CRT_SECURE_NO_WARNINGS 1 #include // For OutputDebugString() -#endif // #if defined(TESTING_ON_WINDOWS) +#endif // _MSC_VER || _IRR_WINDOWS_API_ using namespace irr; diff --git a/tests/tests.cbp b/tests/tests.cbp index cecdd499..f5d2dd10 100644 --- a/tests/tests.cbp +++ b/tests/tests.cbp @@ -107,6 +107,7 @@ + diff --git a/tests/tests_vc10.vcxproj b/tests/tests_vc10.vcxproj index 4903797c..8e225799 100644 --- a/tests/tests_vc10.vcxproj +++ b/tests/tests_vc10.vcxproj @@ -179,6 +179,7 @@ + diff --git a/tests/tests_vc11.vcxproj b/tests/tests_vc11.vcxproj index 17817a4a..ec454632 100644 --- a/tests/tests_vc11.vcxproj +++ b/tests/tests_vc11.vcxproj @@ -179,6 +179,7 @@ + diff --git a/tests/tests_vc12.vcxproj b/tests/tests_vc12.vcxproj index a561f7f7..91a313c7 100644 --- a/tests/tests_vc12.vcxproj +++ b/tests/tests_vc12.vcxproj @@ -179,6 +179,7 @@ + diff --git a/tests/tests_vc14.vcxproj b/tests/tests_vc14.vcxproj index 70c2464d..07229875 100644 --- a/tests/tests_vc14.vcxproj +++ b/tests/tests_vc14.vcxproj @@ -179,6 +179,7 @@ + diff --git a/tools/IrrFontTool/newFontTool/CFontTool.cpp b/tools/IrrFontTool/newFontTool/CFontTool.cpp index 780e9b05..7c957ed9 100644 --- a/tools/IrrFontTool/newFontTool/CFontTool.cpp +++ b/tools/IrrFontTool/newFontTool/CFontTool.cpp @@ -132,7 +132,7 @@ inline u32 getTextureSizeFromSurfaceSize(u32 size) wchar_t currentchar = ch; if ( IsDBCSLeadByte((BYTE) ch)) - continue; // surragate pairs unsupported + continue; // surrogate pairs unsupported // get the dimensions SIZE size; @@ -144,9 +144,9 @@ inline u32 getTextureSizeFromSurfaceSize(u32 size) if (GetCharABCWidthsW(dc, currentchar, currentchar, &abc)) // for unicode fonts, get overhang, underhang, width { - size.cx = abc.abcB; - fa.underhang = abc.abcA; - fa.overhang = abc.abcC; + size.cx = abc.abcB; // full font width (ignoring padding/underhang ) + fa.underhang = abc.abcA; // underhang/padding left - can also be negative (in which case it's overhang left) + fa.overhang = abc.abcC; // overhang/padding right - can also be negative (in which case it's underhand right) if (abc.abcB-abc.abcA+abc.abcC<1) continue; // nothing of width 0 @@ -236,7 +236,7 @@ inline u32 getTextureSizeFromSurfaceSize(u32 size) { s32 currentArea = (*it).getValue(); wchar_t wch = (*it).getKey(); - // sloppy but I couldnt be bothered rewriting it + // sloppy but I couldn't be bothered rewriting it if (Areas[currentArea].sourceimage == currentImage) { // draw letter diff --git a/tools/IrrFontTool/newFontTool/main.cpp b/tools/IrrFontTool/newFontTool/main.cpp index b6f85d7e..2b36547e 100644 --- a/tools/IrrFontTool/newFontTool/main.cpp +++ b/tools/IrrFontTool/newFontTool/main.cpp @@ -2,7 +2,7 @@ Tool for creating Irrlicht bitmap+vector fonts, started by Gaz Davidson in December 2006 - Due to my laziness and Microsoft's unituitive API, surragate pairs and + Due to my laziness and Microsoft's unintuitive API, surrogate pairs and nonspacing diacritical marks are not supported! Linux bitmap font support added by Neil Burlock Oct 2008