From 55e2c6d600f54669ea2079c96ea73728f49b8f3f Mon Sep 17 00:00:00 2001 From: hybrid Date: Tue, 27 Jan 2009 13:23:36 +0000 Subject: [PATCH] Merged from trunk, all revisions from 1977 to 2143. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@2144 dfc29bdd-3216-0410-991c-e03cc46cb475 --- changes.txt | 65 +- examples/01.HelloWorld/main.cpp | 4 +- examples/02.Quake3Map/Makefile | 7 +- examples/02.Quake3Map/main.cpp | 13 +- examples/03.CustomSceneNode/main.cpp | 2 +- examples/04.Movement/main.cpp | 2 +- examples/05.UserInterface/main.cpp | 2 +- examples/06.2DGraphics/main.cpp | 2 +- examples/07.Collision/main.cpp | 31 +- examples/08.SpecialFX/main.cpp | 2 +- examples/09.Meshviewer/main.cpp | 4 +- examples/10.Shaders/main.cpp | 2 +- examples/11.PerPixelLighting/main.cpp | 2 +- examples/12.TerrainRendering/main.cpp | 48 +- examples/13.RenderToTexture/main.cpp | 4 +- examples/15.LoadIrrFile/main.cpp | 2 +- examples/16.Quake3MapShader/main.cpp | 2 +- examples/17.HelloWorld_Mobile/main.cpp | 2 + examples/18.SplitScreen/main.cpp | 5 +- examples/19.MouseAndJoystick/main.cpp | 5 +- examples/20.ManagedLights/Makefile | 39 + examples/20.ManagedLights/ManagedLights.cbp | 38 + examples/20.ManagedLights/ManagedLights.sln | 17 + .../20.ManagedLights/ManagedLights.vcproj | 230 +++++ .../20.ManagedLights/ManagedLights_vc8.vcproj | 231 +++++ .../20.ManagedLights/ManagedLights_vc9.vcproj | 231 +++++ examples/20.ManagedLights/example.dev | 59 ++ examples/20.ManagedLights/main.cpp | 400 ++++++++ examples/BuildAllExamples.workspace | 3 +- examples/BuildAllExamples_v7.sln | 2 + examples/BuildAllExamples_v8.sln | 6 + examples/BuildAllExamples_v9.sln | 4 +- examples/Demo/CDemo.cpp | 10 +- examples/Demo/CMainMenu.cpp | 4 +- examples/Demo/main.cpp | 2 +- include/CDynamicMeshBuffer.h | 2 +- include/CIndexBuffer.h | 2 +- include/CMeshBuffer.h | 2 +- include/CVertexBuffer.h | 2 +- include/ECullingTypes.h | 2 +- include/EDebugSceneTypes.h | 2 +- include/EDriverFeatures.h | 8 +- include/EDriverTypes.h | 51 +- include/EGUIAlignment.h | 3 +- include/EGUIElementTypes.h | 5 +- include/EHardwareBufferFlags.h | 2 +- include/EMaterialFlags.h | 8 +- include/EMaterialTypes.h | 267 +++-- include/EMeshWriterEnums.h | 2 +- include/EMessageBoxFlags.h | 3 +- include/ESceneNodeAnimatorTypes.h | 5 +- include/ESceneNodeTypes.h | 6 +- include/ETerrainElements.h | 2 +- include/IAnimatedMesh.h | 2 +- include/IAnimatedMeshMD2.h | 2 +- include/IAnimatedMeshMD3.h | 2 +- include/IAnimatedMeshSceneNode.h | 2 +- include/IAttributeExchangingObject.h | 2 +- include/IAttributes.h | 2 +- include/IBillboardSceneNode.h | 2 +- include/IBillboardTextSceneNode.h | 2 +- include/IBoneSceneNode.h | 2 +- include/ICameraSceneNode.h | 4 +- include/ICursorControl.h | 2 +- include/IDummyTransformationSceneNode.h | 2 +- include/IDynamicMeshBuffer.h | 2 +- include/IEventReceiver.h | 4 +- include/IFileList.h | 2 +- include/IFileSystem.h | 21 +- include/IGPUProgrammingServices.h | 2 +- include/IGUIButton.h | 2 +- include/IGUICheckBox.h | 2 +- include/IGUIColorSelectDialog.h | 2 +- include/IGUIComboBox.h | 10 +- include/IGUIContextMenu.h | 6 +- include/IGUIEditBox.h | 14 +- include/IGUIElement.h | 109 ++- include/IGUIElementFactory.h | 2 +- include/IGUIEnvironment.h | 63 +- include/IGUIFileOpenDialog.h | 2 +- include/IGUIFont.h | 16 +- include/IGUIFontBitmap.h | 2 +- include/IGUIImage.h | 2 +- include/IGUIInOutFader.h | 25 +- include/IGUIListBox.h | 24 +- include/IGUIMeshViewer.h | 2 +- include/IGUIScrollBar.h | 12 +- include/IGUISkin.h | 12 +- include/IGUISpinBox.h | 2 +- include/IGUISpriteBank.h | 2 +- include/IGUIStaticText.h | 10 +- include/IGUITabControl.h | 8 +- include/IGUITable.h | 49 +- include/IGUIToolbar.h | 2 +- include/IGUIWindow.h | 2 +- include/IImage.h | 6 +- include/IImageLoader.h | 2 +- include/IImageWriter.h | 2 +- include/IIndexBuffer.h | 2 +- include/ILightManager.h | 60 ++ include/ILightSceneNode.h | 8 +- include/ILogger.h | 2 +- include/IMaterialRenderer.h | 2 +- include/IMaterialRendererServices.h | 2 +- include/IMesh.h | 2 +- include/IMeshBuffer.h | 2 +- include/IMeshCache.h | 2 +- include/IMeshLoader.h | 2 +- include/IMeshManipulator.h | 10 +- include/IMeshSceneNode.h | 2 +- include/IMeshWriter.h | 2 +- include/IMetaTriangleSelector.h | 2 +- include/IOSOperator.h | 2 +- include/IParticleAffector.h | 2 +- .../IParticleAnimatedMeshSceneNodeEmitter.h | 2 +- include/IParticleAttractionAffector.h | 2 +- include/IParticleBoxEmitter.h | 2 +- include/IParticleCylinderEmitter.h | 2 +- include/IParticleEmitter.h | 2 +- include/IParticleFadeOutAffector.h | 2 +- include/IParticleGravityAffector.h | 2 +- include/IParticleMeshEmitter.h | 2 +- include/IParticleRingEmitter.h | 2 +- include/IParticleRotationAffector.h | 2 +- include/IParticleSphereEmitter.h | 2 +- include/IParticleSystemSceneNode.h | 2 +- include/IQ3LevelMesh.h | 2 +- include/IQ3Shader.h | 6 +- include/IReadFile.h | 2 +- include/IReferenceCounted.h | 8 +- include/ISceneCollisionManager.h | 17 +- include/ISceneManager.h | 916 +++++++++--------- include/ISceneNode.h | 22 +- include/ISceneNodeAnimator.h | 10 +- include/ISceneNodeAnimatorCameraFPS.h | 11 +- include/ISceneNodeAnimatorCameraMaya.h | 2 +- include/ISceneNodeAnimatorCollisionResponse.h | 51 +- include/ISceneNodeAnimatorFactory.h | 2 +- include/ISceneNodeFactory.h | 8 +- include/ISceneUserDataSerializer.h | 2 +- include/IShaderConstantSetCallBack.h | 2 +- include/IShadowVolumeSceneNode.h | 2 +- include/ISkinnedMesh.h | 2 +- include/ITerrainSceneNode.h | 2 +- include/ITextSceneNode.h | 2 +- include/ITexture.h | 6 +- include/ITimer.h | 2 +- include/ITriangleSelector.h | 47 +- include/IVertexBuffer.h | 2 +- include/IVideoDriver.h | 326 ++++--- include/IVideoModeList.h | 8 +- include/IVolumeLightSceneNode.h | 2 +- include/IWriteFile.h | 2 +- include/IXMLReader.h | 2 +- include/IXMLWriter.h | 2 +- include/IrrCompileConfig.h | 2 +- include/IrrlichtDevice.h | 4 +- include/Keycodes.h | 2 +- include/S3DVertex.h | 2 +- include/SAnimatedMesh.h | 2 +- include/SColor.h | 2 +- include/SExposedVideoData.h | 2 +- include/SIrrCreationParameters.h | 49 +- include/SKeyMap.h | 2 +- include/SLight.h | 2 +- include/SMaterial.h | 111 ++- include/SMaterialLayer.h | 31 +- include/SMesh.h | 2 +- include/SMeshBuffer.h | 2 +- include/SMeshBufferLightMap.h | 2 +- include/SMeshBufferTangents.h | 2 +- include/SParticle.h | 2 +- include/SSharedMeshBuffer.h | 2 +- include/SSkinMeshBuffer.h | 2 +- include/SVertexIndex.h | 2 +- include/SViewFrustum.h | 2 +- include/SceneParameters.h | 17 +- include/aabbox3d.h | 2 +- include/coreutil.h | 2 +- include/dimension2d.h | 42 +- include/fast_atof.h | 2 +- include/heapsort.h | 2 +- include/irrAllocator.h | 2 +- include/irrArray.h | 2 +- include/irrList.h | 2 +- include/irrMap.h | 2 +- include/irrMath.h | 41 +- include/irrString.h | 28 +- include/irrTypes.h | 2 +- include/irrXML.h | 4 +- include/irrlicht.h | 7 +- include/line2d.h | 2 +- include/line3d.h | 2 +- include/matrix4.h | 52 +- include/plane3d.h | 2 +- include/position2d.h | 120 +-- include/quaternion.h | 7 +- include/rect.h | 4 +- include/triangle3d.h | 2 +- include/vector2d.h | 19 +- include/vector3d.h | 2 +- media/017shot.jpg | Bin 0 -> 4704 bytes media/019shot.jpg | Bin 0 -> 4554 bytes media/skydome.jpg | Bin 0 -> 39052 bytes readme.txt | 2 +- scripts/doc/irrlicht/doxygen.css | 622 ++++++------ scripts/doc/irrlicht/footer.html | 2 +- source/Irrlicht/BuiltInFont.h | 2 +- source/Irrlicht/C3DSMeshFileLoader.cpp | 2 +- source/Irrlicht/C3DSMeshFileLoader.h | 2 +- source/Irrlicht/CAnimatedMeshMD2.cpp | 368 +------ source/Irrlicht/CAnimatedMeshMD2.h | 56 +- source/Irrlicht/CAnimatedMeshMD3.cpp | 2 +- source/Irrlicht/CAnimatedMeshMD3.h | 2 +- source/Irrlicht/CAnimatedMeshSceneNode.cpp | 20 +- source/Irrlicht/CAnimatedMeshSceneNode.h | 4 +- source/Irrlicht/CAttributeImpl.h | 104 +- source/Irrlicht/CAttributes.cpp | 2 +- source/Irrlicht/CAttributes.h | 46 +- source/Irrlicht/CB3DMeshFileLoader.cpp | 5 +- source/Irrlicht/CB3DMeshFileLoader.h | 2 +- source/Irrlicht/CBSPMeshFileLoader.cpp | 2 +- source/Irrlicht/CBSPMeshFileLoader.h | 2 +- source/Irrlicht/CBillboardSceneNode.cpp | 2 +- source/Irrlicht/CBillboardSceneNode.h | 2 +- source/Irrlicht/CBoneSceneNode.cpp | 2 +- source/Irrlicht/CBoneSceneNode.h | 2 +- .../CBurningShader_Raster_Reference.cpp | 34 +- source/Irrlicht/CCSMLoader.cpp | 6 +- source/Irrlicht/CCSMLoader.h | 2 +- source/Irrlicht/CCameraSceneNode.cpp | 2 +- source/Irrlicht/CCameraSceneNode.h | 2 +- source/Irrlicht/CColladaFileLoader.cpp | 2 +- source/Irrlicht/CColladaFileLoader.h | 12 +- source/Irrlicht/CColladaMeshWriter.cpp | 2 +- source/Irrlicht/CColladaMeshWriter.h | 2 +- source/Irrlicht/CColorConverter.cpp | 2 +- source/Irrlicht/CColorConverter.h | 2 +- source/Irrlicht/CCubeSceneNode.cpp | 2 +- source/Irrlicht/CCubeSceneNode.h | 2 +- source/Irrlicht/CD3D8Driver.cpp | 242 +++-- source/Irrlicht/CD3D8Driver.h | 27 +- source/Irrlicht/CD3D8MaterialRenderer.h | 5 +- source/Irrlicht/CD3D8NormalMapRenderer.cpp | 2 +- source/Irrlicht/CD3D8NormalMapRenderer.h | 2 +- source/Irrlicht/CD3D8ParallaxMapRenderer.cpp | 2 +- source/Irrlicht/CD3D8ParallaxMapRenderer.h | 2 +- .../Irrlicht/CD3D8ShaderMaterialRenderer.cpp | 2 +- source/Irrlicht/CD3D8ShaderMaterialRenderer.h | 2 +- source/Irrlicht/CD3D8Texture.cpp | 10 +- source/Irrlicht/CD3D8Texture.h | 12 +- source/Irrlicht/CD3D9Driver.cpp | 294 ++++-- source/Irrlicht/CD3D9Driver.h | 40 +- source/Irrlicht/CD3D9HLSLMaterialRenderer.cpp | 141 +-- source/Irrlicht/CD3D9HLSLMaterialRenderer.h | 2 +- source/Irrlicht/CD3D9MaterialRenderer.h | 5 +- source/Irrlicht/CD3D9NormalMapRenderer.cpp | 2 +- source/Irrlicht/CD3D9NormalMapRenderer.h | 2 +- source/Irrlicht/CD3D9ParallaxMapRenderer.cpp | 2 +- source/Irrlicht/CD3D9ParallaxMapRenderer.h | 2 +- .../Irrlicht/CD3D9ShaderMaterialRenderer.cpp | 2 +- source/Irrlicht/CD3D9ShaderMaterialRenderer.h | 2 +- source/Irrlicht/CD3D9Texture.cpp | 10 +- source/Irrlicht/CD3D9Texture.h | 12 +- source/Irrlicht/CDMFLoader.cpp | 26 +- source/Irrlicht/CDMFLoader.h | 2 +- source/Irrlicht/CDefaultGUIElementFactory.cpp | 2 +- source/Irrlicht/CDefaultGUIElementFactory.h | 2 +- .../CDefaultSceneNodeAnimatorFactory.cpp | 2 +- .../CDefaultSceneNodeAnimatorFactory.h | 2 +- source/Irrlicht/CDefaultSceneNodeFactory.cpp | 2 +- source/Irrlicht/CDefaultSceneNodeFactory.h | 2 +- source/Irrlicht/CDepthBuffer.cpp | 12 +- source/Irrlicht/CDepthBuffer.h | 12 +- .../CDummyTransformationSceneNode.cpp | 2 +- .../Irrlicht/CDummyTransformationSceneNode.h | 2 +- source/Irrlicht/CEmptySceneNode.cpp | 2 +- source/Irrlicht/CEmptySceneNode.h | 2 +- source/Irrlicht/CFPSCounter.cpp | 2 +- source/Irrlicht/CFPSCounter.h | 2 +- source/Irrlicht/CFileList.cpp | 2 +- source/Irrlicht/CFileList.h | 2 +- source/Irrlicht/CFileSystem.cpp | 16 +- source/Irrlicht/CFileSystem.h | 5 +- source/Irrlicht/CGUIButton.cpp | 49 +- source/Irrlicht/CGUIButton.h | 15 +- source/Irrlicht/CGUICheckBox.cpp | 25 +- source/Irrlicht/CGUICheckBox.h | 4 +- source/Irrlicht/CGUIColorSelectDialog.cpp | 8 +- source/Irrlicht/CGUIColorSelectDialog.h | 6 +- source/Irrlicht/CGUIComboBox.cpp | 54 +- source/Irrlicht/CGUIComboBox.h | 6 +- source/Irrlicht/CGUIContextMenu.cpp | 17 +- source/Irrlicht/CGUIContextMenu.h | 10 +- source/Irrlicht/CGUIEditBox.cpp | 30 +- source/Irrlicht/CGUIEditBox.h | 8 +- source/Irrlicht/CGUIEnvironment.cpp | 129 ++- source/Irrlicht/CGUIEnvironment.h | 35 +- source/Irrlicht/CGUIFileOpenDialog.cpp | 8 +- source/Irrlicht/CGUIFileOpenDialog.h | 5 +- source/Irrlicht/CGUIFont.cpp | 69 +- source/Irrlicht/CGUIFont.h | 4 +- source/Irrlicht/CGUIImage.cpp | 23 +- source/Irrlicht/CGUIImage.h | 5 +- source/Irrlicht/CGUIInOutFader.cpp | 13 +- source/Irrlicht/CGUIInOutFader.h | 5 +- source/Irrlicht/CGUIListBox.cpp | 7 +- source/Irrlicht/CGUIListBox.h | 22 +- source/Irrlicht/CGUIMenu.cpp | 14 +- source/Irrlicht/CGUIMenu.h | 3 +- source/Irrlicht/CGUIMeshViewer.cpp | 3 +- source/Irrlicht/CGUIMeshViewer.h | 2 +- source/Irrlicht/CGUIMessageBox.cpp | 9 +- source/Irrlicht/CGUIMessageBox.h | 4 +- source/Irrlicht/CGUIModalScreen.cpp | 10 +- source/Irrlicht/CGUIModalScreen.h | 3 +- source/Irrlicht/CGUIScrollBar.cpp | 13 +- source/Irrlicht/CGUIScrollBar.h | 2 +- source/Irrlicht/CGUISkin.cpp | 60 +- source/Irrlicht/CGUISkin.h | 88 +- source/Irrlicht/CGUISpinBox.cpp | 3 +- source/Irrlicht/CGUISpinBox.h | 2 +- source/Irrlicht/CGUISpriteBank.cpp | 2 +- source/Irrlicht/CGUISpriteBank.h | 6 +- source/Irrlicht/CGUIStaticText.cpp | 13 +- source/Irrlicht/CGUIStaticText.h | 4 +- source/Irrlicht/CGUITabControl.cpp | 52 +- source/Irrlicht/CGUITabControl.h | 8 +- source/Irrlicht/CGUITable.cpp | 29 +- source/Irrlicht/CGUITable.h | 18 +- source/Irrlicht/CGUIToolBar.cpp | 12 +- source/Irrlicht/CGUIToolBar.h | 2 +- source/Irrlicht/CGUIWindow.cpp | 20 +- source/Irrlicht/CGUIWindow.h | 10 +- source/Irrlicht/CGeometryCreator.cpp | 20 +- source/Irrlicht/CGeometryCreator.h | 4 +- source/Irrlicht/CImage.cpp | 30 +- source/Irrlicht/CImage.h | 14 +- source/Irrlicht/CImageLoaderBMP.cpp | 14 +- source/Irrlicht/CImageLoaderBMP.h | 2 +- source/Irrlicht/CImageLoaderJPG.cpp | 4 +- source/Irrlicht/CImageLoaderJPG.h | 2 +- source/Irrlicht/CImageLoaderPCX.cpp | 16 +- source/Irrlicht/CImageLoaderPCX.h | 2 +- source/Irrlicht/CImageLoaderPNG.cpp | 32 +- source/Irrlicht/CImageLoaderPNG.h | 2 +- source/Irrlicht/CImageLoaderPPM.cpp | 14 +- source/Irrlicht/CImageLoaderPPM.h | 2 +- source/Irrlicht/CImageLoaderPSD.cpp | 4 +- source/Irrlicht/CImageLoaderPSD.h | 2 +- source/Irrlicht/CImageLoaderTGA.cpp | 8 +- source/Irrlicht/CImageLoaderTGA.h | 2 +- source/Irrlicht/CImageLoaderWAL.cpp | 4 +- source/Irrlicht/CImageLoaderWAL.h | 2 +- source/Irrlicht/CImageWriterBMP.cpp | 2 +- source/Irrlicht/CImageWriterBMP.h | 2 +- source/Irrlicht/CImageWriterJPG.cpp | 6 +- source/Irrlicht/CImageWriterJPG.h | 2 +- source/Irrlicht/CImageWriterPCX.cpp | 6 +- source/Irrlicht/CImageWriterPCX.h | 2 +- source/Irrlicht/CImageWriterPNG.cpp | 4 +- source/Irrlicht/CImageWriterPNG.h | 2 +- source/Irrlicht/CImageWriterPPM.cpp | 14 +- source/Irrlicht/CImageWriterPPM.h | 2 +- source/Irrlicht/CImageWriterPSD.cpp | 2 +- source/Irrlicht/CImageWriterPSD.h | 2 +- source/Irrlicht/CImageWriterTGA.cpp | 2 +- source/Irrlicht/CImageWriterTGA.h | 2 +- source/Irrlicht/CIrrDeviceLinux.cpp | 105 +- source/Irrlicht/CIrrDeviceLinux.h | 4 +- source/Irrlicht/CIrrDeviceSDL.cpp | 39 +- source/Irrlicht/CIrrDeviceSDL.h | 2 +- source/Irrlicht/CIrrDeviceStub.cpp | 2 +- source/Irrlicht/CIrrDeviceStub.h | 16 +- source/Irrlicht/CIrrDeviceWin32.cpp | 58 +- source/Irrlicht/CIrrDeviceWin32.h | 24 +- source/Irrlicht/CIrrDeviceWinCE.cpp | 2 +- source/Irrlicht/CIrrDeviceWinCE.h | 2 +- source/Irrlicht/CIrrMeshFileLoader.cpp | 2 +- source/Irrlicht/CIrrMeshFileLoader.h | 2 +- source/Irrlicht/CIrrMeshWriter.cpp | 2 +- source/Irrlicht/CIrrMeshWriter.h | 2 +- source/Irrlicht/CLMTSMeshFileLoader.cpp | 2 +- source/Irrlicht/CLMTSMeshFileLoader.h | 2 +- source/Irrlicht/CLWOMeshFileLoader.cpp | 2 +- source/Irrlicht/CLWOMeshFileLoader.h | 2 +- source/Irrlicht/CLightSceneNode.cpp | 21 +- source/Irrlicht/CLightSceneNode.h | 10 +- source/Irrlicht/CLimitReadFile.cpp | 2 +- source/Irrlicht/CLimitReadFile.h | 2 +- source/Irrlicht/CLogger.cpp | 2 +- source/Irrlicht/CLogger.h | 2 +- source/Irrlicht/CMD2MeshFileLoader.cpp | 324 ++++++- source/Irrlicht/CMD2MeshFileLoader.h | 8 +- source/Irrlicht/CMD3MeshFileLoader.cpp | 2 +- source/Irrlicht/CMD3MeshFileLoader.h | 2 +- source/Irrlicht/CMS3DMeshFileLoader.cpp | 2 +- source/Irrlicht/CMS3DMeshFileLoader.h | 2 +- source/Irrlicht/CMY3DHelper.h | 2 +- source/Irrlicht/CMY3DMeshFileLoader.cpp | 12 +- source/Irrlicht/CMY3DMeshFileLoader.h | 2 +- .../{CMemoryReadFile.cpp => CMemoryFile.cpp} | 39 +- .../{CMemoryReadFile.h => CMemoryFile.h} | 12 +- source/Irrlicht/CMeshCache.cpp | 2 +- source/Irrlicht/CMeshCache.h | 2 +- source/Irrlicht/CMeshManipulator.cpp | 2 +- source/Irrlicht/CMeshManipulator.h | 2 +- source/Irrlicht/CMeshSceneNode.cpp | 2 +- source/Irrlicht/CMeshSceneNode.h | 2 +- source/Irrlicht/CMetaTriangleSelector.cpp | 37 +- source/Irrlicht/CMetaTriangleSelector.h | 5 +- source/Irrlicht/CNullDriver.cpp | 261 +++-- source/Irrlicht/CNullDriver.h | 74 +- source/Irrlicht/COBJMeshFileLoader.cpp | 2 +- source/Irrlicht/COBJMeshFileLoader.h | 2 +- source/Irrlicht/COBJMeshWriter.cpp | 2 +- source/Irrlicht/COBJMeshWriter.h | 2 +- source/Irrlicht/COCTLoader.cpp | 4 +- source/Irrlicht/COCTLoader.h | 2 +- source/Irrlicht/COSOperator.cpp | 2 +- source/Irrlicht/COSOperator.h | 2 +- source/Irrlicht/COctTreeSceneNode.cpp | 2 +- source/Irrlicht/COctTreeSceneNode.h | 2 +- source/Irrlicht/COctTreeTriangleSelector.cpp | 2 +- source/Irrlicht/COctTreeTriangleSelector.h | 2 +- source/Irrlicht/COgreMeshFileLoader.cpp | 4 +- source/Irrlicht/COgreMeshFileLoader.h | 2 +- source/Irrlicht/COpenGLDriver.cpp | 556 +++++++---- source/Irrlicht/COpenGLDriver.h | 63 +- source/Irrlicht/COpenGLExtensionHandler.cpp | 51 +- source/Irrlicht/COpenGLExtensionHandler.h | 32 +- source/Irrlicht/COpenGLMaterialRenderer.h | 2 +- source/Irrlicht/COpenGLNormalMapRenderer.cpp | 2 +- source/Irrlicht/COpenGLNormalMapRenderer.h | 2 +- .../Irrlicht/COpenGLParallaxMapRenderer.cpp | 2 +- source/Irrlicht/COpenGLParallaxMapRenderer.h | 2 +- source/Irrlicht/COpenGLSLMaterialRenderer.cpp | 2 +- source/Irrlicht/COpenGLSLMaterialRenderer.h | 2 +- .../COpenGLShaderMaterialRenderer.cpp | 2 +- .../Irrlicht/COpenGLShaderMaterialRenderer.h | 2 +- source/Irrlicht/COpenGLTexture.cpp | 57 +- source/Irrlicht/COpenGLTexture.h | 16 +- source/Irrlicht/CPakReader.cpp | 2 +- source/Irrlicht/CPakReader.h | 2 +- .../CParticleAnimatedMeshSceneNodeEmitter.cpp | 2 +- .../CParticleAnimatedMeshSceneNodeEmitter.h | 2 +- .../Irrlicht/CParticleAttractionAffector.cpp | 2 +- source/Irrlicht/CParticleAttractionAffector.h | 2 +- source/Irrlicht/CParticleBoxEmitter.cpp | 2 +- source/Irrlicht/CParticleBoxEmitter.h | 2 +- source/Irrlicht/CParticleCylinderEmitter.cpp | 2 +- source/Irrlicht/CParticleCylinderEmitter.h | 2 +- source/Irrlicht/CParticleFadeOutAffector.cpp | 2 +- source/Irrlicht/CParticleFadeOutAffector.h | 2 +- source/Irrlicht/CParticleGravityAffector.cpp | 2 +- source/Irrlicht/CParticleGravityAffector.h | 2 +- source/Irrlicht/CParticleMeshEmitter.cpp | 2 +- source/Irrlicht/CParticleMeshEmitter.h | 2 +- source/Irrlicht/CParticlePointEmitter.cpp | 2 +- source/Irrlicht/CParticlePointEmitter.h | 2 +- source/Irrlicht/CParticleRingEmitter.cpp | 2 +- source/Irrlicht/CParticleRingEmitter.h | 2 +- source/Irrlicht/CParticleRotationAffector.cpp | 2 +- source/Irrlicht/CParticleRotationAffector.h | 2 +- source/Irrlicht/CParticleSphereEmitter.cpp | 2 +- source/Irrlicht/CParticleSphereEmitter.h | 2 +- source/Irrlicht/CParticleSystemSceneNode.cpp | 2 +- source/Irrlicht/CParticleSystemSceneNode.h | 2 +- source/Irrlicht/CQ3LevelMesh.cpp | 8 +- source/Irrlicht/CQ3LevelMesh.h | 2 +- source/Irrlicht/CQuake3ShaderSceneNode.cpp | 2 +- source/Irrlicht/CQuake3ShaderSceneNode.h | 2 +- source/Irrlicht/CReadFile.cpp | 2 +- source/Irrlicht/CReadFile.h | 2 +- source/Irrlicht/CSTLMeshFileLoader.cpp | 2 +- source/Irrlicht/CSTLMeshFileLoader.h | 2 +- source/Irrlicht/CSTLMeshWriter.cpp | 2 +- source/Irrlicht/CSTLMeshWriter.h | 2 +- source/Irrlicht/CSceneCollisionManager.cpp | 209 ++-- source/Irrlicht/CSceneCollisionManager.h | 31 +- source/Irrlicht/CSceneManager.cpp | 174 +++- source/Irrlicht/CSceneManager.h | 37 +- .../Irrlicht/CSceneNodeAnimatorCameraFPS.cpp | 21 +- source/Irrlicht/CSceneNodeAnimatorCameraFPS.h | 17 +- .../Irrlicht/CSceneNodeAnimatorCameraMaya.cpp | 2 +- .../Irrlicht/CSceneNodeAnimatorCameraMaya.h | 2 +- .../CSceneNodeAnimatorCollisionResponse.cpp | 506 +++++----- .../CSceneNodeAnimatorCollisionResponse.h | 30 +- source/Irrlicht/CSceneNodeAnimatorDelete.cpp | 18 +- source/Irrlicht/CSceneNodeAnimatorDelete.h | 7 +- .../Irrlicht/CSceneNodeAnimatorFlyCircle.cpp | 12 +- source/Irrlicht/CSceneNodeAnimatorFlyCircle.h | 2 +- .../CSceneNodeAnimatorFlyStraight.cpp | 18 +- .../Irrlicht/CSceneNodeAnimatorFlyStraight.h | 8 +- .../CSceneNodeAnimatorFollowSpline.cpp | 2 +- .../Irrlicht/CSceneNodeAnimatorFollowSpline.h | 2 +- .../Irrlicht/CSceneNodeAnimatorRotation.cpp | 2 +- source/Irrlicht/CSceneNodeAnimatorRotation.h | 2 +- source/Irrlicht/CSceneNodeAnimatorTexture.cpp | 14 +- source/Irrlicht/CSceneNodeAnimatorTexture.h | 7 +- source/Irrlicht/CShadowVolumeSceneNode.cpp | 2 +- source/Irrlicht/CShadowVolumeSceneNode.h | 2 +- source/Irrlicht/CSkinnedMesh.cpp | 2 +- source/Irrlicht/CSkinnedMesh.h | 2 +- source/Irrlicht/CSkyBoxSceneNode.cpp | 14 +- source/Irrlicht/CSkyBoxSceneNode.h | 2 +- source/Irrlicht/CSkyDomeSceneNode.cpp | 4 +- source/Irrlicht/CSkyDomeSceneNode.h | 2 +- source/Irrlicht/CSoftware2MaterialRenderer.h | 2 +- source/Irrlicht/CSoftwareDriver.cpp | 31 +- source/Irrlicht/CSoftwareDriver.h | 16 +- source/Irrlicht/CSoftwareDriver2.cpp | 69 +- source/Irrlicht/CSoftwareDriver2.h | 23 +- source/Irrlicht/CSoftwareTexture.cpp | 8 +- source/Irrlicht/CSoftwareTexture.h | 10 +- source/Irrlicht/CSoftwareTexture2.cpp | 14 +- source/Irrlicht/CSoftwareTexture2.h | 12 +- source/Irrlicht/CSphereSceneNode.cpp | 2 +- source/Irrlicht/CSphereSceneNode.h | 2 +- source/Irrlicht/CTRFlat.cpp | 2 +- source/Irrlicht/CTRFlatWire.cpp | 2 +- source/Irrlicht/CTRGouraud.cpp | 2 +- source/Irrlicht/CTRGouraud2.cpp | 2 +- source/Irrlicht/CTRGouraudAlpha2.cpp | 2 +- source/Irrlicht/CTRGouraudAlphaNoZ2.cpp | 2 +- source/Irrlicht/CTRGouraudWire.cpp | 2 +- source/Irrlicht/CTRTextureBlend.cpp | 2 +- source/Irrlicht/CTRTextureDetailMap2.cpp | 2 +- source/Irrlicht/CTRTextureFlat.cpp | 2 +- source/Irrlicht/CTRTextureFlatWire.cpp | 2 +- source/Irrlicht/CTRTextureGouraud.cpp | 2 +- source/Irrlicht/CTRTextureGouraud.h | 2 +- source/Irrlicht/CTRTextureGouraud2.cpp | 2 +- source/Irrlicht/CTRTextureGouraudAdd.cpp | 2 +- source/Irrlicht/CTRTextureGouraudAdd2.cpp | 2 +- source/Irrlicht/CTRTextureGouraudAddNoZ2.cpp | 2 +- source/Irrlicht/CTRTextureGouraudAlpha.cpp | 2 +- source/Irrlicht/CTRTextureGouraudAlphaNoZ.cpp | 2 +- source/Irrlicht/CTRTextureGouraudNoZ.cpp | 2 +- source/Irrlicht/CTRTextureGouraudNoZ2.cpp | 2 +- .../CTRTextureGouraudVertexAlpha2.cpp | 2 +- source/Irrlicht/CTRTextureGouraudWire.cpp | 2 +- source/Irrlicht/CTRTextureLightMap2_Add.cpp | 2 +- source/Irrlicht/CTRTextureLightMap2_M1.cpp | 2 +- source/Irrlicht/CTRTextureLightMap2_M2.cpp | 2 +- source/Irrlicht/CTRTextureLightMap2_M4.cpp | 2 +- .../CTRTextureLightMapGouraud2_M4.cpp | 2 +- source/Irrlicht/CTRTextureWire2.cpp | 2 +- source/Irrlicht/CTerrainSceneNode.cpp | 316 +++--- source/Irrlicht/CTerrainSceneNode.h | 6 +- source/Irrlicht/CTerrainTriangleSelector.cpp | 4 +- source/Irrlicht/CTerrainTriangleSelector.h | 7 +- source/Irrlicht/CTextSceneNode.cpp | 14 +- source/Irrlicht/CTextSceneNode.h | 2 +- source/Irrlicht/CTimer.h | 2 +- source/Irrlicht/CTriangleBBSelector.cpp | 2 +- source/Irrlicht/CTriangleBBSelector.h | 2 +- source/Irrlicht/CTriangleSelector.cpp | 6 +- source/Irrlicht/CTriangleSelector.h | 5 +- source/Irrlicht/CVideoModeList.cpp | 20 +- source/Irrlicht/CVideoModeList.h | 18 +- source/Irrlicht/CVolumeLightSceneNode.cpp | 2 +- source/Irrlicht/CVolumeLightSceneNode.h | 2 +- source/Irrlicht/CWaterSurfaceSceneNode.cpp | 2 +- source/Irrlicht/CWaterSurfaceSceneNode.h | 2 +- source/Irrlicht/CWriteFile.cpp | 2 +- source/Irrlicht/CWriteFile.h | 2 +- source/Irrlicht/CXMLReader.cpp | 2 +- source/Irrlicht/CXMLReader.h | 2 +- source/Irrlicht/CXMLReaderImpl.h | 2 +- source/Irrlicht/CXMLWriter.cpp | 2 +- source/Irrlicht/CXMLWriter.h | 2 +- source/Irrlicht/CXMeshFileLoader.cpp | 87 +- source/Irrlicht/CXMeshFileLoader.h | 32 +- source/Irrlicht/CZBuffer.cpp | 12 +- source/Irrlicht/CZBuffer.h | 12 +- source/Irrlicht/CZipReader.cpp | 2 +- source/Irrlicht/CZipReader.h | 2 +- source/Irrlicht/IBurningShader.cpp | 4 +- source/Irrlicht/IBurningShader.h | 3 +- source/Irrlicht/IDepthBuffer.h | 8 +- source/Irrlicht/IImagePresenter.h | 2 +- source/Irrlicht/ISceneNodeAnimatorFinishing.h | 42 + source/Irrlicht/ITriangleRenderer.h | 2 +- source/Irrlicht/IZBuffer.h | 8 +- source/Irrlicht/Irrlicht-gcc.cbp | 4 +- source/Irrlicht/Irrlicht.cpp | 6 +- source/Irrlicht/Irrlicht.dev | 4 +- source/Irrlicht/Irrlicht7.1.vcproj | 4 +- source/Irrlicht/Irrlicht8.0.vcproj | 12 +- source/Irrlicht/Irrlicht9.0.vcproj | 20 +- source/Irrlicht/MacOSX/AppDelegate.h | 2 +- source/Irrlicht/MacOSX/AppDelegate.mm | 2 +- source/Irrlicht/MacOSX/CIrrDeviceMacOSX.h | 5 +- source/Irrlicht/MacOSX/CIrrDeviceMacOSX.mm | 140 ++- .../MacOSX/MacOSX.xcodeproj/project.pbxproj | 6 +- source/Irrlicht/MacOSX/OSXClipboard.h | 2 +- source/Irrlicht/MacOSX/OSXClipboard.mm | 2 +- source/Irrlicht/Makefile | 2 +- source/Irrlicht/OctTree.h | 2 +- source/Irrlicht/S2DVertex.h | 2 +- source/Irrlicht/S4DVertex.h | 2 +- .../Irrlicht/SoftwareDriver2_compile_config.h | 2 +- source/Irrlicht/SoftwareDriver2_helper.h | 76 +- source/Irrlicht/dmfsupport.h | 6 +- source/Irrlicht/glext.h | 68 +- source/Irrlicht/irrXML.cpp | 2 +- source/Irrlicht/os.cpp | 2 +- source/Irrlicht/os.h | 2 +- tests/b3dAnimation.cpp | 6 +- tests/burningsVideo.cpp | 39 + tests/collisionResponseAnimator.cpp | 100 +- tests/cursorSetVisible.cpp | 70 ++ tests/disambiguateTextures.cpp | 6 +- tests/drawPixel.cpp | 4 +- tests/drawRectOutline.cpp | 28 + tests/exports.cpp | 2 +- tests/fast_atof.cpp | 4 +- tests/flyCircleAnimator.cpp | 59 ++ tests/guiDisabledMenu.cpp | 4 +- tests/irrCoreEquals.cpp | 146 +++ tests/line2dIntersectWith.cpp | 10 +- tests/main.cpp | 159 +-- tests/makeColorKeyTexture.cpp | 72 ++ tests/matrixOps.cpp | 49 + tests/md2Animation.cpp | 6 +- .../Direct3D 8.1-textureRenderStates.png | Bin 0 -> 30383 bytes .../Direct3D 9.0-textureRenderStates.png | Bin 0 -> 30383 bytes ...irect3D 9.0-transparentAlphaChannelRef.png | Bin 0 -> 30225 bytes ...are Device 1.0-makeColorKeyTexture-new.png | Bin 0 -> 13284 bytes ...are Device 1.0-makeColorKeyTexture-old.png | Bin 0 -> 14949 bytes ...oftware Device 1.0-textureRenderStates.png | Bin 0 -> 21298 bytes tests/media/OpenGL-terrainSceneNode-1.png | Bin 0 -> 37019 bytes tests/media/OpenGL-terrainSceneNode-2.png | Bin 0 -> 34107 bytes tests/media/OpenGL-textureRenderStates.png | Bin 0 -> 30383 bytes .../burnings video 0.39b-ambient-lighting.png | Bin 0 -> 391 bytes .../burnings video 0.39b-drawRectOutline.png | Bin 0 -> 492 bytes ...burnings video 0.39b-flyCircleAnimator.png | Bin 0 -> 2577 bytes ...gs video 0.39b-makeColorKeyTexture-new.png | Bin 0 -> 19688 bytes ...gs video 0.39b-makeColorKeyTexture-old.png | Bin 0 -> 20933 bytes ...rnings video 0.39b-textureRenderStates.png | Bin 0 -> 30383 bytes ...video 0.39b-transparentAlphaChannelRef.png | Bin 0 -> 29723 bytes tests/planeMatrix.cpp | 4 +- tests/sceneCollisionManager.cpp | 283 +++++- tests/sceneNodeAnimator.cpp | 117 +++ tests/softwareDevice.cpp | 4 +- tests/terrainSceneNode.cpp | 73 ++ tests/testDimension2d.cpp | 38 + tests/testUtils.cpp | 17 +- tests/testUtils.h | 8 +- tests/testVector2d.cpp | 2 +- tests/testVector3d.cpp | 6 +- tests/tests-last-passed-at.txt | 2 +- tests/tests-readme.txt | 123 ++- tests/tests.cbp | 15 + tests/tests_vc8.vcproj | 60 ++ tests/tests_vc9.vcproj | 263 +---- tests/textureRenderStates.cpp | 61 ++ tests/transparentAlphaChannelRef.cpp | 61 ++ tests/vectorPositionDimension2d.cpp | 73 ++ tests/writeImageToFile.cpp | 132 +++ tools/GUIEditor/CGUIEditFactory.h | 2 +- tools/GUIEditor/CGUIEditWorkspace.cpp | 10 +- tools/GUIEditor/CGUIEditWorkspace.h | 2 +- tools/GUIEditor/CGUIPanel.cpp | 2 +- tools/GUIEditor/CGUIPanel.h | 2 +- tools/GUIEditor/CGUITextureCacheBrowser.cpp | 2 +- tools/GUIEditor/CGUITextureCacheBrowser.h | 2 +- tools/GUIEditor/CMemoryReadWriteFile.cpp | 2 +- tools/GUIEditor/CMemoryReadWriteFile.h | 2 +- tools/IrrFontTool/newFontTool/CFontTool.cpp | 2 +- .../IrrFontTool/newFontTool/CVectorFontTool.h | 2 +- .../newFontTool/irrFontTool_v8.vcproj | 7 +- .../newFontTool/irrFontTool_v9.vcproj | 5 +- tools/IrrFontTool/newFontTool/main.cpp | 38 +- 675 files changed, 9517 insertions(+), 5024 deletions(-) create mode 100644 examples/20.ManagedLights/Makefile create mode 100644 examples/20.ManagedLights/ManagedLights.cbp create mode 100644 examples/20.ManagedLights/ManagedLights.sln create mode 100644 examples/20.ManagedLights/ManagedLights.vcproj create mode 100644 examples/20.ManagedLights/ManagedLights_vc8.vcproj create mode 100644 examples/20.ManagedLights/ManagedLights_vc9.vcproj create mode 100644 examples/20.ManagedLights/example.dev create mode 100644 examples/20.ManagedLights/main.cpp create mode 100644 include/ILightManager.h create mode 100644 media/017shot.jpg create mode 100644 media/019shot.jpg create mode 100644 media/skydome.jpg rename source/Irrlicht/{CMemoryReadFile.cpp => CMemoryFile.cpp} (59%) rename source/Irrlicht/{CMemoryReadFile.h => CMemoryFile.h} (71%) create mode 100644 source/Irrlicht/ISceneNodeAnimatorFinishing.h create mode 100644 tests/burningsVideo.cpp create mode 100644 tests/cursorSetVisible.cpp create mode 100644 tests/drawRectOutline.cpp create mode 100644 tests/flyCircleAnimator.cpp create mode 100644 tests/irrCoreEquals.cpp create mode 100644 tests/makeColorKeyTexture.cpp create mode 100644 tests/matrixOps.cpp create mode 100644 tests/media/Direct3D 8.1-textureRenderStates.png create mode 100644 tests/media/Direct3D 9.0-textureRenderStates.png create mode 100644 tests/media/Direct3D 9.0-transparentAlphaChannelRef.png create mode 100644 tests/media/Irrlicht Software Device 1.0-makeColorKeyTexture-new.png create mode 100644 tests/media/Irrlicht Software Device 1.0-makeColorKeyTexture-old.png create mode 100644 tests/media/Irrlicht Software Device 1.0-textureRenderStates.png create mode 100644 tests/media/OpenGL-terrainSceneNode-1.png create mode 100644 tests/media/OpenGL-terrainSceneNode-2.png create mode 100644 tests/media/OpenGL-textureRenderStates.png create mode 100644 tests/media/burnings video 0.39b-ambient-lighting.png create mode 100644 tests/media/burnings video 0.39b-drawRectOutline.png create mode 100644 tests/media/burnings video 0.39b-flyCircleAnimator.png create mode 100644 tests/media/burnings video 0.39b-makeColorKeyTexture-new.png create mode 100644 tests/media/burnings video 0.39b-makeColorKeyTexture-old.png create mode 100644 tests/media/burnings video 0.39b-textureRenderStates.png create mode 100644 tests/media/burnings video 0.39b-transparentAlphaChannelRef.png create mode 100644 tests/sceneNodeAnimator.cpp create mode 100644 tests/terrainSceneNode.cpp create mode 100644 tests/testDimension2d.cpp create mode 100644 tests/textureRenderStates.cpp create mode 100644 tests/transparentAlphaChannelRef.cpp create mode 100644 tests/vectorPositionDimension2d.cpp create mode 100644 tests/writeImageToFile.cpp diff --git a/changes.txt b/changes.txt index a938f625..ea01342a 100644 --- a/changes.txt +++ b/changes.txt @@ -1,17 +1,74 @@ Changes in version 1.6 + - New scene parameter B3D_LOADER_IGNORE_MIPMAP_FLAG to ignore the often missing mipmap flag in b3d files. If this parameter is true, the old pre Irrlicht-1.5 behavior is restored. + + - Added Mipmap LOD Bias attribute to MaterialLayer. + + - Added ColorMask support to selectively disable color planes on rendering. + + - Added support for all available depth test functions. + + - Add an outNode to getCollisionPoint() that returns the scene node that was hit, as well as the triangle. + + - Initial support for Alpha To Coverage, needs some more fixing until it works on all supported platforms. + + - Added support for Anti-Aliasing modes per material + + - Added an ICollisionCallback to ISceneNodeAnimatorCollisionResponse, to inform the application that a collision has occured. Thanks to garrittg for this. + + - Added an startPosition parameter to createFlyCircleAnimator() to allow starting the animator at any position on the circle. + + - Many uses of dimension2d changed to dimension2d, including IImage, ITexture and screen dimensions. You will have to change (at least) createDevice() calls to use dimension2d + + - Added Doublebuffer flag to SIrrCreationParameters, for better finetuning + + - Added Stereo-Framebuffer support for professional OpenGL cards + + - Added IFileSystem::createMemoryWriteFile() to allow creation of an IWriteFile interface that uses an application supplied memory buffer. + + - Added an IVideoDriver::writeImageToFile() overload that can take an IWriteFile interface. + + - (Internal) Replaced CMemoryReadFile with CMemoryFile, that also implements an IWriteFile interface. + + - Added an optional light manager to the scene manager to allow the user application to turn lights on and off during scene rendering. This can be used to produce "zoned" lighting. See example 20.ManagedLights. + + - Added a method to flip the Y movement of the FPS camera. + + - The Anisotropy filter can now be set to the AF value per texture layer. So no forced MAX_ANISOTROPY anymore. .irr files will probably fail, though. + + - AntiAlias parameter in SIrrCreationParameters is now an u8 value specifying the multisampling level (0 for disabled, 4,6,8, and others for anti-aliasing) + + - D3D devices use DISCARD for windowed renderbuffers now, can be faster. + + - Changed behaviour of PixelBlend16() / PixelBlend16_simd() so that they treat the 1 bit alpha of the source pixel as boolean, i.e. they draw either the source pixel, or the destination pixel, rather than "blending". (Issue revealed by the fix to IVideoDriver::makeColorKeyTexture()). + + - IVideoDriver::makeColorKeyTexture() bug fixed so that only alphas, not whole texel colors, are zeroed. An optional parameter allows using the old (buggy) behaviour for backwards compatibility. + + - position2d is now a synonym for vector2d. position2d is therefore marked as deprecated, although it's unlikely to be removed. + + - ISceneNodeAnimator now has a hasFinished() method. + - ISceneNodeAnimatorCollisionResponse exposes the target node. Setting the node again resets the last position, allowing the node to be teleported. - Add a hitPosition out parameter to ISceneCollisionManager::getCollisionResultPosition() - this is a (small) API breaking change. +------------------------------------- +Changes in version 1.5.1 (??.?? 2009) + + - Fixed OSX device bug where screen size was not set in fullscreen mode. + + - OSX device now supports shift and ctrl keys. + + - MD2 mesh loader: Now uses much less memory, reduced number of allocations when loading meshes. + ----------------------------------- Changes in version 1.5 (15.12.2008) - Construction calls for FPS camera changed to take speed in units/milliseconds, just as the setSpeed method does. - - Code::Blocks workspaces added. C::B projects (using gcc) now output to /lib/gcc and /bin/gcc, when built on either Windows or Linux. + - Code::Blocks workspaces added. C::B projects (using gcc) now output to /lib/gcc and /bin/gcc, when built on either Windows or Linux. - - Added a test suite in the /tests directory. This can be used to perform regression tests, and should be updated with new tests to verify fixes or validate new features. + - Added a test suite in the /tests directory. This can be used to perform regression tests, and should be updated with new tests to verify fixes or validate new features. - Changed the preferred way of altering light node's radius: Use the new member methods of ILightSceneNode instead of directly modifying the SLight structure. @@ -21,7 +78,7 @@ Changes in version 1.5 (15.12.2008) - Terrain heightmap and texture were flipped in order to draw them as expected (looking onto the terrain from high above will just look like the actual texture/heightmap). - - Significant internal change to the way that FPS camera jump speed and collision response animator gravity interact. The behaviour is now much more realistic, but it will require you to adjust your jump speed and gravity. + - Significant internal change to the way that FPS camera jump speed and collision response animator gravity interact. The behaviour is now much more realistic, but it will require you to adjust your jump speed and gravity. - Skybox won't be culled anymore by nearplane or farplane. @@ -47,7 +104,7 @@ Changes in version 1.5 (15.12.2008) - ISceneNode::setParent and addChild now updates node SceneManager pointers if the node was from another SceneManager. - - Basic support for joystick input events on Windows, Linux, SDL and OSX. Tested with wired Logitech and Thrustmaster wired controllers and XBox 360 wireless controller ( http://tattiebogle.net/index.php/ProjectRoot/Xbox360Controller/OsxDriver ) + - Basic support for joystick input events on Windows, Linux, SDL and OSX. Tested with wired Logitech and Thrustmaster wired controllers and XBox 360 wireless controller ( http://tattiebogle.net/index.php/ProjectRoot/Xbox360Controller/OsxDriver ) - Fixed scaled octree nodes being incorrectly frustum culled. diff --git a/examples/01.HelloWorld/main.cpp b/examples/01.HelloWorld/main.cpp index 0cfc7462..fddb223d 100644 --- a/examples/01.HelloWorld/main.cpp +++ b/examples/01.HelloWorld/main.cpp @@ -123,10 +123,10 @@ int main() */ IrrlichtDevice *device = #ifdef _IRR_OSX_PLATFORM_ - createDevice( video::EDT_OPENGL, dimension2d(640, 480), 16, + createDevice( video::EDT_OPENGL, dimension2d(640, 480), 16, false, false, false, 0); #else - createDevice( video::EDT_SOFTWARE, dimension2d(640, 480), 16, + createDevice( video::EDT_SOFTWARE, dimension2d(640, 480), 16, false, false, false, 0); #endif if (!device) diff --git a/examples/02.Quake3Map/Makefile b/examples/02.Quake3Map/Makefile index c193600d..f82bc9be 100644 --- a/examples/02.Quake3Map/Makefile +++ b/examples/02.Quake3Map/Makefile @@ -6,8 +6,8 @@ Sources = main.cpp # general compiler settings CPPFLAGS = -I../../include -I/usr/X11R6/include -CXXFLAGS = -O3 -ffast-math -#CXXFLAGS = -g -Wall +#CXXFLAGS = -O3 -ffast-math +CXXFLAGS = -g -Wall #default target is Linux all: all_linux @@ -16,8 +16,9 @@ ifeq ($(HOSTTYPE), x86_64) LIBSELECT=64 endif +OGLESLIBS := -L$(HOME)/irrlicht/SDKPackage-ogles1/Builds/OGLES/LinuxPC/Lib -lGLES_CM # target specific settings -all_linux: LDFLAGS = -L/usr/X11R6/lib$(LIBSELECT) -L../../lib/Linux -lIrrlicht -lGL -lXxf86vm -lXext -lX11 +all_linux: LDFLAGS = -L/usr/X11R6/lib$(LIBSELECT) -L../../lib/Linux -lIrrlicht $(OGLESLIBS) -lXxf86vm -lXext -lX11 all_linux clean_linux: SYSTEM=Linux all_win32: LDFLAGS = -L../../lib/Win32-gcc -lIrrlicht -lopengl32 -lm all_win32 clean_win32: SYSTEM=Win32-gcc diff --git a/examples/02.Quake3Map/main.cpp b/examples/02.Quake3Map/main.cpp index 5b9be978..61cc2b1d 100644 --- a/examples/02.Quake3Map/main.cpp +++ b/examples/02.Quake3Map/main.cpp @@ -55,8 +55,8 @@ int main() printf("Please select the driver you want for this example:\n"\ " (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\ - " (d) Software Renderer\n (e) Burning's Software Renderer\n"\ - " (f) NullDevice\n (otherKey) exit\n\n"); + " (d) OpenGL-ES1\n (e) Software Renderer\n (f) Burning's Software Renderer\n"\ + " (g) NullDevice\n (otherKey) exit\n\n"); char i; std::cin >> i; @@ -66,16 +66,17 @@ int main() case 'a': driverType = video::EDT_DIRECT3D9;break; case 'b': driverType = video::EDT_DIRECT3D8;break; case 'c': driverType = video::EDT_OPENGL; break; - case 'd': driverType = video::EDT_SOFTWARE; break; - case 'e': driverType = video::EDT_BURNINGSVIDEO;break; - case 'f': driverType = video::EDT_NULL; break; + case 'd': driverType = video::EDT_OGLES1; break; + case 'e': driverType = video::EDT_SOFTWARE; break; + case 'f': driverType = video::EDT_BURNINGSVIDEO;break; + case 'g': driverType = video::EDT_NULL; break; default: return 1; } // create device and exit if creation failed IrrlichtDevice *device = - createDevice(driverType, core::dimension2d(640, 480)); + createDevice(driverType, core::dimension2d(640, 480)); if (device == 0) return 1; // could not create selected driver. diff --git a/examples/03.CustomSceneNode/main.cpp b/examples/03.CustomSceneNode/main.cpp index 9ad26274..7f20497c 100644 --- a/examples/03.CustomSceneNode/main.cpp +++ b/examples/03.CustomSceneNode/main.cpp @@ -192,7 +192,7 @@ int main() // create device IrrlichtDevice *device = createDevice(driverType, - core::dimension2d(640, 480), 16, false); + core::dimension2d(640, 480), 16, false); if (device == 0) return 1; // could not create selected driver. diff --git a/examples/04.Movement/main.cpp b/examples/04.Movement/main.cpp index 63fe3760..bf6684c7 100644 --- a/examples/04.Movement/main.cpp +++ b/examples/04.Movement/main.cpp @@ -97,7 +97,7 @@ int main() MyEventReceiver receiver; IrrlichtDevice* device = createDevice(driverType, - core::dimension2d(640, 480), 16, false, false, false, &receiver); + core::dimension2d(640, 480), 16, false, false, false, &receiver); if (device == 0) return 1; // could not create selected driver. diff --git a/examples/05.UserInterface/main.cpp b/examples/05.UserInterface/main.cpp index 64263970..b836f196 100644 --- a/examples/05.UserInterface/main.cpp +++ b/examples/05.UserInterface/main.cpp @@ -183,7 +183,7 @@ int main() // create device and exit if creation failed - IrrlichtDevice * device = createDevice(driverType, core::dimension2d(640, 480)); + IrrlichtDevice * device = createDevice(driverType, core::dimension2d(640, 480)); if (device == 0) return 1; // could not create selected driver. diff --git a/examples/06.2DGraphics/main.cpp b/examples/06.2DGraphics/main.cpp index 3bda2176..10483477 100644 --- a/examples/06.2DGraphics/main.cpp +++ b/examples/06.2DGraphics/main.cpp @@ -50,7 +50,7 @@ int main() // create device IrrlichtDevice *device = createDevice(driverType, - core::dimension2d(512, 384)); + core::dimension2d(512, 384)); if (device == 0) return 1; // could not create selected driver. diff --git a/examples/07.Collision/main.cpp b/examples/07.Collision/main.cpp index 80e56ada..8b39924a 100644 --- a/examples/07.Collision/main.cpp +++ b/examples/07.Collision/main.cpp @@ -48,7 +48,7 @@ int main() // create device IrrlichtDevice *device = - createDevice(driverType, core::dimension2d(640, 480), 16, false); + createDevice(driverType, core::dimension2d(640, 480), 16, false); if (device == 0) return 1; // could not create selected driver. @@ -64,6 +64,8 @@ int main() if (q3levelmesh) q3node = smgr->addOctTreeSceneNode(q3levelmesh->getMesh(0)); + q3node->setID(0); // Make it an invalid target for bounding box collision + /* So far so good, we've loaded the quake 3 level like in tutorial 2. Now, here comes something different: We create a triangle selector. A @@ -132,6 +134,7 @@ int main() scene::ICameraSceneNode* camera = smgr->addCameraSceneNodeFPS(0, 100.0f, .3f, -1, 0, 0, true, 3.f); camera->setPosition(core::vector3df(-100,50,-150)); + camera->setID(0); // Make it an invalid target for bounding box collision if (selector) { @@ -164,8 +167,11 @@ int main() bill->setMaterialFlag(video::EMF_LIGHTING, false); bill->setMaterialFlag(video::EMF_ZBUFFER, false); bill->setSize(core::dimension2d(20.0f, 20.0f)); + bill->setID(0); // Make it an invalid target for bounding box collision - // add 3 animated faeries. + // add 3 animated faeries. We'll make their bounding boxes visible so + // that we can see the same boxes that the scene collision manager is + // using to perform the getSceneNodeFromCameraBB() check below. video::SMaterial material; material.setTexture(0, driver->getTexture("../../media/faerie2.bmp")); @@ -180,16 +186,19 @@ int main() node->setPosition(core::vector3df(-70,0,-90)); node->setMD2Animation(scene::EMAT_RUN); node->getMaterial(0) = material; - + node->setDebugDataVisible(scene::EDS_BBOX_ALL); + node = smgr->addAnimatedMeshSceneNode(faerie); node->setPosition(core::vector3df(-70,0,-30)); node->setMD2Animation(scene::EMAT_SALUTE); node->getMaterial(0) = material; + node->setDebugDataVisible(scene::EDS_BBOX_ALL); node = smgr->addAnimatedMeshSceneNode(faerie); node->setPosition(core::vector3df(-70,0,-60)); node->setMD2Animation(scene::EMAT_JUMP); node->getMaterial(0) = material; + node->setDebugDataVisible(scene::EDS_BBOX_ALL); } material.setTexture(0, 0); @@ -197,9 +206,10 @@ int main() // Add a light - smgr->addLightSceneNode(0, core::vector3df(-60,100,400), + scene::ILightSceneNode * light = smgr->addLightSceneNode(0, core::vector3df(-60,100,400), video::SColorf(1.0f,1.0f,1.0f,1.0f), 600.0f); + light->setID(0); // Make it an invalid target for bounding box collision /* @@ -241,9 +251,10 @@ int main() core::vector3df intersection; core::triangle3df tri; + const scene::ISceneNode* hitNode; if (smgr->getSceneCollisionManager()->getCollisionPoint( - line, selector, intersection, tri)) + line, selector, intersection, tri, hitNode)) { bill->setPosition(intersection); @@ -261,10 +272,18 @@ int main() we ask the collision manager for this, and if we've got a scene node, we highlight it by disabling Lighting in its material, if it is not the billboard or the quake 3 level. + We use a collision bitmask of 1, i.e. any scene node with a scene ID + with bit 1 set is valid for collision. Scene nodes ID defaults to 0xFFFFFFFF + so all nodes will have this bit by default. We have called setID(0) on + the nodes that we don't care about in order to clear this bit and make + them invalid targets for collision. This makes the test a bit more + efficient, and also stops us from accidentally picking unexpected nodes, + e.g. the quake3 level, camera, light and billboard nodes. By default, + these *are* valid targets for bounding box selection. */ selectedSceneNode = - smgr->getSceneCollisionManager()->getSceneNodeFromCameraBB(camera); + smgr->getSceneCollisionManager()->getSceneNodeFromCameraBB(camera, 1); if (lastSelectedSceneNode) lastSelectedSceneNode->setMaterialFlag(video::EMF_LIGHTING, true); diff --git a/examples/08.SpecialFX/main.cpp b/examples/08.SpecialFX/main.cpp index 856d46fd..0a7d0d93 100644 --- a/examples/08.SpecialFX/main.cpp +++ b/examples/08.SpecialFX/main.cpp @@ -60,7 +60,7 @@ int main() */ IrrlichtDevice *device = - createDevice(driverType, core::dimension2d(640, 480), + createDevice(driverType, core::dimension2d(640, 480), 16, false, shadows); if (device == 0) diff --git a/examples/09.Meshviewer/main.cpp b/examples/09.Meshviewer/main.cpp index 4df2785e..e1630d76 100644 --- a/examples/09.Meshviewer/main.cpp +++ b/examples/09.Meshviewer/main.cpp @@ -570,7 +570,7 @@ int main(int argc, char* argv[]) // create device and exit if creation failed MyEventReceiver receiver; - Device = createDevice(driverType, core::dimension2d(800, 600), + Device = createDevice(driverType, core::dimension2d(800, 600), 16, false, false, false, &receiver); if (Device == 0) @@ -758,7 +758,7 @@ int main(int argc, char* argv[]) // create fps text IGUIStaticText* fpstext = env->addStaticText(L"", - core::rect(GUI_ID_TOGGLE_DEBUG_INFO,4,570,23), true, false, bar); + core::rect(400,4,570,23), true, false, bar); IGUIStaticText* postext = env->addStaticText(L"", core::rect(10,50,470,80),false, false, 0, GUI_ID_POSITION_TEXT); diff --git a/examples/10.Shaders/main.cpp b/examples/10.Shaders/main.cpp index 2964d3c8..6a3872c4 100644 --- a/examples/10.Shaders/main.cpp +++ b/examples/10.Shaders/main.cpp @@ -149,7 +149,7 @@ int main() // create device - device = createDevice(driverType, core::dimension2d(640, 480)); + device = createDevice(driverType, core::dimension2d(640, 480)); if (device == 0) return 1; // could not create selected driver. diff --git a/examples/11.PerPixelLighting/main.cpp b/examples/11.PerPixelLighting/main.cpp index 298d7db7..69d7255f 100644 --- a/examples/11.PerPixelLighting/main.cpp +++ b/examples/11.PerPixelLighting/main.cpp @@ -180,7 +180,7 @@ int main() // create device IrrlichtDevice* device = createDevice(driverType, - core::dimension2d(640, 480)); + core::dimension2d(640, 480)); if (device == 0) return 1; // could not create selected driver. diff --git a/examples/12.TerrainRendering/main.cpp b/examples/12.TerrainRendering/main.cpp index dee05058..114cfb47 100644 --- a/examples/12.TerrainRendering/main.cpp +++ b/examples/12.TerrainRendering/main.cpp @@ -28,10 +28,11 @@ class MyEventReceiver : public IEventReceiver { public: - MyEventReceiver(scene::ISceneNode* terrain) + MyEventReceiver(scene::ISceneNode* terrain, scene::ISceneNode* skybox, scene::ISceneNode* skydome) : + Terrain(terrain), Skybox(skybox), Skydome(skydome), showBox(true) { - // store pointer to terrain so we can change its drawing mode - Terrain = terrain; + Skybox->setVisible(true); + Skydome->setVisible(false); } bool OnEvent(const SEvent& event) @@ -56,6 +57,11 @@ public: Terrain->getMaterial(0).MaterialType == video::EMT_SOLID ? video::EMT_DETAIL_MAP : video::EMT_SOLID); return true; + case irr::KEY_KEY_S: // toggle skies + showBox=!showBox; + Skybox->setVisible(showBox); + Skydome->setVisible(!showBox); + return true; default: break; } @@ -66,12 +72,15 @@ public: private: scene::ISceneNode* Terrain; + scene::ISceneNode* Skybox; + scene::ISceneNode* Skydome; + bool showBox; }; /* The start of the main function starts like in most other example. We ask the user -for the desired renderer and start it up. +for the desired renderer and start it up. This time with the advanced parameter handling. */ int main() { @@ -98,10 +107,12 @@ int main() default: return 1; } - // create device - - IrrlichtDevice* device = createDevice(driverType, - core::dimension2d(640, 480)); + // create device with full flexibility over creation parameters + // you can add more parameters if desired, check irr::SIrrlichtCreationParameters + irr::SIrrlichtCreationParameters params; + params.DriverType=driverType; + params.WindowSize=core::dimension2d(640, 480); + IrrlichtDevice* device = createDeviceEx(params); if (device == 0) return 1; // could not create selected driver. @@ -128,8 +139,8 @@ int main() // add some help text env->addStaticText( - L"Press 'W' to change wireframe mode\nPress 'D' to toggle detail map", - core::rect(10,440,250,475), true, true, 0, -1, true); + L"Press 'W' to change wireframe mode\nPress 'D' to toggle detail map\nPress 'S' to toggle skybox/skydome", + core::rect(10,421,250,475), true, true, 0, -1, true); // add camera scene::ICameraSceneNode* camera = @@ -137,7 +148,7 @@ int main() camera->setPosition(core::vector3df(2700*2,255*2,2600*2)); camera->setTarget(core::vector3df(2397*2,343*2,2700*2)); - camera->setFarValue(12000.0f); + camera->setFarValue(42000.0f); // disable mouse cursor device->getCursorControl()->setVisible(false); @@ -220,26 +231,27 @@ int main() To make the user be able to switch between normal and wireframe mode, we create an instance of the event reciever from above and let Irrlicht know about it. In addition, we add the skybox which we already used in - lots of Irrlicht examples. + lots of Irrlicht examples and a skydome, which is shown mutually + exclusive with the skybox by pressing 'S'. */ - // create event receiver - MyEventReceiver receiver(terrain); - device->setEventReceiver(&receiver); - - // create skybox + // create skybox and skydome driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); - smgr->addSkyBoxSceneNode( + scene::ISceneNode* skybox=smgr->addSkyBoxSceneNode( driver->getTexture("../../media/irrlicht2_up.jpg"), driver->getTexture("../../media/irrlicht2_dn.jpg"), driver->getTexture("../../media/irrlicht2_lf.jpg"), driver->getTexture("../../media/irrlicht2_rt.jpg"), driver->getTexture("../../media/irrlicht2_ft.jpg"), driver->getTexture("../../media/irrlicht2_bk.jpg")); + scene::ISceneNode* skydome=smgr->addSkyDomeSceneNode(driver->getTexture("../../media/skydome.jpg"),16,8,0.95f,2.0f); driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, true); + // create event receiver + MyEventReceiver receiver(terrain, skybox, skydome); + device->setEventReceiver(&receiver); /* That's it, draw everything. diff --git a/examples/13.RenderToTexture/main.cpp b/examples/13.RenderToTexture/main.cpp index 23594a4a..810ff3b8 100644 --- a/examples/13.RenderToTexture/main.cpp +++ b/examples/13.RenderToTexture/main.cpp @@ -45,7 +45,7 @@ int main() // create device and exit if creation failed IrrlichtDevice *device = - createDevice(driverType, core::dimension2d(640, 480), + createDevice(driverType, core::dimension2d(640, 480), 16, false, false); if (device == 0) @@ -140,7 +140,7 @@ int main() if (driver->queryFeature(video::EVDF_RENDER_TO_TARGET)) { - rt = driver->addRenderTargetTexture(core::dimension2d(256,256), "RTT1"); + rt = driver->addRenderTargetTexture(core::dimension2d(256,256), "RTT1"); test->setMaterialTexture(0, rt); // set material of cube to render target // add fixed camera diff --git a/examples/15.LoadIrrFile/main.cpp b/examples/15.LoadIrrFile/main.cpp index 77616c27..9de0c9fe 100644 --- a/examples/15.LoadIrrFile/main.cpp +++ b/examples/15.LoadIrrFile/main.cpp @@ -46,7 +46,7 @@ int main() // create device and exit if creation failed IrrlichtDevice* device = - createDevice(driverType, core::dimension2d(640, 480)); + createDevice(driverType, core::dimension2d(640, 480)); if (device == 0) return 1; // could not create selected driver. diff --git a/examples/16.Quake3MapShader/main.cpp b/examples/16.Quake3MapShader/main.cpp index 64a0cfcc..7fb77bbf 100644 --- a/examples/16.Quake3MapShader/main.cpp +++ b/examples/16.Quake3MapShader/main.cpp @@ -149,7 +149,7 @@ int IRRCALLCONV main(int argc, char* argv[]) } // create device and exit if creation failed - const core::dimension2di videoDim ( 800,600 ); + const core::dimension2du videoDim ( 800,600 ); IrrlichtDevice *device = createDevice(driverType, videoDim, 32, false ); diff --git a/examples/17.HelloWorld_Mobile/main.cpp b/examples/17.HelloWorld_Mobile/main.cpp index 69938867..9d5d188e 100644 --- a/examples/17.HelloWorld_Mobile/main.cpp +++ b/examples/17.HelloWorld_Mobile/main.cpp @@ -187,3 +187,5 @@ int main() return 0; } +/* +**/ diff --git a/examples/18.SplitScreen/main.cpp b/examples/18.SplitScreen/main.cpp index 5ee924e1..3d00f1e6 100644 --- a/examples/18.SplitScreen/main.cpp +++ b/examples/18.SplitScreen/main.cpp @@ -47,7 +47,8 @@ whenever the user press the S-key. All other events are sent to the FPS camera. */ -class MyEventReceiver : public IEventReceiver { +class MyEventReceiver : public IEventReceiver +{ public: virtual bool OnEvent(const SEvent& event) { @@ -100,7 +101,7 @@ int main() //Initialise the engine IrrlichtDevice *device = createDevice(driverType, - dimension2d(ResX,ResY), 32, fullScreen, + dimension2du(ResX,ResY), 32, fullScreen, false, false, &receiver); if (!device) return 1; diff --git a/examples/19.MouseAndJoystick/main.cpp b/examples/19.MouseAndJoystick/main.cpp index 073aaa4f..03adf3b5 100644 --- a/examples/19.MouseAndJoystick/main.cpp +++ b/examples/19.MouseAndJoystick/main.cpp @@ -129,7 +129,7 @@ int main() MyEventReceiver receiver; IrrlichtDevice* device = createDevice(driverType, - core::dimension2d(640, 480), 16, false, false, false, &receiver); + core::dimension2d(640, 480), 16, false, false, false, &receiver); if (device == 0) return 1; // could not create selected driver. @@ -290,3 +290,6 @@ int main() return 0; } + +/* +**/ diff --git a/examples/20.ManagedLights/Makefile b/examples/20.ManagedLights/Makefile new file mode 100644 index 00000000..a64ff737 --- /dev/null +++ b/examples/20.ManagedLights/Makefile @@ -0,0 +1,39 @@ +# Makefile for Irrlicht Examples +# It's usually sufficient to change just the target name and source file list +# and be sure that CXX is set to a valid compiler +Target = 20.ManagedLights +Sources = main.cpp + +# general compiler settings +CPPFLAGS = -I../../include -I/usr/X11R6/include +#CXXFLAGS = -O3 -ffast-math +CXXFLAGS = -g -Wall + +#default target is Linux +all: all_linux + +ifeq ($(HOSTTYPE), x86_64) +LIBSELECT=64 +endif + +# target specific settings +all_linux: LDFLAGS = -L/usr/X11R6/lib$(LIBSELECT) -L../../lib/Linux -lIrrlicht -lGL -lXxf86vm -lXext -lX11 +all_linux clean_linux: SYSTEM=Linux +all_win32: LDFLAGS = -L../../lib/Win32-gcc -lIrrlicht -lopengl32 -lm +all_win32: CPPFLAGS += -D__GNUWIN32__ -D_WIN32 -DWIN32 -D_WINDOWS -D_MBCS -D_USRDLL +all_win32 clean_win32: SYSTEM=Win32-gcc +all_win32 clean_win32: SUF=.exe +# name of the binary - only valid for targets which set SYSTEM +DESTPATH = ../../bin/$(SYSTEM)/$(Target)$(SUF) + +all_linux all_win32: + $(warning Building...) + $(CXX) $(CPPFLAGS) $(CXXFLAGS) $(Sources) -o $(DESTPATH) $(LDFLAGS) + +clean: clean_linux clean_win32 + $(warning Cleaning...) + +clean_linux clean_win32: + @$(RM) $(DESTPATH) + +.PHONY: all all_win32 clean clean_linux clean_win32 diff --git a/examples/20.ManagedLights/ManagedLights.cbp b/examples/20.ManagedLights/ManagedLights.cbp new file mode 100644 index 00000000..6d6ebd86 --- /dev/null +++ b/examples/20.ManagedLights/ManagedLights.cbp @@ -0,0 +1,38 @@ + + + + + + diff --git a/examples/20.ManagedLights/ManagedLights.sln b/examples/20.ManagedLights/ManagedLights.sln new file mode 100644 index 00000000..5d5424a4 --- /dev/null +++ b/examples/20.ManagedLights/ManagedLights.sln @@ -0,0 +1,17 @@ +Microsoft Visual Studio Solution File, Format Version 9.00 +# Visual Studio 2005 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "20.ManagedLights", "ManagedLights.vcproj", "{1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Debug|Win32.ActiveCfg = Debug|Win32 + {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|Win32.ActiveCfg = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/examples/20.ManagedLights/ManagedLights.vcproj b/examples/20.ManagedLights/ManagedLights.vcproj new file mode 100644 index 00000000..794946fa --- /dev/null +++ b/examples/20.ManagedLights/ManagedLights.vcproj @@ -0,0 +1,230 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/20.ManagedLights/ManagedLights_vc8.vcproj b/examples/20.ManagedLights/ManagedLights_vc8.vcproj new file mode 100644 index 00000000..57dfcf46 --- /dev/null +++ b/examples/20.ManagedLights/ManagedLights_vc8.vcproj @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/20.ManagedLights/ManagedLights_vc9.vcproj b/examples/20.ManagedLights/ManagedLights_vc9.vcproj new file mode 100644 index 00000000..736faa65 --- /dev/null +++ b/examples/20.ManagedLights/ManagedLights_vc9.vcproj @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/examples/20.ManagedLights/example.dev b/examples/20.ManagedLights/example.dev new file mode 100644 index 00000000..9804fee2 --- /dev/null +++ b/examples/20.ManagedLights/example.dev @@ -0,0 +1,59 @@ +[Project] +FileName=example.dev +Name=Irrlicht Example 20 ManagedLights +UnitCount=1 +Type=1 +Ver=1 +ObjFiles= +Includes=..\..\include +Libs= +PrivateResource= +ResourceIncludes= +MakeIncludes= +Compiler= +CppCompiler= +Linker=../../lib/Win32-gcc/libIrrlicht.a_@@_ +IsCpp=1 +Icon= +ExeOutput=../../bin/Win32-gcc +ObjectOutput=obj +OverrideOutput=1 +OverrideOutputName=20.ManagedLights.exe +HostApplication= +Folders= +CommandLine= +IncludeVersionInfo=0 +SupportXPThemes=0 +CompilerSet=0 +CompilerSettings=0000000000000000000000 +UseCustomMakefile=0 +CustomMakefile= + +[Unit1] +FileName=main.cpp +CompileCpp=1 +Folder=Projekt1 +Compile=1 +Link=1 +Priority=1000 +OverrideBuildCmd=0 +BuildCmd= + +[VersionInfo] +Major=0 +Minor=1 +Release=1 +Build=1 +LanguageID=1033 +CharsetID=1252 +CompanyName= +FileVersion= +FileDescription=Irrlicht Engine example compiled using DevCpp and gcc +InternalName= +LegalCopyright= +LegalTrademarks= +OriginalFilename= +ProductName= +ProductVersion= +AutoIncBuildNr=0 + diff --git a/examples/20.ManagedLights/main.cpp b/examples/20.ManagedLights/main.cpp new file mode 100644 index 00000000..9a32d221 --- /dev/null +++ b/examples/20.ManagedLights/main.cpp @@ -0,0 +1,400 @@ + +// Written by Colin MacDonald +// Copyright (C) 2002-2009 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include +#include + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +#if defined(_MSC_VER) +#pragma comment(lib, "Irrlicht.lib") +#endif // MSC_VER + +/* + Normally, you are limited to 8 dynamic lights per scene: this is a hardware limit. If you + want to use more dynamic lights in your scene, then you can register an optional light + manager that allows you to to turn lights on and off at specific point during rendering. + You are still limited to 8 lights, but the limit is per scene node. + + This is completely optional: if you do not register a light manager, then a default + distance-based scheme will be used to prioritise hardware lights based on their distance + from the active camera. + + NO_MANAGEMENT disables the light manager and shows Irrlicht's default light behaviour. + The 8 lights nearest to the camera will be turned on, and other lights will be turned off. + In this example, this produces a funky looking but incoherent light display. + + LIGHTS_NEAREST_NODE shows an implementation that turns on a limited number of lights + per mesh scene node. If finds the 3 lights that are nearest to the node being rendered, + and turns them on, turning all other lights off. This works, but as it operates on every + light for every node, it does not scale well with many lights. The flickering you can see + in this demo is due to the lights swapping their relative positions from the cubes + (a deliberate demonstration of the limitations of this technique). + + LIGHTS_IN_ZONE shows a technique for turning on lights based on a 'zone'. Each empty scene + node is considered to be the parent of a zone. When nodes are rendered, they turn off all + lights, then find their parent 'zone' and turn on all lights that are inside that zone, i.e. + are descendents of it in the scene graph. This produces true 'local' lighting for each cube + in this example. You could use a similar technique to locally light all meshes in (e.g.) + a room, without the lights spilling out to other rooms. + + This light manager is also an event receiver; this is purely for simplicity in this example, + it's neither necessary nor recommended for a real application. +*/ +class CMyLightManager : public ILightManager, public IEventReceiver +{ + typedef enum + { + NO_MANAGEMENT, + LIGHTS_NEAREST_NODE, + LIGHTS_IN_ZONE + } + LightManagementMode; + + LightManagementMode Mode; + LightManagementMode RequestedMode; + + // These data represent the state information that this light manager + // is interested in. + ISceneManager * SceneManager; + core::array * SceneLightList; + E_SCENE_NODE_RENDER_PASS CurrentRenderPass; + ISceneNode * CurrentSceneNode; + +public: + CMyLightManager(ISceneManager* sceneManager) + : Mode(NO_MANAGEMENT), RequestedMode(NO_MANAGEMENT), + SceneManager(sceneManager), SceneLightList(0), + CurrentRenderPass(ESNRP_COUNT), CurrentSceneNode(0) + { } + + virtual ~CMyLightManager(void) { } + + // The input receiver interface, which just switches light management strategy + bool OnEvent(const SEvent & event) + { + bool handled = false; + + if (event.EventType == irr::EET_KEY_INPUT_EVENT && event.KeyInput.PressedDown) + { + handled = true; + switch(event.KeyInput.Key) + { + case irr::KEY_KEY_1: + RequestedMode = NO_MANAGEMENT; + break; + case irr::KEY_KEY_2: + RequestedMode = LIGHTS_NEAREST_NODE; + break; + case irr::KEY_KEY_3: + RequestedMode = LIGHTS_IN_ZONE; + break; + default: + handled = false; + break; + } + + if(NO_MANAGEMENT == RequestedMode) + SceneManager->setLightManager(0); // Show that it's safe to register the light manager + else + SceneManager->setLightManager(this); + } + + return handled; + } + + + // This is called before the first scene node is rendered. + virtual void OnPreRender(core::array & lightList) + { + // Update the mode; changing it here ensures that it's consistent throughout a render + Mode = RequestedMode; + + // Store the light list. I am free to alter this list until the end of OnPostRender(). + SceneLightList = &lightList; + } + + // Called after the last scene node is rendered. + virtual void OnPostRender() + { + // Since light management might be switched off in the event handler, we'll turn all + // lights on to ensure that they are in a consistent state. You wouldn't normally have + // to do this when using a light manager, since you'd continue to do light management + // yourself. + for(u32 i = 0; i < SceneLightList->size(); i++) + (*SceneLightList)[i]->setVisible(true); + } + + virtual void OnRenderPassPreRender(E_SCENE_NODE_RENDER_PASS renderPass) + { + // I don't have to do anything here except remember which render pass I am in. + CurrentRenderPass = renderPass; + } + + virtual void OnRenderPassPostRender(E_SCENE_NODE_RENDER_PASS renderPass) + { + // I only want solid nodes to be lit, so after the solid pass, turn all lights off. + if(ESNRP_SOLID == renderPass) + { + for(u32 i = 0; i < SceneLightList->size(); ++i) + (*SceneLightList)[i]->setVisible(false); + } + } + + // This is called before the specified scene node is rendered + virtual void OnNodePreRender(ISceneNode* node) + { + CurrentSceneNode = node; + + // This light manager only considers solid objects, but you are free to manipulate + // lights during any phase, depending on your requirements. + if(ESNRP_SOLID != CurrentRenderPass) + return; + + // And in fact for this example, I only want to consider lighting for cube scene + // nodes. You will probably want to deal with lighting for (at least) mesh / + // animated mesh scene nodes as well. + if(node->getType() != ESNT_CUBE) + return; + + if(LIGHTS_NEAREST_NODE == Mode) + { + // This is a naive implementation that prioritises every light in the scene + // by its proximity to the node being rendered. This produces some flickering + // when lights orbit closer to a cube than its 'zone' lights. + const vector3df nodePosition = node->getAbsolutePosition(); + + // Sort the light list by prioritising them based on their distance from the node + // that's about to be rendered. + array sortingArray; + sortingArray.reallocate(SceneLightList->size()); + + u32 i; + for(i = 0; i < SceneLightList->size(); ++i) + { + ILightSceneNode* lightNode = (*SceneLightList)[i]; + f64 distance = lightNode->getAbsolutePosition().getDistanceFromSQ(nodePosition); + sortingArray.push_back(LightDistanceElement(lightNode, distance)); + } + + sortingArray.sort(); + + // The list is now sorted by proximity to the node. + // Turn on the three nearest lights, and turn the others off. + for(i = 0; i < sortingArray.size(); ++i) + sortingArray[i].node->setVisible(i < 3); + + } + else if(LIGHTS_IN_ZONE == Mode) + { + // Empty scene nodes are used to represent 'zones'. For each solid mesh that + // is being rendered, turn off all lights, then find its 'zone' parent, and turn + // on all lights that are found under that node in the scene graph. + // This is a general purpose algorithm that doesn't use any special + // knowledge of how this particular scene graph is organised. + for(u32 i = 0; i < SceneLightList->size(); ++i) + { + ILightSceneNode* lightNode = (*SceneLightList)[i]; + SLight & lightData = lightNode->getLightData(); + + if(ELT_DIRECTIONAL != lightData.Type) + lightNode->setVisible(false); + } + + ISceneNode * parentZone = findZone(node); + if(parentZone) + turnOnZoneLights(parentZone); + } + } + + // Called after the specified scene node is rendered + virtual void OnNodePostRender(ISceneNode* node) + { + // I don't need to do any light management after individual node rendering. + } + +private: + + // Find the empty scene node that is the parent of the specified node + ISceneNode * findZone(ISceneNode * node) + { + if(!node) + return 0; + + if(node->getType() == ESNT_EMPTY) + return node; + + return findZone(node->getParent()); + } + + // Turn on all lights that are children (directly or indirectly) of the + // specified scene node. + void turnOnZoneLights(ISceneNode * node) + { + core::list const & children = node->getChildren(); + for (core::list::ConstIterator child = children.begin(); + child != children.end(); + ++child) + { + if((*child)->getType() == ESNT_LIGHT) + static_cast(*child)->setVisible(true); + else // Assume that lights don't have any children that are also lights + turnOnZoneLights(*child); + } + } + + + // A utility class to aid in sorting scene nodes into a distance order + class LightDistanceElement + { + public: + LightDistanceElement() {}; + + LightDistanceElement(ILightSceneNode* n, f64 d) + : node(n), distance(d) { } + + ILightSceneNode* node; + f64 distance; + + // Lower distance elements are sorted to the start of the array + bool operator < (const LightDistanceElement& other) const + { + return (distance < other.distance); + } + }; +}; + + + +int main(int argumentCount, char * argumentValues[]) +{ + char driverChoice; + + if(argumentCount > 1) + driverChoice = argumentValues[1][0]; + else + { + printf("Please select the driver you want for this example:\n"\ + " (a) Direct3D 9.0c\n (b) Direct3D 8.1\n (c) OpenGL 1.5\n"\ + " (d) Burning's Software Renderer\n(otherKey) exit\n\n"); + + std::cin >> driverChoice; + } + + video::E_DRIVER_TYPE driverType; + switch(driverChoice) + { + case 'a': driverType = video::EDT_DIRECT3D9;break; + case 'b': driverType = video::EDT_DIRECT3D8;break; + case 'c': driverType = video::EDT_OPENGL; break; + case 'd': driverType = video::EDT_BURNINGSVIDEO; break; + default: return 0; + } + + IrrlichtDevice *device = createDevice(driverType, dimension2d(640, 480), 32, + false, false, false, 0); + if(!device) + return -1; + + f32 const lightRadius = 60.f; // Enough to reach the far side of each 'zone' + + IVideoDriver* driver = device->getVideoDriver(); + ISceneManager* smgr = device->getSceneManager(); + IGUIEnvironment* guienv = device->getGUIEnvironment(); + + gui::IGUISkin* skin = guienv->getSkin(); + if (skin) + { + skin->setColor(EGDC_BUTTON_TEXT, SColor(255, 255, 255, 255)); + gui::IGUIFont* font = guienv->getFont("../../media/fontlucida.png"); + if(font) + skin->setFont(font); + } + + guienv->addStaticText(L"1 - No light management", core::rect(10,10,200,30)); + guienv->addStaticText(L"2 - Closest 3 lights", core::rect(10,30,200,50)); + guienv->addStaticText(L"3 - Lights in zone", core::rect(10,50,200,70)); + + // Add several "zones". You could use this technique to light individual rooms, for example. + for(f32 zoneX = -100.f; zoneX <= 100.f; zoneX += 50.f) + for(f32 zoneY = -60.f; zoneY <= 60.f; zoneY += 60.f) + { + // Start with an empty scene node, which we will use to represent a zone. + ISceneNode * zoneRoot = smgr->addEmptySceneNode(); + zoneRoot->setPosition(vector3df(zoneX, zoneY, 0)); + + // Each zone contains a rotating cube + IMeshSceneNode * node = smgr->addCubeSceneNode(15, zoneRoot); + ISceneNodeAnimator * rotation = smgr->createRotationAnimator(vector3df(0.25f, 0.5f, 0.75f)); + node->addAnimator(rotation); + rotation->drop(); + + // And each cube has three lights attached to it. The lights are attached to billboards so + // that we can see where they are. The billboards are attached to the cube, so that the + // lights are indirect descendents of the same empty scene node as the cube. + IBillboardSceneNode * billboard = smgr->addBillboardSceneNode(node); + billboard->setPosition(vector3df(0, -14, 30)); + billboard->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR ); + billboard->setMaterialTexture(0, driver->getTexture("../../media/particle.bmp")); + billboard->setMaterialFlag(video::EMF_LIGHTING, false); + ILightSceneNode * light = smgr->addLightSceneNode(billboard, vector3df(0, 0, 0), SColorf(1, 0, 0), lightRadius); + + billboard = smgr->addBillboardSceneNode(node); + billboard->setPosition(vector3df(-21, -14, -21)); + billboard->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR ); + billboard->setMaterialTexture(0, driver->getTexture("../../media/particle.bmp")); + billboard->setMaterialFlag(video::EMF_LIGHTING, false); + light = smgr->addLightSceneNode(billboard, vector3df(0, 0, 0), SColorf(0, 1, 0), lightRadius); + + billboard = smgr->addBillboardSceneNode(node); + billboard->setPosition(vector3df(21, -14, -21)); + billboard->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR ); + billboard->setMaterialTexture(0, driver->getTexture("../../media/particle.bmp")); + billboard->setMaterialFlag(video::EMF_LIGHTING, false); + light = smgr->addLightSceneNode(billboard, vector3df(0, 0, 0), SColorf(0, 0, 1), lightRadius); + + // Each cube also has a smaller cube rotating around it, to show that the cubes are being + // lit by the lights in their 'zone', not just lights that are their direct children. + node = smgr->addCubeSceneNode(5, node); + node->setPosition(vector3df(0, 21, 0)); + } + + smgr->addCameraSceneNode(0, vector3df(0,0,-130), vector3df(0,0,0)); + + CMyLightManager * myLightManager = new CMyLightManager(smgr); + smgr->setLightManager(0); // This is the default: we won't do light management until told to do it. + device->setEventReceiver(myLightManager); + + int lastFps = -1; + + while(device->run()) + { + driver->beginScene(true, true, SColor(255,100,101,140)); + smgr->drawAll(); + guienv->drawAll(); + driver->endScene(); + + int fps = driver->getFPS(); + if(fps != lastFps) + { + lastFps = fps; + core::stringw str = L"Managed Lights ["; + str += driver->getName(); + str += "] FPS:"; + str += fps; + device->setWindowCaption(str.c_str()); + } + } + + myLightManager->drop(); // Drop my implicit reference + device->drop(); + return 0; +} diff --git a/examples/BuildAllExamples.workspace b/examples/BuildAllExamples.workspace index 9b2b13b5..015bd15c 100644 --- a/examples/BuildAllExamples.workspace +++ b/examples/BuildAllExamples.workspace @@ -1,7 +1,7 @@ - + @@ -19,6 +19,7 @@ + diff --git a/examples/BuildAllExamples_v7.sln b/examples/BuildAllExamples_v7.sln index e42a3446..bb9897ae 100644 --- a/examples/BuildAllExamples_v7.sln +++ b/examples/BuildAllExamples_v7.sln @@ -76,6 +76,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "16.Quake3MapShader", "16.Qu EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "19.MouseAndJoystick", "19.MouseAndJoystick\MouseAndJoystick.vcproj", "{1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "20.ManagedLights_vc8", "20.ManagedLights\ManagedLights_vc8.vcproj", "{16007FE2-142B-47F8-93E1-519BA3F39E71}" +EndProject Global GlobalSection(SolutionConfiguration) = preSolution Debug = Debug diff --git a/examples/BuildAllExamples_v8.sln b/examples/BuildAllExamples_v8.sln index 3c2c921c..44dd83c7 100644 --- a/examples/BuildAllExamples_v8.sln +++ b/examples/BuildAllExamples_v8.sln @@ -42,6 +42,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "16.Quake3MapShader_vc8", "1 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "19.MouseAndJoystick_vc8", "19.MouseAndJoystick\MouseAndJoystick_vc8.vcproj", "{1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "20.ManagedLights_vc8", "20.ManagedLights\ManagedLights_vc8.vcproj", "{16007FE2-142B-47F8-93E1-519BA3F39E71}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 @@ -124,6 +126,10 @@ Global {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Debug|Win32.Build.0 = Debug|Win32 {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|Win32.ActiveCfg = Release|Win32 {1AB9413E-4F53-42A3-8CB2-CB4BE22336D0}.Release|Win32.Build.0 = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Debug|Win32.ActiveCfg = Debug|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Debug|Win32.Build.0 = Debug|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release|Win32.ActiveCfg = Release|Win32 + {16007FE2-142B-47F8-93E1-519BA3F39E71}.Release|Win32.Build.0 = Release|Win32 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/examples/BuildAllExamples_v9.sln b/examples/BuildAllExamples_v9.sln index 29350699..93af55a1 100644 --- a/examples/BuildAllExamples_v9.sln +++ b/examples/BuildAllExamples_v9.sln @@ -21,7 +21,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "04.Movement_vc9", "04.Movem {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} EndProjectSection EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "05.UserInterface_vc8", "05.UserInterface\UserInterface_vc9.vcproj", "{622C9DD7-0391-49FF-AF53-24F9D5A8EC53}" +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "05.UserInterface_vc9", "05.UserInterface\UserInterface_vc9.vcproj", "{622C9DD7-0391-49FF-AF53-24F9D5A8EC53}" ProjectSection(ProjectDependencies) = postProject {E08E042A-6C45-411B-92BE-3CC31331019F} = {E08E042A-6C45-411B-92BE-3CC31331019F} EndProjectSection @@ -92,6 +92,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "18.SplitScreen_vc9", "18.Sp EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "19.MouseAndJoystick_vc9", "19.MouseAndJoystick\MouseAndJoystick_vc9.vcproj", "{FE853A36-E0D1-4AC5-A792-B643E70D2953}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "20.ManagedLights_vc9", "20.ManagedLights\ManagedLights_vc9.vcproj", "{16007FE2-142B-47F8-93E1-519BA3F39E71}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Win32 = Debug|Win32 diff --git a/examples/Demo/CDemo.cpp b/examples/Demo/CDemo.cpp index fa08cf70..a9325b03 100644 --- a/examples/Demo/CDemo.cpp +++ b/examples/Demo/CDemo.cpp @@ -1,4 +1,4 @@ -// This is a Demo of the Irrlicht Engine (c) 2005-2008 by N.Gebhardt. +// This is a Demo of the Irrlicht Engine (c) 2005-2009 by N.Gebhardt. // This file is not documented. #include "CDemo.h" @@ -37,7 +37,7 @@ CDemo::~CDemo() void CDemo::run() { - core::dimension2d resolution ( 800, 600 ); + core::dimension2d resolution ( 800, 600 ); if ( driverType == video::EDT_BURNINGSVIDEO || driverType == video::EDT_SOFTWARE ) { @@ -570,7 +570,7 @@ void CDemo::loadSceneData() void CDemo::createLoadingScreen() { - core::dimension2d size = device->getVideoDriver()->getScreenSize(); + core::dimension2d size = device->getVideoDriver()->getScreenSize(); device->getCursorControl()->setVisible(false); @@ -635,9 +635,9 @@ void CDemo::shoot() core::line3d line(start, end); // get intersection point with map - + const scene::ISceneNode* hitNode; if (sm->getSceneCollisionManager()->getCollisionPoint( - line, mapSelector, end, triangle)) + line, mapSelector, end, triangle, hitNode)) { // collides with wall core::vector3df out = triangle.getNormal(); diff --git a/examples/Demo/CMainMenu.cpp b/examples/Demo/CMainMenu.cpp index 9c4e87d1..efbef0d4 100644 --- a/examples/Demo/CMainMenu.cpp +++ b/examples/Demo/CMainMenu.cpp @@ -1,4 +1,4 @@ -// This is a Demo of the Irrlicht Engine (c) 2005-2008 by N.Gebhardt. +// This is a Demo of the Irrlicht Engine (c) 2005-2009 by N.Gebhardt. // This file is not documented. #include "CMainMenu.h" @@ -75,7 +75,7 @@ bool CMainMenu::run(bool& outFullscreen, bool& outMusic, bool& outShadows, video::E_DRIVER_TYPE& outDriver) { MenuDevice = createDevice(video::EDT_BURNINGSVIDEO, - core::dimension2d(512, 384), 16, false, false, false, this); + core::dimension2d(512, 384), 16, false, false, false, this); if (MenuDevice->getFileSystem()->existFile("irrlicht.dat")) MenuDevice->getFileSystem()->addZipFileArchive("irrlicht.dat"); diff --git a/examples/Demo/main.cpp b/examples/Demo/main.cpp index b3a2c655..3d269990 100644 --- a/examples/Demo/main.cpp +++ b/examples/Demo/main.cpp @@ -1,4 +1,4 @@ -// This is a Demo of the Irrlicht Engine (c) 2005-2008 by N.Gebhardt. +// This is a Demo of the Irrlicht Engine (c) 2005-2009 by N.Gebhardt. // This file is not documented. #include diff --git a/include/CDynamicMeshBuffer.h b/include/CDynamicMeshBuffer.h index 587a164b..ef497d37 100644 --- a/include/CDynamicMeshBuffer.h +++ b/include/CDynamicMeshBuffer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Nikolaus Gebhardt +// Copyright (C) 2008-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/CIndexBuffer.h b/include/CIndexBuffer.h index 61002f49..b5ac958d 100644 --- a/include/CIndexBuffer.h +++ b/include/CIndexBuffer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Nikolaus Gebhardt +// Copyright (C) 2008-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/CMeshBuffer.h b/include/CMeshBuffer.h index 52f9d4e2..e2b2a50f 100644 --- a/include/CMeshBuffer.h +++ b/include/CMeshBuffer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/CVertexBuffer.h b/include/CVertexBuffer.h index 2bcab457..6d715248 100644 --- a/include/CVertexBuffer.h +++ b/include/CVertexBuffer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Nikolaus Gebhardt +// Copyright (C) 2008-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/ECullingTypes.h b/include/ECullingTypes.h index 61ae0ee9..95c865a8 100644 --- a/include/ECullingTypes.h +++ b/include/ECullingTypes.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/EDebugSceneTypes.h b/include/EDebugSceneTypes.h index f4fe2ce2..025d22b5 100644 --- a/include/EDebugSceneTypes.h +++ b/include/EDebugSceneTypes.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/EDriverFeatures.h b/include/EDriverFeatures.h index 20498d32..863901b3 100644 --- a/include/EDriverFeatures.h +++ b/include/EDriverFeatures.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -85,6 +85,12 @@ namespace video //! Are vertex buffer objects supported? EVDF_VERTEX_BUFFER_OBJECT, + //! Supports Alpha To Coverage + EVDF_ALPHA_TO_COVERAGE, + + //! Supports Color masks (disabling color planes in output) + EVDF_COLOR_MASK, + //! Only used for counting the elements of this enum EVDF_COUNT }; diff --git a/include/EDriverTypes.h b/include/EDriverTypes.h index b5dc121e..e689a581 100644 --- a/include/EDriverTypes.h +++ b/include/EDriverTypes.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -13,44 +13,43 @@ namespace video //! An enum for all types of drivers the Irrlicht Engine supports. enum E_DRIVER_TYPE { - //! Null driver, useful for applications to run the engine - //! without visualisation. The null device is able to load - //! textures, but does not render and display any graphics. + //! Null driver, useful for applications to run the engine without visualisation. + /** The null device is able to load textures, but does not + render and display any graphics. */ EDT_NULL, - //! The Irrlicht Engine Software renderer, runs on all - //! platforms, with every hardware. It should only be used for - //! 2d graphics, but it can also perform some primitive 3d - //! functions. These 3d drawing functions are quite fast, but - //! very inaccurate, and don't even support clipping in 3D mode. + //! The Irrlicht Engine Software renderer. + /** Runs on all platforms, with every hardware. It should only be used for + 2d graphics, but it can also perform some primitive 3d + functions. These 3d drawing functions are quite fast, but + very inaccurate, and don't even support clipping in 3D mode. */ EDT_SOFTWARE, - //! The Burning's Software Renderer, an alternative software - //! renderer for Irrlicht. Basically it can be described as the - //! Irrlicht Software renderer on steroids. It rasterizes 3D - //! geometry perfectly: It is able to perform correct 3d - //! clipping, perspective correct texture mapping, perspective - //! correct color mapping, and renders sub pixel correct, sub - //! texel correct primitives. In addition, it does bilinear - //! texel filtering and supports more materials than the - //! EDT_SOFTWARE driver. This renderer has been written - //! entirely by Thomas Alten, thanks a lot for this huge - //! contribution. + //! The Burning's Software Renderer, an alternative software renderer + /** Basically it can be described as the Irrlicht Software + renderer on steroids. It rasterizes 3D geometry perfectly: It + is able to perform correct 3d clipping, perspective correct + texture mapping, perspective correct color mapping, and renders + sub pixel correct, sub texel correct primitives. In addition, + it does bilinear texel filtering and supports more materials + than the EDT_SOFTWARE driver. This renderer has been written + entirely by Thomas Alten, thanks a lot for this huge + contribution. */ EDT_BURNINGSVIDEO, //! Direct3D8 device, only available on Win32 platforms. - //! Performs hardware accelerated rendering of 3D and 2D - //! primitives. + /** Performs hardware accelerated rendering of 3D and 2D + primitives. */ EDT_DIRECT3D8, //! Direct3D 9 device, only available on Win32 platforms. - //! Performs hardware accelerated rendering of 3D and 2D - //! primitives. + /** Performs hardware accelerated rendering of 3D and 2D + primitives. */ EDT_DIRECT3D9, //! OpenGL device, available on most platforms. - //! Performs hardware accelerated rendering of 3D and 2D - //! primitives. + /** Performs hardware accelerated rendering of 3D and 2D + primitives. */ EDT_OPENGL, EDT_OGLES1 }; diff --git a/include/EGUIAlignment.h b/include/EGUIAlignment.h index 837043ac..9ebd40ce 100644 --- a/include/EGUIAlignment.h +++ b/include/EGUIAlignment.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -35,3 +35,4 @@ const c8* const GUIAlignmentNames[] = } // namespace irr #endif // __E_GUI_ALIGNMENT_H_INCLUDED__ + diff --git a/include/EGUIElementTypes.h b/include/EGUIElementTypes.h index 660fb8c7..30306d40 100644 --- a/include/EGUIElementTypes.h +++ b/include/EGUIElementTypes.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -88,8 +88,7 @@ enum EGUI_ELEMENT_TYPE //! Unknown type. EGUIET_ELEMENT, - //! This enum is never used, it only forces the compiler to - //! compile these enumeration values to 32 bit. + //! This enum is never used, it only forces the compiler to compile this enumeration to 32 bit. EGUIET_FORCE_32_BIT = 0x7fffffff }; diff --git a/include/EHardwareBufferFlags.h b/include/EHardwareBufferFlags.h index c6650080..669fad9a 100644 --- a/include/EHardwareBufferFlags.h +++ b/include/EHardwareBufferFlags.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/EMaterialFlags.h b/include/EMaterialFlags.h index eec4aee2..27e7ef66 100644 --- a/include/EMaterialFlags.h +++ b/include/EMaterialFlags.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -68,6 +68,12 @@ namespace video //! Access to all layers texture wrap settings. Overwrites separate layer settings. EMF_TEXTURE_WRAP, + //! AntiAliasing mode + EMF_ANTI_ALIASING, + + //! ColorMask bits, for enabling the color planes + EMF_COLOR_MASK, + //! This is not a flag, but a value indicating how much flags there are. EMF_MATERIAL_FLAG_COUNT }; diff --git a/include/EMaterialTypes.h b/include/EMaterialTypes.h index e496c540..69f92cdd 100644 --- a/include/EMaterialTypes.h +++ b/include/EMaterialTypes.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -13,37 +13,39 @@ namespace video //! Abstracted and easy to use fixed function/programmable pipeline material modes. enum E_MATERIAL_TYPE { - //! Standard solid material. Only first texture is used, which - //! is supposed to be the diffuse material. + //! Standard solid material. + /** Only first texture is used, which is supposed to be the + diffuse material. */ EMT_SOLID = 0, - //! Solid material with 2 texture layers. The second is blended - //! onto the first using the alpha value of the vertex colors. - //! This material is currently not implemented in OpenGL. + //! Solid material with 2 texture layers. + /** The second is blended onto the first using the alpha value + of the vertex colors. This material is currently not implemented in OpenGL. + */ EMT_SOLID_2_LAYER, - //! Material type with standard lightmap technique: - //! There should be 2 textures: The first texture layer is a - //! diffuse map, the second is a light map. Dynamic light is - //! ignored. + //! Material type with standard lightmap technique + /** There should be 2 textures: The first texture layer is a + diffuse map, the second is a light map. Dynamic light is + ignored. */ EMT_LIGHTMAP, - //! Material type with lightmap technique like EMT_LIGHTMAP. But - //! lightmap and diffuse texture are added instead of modulated. + //! Material type with lightmap technique like EMT_LIGHTMAP. + /** But lightmap and diffuse texture are added instead of modulated. */ EMT_LIGHTMAP_ADD, - //! Material type with standard lightmap technique: - //! There should be 2 textures: The first texture layer is a - //! diffuse map, the second is a light map. Dynamic light is - //! ignored. The texture colors are effectively multiplied by 2 - //! for brightening. Like known in DirectX as D3DTOP_MODULATE2X. + //! Material type with standard lightmap technique + /** There should be 2 textures: The first texture layer is a + diffuse map, the second is a light map. Dynamic light is + ignored. The texture colors are effectively multiplied by 2 + for brightening. Like known in DirectX as D3DTOP_MODULATE2X. */ EMT_LIGHTMAP_M2, - //! Material type with standard lightmap technique: - //! There should be 2 textures: The first texture layer is a - //! diffuse map, the second is a light map. Dynamic light is - //! ignored. The texture colors are effectively multiplyied by 4 - //! for brightening. Like known in DirectX as D3DTOP_MODULATE4X. + //! Material type with standard lightmap technique + /** There should be 2 textures: The first texture layer is a + diffuse map, the second is a light map. Dynamic light is + ignored. The texture colors are effectively multiplyied by 4 + for brightening. Like known in DirectX as D3DTOP_MODULATE4X. */ EMT_LIGHTMAP_M4, //! Like EMT_LIGHTMAP, but also supports dynamic lighting. @@ -55,153 +57,142 @@ namespace video //! Like EMT_LIGHTMAP_4, but also supports dynamic lighting. EMT_LIGHTMAP_LIGHTING_M4, - //! Detail mapped material. The first texture is diffuse color - //! map, the second is added to this and usually displayed with - //! a bigger scale value so that it adds more detail. The - //! detail map is added to the diffuse map using ADD_SIGNED, so - //! that it is possible to add and substract color from the - //! diffuse map. For example a value of (127,127,127) will not - //! change the appearance of the diffuse map at all. Often used - //! for terrain rendering. + //! Detail mapped material. + /** The first texture is diffuse color map, the second is added + to this and usually displayed with a bigger scale value so that + it adds more detail. The detail map is added to the diffuse map + using ADD_SIGNED, so that it is possible to add and substract + color from the diffuse map. For example a value of + (127,127,127) will not change the appearance of the diffuse map + at all. Often used for terrain rendering. */ EMT_DETAIL_MAP, - //! Makes the material look like it was reflection the - //! environment around it. To make this possible, a texture - //! called 'sphere map' is used, which must be set as the first - //! texture. + //! Look like a reflection of the environment around it. + /** To make this possible, a texture called 'sphere map' is + used, which must be set as the first texture. */ EMT_SPHERE_MAP, - //! A reflecting material with an optional additional non - //! reflecting texture layer. The reflection map should be set - //! as first texture. + //! A reflecting material with an optional non reflecting texture layer. + /** The reflection map should be set as first texture. */ EMT_REFLECTION_2_LAYER, - //! A transparent material. Only the first texture is used. - //! The new color is calculated by simply adding the source - //! color and the dest color. This means if for example a - //! billboard using a texture with black background and a red - //! circle on it is drawn with this material, the result is - //! that only the red circle will be drawn a little bit - //! transparent, and everything which was black is 100% - //! transparent and not visible. This material type is useful - //! for particle effects. + //! A transparent material. + /** Only the first texture is used. The new color is calculated + by simply adding the source color and the dest color. This + means if for example a billboard using a texture with black + background and a red circle on it is drawn with this material, + the result is that only the red circle will be drawn a little + bit transparent, and everything which was black is 100% + transparent and not visible. This material type is useful for + particle effects. */ EMT_TRANSPARENT_ADD_COLOR, - //! Makes the material transparent based on the texture alpha - //! channel. The final color is blended together from the - //! destination color and the texture color, using the alpha - //! channel value as blend factor. Only first texture is used. - //! If you are using this material with small textures, it is a - //! good idea to load the texture in 32 bit mode - //! (video::IVideoDriver::setTextureCreationFlag()). Also, an - //! alpha ref is used, which can be manipulated using - //! SMaterial::MaterialTypeParam. If set to 0, the alpha ref - //! gets its default value which is 0.5f and means that - //! pixels with an alpha value >127 will be written, others not. - //! In other, simple words: this value controls how sharp the - //! edges become when going from a transparent to a solid spot - //! on the texture. + //! Makes the material transparent based on the texture alpha channel. + /** The final color is blended together from the destination + color and the texture color, using the alpha channel value as + blend factor. Only first texture is used. If you are using + this material with small textures, it is a good idea to load + the texture in 32 bit mode + (video::IVideoDriver::setTextureCreationFlag()). Also, an alpha + ref is used, which can be manipulated using + SMaterial::MaterialTypeParam. This value controls how sharp the + edges become when going from a transparent to a solid spot on + the texture. */ EMT_TRANSPARENT_ALPHA_CHANNEL, - //! Makes the material transparent based on the texture alpha - //! channel. If the alpha channel value is greater than 127, a - //! pixel is written to the target, otherwise not. This - //! material does not use alpha blending and is a lot faster - //! than EMT_TRANSPARENT_ALPHA_CHANNEL. It is ideal for drawing - //! stuff like leafes of plants, because the borders are not - //! blurry but sharp. Only first texture is used. If you are - //! using this material with small textures and 3d object, it - //! is a good idea to load the texture in 32 bit mode - //! (video::IVideoDriver::setTextureCreationFlag()). + //! Makes the material transparent based on the texture alpha channel. + /** If the alpha channel value is greater than 127, a + pixel is written to the target, otherwise not. This + material does not use alpha blending and is a lot faster + than EMT_TRANSPARENT_ALPHA_CHANNEL. It is ideal for drawing + stuff like leafes of plants, because the borders are not + blurry but sharp. Only first texture is used. If you are + using this material with small textures and 3d object, it + is a good idea to load the texture in 32 bit mode + (video::IVideoDriver::setTextureCreationFlag()). */ EMT_TRANSPARENT_ALPHA_CHANNEL_REF, - //! Makes the material transparent based on the vertex alpha - //! value. + //! Makes the material transparent based on the vertex alpha value. EMT_TRANSPARENT_VERTEX_ALPHA, - //! A transparent reflecting material with an optional - //! additional non reflecting texture layer. The reflection map - //! should be set as first texture. The transparency depends on - //! the alpha value in the vertex colors. A texture which will - //! not reflect can be set as second texture. Please note that - //! this material type is currently not 100% implemented in - //! OpenGL. + //! A transparent reflecting material with an optional additional non reflecting texture layer. + /** The reflection map should be set as first texture. The + transparency depends on the alpha value in the vertex colors. A + texture which will not reflect can be set as second texture. + Please note that this material type is currently not 100% + implemented in OpenGL. */ EMT_TRANSPARENT_REFLECTION_2_LAYER, - //! A solid normal map renderer. First texture is the color - //! map, the second should be the normal map. Note that you - //! should use this material only when drawing geometry - //! consisting of vertices of type S3DVertexTangents - //! (EVT_TANGENTS). You can convert any mesh into this format - //! using IMeshManipulator::createMeshWithTangents() (See - //! SpecialFX2 Tutorial). This shader runs on vertex shader - //! 1.1 and pixel shader 1.1 capable hardware and falls back to - //! a fixed function lighted material if this hardware is not - //! available. Only two lights are supported by this shader, - //! if there are more, the nearest two are chosen. + //! A solid normal map renderer. + /** First texture is the color map, the second should be the + normal map. Note that you should use this material only when + drawing geometry consisting of vertices of type + S3DVertexTangents (EVT_TANGENTS). You can convert any mesh into + this format using IMeshManipulator::createMeshWithTangents() + (See SpecialFX2 Tutorial). This shader runs on vertex shader + 1.1 and pixel shader 1.1 capable hardware and falls back to a + fixed function lighted material if this hardware is not + available. Only two lights are supported by this shader, if + there are more, the nearest two are chosen. */ EMT_NORMAL_MAP_SOLID, - //! A transparent normal map renderer. First texture is the - //! color map, the second should be the normal map. Note that - //! you should use this material only when drawing geometry - //! consisting of vertices of type S3DVertexTangents - //! (EVT_TANGENTS). You can convert any mesh into this format - //! using IMeshManipulator::createMeshWithTangents() (See - //! SpecialFX2 Tutorial). This shader runs on vertex shader - //! 1.1 and pixel shader 1.1 capable hardware and falls back to - //! a fixed function lighted material if this hardware is not - //! available. Only two lights are supported by this shader, - //! if there are more, the nearest two are chosen. + //! A transparent normal map renderer. + /** First texture is the color map, the second should be the + normal map. Note that you should use this material only when + drawing geometry consisting of vertices of type + S3DVertexTangents (EVT_TANGENTS). You can convert any mesh into + this format using IMeshManipulator::createMeshWithTangents() + (See SpecialFX2 Tutorial). This shader runs on vertex shader + 1.1 and pixel shader 1.1 capable hardware and falls back to a + fixed function lighted material if this hardware is not + available. Only two lights are supported by this shader, if + there are more, the nearest two are chosen. */ EMT_NORMAL_MAP_TRANSPARENT_ADD_COLOR, - //! A transparent (based on the vertex alpha value) normal map - //! renderer. First texture is the color map, the second - //! should be the normal map. Note that you should use this - //! material only when drawing geometry consisting of vertices - //! of type S3DVertexTangents (EVT_TANGENTS). You can convert - //! any mesh into this format using - //! IMeshManipulator::createMeshWithTangents() (See SpecialFX2 - //! Tutorial). This shader runs on vertex shader 1.1 and pixel - //! shader 1.1 capable hardware and falls back to a fixed - //! function lighted material if this hardware is not available. - //! Only two lights are supported by this shader, if there are - //! more, the nearest two are chosen. + //! A transparent (based on the vertex alpha value) normal map renderer. + /** First texture is the color map, the second should be the + normal map. Note that you should use this material only when + drawing geometry consisting of vertices of type + S3DVertexTangents (EVT_TANGENTS). You can convert any mesh into + this format using IMeshManipulator::createMeshWithTangents() + (See SpecialFX2 Tutorial). This shader runs on vertex shader + 1.1 and pixel shader 1.1 capable hardware and falls back to a + fixed function lighted material if this hardware is not + available. Only two lights are supported by this shader, if + there are more, the nearest two are chosen. */ EMT_NORMAL_MAP_TRANSPARENT_VERTEX_ALPHA, - //! Just like EMT_NORMAL_MAP_SOLID, but uses parallax mapping - //! too, which looks a lot more realistic. This only works when - //! the hardware supports at least vertex shader 1.1 and pixel - //! shader 1.4. First texture is the color map, the second - //! should be the normal map. The normal map texture should - //! contain the height value in the alpha component. The - //! IVideoDriver::makeNormalMapTexture() method writes this - //! value automatically when creating normal maps from a - //! heightmap when using a 32 bit texture. The height scale of - //! the material (affecting the bumpiness) is being controlled - //! by the SMaterial::MaterialTypeParam member. If set to - //! zero, the default value (0.02f) will be applied. Otherwise - //! the value set in SMaterial::MaterialTypeParam is taken. This - //! value depends on with which scale the texture is mapped on - //! the material. Too high or low values of MaterialTypeParam - //! can result in strange artifacts. + //! Just like EMT_NORMAL_MAP_SOLID, but uses parallax mapping. + /** Looks a lot more realistic. This only works when the + hardware supports at least vertex shader 1.1 and pixel shader + 1.4. First texture is the color map, the second should be the + normal map. The normal map texture should contain the height + value in the alpha component. The + IVideoDriver::makeNormalMapTexture() method writes this value + automatically when creating normal maps from a heightmap when + using a 32 bit texture. The height scale of the material + (affecting the bumpiness) is being controlled by the + SMaterial::MaterialTypeParam member. If set to zero, the + default value (0.02f) will be applied. Otherwise the value set + in SMaterial::MaterialTypeParam is taken. This value depends on + with which scale the texture is mapped on the material. Too + high or low values of MaterialTypeParam can result in strange + artifacts. */ EMT_PARALLAX_MAP_SOLID, - //! A material just like EMT_PARALLAX_MAP_SOLID, but it is - //! transparent, using EMT_TRANSPARENT_ADD_COLOR as base - //! material. + //! A material like EMT_PARALLAX_MAP_SOLID, but transparent. + /** Using EMT_TRANSPARENT_ADD_COLOR as base material. */ EMT_PARALLAX_MAP_TRANSPARENT_ADD_COLOR, - //! A material just like EMT_PARALLAX_MAP_SOLID, but it is - //! transparent, using EMT_TRANSPARENT_VERTEX_ALPHA as base - //! material. + //! A material like EMT_PARALLAX_MAP_SOLID, but transparent. + /** Using EMT_TRANSPARENT_VERTEX_ALPHA as base material. */ EMT_PARALLAX_MAP_TRANSPARENT_VERTEX_ALPHA, //! BlendFunc = source * sourceFactor + dest * destFactor ( E_BLEND_FUNC ) - //! Using only first texture. Generic blending method. + /** Using only first texture. Generic blending method. */ EMT_ONETEXTURE_BLEND, - //! This value is not used. It only forces this enumeration to - //! compile in 32 bit. + //! This value is not used. It only forces this enumeration to compile to 32 bit. EMT_FORCE_32BIT = 0x7fffffff }; diff --git a/include/EMeshWriterEnums.h b/include/EMeshWriterEnums.h index bc0f1d33..8acc2853 100644 --- a/include/EMeshWriterEnums.h +++ b/include/EMeshWriterEnums.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/EMessageBoxFlags.h b/include/EMessageBoxFlags.h index e4d7dc6f..8e8ead8a 100644 --- a/include/EMessageBoxFlags.h +++ b/include/EMessageBoxFlags.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -33,3 +33,4 @@ enum EMESSAGE_BOX_FLAG } // namespace irr #endif + diff --git a/include/ESceneNodeAnimatorTypes.h b/include/ESceneNodeAnimatorTypes.h index 99a4234a..63a78f7f 100644 --- a/include/ESceneNodeAnimatorTypes.h +++ b/include/ESceneNodeAnimatorTypes.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -46,8 +46,7 @@ namespace scene //! Unknown scene node animator ESNAT_UNKNOWN, - //! This enum is never used, it only forces the compiler to - //! compile these enumeration values to 32 bit. + //! This enum is never used, it only forces the compiler to compile this enumeration to 32 bit. ESNAT_FORCE_32_BIT = 0x7fffffff }; diff --git a/include/ESceneNodeTypes.h b/include/ESceneNodeTypes.h index 833608a7..a7148cd4 100644 --- a/include/ESceneNodeTypes.h +++ b/include/ESceneNodeTypes.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -70,11 +70,11 @@ namespace scene ESNT_MD3_SCENE_NODE = MAKE_IRR_ID('m','d','3','_'), //! Maya Camera Scene Node - //! Legacy, for loading version <= 1.4.x .irr files + /** Legacy, for loading version <= 1.4.x .irr files */ ESNT_CAMERA_MAYA = MAKE_IRR_ID('c','a','m','M'), //! First Person Shooter Camera - //! Legacy, for loading version <= 1.4.x .irr files + /** Legacy, for loading version <= 1.4.x .irr files */ ESNT_CAMERA_FPS = MAKE_IRR_ID('c','a','m','F'), //! Unknown scene node diff --git a/include/ETerrainElements.h b/include/ETerrainElements.h index a9b65ee4..dd08ef7f 100644 --- a/include/ETerrainElements.h +++ b/include/ETerrainElements.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IAnimatedMesh.h b/include/IAnimatedMesh.h index 2befba12..dc607002 100644 --- a/include/IAnimatedMesh.h +++ b/include/IAnimatedMesh.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IAnimatedMeshMD2.h b/include/IAnimatedMeshMD2.h index 43852a96..692a8c50 100644 --- a/include/IAnimatedMeshMD2.h +++ b/include/IAnimatedMeshMD2.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IAnimatedMeshMD3.h b/include/IAnimatedMeshMD3.h index 53cb2185..a260e102 100644 --- a/include/IAnimatedMeshMD3.h +++ b/include/IAnimatedMeshMD3.h @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2007-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IAnimatedMeshSceneNode.h b/include/IAnimatedMeshSceneNode.h index ca1a2b41..2d0cba16 100644 --- a/include/IAnimatedMeshSceneNode.h +++ b/include/IAnimatedMeshSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IAttributeExchangingObject.h b/include/IAttributeExchangingObject.h index c430a7a8..0f90e9fc 100644 --- a/include/IAttributeExchangingObject.h +++ b/include/IAttributeExchangingObject.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IAttributes.h b/include/IAttributes.h index 389357f5..b0a616fb 100644 --- a/include/IAttributes.h +++ b/include/IAttributes.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IBillboardSceneNode.h b/include/IBillboardSceneNode.h index 9930dca2..1948fe76 100644 --- a/include/IBillboardSceneNode.h +++ b/include/IBillboardSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IBillboardTextSceneNode.h b/include/IBillboardTextSceneNode.h index 09c71667..e8aca8e6 100644 --- a/include/IBillboardTextSceneNode.h +++ b/include/IBillboardTextSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IBoneSceneNode.h b/include/IBoneSceneNode.h index 97498a06..2fa0b501 100644 --- a/include/IBoneSceneNode.h +++ b/include/IBoneSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/ICameraSceneNode.h b/include/ICameraSceneNode.h index 2bd21ac3..c2f151c1 100644 --- a/include/ICameraSceneNode.h +++ b/include/ICameraSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -146,7 +146,7 @@ namespace scene setTarget() will update its rotation so that its +Z axis will point at the target point. FPS camera use this binding by default; other cameras do not. - \param binding true to bind the camera's scene node rotation + \param bound True to bind the camera's scene node rotation and targetting, false to unbind them. @see getTargetAndRotationBinding() */ virtual void bindTargetAndRotation(bool bound) = 0; diff --git a/include/ICursorControl.h b/include/ICursorControl.h index 915c89e5..5e2b0d16 100644 --- a/include/ICursorControl.h +++ b/include/ICursorControl.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IDummyTransformationSceneNode.h b/include/IDummyTransformationSceneNode.h index 0e4634af..ce42da85 100644 --- a/include/IDummyTransformationSceneNode.h +++ b/include/IDummyTransformationSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IDynamicMeshBuffer.h b/include/IDynamicMeshBuffer.h index 1b6f62f0..8c86da69 100644 --- a/include/IDynamicMeshBuffer.h +++ b/include/IDynamicMeshBuffer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Nikolaus Gebhardt +// Copyright (C) 2008-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IEventReceiver.h b/include/IEventReceiver.h index 33e5380e..3eb15473 100644 --- a/include/IEventReceiver.h +++ b/include/IEventReceiver.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -358,7 +358,7 @@ struct SJoystickInfo //! The ID of the joystick /** This is an internal Irrlicht index; it does not map directly * to any particular hardware joystick. It corresponds to the - * @ref SJoystickEvent Joystick ID. */ + * irr::SJoystickEvent Joystick ID. */ u8 Joystick; //! The name that the joystick uses to identify itself. diff --git a/include/IFileList.h b/include/IFileList.h index dcdd85f7..8a06f816 100644 --- a/include/IFileList.h +++ b/include/IFileList.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IFileSystem.h b/include/IFileSystem.h index ae200ee3..253ce7bc 100644 --- a/include/IFileSystem.h +++ b/include/IFileSystem.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -52,6 +52,21 @@ public: */ virtual IReadFile* createMemoryReadFile(void* memory, s32 len, const c8* fileName, bool deleteMemoryWhenDropped=false) = 0; + //! Creates an IWriteFile interface for accessing memory like a file. + /** This allows you to use a pointer to memory where an IWriteFile is requested. + You are responsible for allocating enough memory. + \param memory: A pointer to the start of the file in memory (allocated by you) + \param len: The length of the memory in bytes + \param fileName: The name given to this file + \param deleteMemoryWhenDropped: True if the memory should be deleted + along with the IWriteFile when it is dropped. + \return Returns a pointer to the created file interface. + The returned pointer should be dropped when no longer needed. + See IReferenceCounted::drop() for more information. + */ + virtual IWriteFile* createMemoryWriteFile(void* memory, s32 len, const c8* fileName, bool deleteMemoryWhenDropped=false) = 0; + + //! Opens a file for write access. /** \param filename: Name of file to open. \param append: If the file already exist, all write operations are @@ -119,7 +134,9 @@ public: //! Returns the base part of a filename, i.e. the name without the directory //! part. If no directory is prefixed, the full name is returned. - /** \param filename: The file to get the basename from */ + /** \param filename: The file to get the basename from + \param keepExtension True if filename with extension is returned otherwise everything + after the final '.' is removed as well. */ virtual core::stringc getFileBasename(const core::stringc& filename, bool keepExtension=true) const = 0; //! Creates a list of files and directories in the current working directory and returns it. diff --git a/include/IGPUProgrammingServices.h b/include/IGPUProgrammingServices.h index 1ae0a749..da866334 100644 --- a/include/IGPUProgrammingServices.h +++ b/include/IGPUProgrammingServices.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IGUIButton.h b/include/IGUIButton.h index 498f2898..41127eb5 100644 --- a/include/IGUIButton.h +++ b/include/IGUIButton.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IGUICheckBox.h b/include/IGUICheckBox.h index a5fc6ccc..d398ad69 100644 --- a/include/IGUICheckBox.h +++ b/include/IGUICheckBox.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IGUIColorSelectDialog.h b/include/IGUIColorSelectDialog.h index 662e3401..342e584f 100644 --- a/include/IGUIColorSelectDialog.h +++ b/include/IGUIColorSelectDialog.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IGUIComboBox.h b/include/IGUIComboBox.h index fabcfa19..1eba9758 100644 --- a/include/IGUIComboBox.h +++ b/include/IGUIComboBox.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -44,10 +44,10 @@ namespace gui virtual void setSelected(s32 idx) = 0; //! Sets text justification of the text area - /** \param horizontal: EGUIA_UPPERLEFT for left justified (default), - EGUIA_LOWEERRIGHT for right justified, or EGUIA_CENTER for centered text. - \param vertical: EGUIA_UPPERLEFT to align with top edge, - EGUIA_LOWEERRIGHT for bottom edge, or EGUIA_CENTER for centered text (default). */ + /** \param horizontal: EGUIA_UPPERLEFT for left justified (default), + EGUIA_LOWEERRIGHT for right justified, or EGUIA_CENTER for centered text. + \param vertical: EGUIA_UPPERLEFT to align with top edge, + EGUIA_LOWEERRIGHT for bottom edge, or EGUIA_CENTER for centered text (default). */ virtual void setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical) = 0; }; diff --git a/include/IGUIContextMenu.h b/include/IGUIContextMenu.h index 1b714ba5..5d8cb3c2 100644 --- a/include/IGUIContextMenu.h +++ b/include/IGUIContextMenu.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -36,9 +36,7 @@ namespace gui \param checked: Specifies if the menu item should be initially checked. \return Returns the index of the new item */ virtual u32 addItem(const wchar_t* text, s32 commandId=-1, bool enabled=true, - bool hasSubMenu=false, - bool checked=false - ) = 0; + bool hasSubMenu=false, bool checked=false) = 0; //! Adds a separator item to the menu virtual void addSeparator() = 0; diff --git a/include/IGUIEditBox.h b/include/IGUIEditBox.h index 37df5b5c..40f9acfc 100644 --- a/include/IGUIEditBox.h +++ b/include/IGUIEditBox.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -61,7 +61,7 @@ namespace gui virtual void setWordWrap(bool enable) = 0; //! Checks if word wrap is enabled - //! \return true if word wrap is enabled, false otherwise + /** \return true if word wrap is enabled, false otherwise */ virtual bool isWordWrapEnabled() const = 0; //! Enables or disables newlines. @@ -70,15 +70,15 @@ namespace gui virtual void setMultiLine(bool enable) = 0; //! Checks if multi line editing is enabled - //! \return true if mult-line is enabled, false otherwise + /** \return true if mult-line is enabled, false otherwise */ virtual bool isMultiLineEnabled() const = 0; //! Enables or disables automatic scrolling with cursor position - //! \param enable: If set to true, the text will move around with the cursor position + /** \param enable: If set to true, the text will move around with the cursor position */ virtual void setAutoScroll(bool enable) = 0; //! Checks to see if automatic scrolling is enabled - //! \return true if automatic scrolling is enabled, false if not + /** \return true if automatic scrolling is enabled, false if not */ virtual bool isAutoScrollEnabled() const = 0; //! Sets whether the edit box is a password box. Setting this to true will @@ -91,8 +91,8 @@ namespace gui virtual bool isPasswordBox() const = 0; //! Gets the size area of the text in the edit box - //! \return Returns the size in pixels of the text - virtual core::dimension2di getTextDimension() = 0; + /** \return The size in pixels of the text */ + virtual core::dimension2du getTextDimension() = 0; //! Sets the maximum amount of characters which may be entered in the box. /** \param max: Maximum amount of characters. If 0, the character amount is diff --git a/include/IGUIElement.h b/include/IGUIElement.h index c896106b..c4f38b5e 100644 --- a/include/IGUIElement.h +++ b/include/IGUIElement.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -83,7 +83,7 @@ public: //! Sets the relative rectangle of this element. - /** \param r The absolute position to set */ + /** \param r The absolute position to set */ void setRelativePosition(const core::rect& r) { if (Parent) @@ -107,22 +107,22 @@ public: } //! Sets the relative rectangle of this element, maintaining its current width and height - /** \param position The new relative position to set. Width and height will not be changed. */ + /** \param position The new relative position to set. Width and height will not be changed. */ void setRelativePosition(const core::position2di & position) { const core::dimension2di mySize = RelativeRect.getSize(); - const core::rect rectangle(position.X, position.Y, - position.X + mySize.Width, position.Y + mySize.Height); + const core::rect rectangle(position.X, position.Y, + position.X + mySize.Width, position.Y + mySize.Height); setRelativePosition(rectangle); } //! Sets the relative rectangle of this element as a proportion of its parent's area. /** \note This method used to be 'void setRelativePosition(const core::rect& r)' - \param r The rectangle to set, interpreted as a proportion of the parent's area. + \param r The rectangle to set, interpreted as a proportion of the parent's area. Meaningful values are in the range [0...1], unless you intend this element to spill outside its parent. */ - void setRelativePositionProportional(const core::rect& r) + void setRelativePositionProportional(const core::rect& r) { if (!Parent) return; @@ -156,7 +156,7 @@ public: //! Sets whether the element will ignore its parent's clipping rectangle - /** \param noClip If true, the element will not be clipped by its parent's clipping rectangle. */ + /** \param noClip If true, the element will not be clipped by its parent's clipping rectangle. */ void setNotClipped(bool noClip) { NoClip = noClip; @@ -173,7 +173,7 @@ public: //! Sets the maximum size allowed for this element /** If set to 0,0, there is no maximum size */ - void setMaxSize(core::dimension2di size) + void setMaxSize(core::dimension2du size) { MaxSize = size; updateAbsolutePosition(); @@ -181,7 +181,7 @@ public: //! Sets the minimum size allowed for this element - void setMinSize(core::dimension2di size) + void setMinSize(core::dimension2du size) { MinSize = size; if (MinSize.Width < 1) @@ -222,7 +222,6 @@ public: { core::rect parentAbsolute(0,0,0,0); core::rect parentAbsoluteClip; - s32 diffx, diffy; f32 fw=0.f, fh=0.f; if (Parent) @@ -240,8 +239,8 @@ public: parentAbsoluteClip = Parent->AbsoluteClippingRect; } - diffx = parentAbsolute.getWidth() - LastParentRect.getWidth(); - diffy = parentAbsolute.getHeight() - LastParentRect.getHeight(); + const s32 diffx = parentAbsolute.getWidth() - LastParentRect.getWidth(); + const s32 diffy = parentAbsolute.getHeight() - LastParentRect.getHeight(); if (AlignLeft == EGUIA_SCALE || AlignRight == EGUIA_SCALE) fw = (f32)parentAbsolute.getWidth(); @@ -315,13 +314,13 @@ public: const s32 h = RelativeRect.getHeight(); // make sure the desired rectangle is allowed - if (w < MinSize.Width) + if (w < (s32)MinSize.Width) RelativeRect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + MinSize.Width; - if (h < MinSize.Height) + if (h < (s32)MinSize.Height) RelativeRect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + MinSize.Height; - if (MaxSize.Width && w > MaxSize.Width) + if (MaxSize.Width && w > (s32)MaxSize.Width) RelativeRect.LowerRightCorner.X = RelativeRect.UpperLeftCorner.X + MaxSize.Width; - if (MaxSize.Height && h > MaxSize.Height) + if (MaxSize.Height && h > (s32)MaxSize.Height) RelativeRect.LowerRightCorner.Y = RelativeRect.UpperLeftCorner.Y + MaxSize.Height; RelativeRect.repair(); @@ -345,7 +344,18 @@ public: } - //! Returns the child element, which is at the position of the point. + //! Returns the topmost GUI element at the specific position. + /** + This will check this GUI element and all of its descendants, so it + may return this GUI element. To check all GUI elements, call this + function on device->getGUIEnvironment()->getRootGUIElement(). Note + that the root element is the size of the screen, so doing so (with + an on-screen point) will always return the root element if no other + element is above it at that point. + \param point: The point at which to find a GUI element. + \return The topmost GUI element at that point, or 0 if there are + no candidate elements at this point. + */ IGUIElement* getElementFromPoint(const core::position2d& point) { IGUIElement* target = 0; @@ -356,6 +366,7 @@ public: core::list::Iterator it = Children.getLast(); if (IsVisible) + { while(it != Children.end()) { target = (*it)->getElementFromPoint(point); @@ -364,6 +375,7 @@ public: --it; } + } if (IsVisible && isPointInside(point)) target = this; @@ -373,12 +385,13 @@ public: //! Returns true if a point is within this element. - //! Elements with a shape other than a rectangle will override this method + /** Elements with a shape other than a rectangle should override this method */ virtual bool isPointInside(const core::position2d& point) const { return AbsoluteClippingRect.isPointInside(point); } + //! Adds a GUI element as new child of this element. virtual void addChild(IGUIElement* child) { @@ -470,19 +483,18 @@ public: } - //! Sets whether this control was created as part of its parent, - //! for example when a scrollbar is part of a listbox. - //! SubElements are not saved to disk when calling guiEnvironment->saveGUI() + //! Sets whether this control was created as part of its parent. + /** For example, it is true when a scrollbar is part of a listbox. + SubElements are not saved to disk when calling guiEnvironment->saveGUI() */ virtual void setSubElement(bool subElement) { IsSubElement = subElement; } - //! If set to true, the focus will visit this element when using - //! the tab key to cycle through elements. - //! If this element is a tab group (see isTabGroup/setTabGroup) then - //! ctrl+tab will be used instead. + //! If set to true, the focus will visit this element when using the tab key to cycle through elements. + /** If this element is a tab group (see isTabGroup/setTabGroup) then + ctrl+tab will be used instead. */ void setTabStop(bool enable) { IsTabStop = enable; @@ -497,9 +509,9 @@ public: } - //! Sets the priority of focus when using the tab key to navigate between a group - //! of elements. See setTabGroup, isTabGroup and getTabGroup for information on tab groups. - //! Elements with a lower number are focused first + //! Sets the priority of focus when using the tab key to navigate between a group of elements. + /** See setTabGroup, isTabGroup and getTabGroup for information on tab groups. + Elements with a lower number are focused first */ void setTabOrder(s32 index) { // negative = autonumber @@ -534,9 +546,9 @@ public: } - //! Sets whether this element is a container for a group of elements which - //! can be navigated using the tab key. For example, windows are tab groups. - //! Groups can be navigated using ctrl+tab, providing isTabStop is true. + //! Sets whether this element is a container for a group of elements which can be navigated using the tab key. + /** For example, windows are tab groups. + Groups can be navigated using ctrl+tab, providing isTabStop is true. */ void setTabGroup(bool isGroup) { IsTabGroup = isGroup; @@ -551,8 +563,7 @@ public: } - //! Returns the container element which holds all elements in this element's - //! tab group. + //! Returns the container element which holds all elements in this element's tab group. IGUIElement* getTabGroup() { IGUIElement *ret=this; @@ -629,7 +640,7 @@ public: //! Brings a child to front - /** \return Returns true if successful, false if not. */ + /** \return True if successful, false if not. */ virtual bool bringToFront(IGUIElement* element) { core::list::Iterator it = Children.begin(); @@ -702,13 +713,13 @@ public: //! searches elements to find the closest next element to tab to - //! \param startOrder: The TabOrder of the current element, -1 if none - //! \param reverse: true if searching for a lower number - //! \param group: true if searching for a higher one - //! \param first: element with the highest/lowest known tab order depending on search direction - //! \param closest: the closest match, depending on tab order and direction - //! \param includeInvisible: includes invisible elements in the search (default=false) - //! \return true if successfully found an element, false to continue searching/fail + /** \param startOrder: The TabOrder of the current element, -1 if none + \param reverse: true if searching for a lower number + \param group: true if searching for a higher one + \param first: element with the highest/lowest known tab order depending on search direction + \param closest: the closest match, depending on tab order and direction + \param includeInvisible: includes invisible elements in the search (default=false) + \return true if successfully found an element, false to continue searching/fail */ bool getNextElement(s32 startOrder, bool reverse, bool group, IGUIElement*& first, IGUIElement*& closest, bool includeInvisible=false) const { @@ -805,8 +816,8 @@ public: //! Writes attributes of the scene node. - //! Implement this to expose the attributes of your scene node for - //! scripting languages, editors, debuggers or xml serialization purposes. + /** Implement this to expose the attributes of your scene node for + scripting languages, editors, debuggers or xml serialization purposes. */ virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const { out->addInt("Id", ID ); @@ -828,8 +839,8 @@ public: //! Reads attributes of the scene node. - //! Implement this to set the attributes of your scene node for - //! scripting languages, editors, debuggers or xml deserialization purposes. + /** Implement this to set the attributes of your scene node for + scripting languages, editors, debuggers or xml deserialization purposes. */ virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) { setID(in->getAttributeAsInt("Id")); @@ -841,10 +852,10 @@ public: TabOrder = in->getAttributeAsInt("TabOrder"); core::position2di p = in->getAttributeAsPosition2d("MaxSize"); - setMaxSize(core::dimension2di(p.X,p.Y)); + setMaxSize(core::dimension2du(p.X,p.Y)); p = in->getAttributeAsPosition2d("MinSize"); - setMinSize(core::dimension2di(p.X,p.Y)); + setMinSize(core::dimension2du(p.X,p.Y)); setNotClipped(in->getAttributeAsBool("NoClip")); setAlignment((EGUI_ALIGNMENT) in->getAttributeAsEnumeration("LeftAlign", GUIAlignmentNames), @@ -883,7 +894,7 @@ protected: core::rect ScaleRect; //! maximum and minimum size of the element - core::dimension2di MaxSize, MinSize; + core::dimension2du MaxSize, MinSize; //! is visible? bool IsVisible; diff --git a/include/IGUIElementFactory.h b/include/IGUIElementFactory.h index d4d78111..1a3a733d 100644 --- a/include/IGUIElementFactory.h +++ b/include/IGUIElementFactory.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IGUIEnvironment.h b/include/IGUIEnvironment.h index 2c082f9f..a8e40e03 100644 --- a/include/IGUIEnvironment.h +++ b/include/IGUIEnvironment.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -62,8 +62,7 @@ class IGUIEnvironment : public virtual IReferenceCounted { public: - //! Draws all gui elements by traversing the GUI environment starting - //! at the root node. + //! Draws all gui elements by traversing the GUI environment starting at the root node. virtual void drawAll() = 0; //! Sets the focus to an element. @@ -75,7 +74,7 @@ public: virtual bool setFocus(IGUIElement* element) = 0; //! Returns the element which holds the focus. - //! \return Pointer to the element with focus. + /** \return Pointer to the element with focus. */ virtual IGUIElement* getFocus() const = 0; //! Removes the focus from an element. @@ -91,15 +90,15 @@ public: virtual bool hasFocus(IGUIElement* element) const = 0; //! Returns the current video driver. - //! \return Pointer to the video driver. + /** \return Pointer to the video driver. */ virtual video::IVideoDriver* getVideoDriver() const = 0; //! Returns the file system. - //! \return Pointer to the file system. + /** \return Pointer to the file system. */ virtual io::IFileSystem* getFileSystem() const = 0; //! returns a pointer to the OS operator - //! \return Pointer to the OS operator. + /** \return Pointer to the OS operator. */ virtual IOSOperator* getOSOperator() const = 0; //! Removes all elements from the environment. @@ -119,7 +118,7 @@ public: virtual void setUserEventReceiver(IEventReceiver* evr) = 0; //! Returns pointer to the current gui skin. - //! \return Pointer to the GUI skin. + /** \return Pointer to the GUI skin. */ virtual IGUISkin* getSkin() const = 0; //! Sets a new GUI Skin @@ -173,10 +172,10 @@ public: virtual IGUISpriteBank* addEmptySpriteBank(const c8 *name) = 0; //! Returns the root gui element. - /** This is the first gui element, parent of all other - gui elements. You'll never need to use this method, unless you are - creating your own gui elements, trying to add them to the gui elements - without a parent. + /** This is the first gui element, the (direct or indirect) parent of all + other gui elements. It is a valid IGUIElement, with dimensions the same + size as the screen. You should not need to use this method directly, unless + you wish to reparent GUI elements to the top level. \return Pointer to the root element of the GUI. The returned pointer should not be dropped. See IReferenceCounted::drop() for more information. */ @@ -208,10 +207,10 @@ public: virtual IGUIWindow* addWindow(const core::rect& rectangle, bool modal = false, const wchar_t* text=0, IGUIElement* parent=0, s32 id=-1) = 0; - //! Adds a modal screen. This control stops its parent's members from - //! being able to recieve input until its last child is removed, it - //! then deletes itself. - /** \param parent Parent gui element of the modal. + //! Adds a modal screen. + /** This control stops its parent's members from being able to receive + input until its last child is removed, it then deletes itself. + \param parent Parent gui element of the modal. \return Pointer to the created modal. Returns 0 if an error occured. This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ @@ -434,7 +433,7 @@ public: IGUIElement* parent=0, s32 id=-1) = 0; //! Adds a menu to the environment. - /* This is like the menu you can find on top of most windows in modern + /** This is like the menu you can find on top of most windows in modern graphical user interfaces. \param parent Parent item of the element, e.g. a window. Set it to 0 to place the menu directly in the environment. @@ -467,7 +466,15 @@ public: IGUIElement* parent=0, s32 id=-1) = 0; //! Adds a table to the environment - virtual IGUITable* addTable(const core::rect& rectangle, + /** \param rectangle Position and dimension of the table. + \param parent Parent item of the element, e.g. a window. Set it to 0 + to place the element directly in the environment. + \param id An identifier for the table. + \param drawBackground Flag whether the background should be drawn. + \return Pointer to the created table. Returns 0 if an error occured. + This pointer should not be dropped. See IReferenceCounted::drop() for + more information. */ + virtual IGUITable* addTable(const core::rect& rectangle, IGUIElement* parent=0, s32 id=-1, bool drawBackground = false) = 0; //! Returns the default element factory which can create all built in elements @@ -484,7 +491,7 @@ public: virtual void registerGUIElementFactory(IGUIElementFactory* factoryToAdd) = 0; //! Returns amount of registered gui element factories. - //! \return Amount of registered gui element factories. + /** \return Amount of registered gui element factories. */ virtual u32 getRegisteredGUIElementFactoryCount() const = 0; //! Returns a gui element factory by index @@ -494,23 +501,23 @@ public: virtual IGUIElement* addGUIElement(const c8* elementName, IGUIElement* parent=0) = 0; //! Saves the current gui into a file. - //! \param filename Name of the file. - //! \param start The GUIElement to start with. Root if 0. + /** \param filename Name of the file. + \param start The GUIElement to start with. Root if 0. */ virtual bool saveGUI(const c8* filename, IGUIElement* start=0) = 0; //! Saves the current gui into a file. - //! \param file The file to write to. - //! \param start The GUIElement to start with. Root if 0. + /** \param file The file to write to. + \param start The GUIElement to start with. Root if 0. */ virtual bool saveGUI(io::IWriteFile* file, IGUIElement* start=0) = 0; //! Loads the gui. Note that the current gui is not cleared before. - //! \param filename Name of the file . - //! \param parent Parent for the loaded GUI, root if 0. + /** \param filename Name of the file. + \param parent Parent for the loaded GUI, root if 0. */ virtual bool loadGUI(const c8* filename, IGUIElement* parent=0) = 0; //! Loads the gui. Note that the current gui is not cleared before. - //! \param file The file to load from. - //! \param parent Parent for the loaded GUI, root if 0. + /** \param file The file to load from. + \param parent Parent for the loaded GUI, root if 0. */ virtual bool loadGUI(io::IReadFile* file, IGUIElement* parent=0) = 0; //! Writes attributes of the gui environment @@ -523,7 +530,7 @@ public: virtual void writeGUIElement(io::IXMLWriter* writer, IGUIElement* node) =0; //! reads an element - virtual void readGUIElement(io::IXMLReader* reader, IGUIElement* parent) =0; + virtual void readGUIElement(io::IXMLReader* reader, IGUIElement* node) =0; }; diff --git a/include/IGUIFileOpenDialog.h b/include/IGUIFileOpenDialog.h index 11e30257..5b7270b7 100644 --- a/include/IGUIFileOpenDialog.h +++ b/include/IGUIFileOpenDialog.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IGUIFont.h b/include/IGUIFont.h index 25cf18bd..21383207 100644 --- a/include/IGUIFont.h +++ b/include/IGUIFont.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -21,13 +21,13 @@ enum EGUI_FONT_TYPE EGFT_BITMAP = 0, //! Scalable vector fonts loaded from an XML file. - //! These fonts reside in system memory and use no video memory - //! until they are displayed. These are slower than bitmap fonts - //! but can be easily scaled and rotated. + /** These fonts reside in system memory and use no video memory + until they are displayed. These are slower than bitmap fonts + but can be easily scaled and rotated. */ EGFT_VECTOR, //! A font which uses a the native API provided by the operating system. - //! Currently not used. + /** Currently not used. */ EGFT_OS, //! An external font type provided by the user. @@ -54,7 +54,7 @@ public: //! Calculates the dimension of a text. /** \return Returns width and height of the area covered by the text if it would be drawn. */ - virtual core::dimension2d getDimension(const wchar_t* text) const = 0; + virtual core::dimension2d getDimension(const wchar_t* text) const = 0; //! Calculates the index of the character in the text which is on a specific position. /** \param text: Text string. @@ -66,8 +66,10 @@ public: //! Returns the type of this font virtual EGUI_FONT_TYPE getType() const { return EGFT_CUSTOM; } - //! Sets global kerning for the font. + //! Sets global kerning width for the font. virtual void setKerningWidth (s32 kerning) = 0; + + //! Sets global kerning height for the font. virtual void setKerningHeight (s32 kerning) = 0; //! Gets kerning values (distance between letters) for the font. If no parameters are provided, diff --git a/include/IGUIFontBitmap.h b/include/IGUIFontBitmap.h index b3487886..152ca106 100644 --- a/include/IGUIFontBitmap.h +++ b/include/IGUIFontBitmap.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IGUIImage.h b/include/IGUIImage.h index 566719e9..55e62473 100644 --- a/include/IGUIImage.h +++ b/include/IGUIImage.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IGUIInOutFader.h b/include/IGUIInOutFader.h index 18357c1e..37324187 100644 --- a/include/IGUIInOutFader.h +++ b/include/IGUIInOutFader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -36,22 +36,23 @@ namespace gui virtual video::SColor getColor() const = 0; //! Sets the color to fade out to or to fade in from. - //! \param color: Color to where it is faded out od from it is faded in. + /** \param color: Color to where it is faded out od from it is faded in. */ virtual void setColor(video::SColor color) = 0; virtual void setColor(video::SColor source, video::SColor dest) = 0; - //! Starts the fade in process. In the beginning the whole rect is drawn by - //! the set color (black by default) and at the end of the overgiven - //! time the color has faded out. - //! \param time: Time specifing how long it should need to fade in, - //! in milliseconds. + //! Starts the fade in process. + /** In the beginning the whole rect is drawn by the set color + (black by default) and at the end of the overgiven time the + color has faded out. + \param time: Time specifing how long it should need to fade in, + in milliseconds. */ virtual void fadeIn(u32 time) = 0; - //! Starts the fade out process. In the beginning everything is visible, - //! and at the end of the time only the set color (black by the fault) - //! will be drawn. - //! \param time: Time specifing how long it should need to fade out, - //! in milliseconds. + //! Starts the fade out process. + /** In the beginning everything is visible, and at the end of + the time only the set color (black by the fault) will be drawn. + \param time: Time specifing how long it should need to fade out, + in milliseconds. */ virtual void fadeOut(u32 time) = 0; //! Returns if the fade in or out process is done. diff --git a/include/IGUIListBox.h b/include/IGUIListBox.h index 40adcc94..26fa089d 100644 --- a/include/IGUIListBox.h +++ b/include/IGUIListBox.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -12,7 +12,6 @@ namespace irr { namespace gui { - class IGUIFont; class IGUISpriteBank; //! Enumeration for listbox colors @@ -49,10 +48,9 @@ namespace gui virtual u32 addItem(const wchar_t* text) = 0; //! adds an list item with an icon - //! \param text Text of list entry - //! \param icon Sprite index of the Icon within the current sprite bank. Set it to -1 if you want no icon - //! \return - //! returns the id of the new created item + /** \param text Text of list entry + \param icon Sprite index of the Icon within the current sprite bank. Set it to -1 if you want no icon + \return The id of the new created item */ virtual u32 addItem(const wchar_t* text, s32 icon) = 0; //! Removes an item from the list @@ -61,10 +59,11 @@ namespace gui //! Returns the icon of an item virtual s32 getIcon(u32 index) const = 0; - //! Sets the sprite bank which should be used to draw list icons. This font is set to the sprite bank of - //! the built-in-font by default. A sprite can be displayed in front of every list item. - //! An icon is an index within the icon sprite bank. Several default icons are available in the - //! skin through getIcon + //! Sets the sprite bank which should be used to draw list icons. + /** This font is set to the sprite bank of the built-in-font by + default. A sprite can be displayed in front of every list item. + An icon is an index within the icon sprite bank. Several + default icons are available in the skin through getIcon. */ virtual void setSpriteBank(IGUISpriteBank* bank) = 0; //! clears the list, deletes all items in the listbox @@ -76,8 +75,7 @@ namespace gui //! sets the selected item. Set this to -1 if no item should be selected virtual void setSelected(s32 index) = 0; - //! set whether the listbox should scroll to show a newly selected item - //! or a new item as it is added to the list. + //! set whether the listbox should scroll to new or newly selected items virtual void setAutoScrollEnabled(bool scroll) = 0; //! returns true if automatic scrolling is enabled, false if not. @@ -108,7 +106,7 @@ namespace gui virtual void setItem(u32 index, const wchar_t* text, s32 icon) = 0; //! Insert the item at the given index - //! Return the index on success or -1 on failure. + /** \return The index on success or -1 on failure. */ virtual s32 insertItem(u32 index, const wchar_t* text, s32 icon) = 0; //! Swap the items at the given indices diff --git a/include/IGUIMeshViewer.h b/include/IGUIMeshViewer.h index a1dd39b3..5bc499f5 100644 --- a/include/IGUIMeshViewer.h +++ b/include/IGUIMeshViewer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IGUIScrollBar.h b/include/IGUIScrollBar.h index cbcb35c1..9b60e1f0 100644 --- a/include/IGUIScrollBar.h +++ b/include/IGUIScrollBar.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -30,15 +30,17 @@ namespace gui //! gets the small step value virtual s32 getSmallStep() const = 0; - //! Sets the small step, the amount that the value changes by when clicking - //! on the buttons or using the cursor keys. + //! Sets the small step + /** That is the amount that the value changes by when clicking + on the buttons or using the cursor keys. */ virtual void setSmallStep(s32 step) = 0; //! gets the large step value virtual s32 getLargeStep() const = 0; - //! Sets the large step, the amount that the value changes by when clicking - //! in the tray, or using the page up and page down keys. + //! Sets the large step + /** That is the amount that the value changes by when clicking + in the tray, or using the page up and page down keys. */ virtual void setLargeStep(s32 step) = 0; //! gets the current position of the scrollbar diff --git a/include/IGUISkin.h b/include/IGUISkin.h index 3b86b4dd..e79df2bb 100644 --- a/include/IGUISkin.h +++ b/include/IGUISkin.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -460,7 +460,8 @@ namespace gui implementations to find out how to draw the part exactly. \param active: Specifies if the tab is currently active. \param rect: Defining area where to draw. - \param clip: Clip area. */ + \param clip: Clip area. + \param alignment Alignment of GUI element. */ virtual void draw3DTabButton(IGUIElement* element, bool active, const core::rect& rect, const core::rect* clip=0, gui::EGUI_ALIGNMENT alignment=EGUIA_UPPERLEFT) = 0; @@ -471,7 +472,9 @@ namespace gui \param border: Specifies if the border should be drawn. \param background: Specifies if the background should be drawn. \param rect: Defining area where to draw. - \param clip: Clip area. */ + \param clip: Clip area. + \param tabHeight Height of tab. + \param alignment Alignment of GUI element. */ virtual void draw3DTabBody(IGUIElement* element, bool border, bool background, const core::rect& rect, const core::rect* clip=0, s32 tabHeight=-1, gui::EGUI_ALIGNMENT alignment=EGUIA_UPPERLEFT ) = 0; @@ -511,6 +514,3 @@ namespace gui #endif - - - diff --git a/include/IGUISpinBox.h b/include/IGUISpinBox.h index f8dafbe2..36c67ab1 100644 --- a/include/IGUISpinBox.h +++ b/include/IGUISpinBox.h @@ -1,4 +1,4 @@ -// Copyright (C) 2006-2008 Michael Zeilfelder +// Copyright (C) 2006-2009 Michael Zeilfelder // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IGUISpriteBank.h b/include/IGUISpriteBank.h index df46002d..0a4032de 100644 --- a/include/IGUISpriteBank.h +++ b/include/IGUISpriteBank.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IGUIStaticText.h b/include/IGUIStaticText.h index b207b0f7..18cc2440 100644 --- a/include/IGUIStaticText.h +++ b/include/IGUIStaticText.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -29,7 +29,7 @@ namespace gui virtual void setOverrideFont(IGUIFont* font=0) = 0; //! Gets the override font (if any) - //! \return The override font (may be 0) + /** \return The override font (may be 0) */ virtual IGUIFont* getOverrideFont(void) const = 0; //! Sets another color for the text. @@ -43,7 +43,7 @@ namespace gui virtual void setOverrideColor(video::SColor color) = 0; //! Gets the override color - //! \return: The override color + /** \return: The override color */ virtual video::SColor const& getOverrideColor(void) const = 0; //! Sets if the static text should use the overide color or the color in the gui skin. @@ -53,7 +53,7 @@ namespace gui virtual void enableOverrideColor(bool enable) = 0; //! Checks if an override color is enabled - //! \return true if the override color is enabled, false otherwise + /** \return true if the override color is enabled, false otherwise */ virtual bool isOverrideColorEnabled(void) const = 0; //! Sets another color for the background. @@ -78,7 +78,7 @@ namespace gui virtual void setWordWrap(bool enable) = 0; //! Checks if word wrap is enabled - //! \return true if word wrap is enabled, false otherwise + /** \return true if word wrap is enabled, false otherwise */ virtual bool isWordWrapEnabled(void) const = 0; //! Returns the height of the text in pixels when it is drawn. diff --git a/include/IGUITabControl.h b/include/IGUITabControl.h index 37251725..b106d6d2 100644 --- a/include/IGUITabControl.h +++ b/include/IGUITabControl.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -87,7 +87,7 @@ namespace gui virtual s32 getTabHeight() const = 0; //! Set the alignment of the tabs - //! Use EGUIA_UPPERLEFT or EGUIA_LOWERRIGHT + /** Use EGUIA_UPPERLEFT or EGUIA_LOWERRIGHT */ virtual void setTabVerticalAlignment( gui::EGUI_ALIGNMENT alignment ) = 0; //! Get the alignment of the tabs @@ -108,7 +108,3 @@ namespace gui #endif - - - - diff --git a/include/IGUITable.h b/include/IGUITable.h index 86f6f704..fb7f81c5 100644 --- a/include/IGUITable.h +++ b/include/IGUITable.h @@ -1,4 +1,4 @@ -// Copyright (C) 2003-2008 Nikolaus Gebhardt +// Copyright (C) 2003-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -21,7 +21,7 @@ namespace gui //! Do not use ordering EGCO_NONE, - //! Send a EGET_TABLE_HEADER_CHANGED message when a column header is clicked. + //! Send a EGET_TABLE_HEADER_CHANGED message when a column header is clicked. EGCO_CUSTOM, //! Sort it ascending by it's ascii value like: a,b,c,... @@ -48,7 +48,7 @@ namespace gui 0, }; - enum EGUI_ORDERING_MODE + enum EGUI_ORDERING_MODE { //! No element ordering EGOM_NONE, @@ -66,6 +66,7 @@ namespace gui const c8* const GUIOrderingModeNames[] = { + "none", "ascending", "descending", 0 @@ -79,8 +80,6 @@ namespace gui EGTDF_COUNT }; - class IGUIFont; - //! Default list box GUI element. class IGUITable : public IGUIElement { @@ -90,7 +89,7 @@ namespace gui : IGUIElement(EGUIET_TABLE, environment, parent, id, rectangle) {} //! Adds a column - //! If columnIndex is outside the current range, do push new colum at the end + /** If columnIndex is outside the current range, do push new colum at the end */ virtual void addColumn(const wchar_t* caption, s32 columnIndex=-1) = 0; //! remove a column from the table @@ -101,8 +100,8 @@ namespace gui //! Makes a column active. This will trigger an ordering process. /** \param idx: The id of the column to make active. - //! \param doOrder: Do also the ordering which depending on mode for active column - \return Returns true if successful. */ + \param doOrder: Do also the ordering which depending on mode for active column + \return True if successful. */ virtual bool setActiveColumn(s32 idx, bool doOrder=false) = 0; //! Returns which header is currently active @@ -113,18 +112,16 @@ namespace gui //! Set the width of a column virtual void setColumnWidth(u32 columnIndex, u32 width) = 0; - + //! columns can be resized by drag 'n drop virtual void setResizableColumns(bool resizable) = 0; - + //! can columns be resized by dran 'n drop? virtual bool hasResizableColumns() const = 0; - //! This tells the table control which ordering mode should be used when - //! a column header is clicked. - /** \param columnIndex: The index of the column header. - \param state: If true, a EGET_TABLE_HEADER_CHANGED message will be sent and you can order the table data as you whish.*/ - //! \param mode: One of the modes defined in EGUI_COLUMN_ORDERING + //! This tells the table control which ordering mode should be used when a column header is clicked. + /** \param columnIndex The index of the column header. + \param mode: One of the modes defined in EGUI_COLUMN_ORDERING */ virtual void setColumnOrdering(u32 columnIndex, EGUI_COLUMN_ORDERING mode) = 0; //! Returns which row is currently selected @@ -134,10 +131,12 @@ namespace gui virtual s32 getRowCount() const = 0; //! adds a row to the table - /** \param rowIndex: zero based index of rows. The row will be inserted at this - position, if a row already exist there, it will be placed after it. If the row - is larger than the actual number of row by more than one, it won't be created. - Note that if you create a row that's not at the end, there might be performance issues*/ + /** \param rowIndex Zero based index of rows. The row will be + inserted at this position, if a row already exist there, it + will be placed after it. If the row is larger than the actual + number of row by more than one, it won't be created. Note that + if you create a row that's not at the end, there might be + performance issues. */ virtual void addRow(u32 rowIndex) = 0; //! Remove a row from the table @@ -149,11 +148,13 @@ namespace gui //! Swap two row positions. This is useful for a custom ordering algo. virtual void swapRows(u32 rowIndexA, u32 rowIndexB) = 0; - //! This tells the table to start ordering all the rows. You need to explicitly - //! tell the table to re order the rows when a new row is added or the cells data is - //! changed. This makes the system more flexible and doesn't make you pay the cost of - //! ordering when adding a lot of rows. - //! \param columnIndex: When set to -1 the active column is used. + //! This tells the table to start ordering all the rows. + /** You need to explicitly tell the table to re order the rows + when a new row is added or the cells data is changed. This + makes the system more flexible and doesn't make you pay the + cost of ordering when adding a lot of rows. + \param columnIndex: When set to -1 the active column is used. + \param mode Ordering mode of the rows. */ virtual void orderRows(s32 columnIndex=-1, EGUI_ORDERING_MODE mode=EGOM_NONE) = 0; //! Set the text of a cell diff --git a/include/IGUIToolbar.h b/include/IGUIToolbar.h index f70fb28b..962d624d 100644 --- a/include/IGUIToolbar.h +++ b/include/IGUIToolbar.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IGUIWindow.h b/include/IGUIWindow.h index 761cbef2..b23aca0d 100644 --- a/include/IGUIWindow.h +++ b/include/IGUIWindow.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IImage.h b/include/IImage.h index 6bb2e21d..c24c9405 100644 --- a/include/IImage.h +++ b/include/IImage.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -58,7 +58,7 @@ public: virtual void unlock() = 0; //! Returns width and height of image data. - virtual const core::dimension2d& getDimension() const = 0; + virtual const core::dimension2d& getDimension() const = 0; //! Returns bits per pixel. virtual u32 getBitsPerPixel() const = 0; @@ -97,7 +97,7 @@ public: virtual u32 getPitch() const =0; //! Copies the image into the target, scaling the image to fit - virtual void copyToScaling(void* target, s32 width, s32 height, ECOLOR_FORMAT format=ECF_A8R8G8B8, u32 pitch=0) =0; + virtual void copyToScaling(void* target, u32 width, u32 height, ECOLOR_FORMAT format=ECF_A8R8G8B8, u32 pitch=0) =0; //! Copies the image into the target, scaling the image to fit virtual void copyToScaling(IImage* target) =0; diff --git a/include/IImageLoader.h b/include/IImageLoader.h index f4f81b8f..f252776b 100644 --- a/include/IImageLoader.h +++ b/include/IImageLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IImageWriter.h b/include/IImageWriter.h index 17759e87..bf622012 100644 --- a/include/IImageWriter.h +++ b/include/IImageWriter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IIndexBuffer.h b/include/IIndexBuffer.h index a2fe01d0..b8d3a7e0 100644 --- a/include/IIndexBuffer.h +++ b/include/IIndexBuffer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Nikolaus Gebhardt +// Copyright (C) 2008-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/ILightManager.h b/include/ILightManager.h new file mode 100644 index 00000000..274c698b --- /dev/null +++ b/include/ILightManager.h @@ -0,0 +1,60 @@ +// Written by Colin MacDonald - all rights assigned to Nikolaus Gebhardt +// Copyright (C) 2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_LIGHT_MANAGER_H_INCLUDED__ +#define __I_LIGHT_MANAGER_H_INCLUDED__ + +#include "IReferenceCounted.h" +#include "irrArray.h" + +namespace irr +{ +namespace scene +{ + class ILightSceneNode; + + //! ILightManager provides an interface for user applications to manipulate the list + //! of lights in the scene. The light list can be trimmed or re-ordered before device/ + //! hardware lights are created, and/or individual lights can be switched on and off + //! before or after each scene node is rendered. + //! It is assumed that the ILightManager implementation will store any data that it wishes + //! to retain, i.e. the ISceneManager to which it is assigned, the lightList, the current + //! render pass, and the current scene node. + class ILightManager : public IReferenceCounted + { + public: + //! Called after the scene's light list has been built, but before rendering has begun. + //! As actual device/hardware lights are not created until the ESNRP_LIGHT render pass, + //! this provides an opportunity for the light manager to trim or re-order the light + //! list, before any device/hardware lights have actually been created. + //! \param[in] smgr: the Scene Manager + //! \param[inout] lightLight: the Scene Manager's light list, which the light manager may + //! modify. This reference will remain valid until OnPostRender(). + virtual void OnPreRender(core::array & lightList) = 0; + + //! Called after the last scene node is rendered. + //! After this call returns, the lightList passed to OnPreRender() becomes invalid. + virtual void OnPostRender(void) = 0; + + //! Called before a render pass begins + //! \param[in] renderPass: the render pass that's about to begin + virtual void OnRenderPassPreRender(E_SCENE_NODE_RENDER_PASS renderPass) = 0; + + //! Called after the render pass specified in OnRenderPassPreRender() ends + //! \param[in] renderPass: the render pass that has finished + virtual void OnRenderPassPostRender(E_SCENE_NODE_RENDER_PASS renderPass) = 0; + + //! Called before the given scene node is rendered + //! \param[in] node: the scene node that's about to be rendered + virtual void OnNodePreRender(ISceneNode* node) = 0; + + //! Called after the the node specified in OnNodePreRender() has been rendered + //! \param[in] node: the scene node that has just been rendered + virtual void OnNodePostRender(ISceneNode* node) = 0; + }; +} // end namespace scene +} // end namespace irr + +#endif diff --git a/include/ILightSceneNode.h b/include/ILightSceneNode.h index 3bc89c0c..53e9f17f 100644 --- a/include/ILightSceneNode.h +++ b/include/ILightSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -40,6 +40,12 @@ public: /** \return The light data. */ virtual video::SLight& getLightData() = 0; + //! Sets if the node should be visible or not. + /** All children of this node won't be visible either, when set + to true. + \param isVisible If the node shall be visible. */ + virtual void setVisible(bool isVisible) = 0; + //! Sets the light's radius of influence. /** Outside this radius the light won't lighten geometry and cast no shadows. Setting the radius will also influence the attenuation, setting diff --git a/include/ILogger.h b/include/ILogger.h index 4377b1b9..bedfa8af 100644 --- a/include/ILogger.h +++ b/include/ILogger.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IMaterialRenderer.h b/include/IMaterialRenderer.h index 1adc8b59..b9396d57 100644 --- a/include/IMaterialRenderer.h +++ b/include/IMaterialRenderer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IMaterialRendererServices.h b/include/IMaterialRendererServices.h index 0670e69b..fc726486 100644 --- a/include/IMaterialRendererServices.h +++ b/include/IMaterialRendererServices.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IMesh.h b/include/IMesh.h index 44820dae..2a1a86ec 100644 --- a/include/IMesh.h +++ b/include/IMesh.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IMeshBuffer.h b/include/IMeshBuffer.h index 3fee8737..de575ef8 100644 --- a/include/IMeshBuffer.h +++ b/include/IMeshBuffer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IMeshCache.h b/include/IMeshCache.h index b2f293a3..4c6837bd 100644 --- a/include/IMeshCache.h +++ b/include/IMeshCache.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IMeshLoader.h b/include/IMeshLoader.h index 9d30ac86..5b26358a 100644 --- a/include/IMeshLoader.h +++ b/include/IMeshLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IMeshManipulator.h b/include/IMeshManipulator.h index 512e33e2..a667384c 100644 --- a/include/IMeshManipulator.h +++ b/include/IMeshManipulator.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -79,10 +79,10 @@ namespace scene /** \param mesh Mesh on which the operation is performed. \param factor Vector which defines the scale for each axis. \param level Number of texture coord, starting from 1. Support for level 2 exists for LightMap buffers. */ - virtual void scaleTCoords(scene::IMesh* mesh, const core::vector2df& factor, u32 layer=1) const =0; + virtual void scaleTCoords(scene::IMesh* mesh, const core::vector2df& factor, u32 level=1) const =0; //! Scale the texture coords of a meshbuffer. - /** \param mesh Mesh on which the operation is performed. + /** \param buffer Meshbuffer on which the operation is performed. \param factor Vector which defines the scale for each axis. \param level Number of texture coord, starting from 1. Support for level 2 exists for LightMap buffers. */ virtual void scaleTCoords(scene::IMeshBuffer* buffer, const core::vector2df& factor, u32 level=1) const =0; @@ -106,8 +106,8 @@ namespace scene //! Clones a static IMesh into a modifiable SMesh. /** All meshbuffers in the returned SMesh are of type SMeshBuffer or SMeshBufferLightMap. - \param mesh: Mesh to copy. - \return Returns the cloned mesh. If you no longer need the + \param mesh Mesh to copy. + \return Cloned mesh. If you no longer need the cloned mesh, you should call SMesh::drop(). See IReferenceCounted::drop() for more information. */ virtual SMesh* createMeshCopy(IMesh* mesh) const = 0; diff --git a/include/IMeshSceneNode.h b/include/IMeshSceneNode.h index c6df634d..77fc9ba2 100644 --- a/include/IMeshSceneNode.h +++ b/include/IMeshSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IMeshWriter.h b/include/IMeshWriter.h index 79e7ddee..9b8f095a 100644 --- a/include/IMeshWriter.h +++ b/include/IMeshWriter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IMetaTriangleSelector.h b/include/IMetaTriangleSelector.h index ba7dee71..a4e07a4d 100644 --- a/include/IMetaTriangleSelector.h +++ b/include/IMetaTriangleSelector.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IOSOperator.h b/include/IOSOperator.h index bf5f0bc0..3bc1737b 100644 --- a/include/IOSOperator.h +++ b/include/IOSOperator.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IParticleAffector.h b/include/IParticleAffector.h index 3af84520..7843c91f 100644 --- a/include/IParticleAffector.h +++ b/include/IParticleAffector.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IParticleAnimatedMeshSceneNodeEmitter.h b/include/IParticleAnimatedMeshSceneNodeEmitter.h index 608af5cd..f29b26a8 100644 --- a/include/IParticleAnimatedMeshSceneNodeEmitter.h +++ b/include/IParticleAnimatedMeshSceneNodeEmitter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IParticleAttractionAffector.h b/include/IParticleAttractionAffector.h index 3a8d5ebf..3ac81497 100644 --- a/include/IParticleAttractionAffector.h +++ b/include/IParticleAttractionAffector.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IParticleBoxEmitter.h b/include/IParticleBoxEmitter.h index 350253a4..5dd1e8a2 100644 --- a/include/IParticleBoxEmitter.h +++ b/include/IParticleBoxEmitter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IParticleCylinderEmitter.h b/include/IParticleCylinderEmitter.h index 1f88cd85..ed66448f 100644 --- a/include/IParticleCylinderEmitter.h +++ b/include/IParticleCylinderEmitter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IParticleEmitter.h b/include/IParticleEmitter.h index 5c2173b5..02c8698d 100644 --- a/include/IParticleEmitter.h +++ b/include/IParticleEmitter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IParticleFadeOutAffector.h b/include/IParticleFadeOutAffector.h index 09a5f4c2..54f14da0 100644 --- a/include/IParticleFadeOutAffector.h +++ b/include/IParticleFadeOutAffector.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IParticleGravityAffector.h b/include/IParticleGravityAffector.h index 5fd49848..45b6da31 100644 --- a/include/IParticleGravityAffector.h +++ b/include/IParticleGravityAffector.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IParticleMeshEmitter.h b/include/IParticleMeshEmitter.h index 30034cf3..69761faa 100644 --- a/include/IParticleMeshEmitter.h +++ b/include/IParticleMeshEmitter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IParticleRingEmitter.h b/include/IParticleRingEmitter.h index 37078f4d..9c3c6b58 100644 --- a/include/IParticleRingEmitter.h +++ b/include/IParticleRingEmitter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IParticleRotationAffector.h b/include/IParticleRotationAffector.h index 738316d1..58c743fd 100644 --- a/include/IParticleRotationAffector.h +++ b/include/IParticleRotationAffector.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IParticleSphereEmitter.h b/include/IParticleSphereEmitter.h index c008e8e4..bc1b6eef 100644 --- a/include/IParticleSphereEmitter.h +++ b/include/IParticleSphereEmitter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IParticleSystemSceneNode.h b/include/IParticleSystemSceneNode.h index 80268e53..5835ca07 100644 --- a/include/IParticleSystemSceneNode.h +++ b/include/IParticleSystemSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IQ3LevelMesh.h b/include/IQ3LevelMesh.h index 19041e86..2f5948c5 100644 --- a/include/IQ3LevelMesh.h +++ b/include/IQ3LevelMesh.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IQ3Shader.h b/include/IQ3Shader.h index 4c0dcf36..fbaf1deb 100644 --- a/include/IQ3Shader.h +++ b/include/IQ3Shader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2006-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2006-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -180,9 +180,9 @@ namespace quake3 switch ( isEqual ( string, pos, funclist, 2 ) ) { case 0: - ret = 1; + ret = video::ECFN_LESSEQUAL; case 1: - ret = 2; + ret = video::ECFN_EQUAL; break; } return ret; diff --git a/include/IReadFile.h b/include/IReadFile.h index 0abbf13c..78d76700 100644 --- a/include/IReadFile.h +++ b/include/IReadFile.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IReferenceCounted.h b/include/IReferenceCounted.h index 74397a7c..68a572ce 100644 --- a/include/IReferenceCounted.h +++ b/include/IReferenceCounted.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -28,7 +28,7 @@ namespace irr If you want to create a texture, you may want to call an imaginable method IDriver::createTexture. You call - ITexture* texture = driver->createTexture(dimension2d(128, 128)); + ITexture* texture = driver->createTexture(dimension2d(128, 128)); If you no longer need the texture, call texture->drop(). If you want to load a texture, you may want to call imaginable method @@ -75,7 +75,7 @@ namespace irr If you want to create a texture, you may want to call an imaginable method IDriver::createTexture. You call - ITexture* texture = driver->createTexture(dimension2d(128, 128)); + ITexture* texture = driver->createTexture(dimension2d(128, 128)); If you no longer need the texture, call texture->drop(). If you want to load a texture, you may want to call imaginable method IDriver::loadTexture. You do this like @@ -104,7 +104,7 @@ namespace irr If you want to create a texture, you may want to call an imaginable method IDriver::createTexture. You call - ITexture* texture = driver->createTexture(dimension2d(128, 128)); + ITexture* texture = driver->createTexture(dimension2d(128, 128)); If you no longer need the texture, call texture->drop(). If you want to load a texture, you may want to call imaginable method IDriver::loadTexture. You do this like diff --git a/include/ISceneCollisionManager.h b/include/ISceneCollisionManager.h index b9c7ee13..ba028661 100644 --- a/include/ISceneCollisionManager.h +++ b/include/ISceneCollisionManager.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -38,10 +38,13 @@ namespace scene 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 outNode: If a collision is detected, this will contain + the scene node associated with the triangle that was hit. \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) = 0; + core::triangle3df& outTriangle, + const ISceneNode*& outNode) = 0; //! 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 @@ -61,6 +64,7 @@ namespace scene causing a collision is stored, if there is a collision. \param outFalling: Is set to true if the ellipsoid is falling down, caused by gravity. + \param outNode: the node with which the ellipoid collided (if any) \param slidingSpeed: DOCUMENTATION NEEDED. \param gravityDirectionAndSpeed: Direction and force of gravity. \return New position of the ellipsoid. */ @@ -72,6 +76,7 @@ namespace scene core::triangle3df& triout, core::vector3df& hitPosition, bool& outFalling, + const ISceneNode*& outNode, f32 slidingSpeed = 0.0005f, const core::vector3df& gravityDirectionAndSpeed = core::vector3df(0.0f, 0.0f, 0.0f)) = 0; @@ -84,7 +89,7 @@ namespace scene at a length of the far value of the camera at a position which would be behind the 2d screen coodinates. */ virtual core::line3d getRayFromScreenCoordinates( - core::position2d pos, ICameraSceneNode* camera = 0) = 0; + const core::position2d & pos, ICameraSceneNode* camera = 0) = 0; //! Calculates 2d screen position from a 3d position. /** \param pos: 3D position in world space to be transformed @@ -98,7 +103,7 @@ namespace scene method for drawing a decorator over a 3d object, it will be clipped by the screen borders. */ virtual core::position2d getScreenCoordinatesFrom3DPosition( - core::vector3df pos, ICameraSceneNode* camera=0) = 0; + const core::vector3df & pos, ICameraSceneNode* camera=0) = 0; //! Gets the scene node, which is currently visible under the given screencoordinates, viewed from the currently active camera. /** The collision tests are done using a bounding box for each @@ -113,7 +118,7 @@ namespace scene \return Visible scene node under screen coordinates with matching bits in its id. If there is no scene node under this position, 0 is returned. */ - virtual ISceneNode* getSceneNodeFromScreenCoordinatesBB(core::position2d pos, + virtual ISceneNode* getSceneNodeFromScreenCoordinatesBB(const core::position2d & pos, s32 idBitMask=0, bool bNoDebugObjects = false) = 0; //! Get the nearest scene node which collides with a 3d ray and whose id matches a bitmask. @@ -128,7 +133,7 @@ namespace scene \return Scene node nearest to ray.start, which collides with the ray and matches the idBitMask, if the mask is not null. If no scene node is found, 0 is returned. */ - virtual ISceneNode* getSceneNodeFromRayBB(core::line3d ray, + virtual ISceneNode* getSceneNodeFromRayBB(const core::line3d & ray, s32 idBitMask=0, bool bNoDebugObjects = false) = 0; //! Get the scene node, which the overgiven camera is looking at and whose id matches the bitmask. diff --git a/include/ISceneManager.h b/include/ISceneManager.h index 5cf411c3..abf364eb 100644 --- a/include/ISceneManager.h +++ b/include/ISceneManager.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -113,6 +113,7 @@ namespace scene class ISceneNodeFactory; class ISceneNodeAnimatorFactory; class ISceneUserDataSerializer; + class ILightManager; namespace quake3 { @@ -144,7 +145,7 @@ namespace scene //! Destructor virtual ~ISceneManager() {} - //! Returns pointer to an animateable mesh. Loads the file if not loaded already. + //! Get pointer to an animateable mesh. Loads the file if not loaded already. /** * If you want to remove a loaded mesh from the cache again, use removeMesh(). * Currently there are the following mesh formats supported: @@ -329,13 +330,12 @@ namespace scene * If you would like to implement and add your own file format loader to Irrlicht, * see addExternalMeshLoader(). * \param filename: Filename of the mesh to load. - * \return Returns NULL if failed and the pointer to the mesh if - * successful. + * \return Null if failed, otherwise pointer to the mesh. * This pointer should not be dropped. See IReferenceCounted::drop() for more information. **/ virtual IAnimatedMesh* getMesh(const c8* filename) = 0; - //! Returns pointer to an animateable mesh. Loads the file if not loaded already. + //! Get pointer to an animateable mesh. Loads the file if not loaded already. /** Works just as getMesh(const char* filename). If you want to remove a loaded mesh from the cache again, use removeMesh(). \param file File handle of the mesh to load. @@ -344,24 +344,23 @@ namespace scene IReferenceCounted::drop() for more information. */ virtual IAnimatedMesh* getMesh(io::IReadFile* file) = 0; - //! Returns an interface to the mesh cache which is shared beween all existing scene managers. + //! Get interface to the mesh cache which is shared beween all existing scene managers. /** With this interface, it is possible to manually add new loaded meshes (if ISceneManager::getMesh() is not sufficient), to remove them and to iterate through already loaded meshes. */ virtual IMeshCache* getMeshCache() = 0; - //! Returns the video driver. - /** \return Returns pointer to the video Driver. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + //! Get the video driver. + /** \return Pointer to the video Driver. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual video::IVideoDriver* getVideoDriver() = 0; - //! Returns the active GUIEnvironment - /** \return Returns pointer to the GUIEnvironment - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + //! Get the active GUIEnvironment + /** \return Pointer to the GUIEnvironment + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual gui::IGUIEnvironment* getGUIEnvironment() = 0; //! adds Volume Lighting Scene Node. - //! the returned pointer must not be dropped. /** Example Usage: scene::IVolumeLightSceneNode * n = smgr->addVolumeLightSceneNode(NULL, -1, 32, 32, //Subdivide U/V @@ -373,7 +372,8 @@ namespace scene n->setScale(core::vector3df(46.0f, 45.0f, 46.0f)); n->getMaterial(0).setTexture(0, smgr->getVideoDriver()->getTexture("lightFalloff.png")); } - **/ + \return Pointer to the volumeLight if successful, otherwise NULL. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual IVolumeLightSceneNode* addVolumeLightSceneNode(ISceneNode* parent=0, s32 id=-1, const u32 subdivU = 32, const u32 subdivV = 32, const video::SColor foot = video::SColor(51, 0, 230, 180), @@ -389,10 +389,10 @@ namespace scene \param parent: Parent of the scene node. Can be NULL if no parent. \param id: Id of the node. This id can be used to identify the scene node. \param position: Position of the space relative to its parent where the - scene node will be placed. + scene node will be placed. \param rotation: Initital rotation of the scene node. \param scale: Initial scale of the scene node. - \return Returns pointer to the created test scene node. This + \return Pointer to the created test scene node. This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual IMeshSceneNode* addCubeSceneNode(f32 size=10.0f, ISceneNode* parent=0, s32 id=-1, @@ -407,10 +407,10 @@ namespace scene \param parent: Parent of the scene node. Can be NULL if no parent. \param id: Id of the node. This id can be used to identify the scene node. \param position: Position of the space relative to its parent where the - scene node will be placed. + scene node will be placed. \param rotation: Initital rotation of the scene node. \param scale: Initial scale of the scene node. - \return Returns pointer to the created test scene node. This + \return Pointer to the created test scene node. This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual IMeshSceneNode* addSphereSceneNode(f32 radius=5.0f, s32 polyCount=16, @@ -428,7 +428,7 @@ namespace scene \param rotation: Initital rotation of the scene node. \param scale: Initial scale of the scene node. \param alsoAddIfMeshPointerZero: Add the scene node even if a 0 pointer is passed. - \return Returns pointer to the created scene node. + \return Pointer to the created scene node. This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual IAnimatedMeshSceneNode* addAnimatedMeshSceneNode(IAnimatedMesh* mesh, ISceneNode* parent=0, s32 id=-1, @@ -446,7 +446,7 @@ namespace scene \param rotation: Initital rotation of the scene node. \param scale: Initial scale of the scene node. \param alsoAddIfMeshPointerZero: Add the scene node even if a 0 pointer is passed. - \return Returns pointer to the created scene node. + \return Pointer to the created scene node. This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual IMeshSceneNode* addMeshSceneNode(IMesh* mesh, ISceneNode* parent=0, s32 id=-1, const core::vector3df& position = core::vector3df(0,0,0), @@ -477,19 +477,19 @@ namespace scene const core::vector3df& scale = core::vector3df(1.0f, 1.0f, 1.0f)) = 0; - //! Adds a scene node for rendering using a octtree to the scene graph. - /** This a good method for rendering - scenes with lots of geometry. The Octree is built on the fly from the mesh. - \param mesh: The mesh containing all geometry from which the octtree will be build. - If this animated mesh has more than one frames in it, the first frame is taken. - \param parent: Parent node of the octtree node. - \param id: id of the node. This id can be used to identify the node. - \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. + //! Adds a scene node for rendering using a octtree to the scene graph. + /** This a good method for rendering + scenes with lots of geometry. The Octree is built on the fly from the mesh. + \param mesh: The mesh containing all geometry from which the octtree will be build. + If this animated mesh has more than one frames in it, the first frame is taken. + \param parent: Parent node of the octtree node. + \param id: id of the node. This id can be used to identify the node. + \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. \param alsoAddIfMeshPointerZero: Add the scene node even if a 0 pointer is passed. - \return Pointer to the OctTree if successful, otherwise 0. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + \return Pointer to the OctTree if successful, otherwise 0. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ISceneNode* addOctTreeSceneNode(IAnimatedMesh* mesh, ISceneNode* parent=0, s32 id=-1, s32 minimalPolysPerNode=512, bool alsoAddIfMeshPointerZero=false) = 0; @@ -513,13 +513,17 @@ namespace scene /** This camera does not react on user input like for example the one created with addCameraSceneNodeFPS(). If you want to move or animate it, use animators or the ISceneNode::setPosition(), ICameraSceneNode::setTarget() etc methods. - \param position: Position of the space relative to its parent where the camera will be placed. - \param lookat: Position where the camera will look at. Also known as target. - \param parent: Parent scene node of the camera. Can be null. If the parent moves, - the camera will move too. - \param id: id of the camera. This id can be used to identify the camera. - \return Returns pointer to interface to camera if successful, otherwise 0. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + By default, a camera's look at position (set with setTarget()) and its scene node + rotation (set with setRotation()) are independent. If you want to be able to + control the direction that the camera looks by using setRotation() then call + ICameraSceneNode::bindTargetAndRotation(true) on it. + \param position: Position of the space relative to its parent where the camera will be placed. + \param lookat: Position where the camera will look at. Also known as target. + \param parent: Parent scene node of the camera. Can be null. If the parent moves, + the camera will move too. + \param id: id of the camera. This id can be used to identify the camera. + \return Pointer to interface to camera if successful, otherwise 0. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ICameraSceneNode* addCameraSceneNode(ISceneNode* parent = 0, const core::vector3df& position = core::vector3df(0,0,0), const core::vector3df& lookat = core::vector3df(0,0,100), s32 id=-1) = 0; @@ -591,27 +595,30 @@ namespace scene 'false', with which it is possible to fly around in space, if no gravity is there. \param jumpSpeed: Speed with which the camera is moved when jumping. + \param invertMouse: Setting this to true makes the camera look up when + the mouse is moved down and down when the mouse is moved up, the default + is 'false' which means it will follow the movement of the mouse cursor. \return Pointer to the interface of the camera if successful, otherwise 0. This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ICameraSceneNode* addCameraSceneNodeFPS(ISceneNode* parent = 0, f32 rotateSpeed = 100.0f, f32 moveSpeed = .5f, s32 id=-1, SKeyMap* keyMapArray=0, s32 keyMapSize=0, bool noVerticalMovement=false, - f32 jumpSpeed = 0.f) = 0; + f32 jumpSpeed = 0.f, bool invertMouse=false) = 0; //! Adds a dynamic light scene node to the scene graph. /** The light will cast dynamic light on all - other scene nodes in the scene, which have the material flag video::MTF_LIGHTING - turned on. (This is the default setting in most scene nodes). - \param parent: Parent scene node of the light. Can be null. If the parent moves, - the light will move too. - \param position: Position of the space relative to its parent where the light will be placed. - \param color: Diffuse color of the light. Ambient or Specular colors can be set manually with - the ILightSceneNode::getLightData() method. - \param radius: Radius of the light. - \param id: id of the node. This id can be used to identify the node. - \return Returns pointer to the interface of the light if successful, otherwise NULL. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + other scene nodes in the scene, which have the material flag video::MTF_LIGHTING + turned on. (This is the default setting in most scene nodes). + \param parent: Parent scene node of the light. Can be null. If the parent moves, + the light will move too. + \param position: Position of the space relative to its parent where the light will be placed. + \param color: Diffuse color of the light. Ambient or Specular colors can be set manually with + the ILightSceneNode::getLightData() method. + \param radius: Radius of the light. + \param id: id of the node. This id can be used to identify the node. + \return Pointer to the interface of the light if successful, otherwise NULL. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ILightSceneNode* addLightSceneNode(ISceneNode* parent = 0, const core::vector3df& position = core::vector3df(0,0,0), video::SColorf color = video::SColorf(1.0f, 1.0f, 1.0f), @@ -619,19 +626,19 @@ namespace scene //! Adds a billboard scene node to the scene graph. /** A billboard is like a 3d sprite: A 2d element, - which always looks to the camera. It is usually used for things like explosions, fire, - lensflares and things like that. - \param parent: Parent scene node of the billboard. Can be null. If the parent moves, - the billboard will move too. - \param position: Position of the space relative to its parent - where the billboard will be placed. - \param size: Size of the billboard. This size is 2 dimensional because a billboard only has - width and height. - \param id: An id of the node. This id can be used to identify the node. - \param colorTop: The color of the vertices at the top of the billboard (default: white). - \param colorBottom: The color of the vertices at the bottom of the billboard (default: white). - \return Returns pointer to the billboard if successful, otherwise NULL. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + which always looks to the camera. It is usually used for things like explosions, fire, + lensflares and things like that. + \param parent: Parent scene node of the billboard. Can be null. If the parent moves, + the billboard will move too. + \param position: Position of the space relative to its parent + where the billboard will be placed. + \param size: Size of the billboard. This size is 2 dimensional because a billboard only has + width and height. + \param id: An id of the node. This id can be used to identify the node. + \param colorTop: The color of the vertices at the top of the billboard (default: white). + \param colorBottom: The color of the vertices at the bottom of the billboard (default: white). + \return Pointer to the billboard if successful, otherwise NULL. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual IBillboardSceneNode* addBillboardSceneNode(ISceneNode* parent = 0, const core::dimension2d& size = core::dimension2d(10.0f, 10.0f), const core::vector3df& position = core::vector3df(0,0,0), s32 id=-1, @@ -639,40 +646,40 @@ namespace scene //! Adds a skybox scene node to the scene graph. /** A skybox is a big cube with 6 textures on it and - is drawn around the camera position. - \param top: Texture for the top plane of the box. - \param bottom: Texture for the bottom plane of the box. - \param left: Texture for the left plane of the box. - \param right: Texture for the right plane of the box. - \param front: Texture for the front plane of the box. - \param back: Texture for the back plane of the box. - \param parent: Parent scene node of the skybox. A skybox usually has no parent, - so this should be null. Note: If a parent is set to the skybox, the box will not - change how it is drawn. - \param id: An id of the node. This id can be used to identify the node. - \return Returns a pointer to the sky box if successful, otherwise NULL. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + is drawn around the camera position. + \param top: Texture for the top plane of the box. + \param bottom: Texture for the bottom plane of the box. + \param left: Texture for the left plane of the box. + \param right: Texture for the right plane of the box. + \param front: Texture for the front plane of the box. + \param back: Texture for the back plane of the box. + \param parent: Parent scene node of the skybox. A skybox usually has no parent, + so this should be null. Note: If a parent is set to the skybox, the box will not + change how it is drawn. + \param id: An id of the node. This id can be used to identify the node. + \return Pointer to the sky box if successful, otherwise NULL. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ISceneNode* addSkyBoxSceneNode(video::ITexture* top, video::ITexture* bottom, video::ITexture* left, video::ITexture* right, video::ITexture* front, video::ITexture* back, ISceneNode* parent = 0, s32 id=-1) = 0; //! Adds a skydome scene node to the scene graph. /** A skydome is a large (half-) sphere with a panoramic texture - on the inside and is drawn around the camera position. - \param texture: Texture for the dome. - \param horiRes: Number of vertices of a horizontal layer of the sphere. - \param vertRes: Number of vertices of a vertical layer of the sphere. - \param texturePercentage: How much of the height of the - texture is used. Should be between 0 and 1. - \param spherePercentage: How much of the sphere is drawn. - Value should be between 0 and 2, where 1 is an exact - half-sphere and 2 is a full sphere. - \param parent: Parent scene node of the dome. A dome usually has no parent, - so this should be null. Note: If a parent is set, the dome will not - change how it is drawn. - \param id: An id of the node. This id can be used to identify the node. - \return Returns a pointer to the sky dome if successful, otherwise NULL. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + on the inside and is drawn around the camera position. + \param texture: Texture for the dome. + \param horiRes: Number of vertices of a horizontal layer of the sphere. + \param vertRes: Number of vertices of a vertical layer of the sphere. + \param texturePercentage: How much of the height of the + texture is used. Should be between 0 and 1. + \param spherePercentage: How much of the sphere is drawn. + Value should be between 0 and 2, where 1 is an exact + half-sphere and 2 is a full sphere. + \param parent: Parent scene node of the dome. A dome usually has no parent, + so this should be null. Note: If a parent is set, the dome will not + change how it is drawn. + \param id: An id of the node. This id can be used to identify the node. + \return Pointer to the sky dome if successful, otherwise NULL. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ISceneNode* addSkyDomeSceneNode(video::ITexture* texture, u32 horiRes=16, u32 vertRes=8, f64 texturePercentage=0.9, f64 spherePercentage=2.0, @@ -680,17 +687,17 @@ namespace scene //! Adds a particle system scene node to the scene graph. /** \param withDefaultEmitter: Creates a default working point emitter - which emitts some particles. Set this to true to see a particle system - in action. If set to false, you'll have to set the emitter you want by - calling IParticleSystemSceneNode::setEmitter(). - \param parent: Parent of the scene node. Can be NULL if no parent. - \param id: Id of the node. This id can be used to identify the scene node. - \param position: Position of the space relative to its parent where the - scene node will be placed. - \param rotation: Initital rotation of the scene node. - \param scale: Initial scale of the scene node. - \return Returns pointer to the created scene node. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + which emitts some particles. Set this to true to see a particle system + in action. If set to false, you'll have to set the emitter you want by + calling IParticleSystemSceneNode::setEmitter(). + \param parent: Parent of the scene node. Can be NULL if no parent. + \param id: Id of the node. This id can be used to identify the scene node. + \param position: Position of the space relative to its parent where the + scene node will be placed. + \param rotation: Initital rotation of the scene node. + \param scale: Initial scale of the scene node. + \return Pointer to the created scene node. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual IParticleSystemSceneNode* addParticleSystemSceneNode( bool withDefaultEmitter=true, ISceneNode* parent=0, s32 id=-1, const core::vector3df& position = core::vector3df(0,0,0), @@ -699,60 +706,60 @@ namespace scene //! Adds a terrain scene node to the scene graph. /** This node implements is a simple terrain renderer which uses - a technique known as geo mip mapping - for reducing the detail of triangle blocks which are far away. - The code for the TerrainSceneNode is based on the terrain - renderer by Soconne and the GeoMipMapSceneNode developed by - Spintz. They made their code available for Irrlicht and allowed - it to be distributed under this licence. I only modified some - parts. A lot of thanks go to them. + a technique known as geo mip mapping + for reducing the detail of triangle blocks which are far away. + The code for the TerrainSceneNode is based on the terrain + renderer by Soconne and the GeoMipMapSceneNode developed by + Spintz. They made their code available for Irrlicht and allowed + it to be distributed under this licence. I only modified some + parts. A lot of thanks go to them. - This scene node is capable of loading terrains and updating - the indices at runtime to enable viewing very large terrains - very quickly. It uses a CLOD (Continuous Level of Detail) - algorithm which updates the indices for each patch based on - a LOD (Level of Detail) which is determined based on a patch's - distance from the camera. + This scene node is capable of loading terrains and updating + the indices at runtime to enable viewing very large terrains + very quickly. It uses a CLOD (Continuous Level of Detail) + algorithm which updates the indices for each patch based on + a LOD (Level of Detail) which is determined based on a patch's + distance from the camera. - The patch size of the terrain must always be a size of 2^N+1, - i.e. 8+1(9), 16+1(17), etc. - The MaxLOD available is directly dependent on the patch size - of the terrain. LOD 0 contains all of the indices to draw all - the triangles at the max detail for a patch. As each LOD goes - up by 1 the step taken, in generating indices increases by - -2^LOD, so for LOD 1, the step taken is 2, for LOD 2, the step - taken is 4, LOD 3 - 8, etc. The step can be no larger than - the size of the patch, so having a LOD of 8, with a patch size - of 17, is asking the algoritm to generate indices every 2^8 ( - 256 ) vertices, which is not possible with a patch size of 17. - The maximum LOD for a patch size of 17 is 2^4 ( 16 ). So, - with a MaxLOD of 5, you'll have LOD 0 ( full detail ), LOD 1 ( - every 2 vertices ), LOD 2 ( every 4 vertices ), LOD 3 ( every - 8 vertices ) and LOD 4 ( every 16 vertices ). - \param heightMapFileName: The name of the file on disk, to read vertex data from. This should - be a gray scale bitmap. - \param parent: Parent of the scene node. Can be 0 if no parent. - \param id: Id of the node. This id can be used to identify the scene node. - \param position: The absolute position of this node. - \param rotation: The absolute rotation of this node. ( NOT YET IMPLEMENTED ) - \param scale: The scale factor for the terrain. If you're - using a heightmap of size 129x129 and would like your terrain - to be 12900x12900 in game units, then use a scale factor of ( - core::vector ( 100.0f, 100.0f, 100.0f ). If you use a Y - scaling factor of 0.0f, then your terrain will be flat. - \param vertexColor: The default color of all the vertices. If no texture is associated - with the scene node, then all vertices will be this color. Defaults to white. - \param maxLOD: The maximum LOD (level of detail) for the node. Only change if you - know what you are doing, this might lead to strange behaviour. - \param patchSize: patch size of the terrain. Only change if you - know what you are doing, this might lead to strange behaviour. - \param smoothFactor: The number of times the vertices are smoothed. - \param addAlsoIfHeightmapEmpty: Add terrain node even with empty heightmap. - \return Returns pointer to the created scene node. Can be null - if the terrain could not be created, for example because the - heightmap could not be loaded. The returned pointer should - not be dropped. See IReferenceCounted::drop() for more - information. */ + The patch size of the terrain must always be a size of 2^N+1, + i.e. 8+1(9), 16+1(17), etc. + The MaxLOD available is directly dependent on the patch size + of the terrain. LOD 0 contains all of the indices to draw all + the triangles at the max detail for a patch. As each LOD goes + up by 1 the step taken, in generating indices increases by + -2^LOD, so for LOD 1, the step taken is 2, for LOD 2, the step + taken is 4, LOD 3 - 8, etc. The step can be no larger than + the size of the patch, so having a LOD of 8, with a patch size + of 17, is asking the algoritm to generate indices every 2^8 ( + 256 ) vertices, which is not possible with a patch size of 17. + The maximum LOD for a patch size of 17 is 2^4 ( 16 ). So, + with a MaxLOD of 5, you'll have LOD 0 ( full detail ), LOD 1 ( + every 2 vertices ), LOD 2 ( every 4 vertices ), LOD 3 ( every + 8 vertices ) and LOD 4 ( every 16 vertices ). + \param heightMapFileName: The name of the file on disk, to read vertex data from. This should + be a gray scale bitmap. + \param parent: Parent of the scene node. Can be 0 if no parent. + \param id: Id of the node. This id can be used to identify the scene node. + \param position: The absolute position of this node. + \param rotation: The absolute rotation of this node. ( NOT YET IMPLEMENTED ) + \param scale: The scale factor for the terrain. If you're + using a heightmap of size 129x129 and would like your terrain + to be 12900x12900 in game units, then use a scale factor of ( + core::vector ( 100.0f, 100.0f, 100.0f ). If you use a Y + scaling factor of 0.0f, then your terrain will be flat. + \param vertexColor: The default color of all the vertices. If no texture is associated + with the scene node, then all vertices will be this color. Defaults to white. + \param maxLOD: The maximum LOD (level of detail) for the node. Only change if you + know what you are doing, this might lead to strange behaviour. + \param patchSize: patch size of the terrain. Only change if you + know what you are doing, this might lead to strange behaviour. + \param smoothFactor: The number of times the vertices are smoothed. + \param addAlsoIfHeightmapEmpty: Add terrain node even with empty heightmap. + \return Pointer to the created scene node. Can be null + if the terrain could not be created, for example because the + heightmap could not be loaded. The returned pointer should + not be dropped. See IReferenceCounted::drop() for more + information. */ virtual ITerrainSceneNode* addTerrainSceneNode( const c8* heightMapFileName, ISceneNode* parent=0, s32 id=-1, @@ -765,32 +772,32 @@ namespace scene //! Adds a terrain scene node to the scene graph. /** Just like the other addTerrainSceneNode() method, but takes an IReadFile - pointer as parameter for the heightmap. For more informations take a look - at the other function. - \param heightMapFile: The file handle to read vertex data from. This should - be a gray scale bitmap. - \param parent: Parent of the scene node. Can be 0 if no parent. - \param id: Id of the node. This id can be used to identify the scene node. - \param position: The absolute position of this node. - \param rotation: The absolute rotation of this node. ( NOT YET IMPLEMENTED ) - \param scale: The scale factor for the terrain. If you're - using a heightmap of size 129x129 and would like your terrain - to be 12900x12900 in game units, then use a scale factor of ( - core::vector ( 100.0f, 100.0f, 100.0f ). If you use a Y - scaling factor of 0.0f, then your terrain will be flat. - \param vertexColor: The default color of all the vertices. If no texture is associated - with the scene node, then all vertices will be this color. Defaults to white. - \param maxLOD: The maximum LOD (level of detail) for the node. Only change if you - know what you are doing, this might lead to strange behaviour. - \param patchSize: patch size of the terrain. Only change if you - know what you are doing, this might lead to strange behaviour. - \param smoothFactor: The number of times the vertices are smoothed. - \param addAlsoIfHeightmapEmpty: Add terrain node even with empty heightmap. - \return Returns pointer to the created scene node. Can be null - if the terrain could not be created, for example because the - heightmap could not be loaded. The returned pointer should - not be dropped. See IReferenceCounted::drop() for more - information. */ + pointer as parameter for the heightmap. For more informations take a look + at the other function. + \param heightMapFile: The file handle to read vertex data from. This should + be a gray scale bitmap. + \param parent: Parent of the scene node. Can be 0 if no parent. + \param id: Id of the node. This id can be used to identify the scene node. + \param position: The absolute position of this node. + \param rotation: The absolute rotation of this node. ( NOT YET IMPLEMENTED ) + \param scale: The scale factor for the terrain. If you're + using a heightmap of size 129x129 and would like your terrain + to be 12900x12900 in game units, then use a scale factor of ( + core::vector ( 100.0f, 100.0f, 100.0f ). If you use a Y + scaling factor of 0.0f, then your terrain will be flat. + \param vertexColor: The default color of all the vertices. If no texture is associated + with the scene node, then all vertices will be this color. Defaults to white. + \param maxLOD: The maximum LOD (level of detail) for the node. Only change if you + know what you are doing, this might lead to strange behaviour. + \param patchSize: patch size of the terrain. Only change if you + know what you are doing, this might lead to strange behaviour. + \param smoothFactor: The number of times the vertices are smoothed. + \param addAlsoIfHeightmapEmpty: Add terrain node even with empty heightmap. + \return Pointer to the created scene node. Can be null + if the terrain could not be created, for example because the + heightmap could not be loaded. The returned pointer should + not be dropped. See IReferenceCounted::drop() for more + information. */ virtual ITerrainSceneNode* addTerrainSceneNode( io::IReadFile* heightMapFile, ISceneNode* parent=0, s32 id=-1, @@ -803,8 +810,8 @@ namespace scene //! Adds a quake3 scene node to the scene graph. /** A Quake3 Scene renders multiple meshes for a specific HighLanguage Shader (Quake3 Style ) - \return Returns a pointer to the quake3 scene node if successful, otherwise NULL. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + \return Pointer to the quake3 scene node if successful, otherwise NULL. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ISceneNode* addQuake3SceneNode(IMeshBuffer* meshBuffer, const quake3::SShader * shader, ISceneNode* parent=0, s32 id=-1 ) = 0; @@ -812,18 +819,18 @@ namespace scene //! Adds an empty scene node to the scene graph. /** Can be used for doing advanced transformations - or structuring the scene graph. - \return Returns pointer to the created scene node. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + or structuring the scene graph. + \return Pointer to the created scene node. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ISceneNode* addEmptySceneNode(ISceneNode* parent=0, s32 id=-1) = 0; //! Adds a dummy transformation scene node to the scene graph. /** This scene node does not render itself, and does not respond to set/getPosition, - set/getRotation and set/getScale. Its just a simple scene node that takes a - matrix as relative transformation, making it possible to insert any transformation - anywhere into the scene graph. - \return Returns pointer to the created scene node. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + set/getRotation and set/getScale. Its just a simple scene node that takes a + matrix as relative transformation, making it possible to insert any transformation + anywhere into the scene graph. + \return Pointer to the created scene node. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual IDummyTransformationSceneNode* addDummyTransformationSceneNode( ISceneNode* parent=0, s32 id=-1) = 0; @@ -840,9 +847,10 @@ namespace scene \param parent The billboard's parent. Pass 0 to use the root scene node. \param size The billboard's width and height. \param position The billboards position relative to its parent. + \param id: An id of the node. This id can be used to identify the node. \param colorTop: The color of the vertices at the top of the billboard (default: white). \param colorBottom: The color of the vertices at the bottom of the billboard (default: white). - \return Returns pointer to the billboard if successful, otherwise NULL. + \return Pointer to the billboard if successful, otherwise NULL. This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual IBillboardTextSceneNode* addBillboardTextSceneNode( gui::IGUIFont* font, const wchar_t* text, ISceneNode* parent = 0, @@ -852,65 +860,65 @@ namespace scene //! Adds a Hill Plane mesh to the mesh pool. /** The mesh is generated on the fly - and looks like a plane with some hills on it. It is uses mostly for quick - tests of the engine only. You can specify how many hills there should be - on the plane and how high they should be. Also you must specify a name for - the mesh, because the mesh is added to the mesh pool, and can be retrieved - again using ISceneManager::getMesh() with the name as parameter. - \param name: The name of this mesh which must be specified in order - to be able to retrieve the mesh later with ISceneManager::getMesh(). - \param tileSize: Size of a tile of the mesh. (10.0f, 10.0f) would be a - good value to start, for example. - \param tileCount: Specifies how much tiles there will be. If you specifiy - for example that a tile has the size (10.0f, 10.0f) and the tileCount is - (10,10), than you get a field of 100 tiles which has the dimension 100.0fx100.0f. - \param material: Material of the hill mesh. - \param hillHeight: Height of the hills. If you specify a negative value - you will get holes instead of hills. If the height is 0, no hills will be - created. - \param countHills: Amount of hills on the plane. There will be countHills.X - hills along the X axis and countHills.Y along the Y axis. So in total there - will be countHills.X * countHills.Y hills. - \param textureRepeatCount: Defines how often the texture will be repeated in - x and y direction. - \return Returns null if the creation failed. The reason could be that you - specified some invalid parameters or that a mesh with that name already - exists. If successful, a pointer to the mesh is returned. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + and looks like a plane with some hills on it. It is uses mostly for quick + tests of the engine only. You can specify how many hills there should be + on the plane and how high they should be. Also you must specify a name for + the mesh, because the mesh is added to the mesh pool, and can be retrieved + again using ISceneManager::getMesh() with the name as parameter. + \param name: The name of this mesh which must be specified in order + to be able to retrieve the mesh later with ISceneManager::getMesh(). + \param tileSize: Size of a tile of the mesh. (10.0f, 10.0f) would be a + good value to start, for example. + \param tileCount: Specifies how much tiles there will be. If you specifiy + for example that a tile has the size (10.0f, 10.0f) and the tileCount is + (10,10), than you get a field of 100 tiles which has the dimension 100.0fx100.0f. + \param material: Material of the hill mesh. + \param hillHeight: Height of the hills. If you specify a negative value + you will get holes instead of hills. If the height is 0, no hills will be + created. + \param countHills: Amount of hills on the plane. There will be countHills.X + hills along the X axis and countHills.Y along the Y axis. So in total there + will be countHills.X * countHills.Y hills. + \param textureRepeatCount: Defines how often the texture will be repeated in + x and y direction. + return Null if the creation failed. The reason could be that you + specified some invalid parameters or that a mesh with that name already + exists. If successful, a pointer to the mesh is returned. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual IAnimatedMesh* addHillPlaneMesh(const c8* name, const core::dimension2d& tileSize, const core::dimension2d& tileCount, video::SMaterial* material = 0, f32 hillHeight = 0.0f, const core::dimension2d& countHills = core::dimension2d(0.0f, 0.0f), const core::dimension2d& textureRepeatCount = core::dimension2d(1.0f, 1.0f)) = 0; - //! Adds a static terrain mesh to the mesh pool. - /** The mesh is generated on the fly - from a texture file and a height map file. Both files may be huge - (8000x8000 pixels would be no problem) because the generator splits the - files into smaller textures if necessary. - You must specify a name for the mesh, because the mesh is added to the mesh pool, - and can be retrieved again using ISceneManager::getMesh() with the name as parameter. - \param meshname: The name of this mesh which must be specified in order - to be able to retrieve the mesh later with ISceneManager::getMesh(). - \param texture: Texture for the terrain. Please note that this is not a - hardware texture as usual (ITexture), but an IImage software texture. - You can load this texture with IVideoDriver::createImageFromFile(). - \param heightmap: A grayscaled heightmap image. Like the texture, - it can be created with IVideoDriver::createImageFromFile(). The amount - of triangles created depends on the size of this texture, so use a small - heightmap to increase rendering speed. - \param stretchSize: Parameter defining how big a is pixel on the heightmap. - \param maxHeight: Defines how high a white pixel on the heighmap is. - \param defaultVertexBlockSize: Defines the initial dimension between vertices. - \return Returns null if the creation failed. The reason could be that you - specified some invalid parameters, that a mesh with that name already - exists, or that a texture could not be found. If successful, a pointer to the mesh is returned. - This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ + //! Adds a static terrain mesh to the mesh pool. + /** The mesh is generated on the fly + from a texture file and a height map file. Both files may be huge + (8000x8000 pixels would be no problem) because the generator splits the + files into smaller textures if necessary. + You must specify a name for the mesh, because the mesh is added to the mesh pool, + and can be retrieved again using ISceneManager::getMesh() with the name as parameter. + \param meshname: The name of this mesh which must be specified in order + to be able to retrieve the mesh later with ISceneManager::getMesh(). + \param texture: Texture for the terrain. Please note that this is not a + hardware texture as usual (ITexture), but an IImage software texture. + You can load this texture with IVideoDriver::createImageFromFile(). + \param heightmap: A grayscaled heightmap image. Like the texture, + it can be created with IVideoDriver::createImageFromFile(). The amount + of triangles created depends on the size of this texture, so use a small + heightmap to increase rendering speed. + \param stretchSize: Parameter defining how big a is pixel on the heightmap. + \param maxHeight: Defines how high a white pixel on the heighmap is. + \param defaultVertexBlockSize: Defines the initial dimension between vertices. + \return Null if the creation failed. The reason could be that you + specified some invalid parameters, that a mesh with that name already + exists, or that a texture could not be found. If successful, a pointer to the mesh is returned. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual IAnimatedMesh* addTerrainMesh(const c8* meshname, video::IImage* texture, video::IImage* heightmap, const core::dimension2d& stretchSize = core::dimension2d(10.0f,10.0f), f32 maxHeight=200.0f, - const core::dimension2d& defaultVertexBlockSize = core::dimension2d(64,64)) = 0; + const core::dimension2d& defaultVertexBlockSize = core::dimension2d(64,64)) = 0; //! add a static arrow mesh to the meshpool /** \param name Name of the mesh @@ -921,7 +929,9 @@ namespace scene \param height Total height of the arrow \param cylinderHeight Total height of the cylinder, should be lesser than total height \param width0 Diameter of the cylinder - \param width1 Diameter of the cone's base, should be not smaller than the cylinder's diameter */ + \param width1 Diameter of the cone's base, should be not smaller than the cylinder's diameter + \return Pointer to the arrow mesh if successful, otherwise 0. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual IAnimatedMesh* addArrowMesh(const c8* name, video::SColor vtxColor0=0xFFFFFFFF, video::SColor vtxColor1=0xFFFFFFFF, @@ -933,44 +943,50 @@ namespace scene /** \param name Name of the mesh \param radius Radius of the sphere \param polyCountX Number of quads used for the horizontal tiling - \param polyCountY Number of quads used for the vertical tiling */ + \param polyCountY Number of quads used for the vertical tiling + \return Pointer to the sphere mesh if successful, otherwise 0. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual IAnimatedMesh* addSphereMesh(const c8* name, f32 radius=5.f, u32 polyCountX = 16, u32 polyCountY = 16) = 0; - //! Returns the root scene node. + //! Gets the root scene node. /** This is the scene node which is parent - of all scene nodes. The root scene node is a special scene node which - only exists to manage all scene nodes. It will not be rendered and cannot - be removed from the scene. - \return Returns a pointer to the root scene node. */ + of all scene nodes. The root scene node is a special scene node which + only exists to manage all scene nodes. It will not be rendered and cannot + be removed from the scene. + \return Pointer to the root scene node. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ISceneNode* getRootSceneNode() = 0; - //! Returns the first scene node with the specified id. + //! Get the first scene node with the specified id. /** \param id: The id to search for - \param start: Scene node to start from. All children of this scene - node are searched. If null is specified, the root scene node is - taken. - \return Returns pointer to the first scene node with this id, - and null if no scene node could be found. */ + \param start: Scene node to start from. All children of this scene + node are searched. If null is specified, the root scene node is + taken. + \return Pointer to the first scene node with this id, + and null if no scene node could be found. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ISceneNode* getSceneNodeFromId(s32 id, ISceneNode* start=0) = 0; - //! Returns the first scene node with the specified name. + //! Get the first scene node with the specified name. /** \param name: The name to search for - \param start: Scene node to start from. All children of this scene - node are searched. If null is specified, the root scene node is - taken. - \return Returns pointer to the first scene node with this id, - and null if no scene node could be found. */ + \param start: Scene node to start from. All children of this scene + node are searched. If null is specified, the root scene node is + taken. + \return Pointer to the first scene node with this id, + and null if no scene node could be found. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ISceneNode* getSceneNodeFromName(const c8* name, ISceneNode* start=0) = 0; - //! Returns the first scene node with the specified type. + //! Get the first scene node with the specified type. /** \param type: The type to search for - \param start: Scene node to start from. All children of this scene - node are searched. If null is specified, the root scene node is - taken. - \return Returns pointer to the first scene node with this type, - and null if no scene node could be found. */ + \param start: Scene node to start from. All children of this scene + node are searched. If null is specified, the root scene node is + taken. + \return Pointer to the first scene node with this type, + and null if no scene node could be found. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ISceneNode* getSceneNodeFromType(scene::ESCENE_NODE_TYPE type, ISceneNode* start=0) = 0; //! Get scene nodes by type. @@ -984,128 +1000,132 @@ namespace scene ISceneNode* start=0) = 0; //! Get the current active camera. - /** \return The active camera is returned. Note that this can be NULL, if there - was no camera created yet. */ + /** \return The active camera is returned. Note that this can + be NULL, if there was no camera created yet. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ICameraSceneNode* getActiveCamera() = 0; //! Sets the currently active camera. /** The previous active camera will be deactivated. - \param camera: The new camera which should be active. */ + \param camera: The new camera which should be active. */ virtual void setActiveCamera(ICameraSceneNode* camera) = 0; //! Sets the color of stencil buffers shadows drawn by the scene manager. virtual void setShadowColor(video::SColor color = video::SColor(150,0,0,0)) = 0; - //! Returns the current color of shadows. + //! Get the current color of shadows. virtual video::SColor getShadowColor() const = 0; //! Registers a node for rendering it at a specific time. /** This method should only be used by SceneNodes when they get a - ISceneNode::OnRegisterSceneNode() call. - \param node: Node to register for drawing. Usually scene nodes would set 'this' - as parameter here because they want to be drawn. - \param pass: Specifies when the node wants to be drawn in relation to the other nodes. - For example, if the node is a shadow, it usually wants to be drawn after all other nodes - and will use ESNRP_SHADOW for this. See scene::E_SCENE_NODE_RENDER_PASS for details. - \return scene will be rendered ( passed culling ) */ + ISceneNode::OnRegisterSceneNode() call. + \param node: Node to register for drawing. Usually scene nodes would set 'this' + as parameter here because they want to be drawn. + \param pass: Specifies when the node wants to be drawn in relation to the other nodes. + For example, if the node is a shadow, it usually wants to be drawn after all other nodes + and will use ESNRP_SHADOW for this. See scene::E_SCENE_NODE_RENDER_PASS for details. + \return scene will be rendered ( passed culling ) */ virtual u32 registerNodeForRendering(ISceneNode* node, E_SCENE_NODE_RENDER_PASS pass = ESNRP_AUTOMATIC) = 0; //! Draws all the scene nodes. /** This can only be invoked between - IVideoDriver::beginScene() and IVideoDriver::endScene(). Please note that - the scene is not only drawn when calling this, but also animated - by existing scene node animators, culling of scene nodes is done, etc. */ + IVideoDriver::beginScene() and IVideoDriver::endScene(). Please note that + the scene is not only drawn when calling this, but also animated + by existing scene node animators, culling of scene nodes is done, etc. */ virtual void drawAll() = 0; //! Creates a rotation animator, which rotates the attached scene node around itself. /** \param rotationPerSecond: Specifies the speed of the animation - \return The animator. Attach it to a scene node with ISceneNode::addAnimator() - and the animator will animate it. - If you no longer need the animator, you should call ISceneNodeAnimator::drop(). - See IReferenceCounted::drop() for more information. */ + \return The animator. Attach it to a scene node with ISceneNode::addAnimator() + and the animator will animate it. + If you no longer need the animator, you should call ISceneNodeAnimator::drop(). + See IReferenceCounted::drop() for more information. */ virtual ISceneNodeAnimator* createRotationAnimator(const core::vector3df& rotationPerSecond) = 0; //! Creates a fly circle animator, which lets the attached scene node fly around a center. /** \param center: Center of the circle. - \param radius: Radius of the circle. - \param speed: Specifies the speed of the flight. - \param direction: Specifies the upvector used for alignment of the mesh. - \return The animator. Attach it to a scene node with ISceneNode::addAnimator() - and the animator will animate it. - If you no longer need the animator, you should call ISceneNodeAnimator::drop(). - See IReferenceCounted::drop() for more information. */ + \param radius: Radius of the circle. + \param speed: The orbital speed, in radians per millisecond. + \param direction: Specifies the upvector used for alignment of the mesh. + \param startPosition: The position on the circle where the animator will + begin. Value is in multiples of a circle, i.e. 0.5 is half way around. + \return The animator. Attach it to a scene node with ISceneNode::addAnimator() + and the animator will animate it. + If you no longer need the animator, you should call ISceneNodeAnimator::drop(). + See IReferenceCounted::drop() for more information. */ virtual ISceneNodeAnimator* createFlyCircleAnimator( const core::vector3df& center=core::vector3df(0.f,0.f,0.f), f32 radius=100.f, f32 speed=0.001f, - const core::vector3df& direction=core::vector3df(0.f, 1.f, 0.f)) = 0; + const core::vector3df& direction=core::vector3df(0.f, 1.f, 0.f), + f32 startPosition = 0.f) = 0; //! Creates a fly straight animator, which lets the attached scene node fly or move along a line between two points. /** \param startPoint: Start point of the line. - \param endPoint: End point of the line. - \param timeForWay: Time in milli seconds how long the node should need to - move from the start point to the end point. - \param loop: If set to false, the node stops when the end point is reached. - If loop is true, the node begins again at the start. - \return Returns the animator. Attach it to a scene node with ISceneNode::addAnimator() - and the animator will animate it. - If you no longer need the animator, you should call ISceneNodeAnimator::drop(). - See IReferenceCounted::drop() for more information. */ + \param endPoint: End point of the line. + \param timeForWay: Time in milli seconds how long the node should need to + move from the start point to the end point. + \param loop: If set to false, the node stops when the end point is reached. + If loop is true, the node begins again at the start. + \return The animator. Attach it to a scene node with ISceneNode::addAnimator() + and the animator will animate it. + If you no longer need the animator, you should call ISceneNodeAnimator::drop(). + See IReferenceCounted::drop() for more information. */ virtual ISceneNodeAnimator* createFlyStraightAnimator(const core::vector3df& startPoint, const core::vector3df& endPoint, u32 timeForWay, bool loop=false) = 0; //! Creates a texture animator, which switches the textures of the target scene node based on a list of textures. /** \param textures: List of textures to use. - \param timePerFrame: Time in milliseconds, how long any texture in the list - should be visible. - \param loop: If set to to false, the last texture remains set, and the animation - stops. If set to true, the animation restarts with the first texture. - \return Returns the animator. Attach it to a scene node with ISceneNode::addAnimator() - and the animator will animate it. - If you no longer need the animator, you should call ISceneNodeAnimator::drop(). - See IReferenceCounted::drop() for more information. */ + \param timePerFrame: Time in milliseconds, how long any texture in the list + should be visible. + \param loop: If set to to false, the last texture remains set, and the animation + stops. If set to true, the animation restarts with the first texture. + \return The animator. Attach it to a scene node with ISceneNode::addAnimator() + and the animator will animate it. + If you no longer need the animator, you should call ISceneNodeAnimator::drop(). + See IReferenceCounted::drop() for more information. */ virtual ISceneNodeAnimator* createTextureAnimator(const core::array& textures, s32 timePerFrame, bool loop=true) = 0; //! Creates a scene node animator, which deletes the scene node after some time automatically. /** \param timeMs: Time in milliseconds, after when the node will be deleted. - \return Returns the animator. Attach it to a scene node with ISceneNode::addAnimator() - and the animator will animate it. - If you no longer need the animator, you should call ISceneNodeAnimator::drop(). - See IReferenceCounted::drop() for more information. */ + \return The animator. Attach it to a scene node with ISceneNode::addAnimator() + and the animator will animate it. + If you no longer need the animator, you should call ISceneNodeAnimator::drop(). + See IReferenceCounted::drop() for more information. */ virtual ISceneNodeAnimator* createDeleteAnimator(u32 timeMs) = 0; //! Creates a special scene node animator for doing automatic collision detection and response. /** See ISceneNodeAnimatorCollisionResponse for details. - \param world: Triangle selector holding all triangles of the world with which - the scene node may collide. You can create a triangle selector with - ISceneManager::createTriangleSelector(); - \param sceneNode: SceneNode which should be manipulated. After you added this animator - to the scene node, the scene node will not be able to move through walls and is - affected by gravity. If you need to teleport the scene node to a new position without - it being effected by the collision geometry, then call sceneNode->setPosition(); then - animator->setTargetNode(sceneNode); - \param ellipsoidRadius: Radius of the ellipsoid with which collision detection and - response is done. If you have got a scene node, and you are unsure about - how big the radius should be, you could use the following code to determine - it: - \code - const core::aabbox3d& box = yourSceneNode->getBoundingBox(); - core::vector3df radius = box.MaxEdge - box.getCenter(); - \endcode - \param gravityPerSecond: Sets the gravity of the environment, as an acceleration in - units per second per second. If your units are equivalent to metres, then - core::vector3df(0,-10.0f,0) would give an approximately realistic gravity. - You can disable gravity by setting it to core::vector3df(0,0,0). - \param ellipsoidTranslation: By default, the ellipsoid for collision detection is created around - the center of the scene node, which means that the ellipsoid surrounds - it completely. If this is not what you want, you may specify a translation - for the ellipsoid. - \param slidingValue: DOCUMENTATION NEEDED. - \return Returns the animator. Attach it to a scene node with ISceneNode::addAnimator() - and the animator will cause it to do collision detection and response. - If you no longer need the animator, you should call ISceneNodeAnimator::drop(). - See IReferenceCounted::drop() for more information. */ + \param world: Triangle selector holding all triangles of the world with which + the scene node may collide. You can create a triangle selector with + ISceneManager::createTriangleSelector(); + \param sceneNode: SceneNode which should be manipulated. After you added this animator + to the scene node, the scene node will not be able to move through walls and is + affected by gravity. If you need to teleport the scene node to a new position without + it being effected by the collision geometry, then call sceneNode->setPosition(); then + animator->setTargetNode(sceneNode); + \param ellipsoidRadius: Radius of the ellipsoid with which collision detection and + response is done. If you have got a scene node, and you are unsure about + how big the radius should be, you could use the following code to determine + it: + \code + const core::aabbox3d& box = yourSceneNode->getBoundingBox(); + core::vector3df radius = box.MaxEdge - box.getCenter(); + \endcode + \param gravityPerSecond: Sets the gravity of the environment, as an acceleration in + units per second per second. If your units are equivalent to metres, then + core::vector3df(0,-10.0f,0) would give an approximately realistic gravity. + You can disable gravity by setting it to core::vector3df(0,0,0). + \param ellipsoidTranslation: By default, the ellipsoid for collision detection is created around + the center of the scene node, which means that the ellipsoid surrounds + it completely. If this is not what you want, you may specify a translation + for the ellipsoid. + \param slidingValue: DOCUMENTATION NEEDED. + \return The animator. Attach it to a scene node with ISceneNode::addAnimator() + and the animator will cause it to do collision detection and response. + If you no longer need the animator, you should call ISceneNodeAnimator::drop(). + See IReferenceCounted::drop() for more information. */ virtual ISceneNodeAnimatorCollisionResponse* createCollisionResponseAnimator( ITriangleSelector* world, ISceneNode* sceneNode, const core::vector3df& ellipsoidRadius = core::vector3df(30,60,30), @@ -1115,142 +1135,153 @@ namespace scene //! Creates a follow spline animator. /** The animator modifies the position of - the attached scene node to make it follow a hermite spline. - It uses a subset of hermite splines: either cardinal splines - (tightness != 0.5) or catmull-rom-splines (tightness == 0.5). - The animator moves from one control point to the next in - 1/speed seconds. This code was sent in by Matthias Gall. */ + the attached scene node to make it follow a hermite spline. + It uses a subset of hermite splines: either cardinal splines + (tightness != 0.5) or catmull-rom-splines (tightness == 0.5). + The animator moves from one control point to the next in + 1/speed seconds. This code was sent in by Matthias Gall. + If you no longer need the animator, you should call ISceneNodeAnimator::drop(). + See IReferenceCounted::drop() for more information. */ virtual ISceneNodeAnimator* createFollowSplineAnimator(s32 startTime, const core::array< core::vector3df >& points, f32 speed = 1.0f, f32 tightness = 0.5f) = 0; //! Creates a simple ITriangleSelector, based on a mesh. /** Triangle selectors - can be used for doing collision detection. Don't use this selector - for a huge amount of triangles like in Quake3 maps. - Instead, use for example ISceneManager::createOctTreeTriangleSelector(). - Please note that the created triangle selector is not automaticly 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->createTriangleSelector(yourMesh, + can be used for doing collision detection. Don't use this selector + for a huge amount of triangles like in Quake3 maps. + Instead, use for example ISceneManager::createOctTreeTriangleSelector(). + Please note that the created triangle selector is not automaticly 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->createTriangleSelector(yourMesh, yourSceneNode); - yourSceneNode->setTriangleSelector(s); - s->drop(); - \endcode - \param mesh: Mesh of which the triangles are taken. - \param node: Scene node of which visibility and transformation is used. - \return Returns 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. */ + yourSceneNode->setTriangleSelector(s); + s->drop(); + \endcode + \param mesh: Mesh of which the triangles are taken. + \param node: Scene node of which visibility and transformation is used. + \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; //! Creates a simple dynamic ITriangleSelector, based on a axis aligned bounding box. /** Triangle selectors - can be used for doing collision detection. Every time when triangles are - queried, the triangle selector gets the bounding box of the scene node, - an creates new triangles. In this way, it works good with animated scene nodes. - \param node: Scene node of which the bounding box, visibility and transformation is used. - \return Returns 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. */ + can be used for doing collision detection. Every time when triangles are + queried, the triangle selector gets the bounding box of the scene node, + an creates new triangles. In this way, it works good with animated scene nodes. + \param node: Scene node of which the bounding box, visibility and transformation is used. + \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* createTriangleSelectorFromBoundingBox(ISceneNode* node) = 0; //! Creates a Triangle Selector, optimized by an octtree. /** Triangle selectors - can be used for doing collision detection. This triangle selector is - optimized for huge amounts of triangle, it organizes them in an octtree. - Please note that the created triangle selector is not automaticly 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->createOctTreeTriangleSelector(yourMesh, + can be used for doing collision detection. This triangle selector is + optimized for huge amounts of triangle, it organizes them in an octtree. + Please note that the created triangle selector is not automaticly 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->createOctTreeTriangleSelector(yourMesh, yourSceneNode); - yourSceneNode->setTriangleSelector(s); - s->drop(); - \endcode - For more informations and examples on this, take a look at the collision - tutorial in the SDK. - \param mesh: Mesh of which the triangles are taken. - \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 the this value, it will not be splitted into - smaller nodes. - \return Returns 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. */ + yourSceneNode->setTriangleSelector(s); + s->drop(); + \endcode + For more informations and examples on this, take a look at the collision + tutorial in the SDK. + \param mesh: Mesh of which the triangles are taken. + \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 the this value, it will not be splitted 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* createOctTreeTriangleSelector(IMesh* mesh, ISceneNode* node, s32 minimalPolysPerNode=32) = 0; //! Creates a meta triangle selector. /** A meta triangle selector is nothing more than a - collection of one or more triangle selectors providing together - the interface of one triangle selector. In this way, - collision tests can be done with different triangle soups in one pass. - \return Returns 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. */ + collection of one or more triangle selectors providing together + the interface of one triangle selector. In this way, + collision tests can be done with different triangle soups in one pass. + \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 IMetaTriangleSelector* createMetaTriangleSelector() = 0; //! Creates a triangle selector which can select triangles from a terrain scene node. /** \param node: Pointer to the created terrain scene node - \param LOD: Level of detail, 0 for highest detail. */ + \param LOD: Level of detail, 0 for highest detail. + \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* createTerrainTriangleSelector( ITerrainSceneNode* node, s32 LOD=0) = 0; //! Adds an external mesh loader for extending the engine with new file formats. /** If you want the engine to be extended with - file formats it currently is not able to load (e.g. .cob), just implement - the IMeshLoader interface in your loading class and add it with this method. - Using this method it is also possible to override built-in mesh loaders with - newer or updated versions without the need of recompiling the engine. - \param externalLoader: Implementation of a new mesh loader. */ + file formats it currently is not able to load (e.g. .cob), just implement + the IMeshLoader interface in your loading class and add it with this method. + Using this method it is also possible to override built-in mesh loaders with + newer or updated versions without the need of recompiling the engine. + \param externalLoader: Implementation of a new mesh loader. */ virtual void addExternalMeshLoader(IMeshLoader* externalLoader) = 0; - //! Returns a pointer to the scene collision manager. + //! Get pointer to the scene collision manager. + /** \return Pointer to the collision manager + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ISceneCollisionManager* getSceneCollisionManager() = 0; - //! Returns a pointer to the mesh manipulator. + //! Get pointer to the mesh manipulator. + /** \return Pointer to the mesh manipulator + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual IMeshManipulator* getMeshManipulator() = 0; //! Adds a scene node to the deletion queue. /** The scene node is immediatly - deleted when it's secure. Which means when the scene node does not - execute animators and things like that. This method is for example - used for deleting scene nodes by their scene node animators. In - most other cases, a ISceneNode::remove() call is enough, using this - deletion queue is not necessary. - See ISceneManager::createDeleteAnimator() for details. - \param node: Node to detete. */ + deleted when it's secure. Which means when the scene node does not + execute animators and things like that. This method is for example + used for deleting scene nodes by their scene node animators. In + most other cases, a ISceneNode::remove() call is enough, using this + deletion queue is not necessary. + See ISceneManager::createDeleteAnimator() for details. + \param node: Node to detete. */ virtual void addToDeletionQueue(ISceneNode* node) = 0; //! Posts an input event to the environment. /** Usually you do not have to - use this method, it is used by the internal engine. */ + use this method, it is used by the internal engine. */ virtual bool postEventFromUser(const SEvent& event) = 0; //! Clears the whole scene. /** All scene nodes are removed. */ virtual void clear() = 0; - //! Returns interface to the parameters set in this scene. + //! Get interface to the parameters set in this scene. /** String parameters can be used by plugins and mesh loaders. - For example the CMS and LMTS loader want a parameter named 'CSM_TexturePath' - and 'LMTS_TexturePath' set to the path were attached textures can be found. See - CSM_TEXTURE_PATH, LMTS_TEXTURE_PATH, MY3D_TEXTURE_PATH, - COLLADA_CREATE_SCENE_INSTANCES, DMF_TEXTURE_PATH and DMF_USE_MATERIALS_DIRS*/ + For example the CMS and LMTS loader want a parameter named 'CSM_TexturePath' + and 'LMTS_TexturePath' set to the path were attached textures can be found. See + CSM_TEXTURE_PATH, LMTS_TEXTURE_PATH, MY3D_TEXTURE_PATH, + COLLADA_CREATE_SCENE_INSTANCES, DMF_TEXTURE_PATH and DMF_USE_MATERIALS_DIRS*/ virtual io::IAttributes* getParameters() = 0; - //! Returns current render pass. + //! Get current render pass. /** All scene nodes are being rendered in a specific order. - First lights, cameras, sky boxes, solid geometry, and then transparent - stuff. During the rendering process, scene nodes may want to know what the scene - manager is rendering currently, because for example they registered for rendering - twice, once for transparent geometry and once for solid. When knowing what rendering - pass currently is active they can render the correct part of their geometry. */ + First lights, cameras, sky boxes, solid geometry, and then transparent + stuff. During the rendering process, scene nodes may want to know what the scene + manager is rendering currently, because for example they registered for rendering + twice, once for transparent geometry and once for solid. When knowing what rendering + pass currently is active they can render the correct part of their geometry. */ virtual E_SCENE_NODE_RENDER_PASS getSceneNodeRenderPass() const = 0; - //! Returns the default scene node factory which can create all built in scene nodes + //! Get the default scene node factory which can create all built in scene nodes + /** \return Pointer to the default scene node factory + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ISceneNodeFactory* getDefaultSceneNodeFactory() = 0; //! Adds a scene node factory to the scene manager. @@ -1258,13 +1289,17 @@ namespace scene able to create automaticly, for example when loading data from xml files. */ virtual void registerSceneNodeFactory(ISceneNodeFactory* factoryToAdd) = 0; - //! Returns amount of registered scene node factories. + //! Get amount of registered scene node factories. virtual u32 getRegisteredSceneNodeFactoryCount() const = 0; - //! Returns a scene node factory by index + //! Get a scene node factory by index + /** \return Pointer to the requested scene node factory, or 0 if it does not exist. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ISceneNodeFactory* getSceneNodeFactory(u32 index) = 0; - //! Returns the default scene node animator factory which can create all built-in scene node animators + //! Get the default scene node animator factory which can create all built-in scene node animators + /** \return Pointer to the default scene node animator factory + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ISceneNodeAnimatorFactory* getDefaultSceneNodeAnimatorFactory() = 0; //! Adds a scene node animator factory to the scene manager. @@ -1272,16 +1307,20 @@ namespace scene able to create automaticly, for example when loading data from xml files. */ virtual void registerSceneNodeAnimatorFactory(ISceneNodeAnimatorFactory* factoryToAdd) = 0; - //! Returns amount of registered scene node animator factories. + //! Get amount of registered scene node animator factories. virtual u32 getRegisteredSceneNodeAnimatorFactoryCount() const = 0; - //! Returns a scene node animator factory by index + //! Get scene node animator factory by index + /** \return Pointer to the requested scene node animator factory, or 0 if it does not exist. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ISceneNodeAnimatorFactory* getSceneNodeAnimatorFactory(u32 index) = 0; - //! Returns a typename from a scene node type or null if not found + //! Get typename from a scene node type or null if not found virtual const c8* getSceneNodeTypeName(ESCENE_NODE_TYPE type) = 0; //! Adds a scene node to the scene by name + /** \return Pointer to the scene node added by a factory + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ISceneNode* addSceneNode(const char* sceneNodeTypeName, ISceneNode* parent=0) = 0; //! Creates a new scene manager. @@ -1314,7 +1353,7 @@ namespace scene \param userDataSerializer: If you want to save some user data for every scene node into the file, implement the ISceneUserDataSerializer interface and provide it as parameter here. Otherwise, simply specify 0 as this parameter. - \return Returns true if successful. */ + \return True if successful. */ virtual bool saveScene(const c8* filename, ISceneUserDataSerializer* userDataSerializer=0) = 0; //! Saves the current scene into a file. @@ -1326,7 +1365,7 @@ namespace scene \param userDataSerializer: If you want to save some user data for every scene node into the file, implement the ISceneUserDataSerializer interface and provide it as parameter here. Otherwise, simply specify 0 as this parameter. - \return Returns true if successful. */ + \return True if successful. */ virtual bool saveScene(io::IWriteFile* file, ISceneUserDataSerializer* userDataSerializer=0) = 0; //! Loads a scene. Note that the current scene is not cleared before. @@ -1339,7 +1378,7 @@ namespace scene implement the ISceneUserDataSerializer interface and provide it as parameter here. Otherwise, simply specify 0 as this parameter. - \return Returns true if successful. */ + \return True if successful. */ virtual bool loadScene(const c8* filename, ISceneUserDataSerializer* userDataSerializer=0) = 0; //! Loads a scene. Note that the current scene is not cleared before. @@ -1352,10 +1391,10 @@ namespace scene implement the ISceneUserDataSerializer interface and provide it as parameter here. Otherwise, simply specify 0 as this parameter. - \return Returns true if successful. */ + \return True if successful. */ virtual bool loadScene(io::IReadFile* file, ISceneUserDataSerializer* userDataSerializer=0) = 0; - //! Returns a mesh writer implementation if available + //! Get a mesh writer implementation if available /** Note: You need to drop() the pointer after use again, see IReferenceCounted::drop() for details. */ virtual IMeshWriter* createMeshWriter(EMESH_WRITER_TYPE type) = 0; @@ -1363,8 +1402,13 @@ namespace scene //! Sets ambient color of the scene virtual void setAmbientLight(const video::SColorf &ambientColor) = 0; - //! Returns ambient color of the scene + //! Get ambient color of the scene virtual const video::SColorf& getAmbientLight() const = 0; + + //! Register a custom callbacks manager which gets callbacks during scene rendering. + /** \param[in] lightManager: the new callbacks manager. You may pass 0 to remove the + current callbacks manager and restore the default behaviour. */ + virtual void setLightManager(ILightManager* lightManager) = 0; }; diff --git a/include/ISceneNode.h b/include/ISceneNode.h index 459d9b94..1e3b258c 100644 --- a/include/ISceneNode.h +++ b/include/ISceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -201,20 +201,34 @@ namespace scene } - //! Returns true if the node is visible. + //! Returns whether the node should be visible (if all of its parents are visible). /** This is only an option set by the user, but has nothing to do with geometry culling - \return The visibility of the node, true means visible. */ + \return The requested visibility of the node, true means visible (if all parents are also visible). */ virtual bool isVisible() const { _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; return IsVisible; } + //! Returns whether the node is truly visible, taking into accounts its parents' visibility + /** \return true if the node and all its parents are visible, false if this or any parent node is invisible. */ + virtual bool isTrulyVisible() const + { + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + if(!IsVisible) + return false; + + if(!Parent) + return true; + + return Parent->isTrulyVisible(); + } //! Sets if the node should be visible or not. /** All children of this node won't be visible either, when set - to false. + to false. Invisible nodes are not valid candidates for selection by + collision manager bounding box methods. \param isVisible If the node shall be visible. */ virtual void setVisible(bool isVisible) { diff --git a/include/ISceneNodeAnimator.h b/include/ISceneNodeAnimator.h index c8346367..0176b81f 100644 --- a/include/ISceneNodeAnimator.h +++ b/include/ISceneNodeAnimator.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -64,6 +64,14 @@ namespace scene { return ESNAT_UNKNOWN; } + + //! Returns if the animator has finished. + /** This is only valid for non-looping animators with a discrete end state. + \return true if the animator has finished, false if it is still running. */ + virtual bool hasFinished(void) const + { + return false; + } }; diff --git a/include/ISceneNodeAnimatorCameraFPS.h b/include/ISceneNodeAnimatorCameraFPS.h index 7676d570..5b21584d 100644 --- a/include/ISceneNodeAnimatorCameraFPS.h +++ b/include/ISceneNodeAnimatorCameraFPS.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -39,8 +39,8 @@ namespace scene virtual void setRotateSpeed(f32 rotateSpeed) = 0; //! Sets the keyboard mapping for this animator - /** \param keymap Array of keyboard mappings, see SKeyMap - \param count Size of the keyboard map array */ + /** \param map Array of keyboard mappings, see irr::SKeyMap + \param count Size of the keyboard map array. */ virtual void setKeyMap(SKeyMap *map, u32 count) = 0; //! Sets whether vertical movement should be allowed. @@ -48,6 +48,11 @@ namespace scene gravity causing camera shake. Disable this if the camera has a collision animator with gravity enabled. */ virtual void setVerticalMovement(bool allow) = 0; + + //! Sets whether the Y axis of the mouse should be inverted. + /** If enabled then moving the mouse down will cause + the camera to look up. It is disabled by default. */ + virtual void setInvertMouse(bool invert) = 0; }; } // end namespace scene } // end namespace irr diff --git a/include/ISceneNodeAnimatorCameraMaya.h b/include/ISceneNodeAnimatorCameraMaya.h index 41698148..15b0b869 100644 --- a/include/ISceneNodeAnimatorCameraMaya.h +++ b/include/ISceneNodeAnimatorCameraMaya.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/ISceneNodeAnimatorCollisionResponse.h b/include/ISceneNodeAnimatorCollisionResponse.h index f8a2d97b..5e30d11c 100644 --- a/include/ISceneNodeAnimatorCollisionResponse.h +++ b/include/ISceneNodeAnimatorCollisionResponse.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -12,6 +12,30 @@ namespace irr namespace scene { + class ISceneNodeAnimatorCollisionResponse; + + //! Callback interface for catching events of collisions. + /** Implement this interface and use + ISceneNodeAnimatorCollisionResponse::setCollisionCallback to be able to + be notified if a collision has occurred. + **/ + class ICollisionCallback : public virtual IReferenceCounted + { + public: + + //! Will be called when a collision occurrs. + /** See ISceneNodeAnimatorCollisionResponse::setCollisionCallback for more information. + \param animator: Collision response animator in which the collision occurred. You can call + this animator's methods to find the node, collisionPoint and/or collision triangle. + \retval true if the collision was handled in the animator. The animator's target + node will *not* be stopped at the collision point, but will instead move fully + to the location that triggered the collision check. + \retval false if the collision was not handled in the animator. The animator's + target node will be moved to the collision position. + */ + virtual bool onCollision(const ISceneNodeAnimatorCollisionResponse& animator) = 0; + }; + //! Special scene node animator for doing automatic collision detection and response. /** This scene node animator can be attached to any single scene node and will then prevent it from moving through specified collision geometry @@ -108,6 +132,31 @@ namespace scene /** \return The node that this animator is acting on. */ virtual ISceneNode* getTargetNode(void) const = 0; + //! Returns true if a collision occurred during the last animateNode() + virtual bool collisionOccurred() const = 0; + + //! Returns the last point of collision. + virtual const core::vector3df & getCollisionPoint() const = 0; + + //! Returns the last triangle that caused a collision + virtual const core::triangle3df & getCollisionTriangle() const = 0; + + //! Returns the position that the target node will be moved to, unless the collision is consumed in a callback). + /** + If you have a collision callback registered, and it consumes the collision, then the + node will ignore the collision and will not stop at this position. Instead, it will + move fully to the position that caused the collision to occur. */ + virtual const core::vector3df & getCollisionResultPosition(void) const = 0; + + //! Returns the node that was collided with. + virtual const ISceneNode* getCollisionNode(void) const = 0; + + //! Sets a callback interface which will be called if a collision occurs. + /** \param callback: collision callback handler that will be called when a collision + occurs. Set this to 0 to disable the callback. + */ + virtual void setCollisionCallback(ICollisionCallback* callback) = 0; + }; diff --git a/include/ISceneNodeAnimatorFactory.h b/include/ISceneNodeAnimatorFactory.h index 5e220e5d..589682b5 100644 --- a/include/ISceneNodeAnimatorFactory.h +++ b/include/ISceneNodeAnimatorFactory.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/ISceneNodeFactory.h b/include/ISceneNodeFactory.h index 4ca6bf15..3102e085 100644 --- a/include/ISceneNodeFactory.h +++ b/include/ISceneNodeFactory.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -33,13 +33,15 @@ namespace scene //! adds a scene node to the scene graph based on its type id /** \param type: Type of the scene node to add. \param parent: Parent scene node of the new node, can be null to add the scene node to the root. - \return Returns pointer to the new scene node or null if not successful. */ + \return Returns pointer to the new scene node or null if not successful. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ISceneNode* addSceneNode(ESCENE_NODE_TYPE type, ISceneNode* parent=0) = 0; //! adds a scene node to the scene graph based on its type name /** \param typeName: Type name of the scene node to add. \param parent: Parent scene node of the new node, can be null to add the scene node to the root. - \return Returns pointer to the new scene node or null if not successful. */ + \return Returns pointer to the new scene node or null if not successful. + This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ virtual ISceneNode* addSceneNode(const c8* typeName, ISceneNode* parent=0) = 0; //! returns amount of scene node types this factory is able to create diff --git a/include/ISceneUserDataSerializer.h b/include/ISceneUserDataSerializer.h index d756fe31..33c299da 100644 --- a/include/ISceneUserDataSerializer.h +++ b/include/ISceneUserDataSerializer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IShaderConstantSetCallBack.h b/include/IShaderConstantSetCallBack.h index f486b343..84469710 100644 --- a/include/IShaderConstantSetCallBack.h +++ b/include/IShaderConstantSetCallBack.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IShadowVolumeSceneNode.h b/include/IShadowVolumeSceneNode.h index 8a77fab2..e0e838f6 100644 --- a/include/IShadowVolumeSceneNode.h +++ b/include/IShadowVolumeSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/ISkinnedMesh.h b/include/ISkinnedMesh.h index 047b9d62..d4a733be 100644 --- a/include/ISkinnedMesh.h +++ b/include/ISkinnedMesh.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/ITerrainSceneNode.h b/include/ITerrainSceneNode.h index 75f29add..88f64533 100644 --- a/include/ITerrainSceneNode.h +++ b/include/ITerrainSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/ITextSceneNode.h b/include/ITextSceneNode.h index 770693f3..9542199e 100644 --- a/include/ITextSceneNode.h +++ b/include/ITextSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/ITexture.h b/include/ITexture.h index 11731b9c..ef7580f7 100644 --- a/include/ITexture.h +++ b/include/ITexture.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -130,11 +130,11 @@ public: of the original texture. Use ITexture::getSize() if you want to know the real size it has now stored in the system. \return Returns the original size of the texture. */ - virtual const core::dimension2d& getOriginalSize() const = 0; + virtual const core::dimension2d& getOriginalSize() const = 0; //! Returns dimension (=size) of the texture. /** \return Returns the size of the texture. */ - virtual const core::dimension2d& getSize() const = 0; + virtual const core::dimension2d& getSize() const = 0; //! Returns driver type of texture. /** This is the driver, which created the texture. diff --git a/include/ITimer.h b/include/ITimer.h index 88634bb9..104225ee 100644 --- a/include/ITimer.h +++ b/include/ITimer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/ITriangleSelector.h b/include/ITriangleSelector.h index 1502d577..65de2592 100644 --- a/include/ITriangleSelector.h +++ b/include/ITriangleSelector.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -16,6 +16,8 @@ namespace irr namespace scene { +class ISceneNode; + //! Interface to return triangles with specific properties. /** Every ISceneNode may have a triangle selector, available with ISceneNode::getTriangleScelector() or ISceneManager::createTriangleSelector. @@ -33,8 +35,13 @@ public: //! Returns amount of all available triangles in this selector virtual s32 getTriangleCount() const = 0; - //! Gets all triangles. - /** \param triangles: Array where the resulting triangles will be + //! Gets the triangles for one associated node. + /** + This returns all triangles for one scene node associated with this + selector. If there is more than one scene node associated (e.g. for + an IMetaTriangleSelector) this this function may be called multiple + times to retrieve all triangles. + \param triangles: Array where the resulting triangles will be written to. \param arraySize: Size of the target array. \param outTriangleCount: Amount of triangles which have been written @@ -46,9 +53,15 @@ public: virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, const core::matrix4* transform=0) const = 0; - //! Gets all triangles which lie within a specific bounding box. - /** Please note that unoptimized triangle selectors also may return - triangles which are not in the specific box at all. + //! Gets the triangles for one associated node which lie or may lie within a specific bounding box. + /** + This returns all triangles for one scene node associated with this + selector. If there is more than one scene node associated (e.g. for + an IMetaTriangleSelector) this this function may be called multiple + times to retrieve all triangles. + + Please note that unoptimized triangle selectors also may return + triangles which are not in the specified box at all. \param triangles: Array where the resulting triangles will be written to. \param arraySize: Size of the target array. @@ -64,8 +77,14 @@ public: s32& outTriangleCount, const core::aabbox3d& box, const core::matrix4* transform=0) const = 0; - //! Gets all triangles which have or may have contact with a 3d line. - /** Please note that unoptimized triangle selectors also may return + //! Gets the triangles for one associated node which have or may have contact with a 3d line. + /** + This returns all triangles for one scene node associated with this + selector. If there is more than one scene node associated (e.g. for + an IMetaTriangleSelector) this this function may be called multiple + times to retrieve all triangles. + + Please note that unoptimized triangle selectors also may return triangles which are not in contact at all with the 3d line. \param triangles: Array where the resulting triangles will be written to. @@ -81,6 +100,18 @@ public: virtual void getTriangles(core::triangle3df* triangles, s32 arraySize, s32& outTriangleCount, const core::line3d& line, const core::matrix4* transform=0) const = 0; + + //! Return the scene node associated with a given triangle. + /** + This allows you 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 const ISceneNode* getSceneNodeForTriangle(u32 triangleIndex) const = 0; + }; } // end namespace scene diff --git a/include/IVertexBuffer.h b/include/IVertexBuffer.h index 5192139b..c90a0f7e 100644 --- a/include/IVertexBuffer.h +++ b/include/IVertexBuffer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Nikolaus Gebhardt +// Copyright (C) 2008-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IVideoDriver.h b/include/IVideoDriver.h index 329a6a38..4288be8e 100644 --- a/include/IVideoDriver.h +++ b/include/IVideoDriver.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -25,6 +25,7 @@ namespace io { class IAttributes; class IReadFile; + class IWriteFile; } // end namespace io namespace scene { @@ -77,6 +78,30 @@ namespace video ELR_HW_BUFFERS = 8 }; + enum E_RENDER_TARGET + { + //! Render target is the main color frame buffer + ERT_FRAME_BUFFER=0, + //! Render target is the main color frame buffer + ERT_STEREO_LEFT_BUFFER=0, + //! Render target is a render texture + ERT_RENDER_TEXTURE, + //! Render target is the right color buffer (left is the main buffer) + ERT_STEREO_RIGHT_BUFFER, + //! Render to both stereo buffers at once + ERT_STEREO_BOTH_BUFFERS, + //! Auxiliary buffer 0 + ERT_AUX_BUFFER0, + //! Auxiliary buffer 1 + ERT_AUX_BUFFER1, + //! Auxiliary buffer 2 + ERT_AUX_BUFFER2, + //! Auxiliary buffer 3 + ERT_AUX_BUFFER3, + //! Auxiliary buffer 4 + ERT_AUX_BUFFER4 + }; + //! Interface to driver which is able to perform 2d and 3d graphics functions. /** This interface is one of the most important interfaces of the Irrlicht Engine: All rendering and texture manipulation is done with @@ -110,19 +135,19 @@ namespace video virtual bool beginScene(bool backBuffer=true, bool zBuffer=true, SColor color=SColor(255,0,0,0), void* windowId=0, - core::rect* sourceRect=0) = 0; + core::rect* sourceRect=0) =0; //! Presents the rendered image to the screen. /** Applications must call this method after performing any rendering. \return False if failed and true if succeeded. */ - virtual bool endScene() = 0; + virtual bool endScene() =0; //! Queries the features of the driver. /** Returns true if a feature is available \param feature Feature to query. \return True if the feature is available, false if not. */ - virtual bool queryFeature(E_VIDEO_DRIVER_FEATURE feature) const = 0; + virtual bool queryFeature(E_VIDEO_DRIVER_FEATURE feature) const =0; //! Disable a feature of the driver. /** Can also be used to enable the features again. It is not @@ -141,17 +166,17 @@ namespace video /** \param state Transformation type to be set, e.g. view, world, or projection. \param mat Matrix describing the transformation. */ - virtual void setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) = 0; + virtual void setTransform(E_TRANSFORMATION_STATE state, const core::matrix4& mat) =0; //! Returns the transformation set by setTransform /** \param state Transformation type to query \return Matrix describing the transformation. */ - virtual const core::matrix4& getTransform(E_TRANSFORMATION_STATE state) const = 0; + virtual const core::matrix4& getTransform(E_TRANSFORMATION_STATE state) const =0; //! Sets a material. /** All 3d drawing functions will draw geometry using this material thereafter. \param material: Material to be used from now on. */ - virtual void setMaterial(const SMaterial& material) = 0; + virtual void setMaterial(const SMaterial& material) =0; //! Get access to a named texture. /** Loads the texture from disk if it is not @@ -163,7 +188,7 @@ namespace video \return Pointer to the texture, or 0 if the texture could not be loaded. This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ITexture* getTexture(const c8* filename) = 0; + virtual ITexture* getTexture(const c8* filename) =0; //! Get access to a named texture. /** Loads the texture from disk if it is not @@ -175,7 +200,7 @@ namespace video \return Pointer to the texture, or 0 if the texture could not be loaded. This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ITexture* getTexture(const core::stringc& filename) = 0; + virtual ITexture* getTexture(const core::stringc& filename) =0; //! Get access to a named texture. /** Loads the texture from disk if it is not @@ -187,7 +212,7 @@ namespace video \return Pointer to the texture, or 0 if the texture could not be loaded. This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ITexture* getTexture(io::IReadFile* file) = 0; + virtual ITexture* getTexture(io::IReadFile* file) =0; //! Returns a texture by index /** \param index: Index of the texture, must be smaller than @@ -196,7 +221,7 @@ namespace video \return Pointer to the texture, or 0 if the texture was not set or index is out of bounds. This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ITexture* getTextureByIndex(u32 index) = 0; + virtual ITexture* getTextureByIndex(u32 index) =0; //! Returns amount of textures currently loaded /** \return Amount of textures currently loaded */ @@ -205,7 +230,7 @@ namespace video //! Renames a texture /** \param texture Pointer to the texture to rename. \param newName New name for the texture. This should be a unique name. */ - virtual void renameTexture(ITexture* texture, const c8* newName) = 0; + virtual void renameTexture(ITexture* texture, const c8* newName) =0; //! Creates an empty texture of specified size. /** \param size: Size of the texture. @@ -217,8 +242,8 @@ namespace video \return Pointer to the newly created texture. This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ITexture* addTexture(const core::dimension2d& size, - const c8* name, ECOLOR_FORMAT format = ECF_A8R8G8B8) = 0; + virtual ITexture* addTexture(const core::dimension2d& size, + const c8* name, ECOLOR_FORMAT format = ECF_A8R8G8B8) =0; //! Creates a texture from an IImage. /** \param name A name for the texture. Later calls of @@ -227,7 +252,7 @@ namespace video \return Pointer to the newly created texture. This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ITexture* addTexture(const c8* name, IImage* image) = 0; + virtual ITexture* addTexture(const c8* name, IImage* image) =0; //! Adds a new render target texture to the texture cache. /** \param size Size of the texture, in pixels. Width and @@ -238,12 +263,12 @@ namespace video \return Pointer to the created texture or 0 if the texture could not be created. This pointer should not be dropped. See IReferenceCounted::drop() for more information. */ - virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, const c8* name=0) =0; //! Adds a new render target texture /** \deprecated use addRenderTargetTexture instead. */ - virtual ITexture* createRenderTargetTexture(const core::dimension2d& size, + virtual ITexture* createRenderTargetTexture(const core::dimension2d& size, const c8* name=0) =0; //! Removes a texture from the texture cache and deletes it. @@ -254,7 +279,7 @@ namespace video good idea to set all materials which are using this texture to 0 or another texture first. \param texture Texture to delete from the engine cache. */ - virtual void removeTexture(ITexture* texture) = 0; + virtual void removeTexture(ITexture* texture) =0; //! Removes all textures from the texture cache and deletes them. /** This method can free a lot of memory! @@ -263,38 +288,49 @@ namespace video by other parts of the engine for storing it longer. So it is a good idea to set all materials which are using this texture to 0 or another texture first. */ - virtual void removeAllTextures() = 0; + virtual void removeAllTextures() =0; //! Remove hardware buffer - virtual void removeHardwareBuffer(const scene::IMeshBuffer* mb) = 0; + virtual void removeHardwareBuffer(const scene::IMeshBuffer* mb) =0; //! Remove all hardware buffers - virtual void removeAllHardwareBuffers() = 0; + virtual void removeAllHardwareBuffers() =0; - //! Creates a 1bit alpha channel of the texture based of an color key. - /** This makes the texture transparent at the regions where + //! Sets a boolean alpha channel on the texture based on a color key. + /** This makes the texture fully transparent at the texels where this color key can be found when using for example draw2DImage - with useAlphachannel==true. + with useAlphachannel==true. The alpha of other texels is not modified. \param texture Texture whose alpha channel is modified. - \param color Color key color. Every pixel with this color will - become transparent as described above. Please note that the + \param color Color key color. Every texel with this color will + become fully transparent as described above. Please note that the colors of a texture may be converted when loading it, so the color values may not be exactly the same in the engine and for example in picture edit programs. To avoid this problem, you could use the makeColorKeyTexture method, which takes the - position of a pixel instead a color value. */ - virtual void makeColorKeyTexture(video::ITexture* texture, video::SColor color) const = 0; + position of a pixel instead a color value. + \param \deprecated zeroTexels If set to true, then any texels that match + the color key will have their color, as well as their alpha, set to zero + (i.e. black). This behaviour matches the legacy (buggy) behaviour prior + to release 1.5 and is provided for backwards compatibility only.*/ + virtual void makeColorKeyTexture(video::ITexture* texture, + video::SColor color, + bool zeroTexels = false) const =0; - //! Creates a 1bit alpha channel of the texture based of an color key position. - /** This makes the texture transparent at the regions where - this color key can be found when using for example draw2DImage - with useAlphachannel==true. + //! Sets a boolean alpha channel on the texture based on the color at a position. + /** This makes the texture fully transparent at the texels where + the color key can be found when using for example draw2DImage + with useAlphachannel==true. The alpha of other texels is not modified. \param texture Texture whose alpha channel is modified. \param colorKeyPixelPos Position of a pixel with the color key - color. Every pixel with this color will become transparent as - described above. */ + color. Every texel with this color will become fully transparent as + described above. + \param \deprecated zeroTexels If set to true, then any texels that match + the color key will have their color, as well as their alpha, set to zero + (i.e. black). This behaviour matches the legacy (buggy) behaviour prior + to release 1.5 and is provided for backwards compatibility only.*/ virtual void makeColorKeyTexture(video::ITexture* texture, - core::position2d colorKeyPixelPos) const = 0; + core::position2d colorKeyPixelPos, + bool zeroTexels = false) const =0; //! Creates a normal map from a height map texture. /** If the target texture has 32 bit, the height value is @@ -304,7 +340,7 @@ namespace video \param texture Texture whose alpha channel is modified. \param amplitude Constant value by which the height information is multiplied.*/ - virtual void makeNormalMapTexture(video::ITexture* texture, f32 amplitude=1.0f) const = 0; + virtual void makeNormalMapTexture(video::ITexture* texture, f32 amplitude=1.0f) const =0; //! Sets a new render target. /** This will only work if the driver supports the @@ -340,32 +376,49 @@ namespace video \return True if sucessful and false if not. */ virtual bool setRenderTarget(video::ITexture* texture, bool clearBackBuffer=true, bool clearZBuffer=true, - SColor color=video::SColor(0,0,0,0)) = 0; + SColor color=video::SColor(0,0,0,0)) =0; + + //! set or reset special render targets + /** This method enables access to special color buffers such as + stereoscopic buffers or auxiliary buffers. + \param target Enum value for the render target + \param clearTarget Clears the target buffer with the color + parameter + \param clearZBuffer Clears the zBuffer of the rendertarget. + Note that because the main frame buffer may share the zbuffer with + the rendertarget, its zbuffer might be partially cleared too + by this. + \param color The background color for the render target. + \return True if sucessful and false if not. */ + virtual bool setRenderTarget(E_RENDER_TARGET target, bool clearTarget, + bool clearZBuffer, SColor color) =0; //! Sets a new viewport. /** Every rendering operation is done into this new area. \param area: Rectangle defining the new area of rendering operations. */ - virtual void setViewPort(const core::rect& area) = 0; + virtual void setViewPort(const core::rect& area) =0; //! Gets the area of the current viewport. /** \return Rectangle of the current viewport. */ - virtual const core::rect& getViewPort() const = 0; + virtual const core::rect& getViewPort() const =0; //! Draws a vertex primitive list - /** Note that there may be at maximum 65536 vertices, because - the index list is an array of 16 bit values each with a maximum - value of 65536. If there are more than 65536 vertices in the - list, results of this operation are not defined. + /** Note that, depending on the index type, some vertices might be not + accessible through the index list. The limit is at 65535 vertices for 16bit + indices. \param vertices Pointer to array of vertices. \param vertexCount Amount of vertices in the array. \param indexList Pointer to array of indices. \param primCount Amount of Primitives - \param vType Vertex type, e.g. EVT_STANDARD for S3DVertex. - \param pType Primitive type, e.g. EPT_TRIANGLE_FAN for a triangle fan. */ + \param vType Vertex type, e.g. video::EVT_STANDARD for S3DVertex. + \param pType Primitive type, e.g. scene::EPT_TRIANGLE_FAN for a triangle fan. + \param iType Index type, e.g. video::EIT_16BIT for a triangle fan. */ virtual void drawVertexPrimitiveList(const void* vertices, u32 vertexCount, const void* indexList, u32 primCount, - E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) = 0; + E_VERTEX_TYPE vType=EVT_STANDARD, + scene::E_PRIMITIVE_TYPE pType=scene::EPT_TRIANGLES, + E_INDEX_TYPE iType=EIT_16BIT) =0; //! Draws an indexed triangle list. /** Note that there may be at maximum 65536 vertices, because @@ -377,7 +430,7 @@ namespace video \param indexList Pointer to array of indices. \param triangleCount Amount of Triangles. Usually amount of indices / 3. */ virtual void drawIndexedTriangleList(const S3DVertex* vertices, - u32 vertexCount, const u16* indexList, u32 triangleCount) = 0; + u32 vertexCount, const u16* indexList, u32 triangleCount) =0; //! Draws an indexed triangle list. /** Note that there may be at maximum 65536 vertices, because @@ -389,7 +442,7 @@ namespace video \param indexList Pointer to array of indices. \param triangleCount Amount of Triangles. Usually amount of indices / 3. */ virtual void drawIndexedTriangleList(const S3DVertex2TCoords* vertices, - u32 vertexCount, const u16* indexList, u32 triangleCount) = 0; + u32 vertexCount, const u16* indexList, u32 triangleCount) =0; //! Draws an indexed triangle list. /** Note that there may be at maximum 65536 vertices, because @@ -401,7 +454,7 @@ namespace video \param indexList Pointer to array of indices. \param triangleCount Amount of Triangles. Usually amount of indices / 3. */ virtual void drawIndexedTriangleList(const S3DVertexTangents* vertices, - u32 vertexCount, const u16* indexList, u32 triangleCount) = 0; + u32 vertexCount, const u16* indexList, u32 triangleCount) =0; //! Draws an indexed triangle fan. /** Note that there may be at maximum 65536 vertices, because @@ -413,7 +466,7 @@ namespace video \param indexList Pointer to array of indices. \param triangleCount Amount of Triangles. Usually amount of indices - 2. */ virtual void drawIndexedTriangleFan(const S3DVertex* vertices, - u32 vertexCount, const u16* indexList, u32 triangleCount) = 0; + u32 vertexCount, const u16* indexList, u32 triangleCount) =0; //! Draws an indexed triangle fan. /** Note that there may be at maximum 65536 vertices, because @@ -425,7 +478,7 @@ namespace video \param indexList Pointer to array of indices. \param triangleCount Amount of Triangles. Usually amount of indices - 2. */ virtual void drawIndexedTriangleFan(const S3DVertex2TCoords* vertices, - u32 vertexCount, const u16* indexList, u32 triangleCount) = 0; + u32 vertexCount, const u16* indexList, u32 triangleCount) =0; //! Draws a 3d line. /** For some implementations, this method simply calls @@ -443,7 +496,7 @@ namespace video \param end End of the 3d line. \param color Color of the line. */ virtual void draw3DLine(const core::vector3df& start, - const core::vector3df& end, SColor color = SColor(255,255,255,255)) = 0; + const core::vector3df& end, SColor color = SColor(255,255,255,255)) =0; //! Draws a 3d triangle. /** This method calls drawIndexedTriangles for some triangles. @@ -460,7 +513,7 @@ namespace video \param triangle The triangle to draw. \param color Color of the line. */ virtual void draw3DTriangle(const core::triangle3df& triangle, - SColor color = SColor(255,255,255,255)) = 0; + SColor color = SColor(255,255,255,255)) =0; //! Draws a 3d axis aligned box. /** This method simply calls draw3DLine for the edges of the @@ -475,14 +528,14 @@ namespace video \param box The axis aligned box to draw \param color Color to use while drawing the box. */ virtual void draw3DBox(const core::aabbox3d& box, - SColor color = SColor(255,255,255,255)) = 0; + SColor color = SColor(255,255,255,255)) =0; //! Draws a 2d image without any special effects /** \param texture Pointer to texture to use. \param destPos Upper left 2d destination position where the image will be drawn. */ virtual void draw2DImage(const video::ITexture* texture, - const core::position2d& destPos) = 0; + const core::position2d& destPos) =0; //! Draws a 2d image using a color /** (if color is other than @@ -501,8 +554,8 @@ namespace video \param useAlphaChannelOfTexture: If true, the alpha channel of the texture is used to draw the image.*/ virtual void draw2DImage(const video::ITexture* texture, const core::position2d& destPos, - const core::rect& sourceRect, const core::rect* clipRect = 0, - SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false) = 0; + const core::rect& sourceRect, const core::rect* clipRect =0, + SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false) =0; //! Draws a set of 2d images, using a color and the alpha channel of the texture. /** The images are drawn beginning at pos and concatenated in @@ -531,7 +584,7 @@ namespace video s32 kerningWidth=0, const core::rect* clipRect=0, SColor color=SColor(255,255,255,255), - bool useAlphaChannelOfTexture=false) = 0; + bool useAlphaChannelOfTexture=false) =0; //! Draws a part of the texture into the rectangle. Note that colors must be an array of 4 colors if used. /** Suggested and first implemented by zola. @@ -544,8 +597,8 @@ namespace video \param useAlphaChannelOfTexture True if alpha channel will be blended. */ virtual void draw2DImage(const video::ITexture* texture, const core::rect& destRect, - const core::rect& sourceRect, const core::rect* clipRect = 0, - const video::SColor * const colors=0, bool useAlphaChannelOfTexture=false) = 0; + const core::rect& sourceRect, const core::rect* clipRect =0, + const video::SColor * const colors=0, bool useAlphaChannelOfTexture=false) =0; //! Draws a 2d rectangle. /** \param color Color of the rectangle to draw. The alpha @@ -556,9 +609,9 @@ namespace video will be clipped. If the pointer is null, no clipping will be performed. */ virtual void draw2DRectangle(SColor color, const core::rect& pos, - const core::rect* clip = 0) = 0; + const core::rect* clip =0) =0; - //! Draws an 2d rectangle with a gradient. + //! Draws a 2d rectangle with a gradient. /** \param colorLeftUp Color of the upper left corner to draw. The alpha component will not be ignored and specifies how transparent the rectangle will be. @@ -578,22 +631,30 @@ namespace video virtual void draw2DRectangle(const core::rect& pos, SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, - const core::rect* clip = 0) = 0; + const core::rect* clip =0) =0; + + //! Draws the outline of a 2D rectangle. + /** \param pos Position of the rectangle. + \param color Color of the rectangle to draw. The alpha component + specifies how transparent the rectangle outline will be. */ + virtual void draw2DRectangleOutline(const core::recti& pos, + SColor color=SColor(255,255,255,255)) =0; //! Draws a 2d line. - /** \param start: Screen coordinates of the start of the line + /** \param start Screen coordinates of the start of the line in pixels. - \param end: Screen coordinates of the start of the line in + \param end Screen coordinates of the start of the line in pixels. - \param color: Color of the line to draw. */ + \param color Color of the line to draw. */ virtual void draw2DLine(const core::position2d& start, const core::position2d& end, - SColor color=SColor(255,255,255,255)) = 0; + SColor color=SColor(255,255,255,255)) =0; //! Draws a pixel. - /** \param position: the position of the pixel. - \param color: Color of the pixel to draw. */ - virtual void drawPixel(u32 x, u32 y, const SColor & color) = 0; + /** \param x The x-position of the pixel. + \param y The y-position of the pixel. + \param color Color of the pixel to draw. */ + virtual void drawPixel(u32 x, u32 y, const SColor& color) =0; //! Draws a non filled concyclic regular 2d polyon. /** This method can be used to draw circles, but also @@ -611,7 +672,7 @@ namespace video virtual void draw2DPolygon(core::position2d center, f32 radius, video::SColor color=SColor(100,255,255,255), - s32 vertexCount=10) = 0; + s32 vertexCount=10) =0; //! Draws a shadow volume into the stencil buffer. /** To draw a stencil shadow, do this: First, draw all geometry. @@ -625,7 +686,7 @@ namespace video \param count Amount of triangles in the array. \param zfail If set to true, zfail method is used, otherwise zpass. */ - virtual void drawStencilShadowVolume(const core::vector3df* triangles, s32 count, bool zfail=true) = 0; + virtual void drawStencilShadowVolume(const core::vector3df* triangles, s32 count, bool zfail=true) =0; //! Fills the stencil shadow with color. /** After the shadow volume has been drawn into the stencil @@ -651,11 +712,11 @@ namespace video video::SColor leftUpEdge = video::SColor(255,0,0,0), video::SColor rightUpEdge = video::SColor(255,0,0,0), video::SColor leftDownEdge = video::SColor(255,0,0,0), - video::SColor rightDownEdge = video::SColor(255,0,0,0)) = 0; + video::SColor rightDownEdge = video::SColor(255,0,0,0)) =0; //! Draws a mesh buffer - /** \param mb: Buffer to draw; */ - virtual void drawMeshBuffer( const scene::IMeshBuffer* mb) = 0; + /** \param mb Buffer to draw; */ + virtual void drawMeshBuffer(const scene::IMeshBuffer* mb) =0; //! Sets the fog mode. /** These are global values attached to each 3d object rendered, @@ -678,22 +739,22 @@ namespace video virtual void setFog(SColor color=SColor(0,255,255,255), bool linearFog=true, f32 start=50.0f, f32 end=100.0f, f32 density=0.01f, - bool pixelFog=false, bool rangeFog=false) = 0; + bool pixelFog=false, bool rangeFog=false) =0; //! Get the current color format of the color buffer /** \return Color format of the color buffer. */ - virtual ECOLOR_FORMAT getColorFormat() const = 0; + virtual ECOLOR_FORMAT getColorFormat() const =0; //! Get the size of the screen or render window. /** \return Size of screen or render window. */ - virtual const core::dimension2d& getScreenSize() const = 0; + virtual const core::dimension2d& getScreenSize() const =0; //! Get the size of the current render target /** This method will return the screen size if the driver doesn't support render to texture, or if the current render target is the screen. \return Size of render target or screen/window */ - virtual const core::dimension2d& getCurrentRenderTargetSize() const = 0; + virtual const core::dimension2d& getCurrentRenderTargetSize() const =0; //! Returns current frames per second value. /** This value is updated approximately every 1.5 seconds and @@ -701,40 +762,46 @@ namespace video rate. It is not suitable for use in performing timing calculations or framerate independent movement. \return Approximate amount of frames per second drawn. */ - virtual s32 getFPS() const = 0; + virtual s32 getFPS() const =0; //! Returns amount of primitives (mostly triangles) which were drawn in the last frame. /** Together with getFPS() very useful method for statistics. \param mode Defines if the primitives drawn are accumulated or counted per frame. \return Amount of primitives drawn in the last frame. */ - virtual u32 getPrimitiveCountDrawn( u32 mode = 0 ) const = 0; + virtual u32 getPrimitiveCountDrawn( u32 mode =0 ) const =0; //! Deletes all dynamic lights which were previously added with addDynamicLight(). - virtual void deleteAllDynamicLights() = 0; + virtual void deleteAllDynamicLights() =0; - //! Adds a dynamic light. - /** \param light Data specifying the dynamic light. */ - virtual void addDynamicLight(const SLight& light) = 0; + //! adds a dynamic light, returning an index to the light + //! \param light: the light data to use to create the light + //! \return An index to the light, or -1 if an error occurs + virtual s32 addDynamicLight(const SLight& light) =0; //! Returns the maximal amount of dynamic lights the device can handle /** \return Maximal amount of dynamic lights. */ - virtual u32 getMaximalDynamicLightAmount() const = 0; + virtual u32 getMaximalDynamicLightAmount() const =0; //! Returns amount of dynamic lights currently set /** \return Amount of dynamic lights currently set */ - virtual u32 getDynamicLightCount() const = 0; + virtual u32 getDynamicLightCount() const =0; //! Returns light data which was previously set by IVideoDriver::addDynamicLight(). /** \param idx Zero based index of the light. Must be 0 or greater and smaller than IVideoDriver()::getDynamicLightCount. \return Light data. */ - virtual const SLight& getDynamicLight(u32 idx) const = 0; + virtual const SLight& getDynamicLight(u32 idx) const =0; + + //! Turns a dynamic light on or off + //! \param lightIndex: the index returned by addDynamicLight + //! \param turnOn: true to turn the light on, false to turn it off + virtual void turnLightOn(s32 lightIndex, bool turnOn) =0; //! Gets name of this video driver. /** \return Returns the name of the video driver, e.g. in case of the Direct3D8 driver, it would return "Direct3D 8.1". */ - virtual const wchar_t* getName() const = 0; + virtual const wchar_t* getName() const =0; //! Adds an external image loader to the engine. /** This is useful if the Irrlicht Engine should be able to load @@ -743,7 +810,7 @@ namespace video format. A pointer to the implementation can be passed to the engine using this method. \param loader Pointer to the external loader created. */ - virtual void addExternalImageLoader(IImageLoader* loader) = 0; + virtual void addExternalImageLoader(IImageLoader* loader) =0; //! Adds an external image writer to the engine. /** This is useful if the Irrlicht Engine should be able to @@ -752,13 +819,13 @@ namespace video writing this file format. A pointer to the implementation can be passed to the engine using this method. \param writer: Pointer to the external writer created. */ - virtual void addExternalImageWriter(IImageWriter* writer) = 0; + virtual void addExternalImageWriter(IImageWriter* writer) =0; //! Returns the maximum amount of primitives /** (mostly vertices) which the device is able to render with one drawIndexedTriangleList call. \return Maximum amount of primitives. */ - virtual u32 getMaximalPrimitiveCount() const = 0; + virtual u32 getMaximalPrimitiveCount() const =0; //! Enables or disables a texture creation flag. /** These flags define how textures should be created. By @@ -770,13 +837,13 @@ namespace video \param flag Texture creation flag. \param enabled Specifies if the given flag should be enabled or disabled. */ - virtual void setTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag, bool enabled) = 0; + virtual void setTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag, bool enabled) =0; //! Returns if a texture creation flag is enabled or disabled. /** You can change this value using setTextureCreationMode(). \param flag Texture creation flag. \return The current texture creation mode. */ - virtual bool getTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag) const = 0; + virtual bool getTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag) const =0; //! Creates a software image from a file. /** No hardware texture will be created for this image. This @@ -787,7 +854,7 @@ namespace video \return The created image. If you no longer need the image, you should call IImage::drop(). See IReferenceCounted::drop() for more information. */ - virtual IImage* createImageFromFile(const c8* filename) = 0; + virtual IImage* createImageFromFile(const c8* filename) =0; //! Creates a software image from a file. /** No hardware texture will be created for this image. This @@ -797,7 +864,7 @@ namespace video \return The created image. If you no longer need the image, you should call IImage::drop(). See IReferenceCounted::drop() for more information. */ - virtual IImage* createImageFromFile(io::IReadFile* file) = 0; + virtual IImage* createImageFromFile(io::IReadFile* file) =0; //! Writes the provided image to a file. /** Requires that there is a suitable image writer registered @@ -807,7 +874,18 @@ namespace video \param param Control parameter for the backend (e.g. compression level). \return True on successful write. */ - virtual bool writeImageToFile(IImage* image, const c8* filename, u32 param = 0) = 0; + virtual bool writeImageToFile(IImage* image, const c8* filename, u32 param =0) =0; + + //! Writes the provided image to a file. + /** Requires that there is a suitable image writer registered + for writing the image. + \param image Image to write. + \param file An already open io::IWriteFile object. The name will be used to determine + the appropriate image writer to use. + \param param Control parameter for the backend (e.g. compression + level). + \return True on successful write. */ + virtual bool writeImageToFile(IImage* image, io::IWriteFile* file, u32 param =0) =0; //! Creates a software image from a byte array. /** No hardware texture will be created for this image. This @@ -825,9 +903,9 @@ namespace video If you no longer need the image, you should call IImage::drop(). See IReferenceCounted::drop() for more information. */ virtual IImage* createImageFromData(ECOLOR_FORMAT format, - const core::dimension2d& size, void *data, + const core::dimension2d& size, void *data, bool ownForeignMemory=false, - bool deleteMemory = true) = 0; + bool deleteMemory = true) =0; //! Creates an empty software image. /** @@ -836,7 +914,7 @@ namespace video \return The created image. If you no longer need the image, you should call IImage::drop(). See IReferenceCounted::drop() for more information. */ - virtual IImage* createImage(ECOLOR_FORMAT format, const core::dimension2d& size) =0; + virtual IImage* createImage(ECOLOR_FORMAT format, const core::dimension2d& size) =0; //! Creates a software image by converting it to given format from another image. /** @@ -857,12 +935,12 @@ namespace video See IReferenceCounted::drop() for more information. */ virtual IImage* createImage(IImage* imageToCopy, const core::position2d& pos, - const core::dimension2d& size) =0; + const core::dimension2d& size) =0; //! Event handler for resize events. Only used by the engine internally. /** Used to notify the driver that the window was resized. Usually, there is no need to call this method. */ - virtual void OnResize(const core::dimension2d& size) = 0; + virtual void OnResize(const core::dimension2d& size) =0; //! Adds a new material renderer to the video device. /** Use this method to extend the VideoDriver with new material @@ -885,18 +963,18 @@ namespace video an error occured. For example if you tried to add an material renderer to the software renderer or the null device, which do not accept material renderers. */ - virtual s32 addMaterialRenderer(IMaterialRenderer* renderer, const c8* name = 0) = 0; + virtual s32 addMaterialRenderer(IMaterialRenderer* renderer, const c8* name =0) =0; //! Get access to a material renderer by index. /** \param idx Id of the material renderer. Can be a value of the E_MATERIAL_TYPE enum or a value which was returned by addMaterialRenderer(). \return Pointer to material renderer or null if not existing. */ - virtual IMaterialRenderer* getMaterialRenderer(u32 idx) = 0; + virtual IMaterialRenderer* getMaterialRenderer(u32 idx) =0; //! Get amount of currently available material renderers. /** \return Amount of currently available material renderers. */ - virtual u32 getMaterialRendererCount() const = 0; + virtual u32 getMaterialRendererCount() const =0; //! Get name of a material renderer /** This string can, e.g., be used to test if a specific @@ -908,7 +986,7 @@ namespace video addMaterialRenderer(). \return String with the name of the renderer, or 0 if not exisiting */ - virtual const c8* getMaterialRendererName(u32 idx) const = 0; + virtual const c8* getMaterialRendererName(u32 idx) const =0; //! Sets the name of a material renderer. /** Will have no effect on built-in material renderers. @@ -916,7 +994,7 @@ namespace video E_MATERIAL_TYPE enum or a value which was returned by addMaterialRenderer(). \param name: New name of the material renderer. */ - virtual void setMaterialRendererName(s32 idx, const c8* name) = 0; + virtual void setMaterialRendererName(s32 idx, const c8* name) =0; //! Creates material attributes list from a material /** This method is useful for serialization and more. @@ -926,7 +1004,7 @@ namespace video \param material The material to serialize. \return The io::IAttributes container holding the material properties. */ - virtual io::IAttributes* createAttributesFromMaterial(const video::SMaterial& material) = 0; + virtual io::IAttributes* createAttributesFromMaterial(const video::SMaterial& material) =0; //! Fills an SMaterial structure from attributes. /** Please note that for setting material types of the @@ -935,26 +1013,26 @@ namespace video have been created before calling this method. \param outMaterial The material to set the properties for. \param attributes The attributes to read from. */ - virtual void fillMaterialStructureFromAttributes(video::SMaterial& outMaterial, io::IAttributes* attributes) = 0; + virtual void fillMaterialStructureFromAttributes(video::SMaterial& outMaterial, io::IAttributes* attributes) =0; //! Returns driver and operating system specific data about the IVideoDriver. /** This method should only be used if the engine should be extended without having to modify the source of the engine. \return Collection of device dependent pointers. */ - virtual const SExposedVideoData& getExposedVideoData() = 0; + virtual const SExposedVideoData& getExposedVideoData() =0; //! Get type of video driver /** \return Type of driver. */ - virtual E_DRIVER_TYPE getDriverType() const = 0; + virtual E_DRIVER_TYPE getDriverType() const =0; //! Gets the IGPUProgrammingServices interface. /** \return Pointer to the IGPUProgrammingServices. Returns 0 if the video driver does not support this. For example the Software driver and the Null driver will always return 0. */ - virtual IGPUProgrammingServices* getGPUProgrammingServices() = 0; + virtual IGPUProgrammingServices* getGPUProgrammingServices() =0; //! Returns a pointer to the mesh manipulator. - virtual scene::IMeshManipulator* getMeshManipulator() = 0; + virtual scene::IMeshManipulator* getMeshManipulator() =0; //! Clears the ZBuffer. /** Note that you usually need not to call this method, as it @@ -963,18 +1041,18 @@ namespace video you have to render some special things, you can clear the zbuffer during the rendering process with this method any time. */ - virtual void clearZBuffer() = 0; + virtual void clearZBuffer() =0; //! Make a screenshot of the last rendered frame. /** \return An image created from the last rendered frame. */ - virtual IImage* createScreenShot() = 0; + virtual IImage* createScreenShot() =0; //! Check if the image is already loaded. /** Works similar to getTexture(), but does not load the texture if it is not currently loaded. \param filename Name of the texture. \return Pointer to loaded texture, or 0 if not found. */ - virtual video::ITexture* findTexture(const c8* filename) = 0; + virtual video::ITexture* findTexture(const c8* filename) =0; //! Set or unset a clipping plane. /** There are at least 6 clipping planes available for the user @@ -985,7 +1063,7 @@ namespace video \param enable If true, enable the clipping plane else disable it. \return True if the clipping plane is usable. */ - virtual bool setClipPlane(u32 index, const core::plane3df& plane, bool enable=false) = 0; + virtual bool setClipPlane(u32 index, const core::plane3df& plane, bool enable=false) =0; //! Enable or disable a clipping plane. /** There are at least 6 clipping planes available for the user @@ -994,22 +1072,26 @@ namespace video MaxUserClipPlanes. \param enable If true, enable the clipping plane else disable it. */ - virtual void enableClipPlane(u32 index, bool enable) = 0; + virtual void enableClipPlane(u32 index, bool enable) =0; + + //! Set the minimum number of vertices for which a hw buffer will be created + /** \param count Number of vertices to set as minimum. */ + virtual void setMinHardwareBufferVertexCount(u32 count) =0; //! Returns the graphics card vendor name. - virtual core::stringc getVendorInfo() = 0; + virtual core::stringc getVendorInfo() =0; //! Only used by the engine internally. /** The ambient color is set in the scene manager, see scene::ISceneManager::setAmbientLight(). \param color New color of the ambient light. */ - virtual void setAmbientLight(const SColorf& color) = 0; + virtual void setAmbientLight(const SColorf& color) =0; //! Only used by the engine internally. /** Passes the global material flag AllowZWriteOnTransparent. Use the SceneManager attribute to set this value from your app. \param flag Default behavior is to disable ZWrite, i.e. false. */ - virtual void setAllowZWriteOnTransparent(bool flag) = 0; + virtual void setAllowZWriteOnTransparent(bool flag) =0; }; } // end namespace video @@ -1018,5 +1100,3 @@ namespace video #endif - - diff --git a/include/IVideoModeList.h b/include/IVideoModeList.h index 1e181ccf..57ba857e 100644 --- a/include/IVideoModeList.h +++ b/include/IVideoModeList.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -31,14 +31,14 @@ namespace video //! Get the screen size of a video mode in pixels. /** \param modeNumber: zero based index of the video mode. \return Size of screen in pixels of the specified video mode. */ - virtual core::dimension2d getVideoModeResolution(s32 modeNumber) const = 0; + virtual core::dimension2d getVideoModeResolution(s32 modeNumber) const = 0; //! Get a supported screen size with certain constraints. /** \param minSize: Minimum dimensions required. \param maxSize: Maximum dimensions allowed. \return Size of screen in pixels which matches the requirements. as good as possible. */ - virtual core::dimension2d getVideoModeResolution(const core::dimension2d& minSize, const core::dimension2d& maxSize) const = 0; + virtual core::dimension2d getVideoModeResolution(const core::dimension2d& minSize, const core::dimension2d& maxSize) const = 0; //! Get the pixel depth of a video mode in bits. /** \param modeNumber: zero based index of the video mode. @@ -47,7 +47,7 @@ namespace video //! Get current desktop screen resolution. /** \return Size of screen in pixels of the current desktop video mode. */ - virtual const core::dimension2d& getDesktopResolution() const = 0; + virtual const core::dimension2d& getDesktopResolution() const = 0; //! Get the pixel depth of a video mode in bits. /** \return Size of each pixel of the current desktop video mode in bits. */ diff --git a/include/IVolumeLightSceneNode.h b/include/IVolumeLightSceneNode.h index f3ef5ac0..b9a3a756 100644 --- a/include/IVolumeLightSceneNode.h +++ b/include/IVolumeLightSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // diff --git a/include/IWriteFile.h b/include/IWriteFile.h index aaf182fc..4f1a694b 100644 --- a/include/IWriteFile.h +++ b/include/IWriteFile.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IXMLReader.h b/include/IXMLReader.h index 1058e4b5..d0bec498 100644 --- a/include/IXMLReader.h +++ b/include/IXMLReader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IXMLWriter.h b/include/IXMLWriter.h index 1fc906d2..d75e0fdd 100644 --- a/include/IXMLWriter.h +++ b/include/IXMLWriter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IrrCompileConfig.h b/include/IrrCompileConfig.h index cc075909..c16181cb 100644 --- a/include/IrrCompileConfig.h +++ b/include/IrrCompileConfig.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/IrrlichtDevice.h b/include/IrrlichtDevice.h index 4f7e98c9..ef7bad1d 100644 --- a/include/IrrlichtDevice.h +++ b/include/IrrlichtDevice.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -211,7 +211,7 @@ namespace irr //! Activate any joysticks, and generate events for them. /** Irrlicht contains support for joysticks, but does not generate joystick events by default, as this would consume joystick info that 3rd party libraries might rely on. Call this method to - activate joystick support in Irrlicht and to receive @ref SJoystickEvent events. + activate joystick support in Irrlicht and to receive irr::SJoystickEvent events. \param joystickInfo On return, this will contain an array of each joystick that was found and activated. \return true if joysticks are supported on this device and _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ is defined, false if joysticks are not supported or support is compiled out. diff --git a/include/Keycodes.h b/include/Keycodes.h index 79dbc90c..a8d8bff8 100644 --- a/include/Keycodes.h +++ b/include/Keycodes.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/S3DVertex.h b/include/S3DVertex.h index 15f472cd..86d64fd5 100644 --- a/include/S3DVertex.h +++ b/include/S3DVertex.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/SAnimatedMesh.h b/include/SAnimatedMesh.h index 09e4c9c0..12d191e7 100644 --- a/include/SAnimatedMesh.h +++ b/include/SAnimatedMesh.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/SColor.h b/include/SColor.h index d10255bf..c3c5b9b3 100644 --- a/include/SColor.h +++ b/include/SColor.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/SExposedVideoData.h b/include/SExposedVideoData.h index f38124c4..d90130cb 100644 --- a/include/SExposedVideoData.h +++ b/include/SExposedVideoData.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/SIrrCreationParameters.h b/include/SIrrCreationParameters.h index a24b4d70..9b442a16 100644 --- a/include/SIrrCreationParameters.h +++ b/include/SIrrCreationParameters.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -19,15 +19,17 @@ namespace irr //! Constructs a SIrrlichtCreationParameters structure with default values. SIrrlichtCreationParameters() : DriverType(video::EDT_BURNINGSVIDEO), - WindowSize(core::dimension2d(800, 600)), + WindowSize(core::dimension2d(800, 600)), Bits(16), ZBufferBits(16), Fullscreen(false), Stencilbuffer(false), Vsync(false), - AntiAlias(false), + AntiAlias(0), WithAlphaChannel(false), + Doublebuffer(true), IgnoreInput(false), + Stereobuffer(false), HighPrecisionFPU(false), EventReceiver(0), WindowId(0), @@ -50,7 +52,9 @@ namespace irr Vsync = other.Vsync; AntiAlias = other.AntiAlias; WithAlphaChannel = other.WithAlphaChannel; + Doublebuffer = other.Doublebuffer; IgnoreInput = other.IgnoreInput; + Stereobuffer = other.Stereobuffer; HighPrecisionFPU = other.HighPrecisionFPU; EventReceiver = other.EventReceiver; WindowId = other.WindowId; @@ -65,7 +69,7 @@ namespace irr video::E_DRIVER_TYPE DriverType; //! Size of the window or the video mode in fullscreen mode. Default: 800x600 - core::dimension2d WindowSize; + core::dimension2d WindowSize; //! Minimum Bits per pixel of the color buffer in fullscreen mode. Ignored if windowed mode. Default: 16. u8 Bits; @@ -80,13 +84,14 @@ namespace irr //! Specifies if the stencil buffer should be enabled. /** Set this to true, if you want the engine be able to draw stencil buffer shadows. Note that not all devices are able to - use the stencil buffer. If they don't no shadows will be drawn. + use the stencil buffer, hence it can be ignored during device + creation. Without the stencil buffer no shadows will be drawn. Default: false. */ bool Stencilbuffer; //! Specifies vertical syncronisation. /** If set to true, the driver will wait for the vertical - retrace period, otherwise not. + retrace period, otherwise not. May be silently ignored. Default: false */ bool Vsync; @@ -99,25 +104,49 @@ namespace irr writing a game/application with AntiAlias switched on, it would be a good idea to make it possible to switch this option off again by the user. - This is curently not supported in OpenGL under Windows. - Default value: false */ - bool AntiAlias; + The value is the maximal antialiasing factor requested for + the device. The cretion method will automatically try smaller + values if no window can be created with the diven value. + Value one is usually the same as 0 (disabled), but might be a + special value on some platforms. On D3D devices it maps to + NONMASKABLE. + Default value: 0 - disabled */ + u8 AntiAlias; //! Whether the main framebuffer uses an alpha channel. /** In some situations it might be desireable to get a color buffer with an alpha channel, e.g. when rendering into a transparent window or overlay. If this flag is set the device tries to create a framebuffer with alpha channel. + If this flag is set, only color buffers with alpha channel + are considered. Otherwise, it depends on the actual hardware + if the colorbuffer has an alpha channel or not. Default value: false */ bool WithAlphaChannel; + //! Whether the main framebuffer uses doublebuffering. + /** This should be usually enabled, in order to avoid render + artifacts on the visible framebuffer. However, it might be + useful to use only one buffer on very small devices. If no + doublebuffering is available, the drivers will fall back to + single buffers. Default value: true */ + bool Doublebuffer; + //! Specifies if the device should ignore input events /** This is only relevant when using external I/O handlers. External windows need to take care of this themselves. - Currently only supported under X11. + Currently only supported by X11. Default value: false */ bool IgnoreInput; + //! Specifies if the device should use stereo buffers + /** Some high-end gfx cards support two framebuffers for direct + support of stereoscopic output devices. If this flag is set the + device tries to create a stereo context. + Currently only supported by OpenGL. + Default value: false */ + bool Stereobuffer; + //! Specifies if the device should use high precision FPU setting /** This is only relevant for DirectX Devices, which switch to low FPU precision by default for performance reasons. However, diff --git a/include/SKeyMap.h b/include/SKeyMap.h index d86bbb9b..1836b5c5 100644 --- a/include/SKeyMap.h +++ b/include/SKeyMap.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/SLight.h b/include/SLight.h index 5fcd7651..7a45baae 100644 --- a/include/SLight.h +++ b/include/SLight.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/SMaterial.h b/include/SMaterial.h index 92a851e4..1bcc5e0f 100644 --- a/include/SMaterial.h +++ b/include/SMaterial.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -42,6 +42,46 @@ namespace video EMFN_MODULATE_4X = 4 }; + //! Comparison function, e.g. for depth buffer test + enum E_COMPARISON_FUNC + { + //! Test never succeeds, this equals disable + ECFN_NEVER=0, + //! <= test, default for e.g. depth test + ECFN_LESSEQUAL=1, + //! Exact equality + ECFN_EQUAL=2, + //! exclusive less comparison, i.e. < + ECFN_LESS, + //! Succeeds almost always, except for exact equality + ECFN_NOTEQUAL, + //! >= test + ECFN_GREATEREQUAL, + //! inverse of <= + ECFN_GREATER, + //! test succeeds always + ECFN_ALWAYS + }; + + //! Enum values for enabling/disabling color planes for rendering + enum E_COLOR_PLANE + { + //! No color enabled + ECP_NONE=0, + //! Alpha enabled + ECP_ALPHA=1, + //! Red enabled + ECP_RED=2, + //! Green enabled + ECP_GREEN=4, + //! Blue enabled + ECP_BLUE=8, + //! All colors, no alpha + ECP_RGB=14, + //! All planes enabled + ECP_ALL=15 + }; + //! EMT_ONETEXTURE_BLEND: pack srcFact & dstFact and Modulo to MaterialTypeParam inline f32 pack_texureBlendFunc ( const E_BLEND_FACTOR srcFact, const E_BLEND_FACTOR dstFact, const E_MODULATE_FUNC modulate ) { @@ -58,6 +98,32 @@ namespace video dstFact = E_BLEND_FACTOR ( ( state & 0x000000FF ) ); } + //! These flags are used to specify the anti-aliasing and smoothing modes + /** Techniques supported are multisampling, geometry smoothing, and alpha + to coverage. + Some drivers don't support a per-material setting of the anti-aliasing + modes. In those cases, FSAA/multisampling is defined by the device mode + chosen upon creation via irr::SIrrCreationParameters. + */ + enum E_ANTI_ALIASING_MODE + { + //! Use to turn off anti-aliasing for this material + EAAM_OFF=0, + //! Default anti-aliasing mode + EAAM_SIMPLE=1, + //! High-quality anti-aliasing, not always supported, automatically enables SIMPLE mode + EAAM_QUALITY=3, + //! Line smoothing + EAAM_LINE_SMOOTH=4, + //! point smoothing, often in software and slow, only with OpenGL + EAAM_POINT_SMOOTH=8, + //! All typical anti-alias and smooth modes + EAAM_FULL_BASIC=15, + //! Enhanced anti-aliasing for transparent materials + /** Usually used with EMT_TRANSPARENT_ALPHA_REF and multisampling. */ + EAAM_ALPHA_TO_COVERAGE=16 + }; + //! Maximum number of texture an SMaterial can have. const u32 MATERIAL_MAX_TEXTURES = 4; @@ -72,7 +138,7 @@ namespace video Shininess(0.0f), MaterialTypeParam(0.0f), MaterialTypeParam2(0.0f), Thickness(1.0f), Wireframe(false), PointCloud(false), GouraudShading(true), Lighting(true), ZWriteEnable(true), BackfaceCulling(true), FrontfaceCulling(false), - FogEnable(false), NormalizeNormals(false), ZBuffer(1) + FogEnable(false), NormalizeNormals(false), ZBuffer(ECFN_LESSEQUAL), AntiAliasing(EAAM_SIMPLE|EAAM_LINE_SMOOTH), ColorMask(ECP_ALL) { } //! Copy constructor @@ -118,6 +184,8 @@ namespace video FogEnable = other.FogEnable; NormalizeNormals = other.NormalizeNormals; ZBuffer = other.ZBuffer; + AntiAliasing = other.AntiAliasing; + ColorMask = other.ColorMask; return *this; } @@ -226,7 +294,17 @@ namespace video /** Changed from bool to integer (0 == ZBuffer Off, 1 == ZBuffer LessEqual, 2 == ZBuffer Equal) */ - char ZBuffer; + u8 ZBuffer; + + //! Sets the antialiasing mode + u8 AntiAliasing; + + //! Defines the enabled color planes + /** Values are defined as or'ed values of the E_COLOR_PLANE enum. + Only enabled color planes will be rendered to the current render + target. Typical use is to disable all colors when rendering only to + depth or stencil buffer, or using Red and Green for Stereo rendering. */ + u8 ColorMask; //! Gets the texture transformation matrix for level i /** \param i The desired level. Must not be larger than MATERIAL_MAX_TEXTURES. @@ -313,8 +391,12 @@ namespace video break; case EMF_ANISOTROPIC_FILTER: { - for (u32 i=0; igetParameters()->setAttribute(scene::OBJ_LOADER_IGNORE_GROUPS, true); + \code + SceneManager->getParameters()->setAttribute(scene::OBJ_LOADER_IGNORE_GROUPS, true); \endcode - **/ + **/ const c8* const OBJ_LOADER_IGNORE_GROUPS = "OBJ_IgnoreGroups"; + //! Flag to ignore the b3d file's mipmapping flag + /** Instead Irrlicht's texture creation flag is used. Use it like this: + \code + SceneManager->getParameters()->setAttribute(scene::B3D_LOADER_IGNORE_MIPMAP_FLAG, true); + \endcode + **/ + const c8* const B3D_LOADER_IGNORE_MIPMAP_FLAG = "B3D_IgnoreMipmapFlag"; + + //! Flag set as parameter when the scene manager is used as editor /** In this way special animators like deletion animators can be stopped from deleting scene nodes for example */ diff --git a/include/aabbox3d.h b/include/aabbox3d.h index df27b9c3..19eacc93 100644 --- a/include/aabbox3d.h +++ b/include/aabbox3d.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/coreutil.h b/include/coreutil.h index e3b56c6b..e69bbddd 100644 --- a/include/coreutil.h +++ b/include/coreutil.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/dimension2d.h b/include/dimension2d.h index 360f5cad..4c3c8862 100644 --- a/include/dimension2d.h +++ b/include/dimension2d.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -6,11 +6,14 @@ #define __IRR_DIMENSION2D_H_INCLUDED__ #include "irrTypes.h" +#include "irrMath.h" // for irr::core::equals() namespace irr { namespace core { + template + class vector2d; //! Specifies a 2 dimensional size. template @@ -23,10 +26,18 @@ namespace core dimension2d(const T& width, const T& height) : Width(width), Height(height) {} + dimension2d(const vector2d& other); // Defined in vector2d.h + + //! Use this constructor only where you are sure that the conversion is valid. + template + explicit dimension2d(const dimension2d& other) : + Width((T)other.Width), Height((T)other.Height) { } + //! Equality operator bool operator==(const dimension2d& other) const { - return Width == other.Width && Height == other.Height; + return core::equals(Width, other.Width) && + core::equals(Height, other.Height); } //! Inequality operator @@ -35,6 +46,12 @@ namespace core return ! (*this == other); } + bool operator==(const vector2d& other) const; // Defined in vector2d.h + + bool operator!=(const vector2d& other) const + { + return !(*this == other); + } //! Set to new values dimension2d& set(const T& width, const T& height) @@ -72,14 +89,23 @@ namespace core return dimension2d(Width*scale, Height*scale); } - //! Add two dimensions + //! Add another dimension to this one. dimension2d& operator+=(const dimension2d& other) { - Width *= other.Width; - Height *= other.Height; + Width += other.Width; + Height += other.Height; return *this; } + //! Subtract a dimension from this one + dimension2d& operator-=(const dimension2d& other) + { + Width -= other.Width; + Height -= other.Height; + return *this; + } + + //! Add two dimensions dimension2d operator+(const dimension2d& other) const { @@ -158,9 +184,15 @@ namespace core //! Typedef for an f32 dimension. typedef dimension2d dimension2df; + //! Typedef for an unsigned integer dimension. + typedef dimension2d dimension2du; + //! Typedef for an integer dimension. + /** There are few cases where negative dimensions make sense. Please consider using + dimension2du instead. */ typedef dimension2d dimension2di; + } // end namespace core } // end namespace irr diff --git a/include/fast_atof.h b/include/fast_atof.h index e31af6e3..596a56c5 100644 --- a/include/fast_atof.h +++ b/include/fast_atof.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine" and the "irrXML" project. // For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h diff --git a/include/heapsort.h b/include/heapsort.h index 10bb08d5..9c2b3b7c 100644 --- a/include/heapsort.h +++ b/include/heapsort.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/irrAllocator.h b/include/irrAllocator.h index 9d5b5d4f..b4bb7611 100644 --- a/include/irrAllocator.h +++ b/include/irrAllocator.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine" and the "irrXML" project. // For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h diff --git a/include/irrArray.h b/include/irrArray.h index c4a7185c..4904faaa 100644 --- a/include/irrArray.h +++ b/include/irrArray.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine" and the "irrXML" project. // For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h diff --git a/include/irrList.h b/include/irrList.h index 8c89a024..230273c5 100644 --- a/include/irrList.h +++ b/include/irrList.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/irrMap.h b/include/irrMap.h index b53b1c83..75f7f201 100644 --- a/include/irrMap.h +++ b/include/irrMap.h @@ -1,4 +1,4 @@ -// Copyright 2006-2008 by Kat'Oun +// Copyright (C) 2006-2009 by Kat'Oun // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/irrMath.h b/include/irrMath.h index 7da1c81f..331ad816 100644 --- a/include/irrMath.h +++ b/include/irrMath.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -170,22 +170,41 @@ namespace core return (a + tolerance >= b) && (a - tolerance <= b); } - //! returns if a equals b, taking possible rounding errors into account - inline bool equals(const s32 a, const s32 b, const s32 tolerance = 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); + } + + //! returns if a equals b, taking an explicit rounding tolerance into account + inline bool equals(const s32 a, const s32 b, const s32 tolerance) { return (a + tolerance >= b) && (a - tolerance <= b); } - //! returns if a equals b, taking possible rounding errors into account - inline bool equals(const u32 a, const u32 b, const u32 tolerance = 0) + //! returns if a equals b, taking an explicit rounding tolerance into account + inline bool equals(const u32 a, const u32 b, const u32 tolerance) { return (a + tolerance >= b) && (a - tolerance <= b); } + + //! returns if a equals zero, taking rounding errors into account + inline bool iszero(const f64 a, const f64 tolerance = ROUNDING_ERROR_64) + { + return fabs(a) <= tolerance; + } + //! returns if a equals zero, taking rounding errors into account inline bool iszero(const f32 a, const f32 tolerance = ROUNDING_ERROR_32) { - return fabsf ( a ) <= tolerance; + return fabsf(a) <= tolerance; } //! returns if a equals zero, taking rounding errors into account @@ -200,21 +219,21 @@ namespace core return a <= tolerance; } - inline s32 s32_min ( s32 a, s32 b) + inline s32 s32_min(s32 a, s32 b) { - s32 mask = (a - b) >> 31; + const s32 mask = (a - b) >> 31; return (a & mask) | (b & ~mask); } - inline s32 s32_max ( s32 a, s32 b) + inline s32 s32_max(s32 a, s32 b) { - s32 mask = (a - b) >> 31; + const s32 mask = (a - b) >> 31; return (b & mask) | (a & ~mask); } inline s32 s32_clamp (s32 value, s32 low, s32 high) { - return s32_min (s32_max(value,low), high); + return s32_min(s32_max(value,low), high); } /* diff --git a/include/irrString.h b/include/irrString.h index 26ea4bcb..bf31e817 100644 --- a/include/irrString.h +++ b/include/irrString.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine" and the "irrXML" project. // For conditions of distribution and use, see copyright notice in irrlicht.h and irrXML.h @@ -184,7 +184,7 @@ public: } - //! destructor + //! Destructor ~string() { allocator.deallocate(array); // delete [] array; @@ -748,7 +748,7 @@ public: //! Appends a character to this string - /** \param character: Character to append. */ + /** \param c Character to append. */ string& operator += (T c) { append(c); @@ -757,7 +757,7 @@ public: //! Appends a char string to this string - /** \param other: Char string to append. */ + /** \param c Char string to append. */ string& operator += (const T* const c) { append(c); @@ -766,7 +766,7 @@ public: //! Appends a string to this string - /** \param other: String to append. */ + /** \param other String to append. */ string& operator += (const string& other) { append(other); @@ -774,6 +774,8 @@ public: } + //! Appends a string representation of a number to this string + /** \param i Number to append. */ string& operator += (const int i) { append(string(i)); @@ -781,6 +783,8 @@ public: } + //! Appends a string representation of a number to this string + /** \param i Number to append. */ string& operator += (const unsigned int i) { append(string(i)); @@ -788,6 +792,8 @@ public: } + //! Appends a string representation of a number to this string + /** \param i Number to append. */ string& operator += (const long i) { append(string(i)); @@ -795,6 +801,8 @@ public: } + //! Appends a string representation of a number to this string + /** \param i Number to append. */ string& operator += (const unsigned long& i) { append(string(i)); @@ -802,6 +810,8 @@ public: } + //! Appends a string representation of a number to this string + /** \param i Number to append. */ string& operator += (const double i) { append(string(i)); @@ -809,6 +819,8 @@ public: } + //! Appends a string representation of a number to this string + /** \param i Number to append. */ string& operator += (const float i) { append(string(i)); @@ -816,7 +828,9 @@ public: } - //! replaces all characters of a special type with another one + //! Replaces all characters of a special type with another one + /** \param toReplace Character to replace. + \param replaceWith Character replacing the old one. */ void replace(T toReplace, T replaceWith) { for (u32 i=0; i& trim(const string & whitespace = " \t\n\r") diff --git a/include/irrTypes.h b/include/irrTypes.h index dd76df55..01b31f1a 100644 --- a/include/irrTypes.h +++ b/include/irrTypes.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/irrXML.h b/include/irrXML.h index 3b03b7c9..0cb6700c 100644 --- a/include/irrXML.h +++ b/include/irrXML.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine" and the "irrXML" project. // For conditions of distribution and use, see copyright notice in irrlicht.h and/or irrXML.h @@ -120,7 +120,7 @@ The irrXML license is based on the zlib license. Basicly, this means you can do with irrXML whatever you want: - Copyright (C) 2002-2008 Nikolaus Gebhardt + Copyright (C) 2002-2009 Nikolaus Gebhardt This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages diff --git a/include/irrlicht.h b/include/irrlicht.h index 96a51582..3a4db604 100644 --- a/include/irrlicht.h +++ b/include/irrlicht.h @@ -1,6 +1,6 @@ /* irrlicht.h -- interface of the 'Irrlicht Engine' - Copyright (C) 2002-2008 Nikolaus Gebhardt + Copyright (C) 2002-2009 Nikolaus Gebhardt This software is provided 'as-is', without any express or implied warranty. In no event will the authors be held liable for any damages @@ -150,6 +150,7 @@ #include "IWriteFile.h" #include "IXMLReader.h" #include "IXMLWriter.h" +#include "ILightManager.h" #include "Keycodes.h" #include "line2d.h" #include "line3d.h" @@ -222,7 +223,7 @@ * { * // start up the engine * IrrlichtDevice *device = createDevice(video::EDT_DIRECT3D8, - * core::dimension2d(640,480)); + * core::dimension2d(640,480)); * * video::IVideoDriver* driver = device->getVideoDriver(); * scene::ISceneManager* scenemgr = device->getSceneManager(); @@ -317,7 +318,7 @@ namespace irr IRRLICHT_API IrrlichtDevice* IRRCALLCONV createDevice( video::E_DRIVER_TYPE deviceType = video::EDT_SOFTWARE, // parantheses are necessary for some compilers - const core::dimension2d& windowSize = (core::dimension2d(640,480)), + const core::dimension2d& windowSize = (core::dimension2d(640,480)), u32 bits = 16, bool fullscreen = false, bool stencilbuffer = false, diff --git a/include/line2d.h b/include/line2d.h index 1e1c5b60..e6f6d36e 100644 --- a/include/line2d.h +++ b/include/line2d.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/line3d.h b/include/line3d.h index 6aff4f6f..e4ae5d0a 100644 --- a/include/line3d.h +++ b/include/line3d.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/matrix4.h b/include/matrix4.h index 980ed8b3..a1810063 100644 --- a/include/matrix4.h +++ b/include/matrix4.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -110,6 +110,9 @@ namespace core //! Returns true if the matrix is the identity matrix inline bool isIdentity() const; + //! Returns true if the matrix is orthogonal + inline bool isOrthogonal() const; + //! Returns true if the matrix is the identity matrix bool isIdentity_integer_base () const; @@ -662,10 +665,30 @@ namespace core return *this; } + //! Returns the absolute values of the scales of the matrix. + /** + Note that this always returns the absolute (positive) values. Unfortunately it + does not appear to be possible to extract any original negative values. The best + that we could do would be to arbitrarily make one scale negative if one or three + of them were negative. + FIXME - return the original values. + */ template inline vector3d CMatrix4::getScale() const { - return vector3d(M[0],M[5],M[10]); + // See http://www.robertblum.com/articles/2005/02/14/decomposing-matrices + + // Deal with the 0 rotation case first + // Prior to Irrlicht 1.6, we always returned this value. + if(core::iszero(M[1]) && core::iszero(M[2]) && + core::iszero(M[4]) && core::iszero(M[6]) && + core::iszero(M[8]) && core::iszero(M[9])) + return vector3d(M[0], M[5], M[10]); + + // We have to do the full calculation. + return vector3d(sqrtf(M[0] * M[0] + M[1] * M[1] + M[2] * M[2]), + sqrtf(M[4] * M[4] + M[5] * M[5] + M[6] * M[6]), + sqrtf(M[8] * M[8] + M[9] * M[9] + M[10] * M[10])); } template @@ -818,6 +841,31 @@ namespace core return true; } + + /* Check orthogonality of matrix. */ + template + inline bool CMatrix4::isOrthogonal() const + { + T dp=M[0] * M[4 ] + M[1] * M[5 ] + M[2 ] * M[6 ] + M[3 ] * M[7 ]; + if (!iszero(dp)) + return false; + dp = M[0] * M[8 ] + M[1] * M[9 ] + M[2 ] * M[10] + M[3 ] * M[11]; + if (!iszero(dp)) + return false; + dp = M[0] * M[12] + M[1] * M[13] + M[2 ] * M[14] + M[3 ] * M[15]; + if (!iszero(dp)) + return false; + dp = M[4] * M[8 ] + M[5] * M[9 ] + M[6 ] * M[10] + M[7 ] * M[11]; + if (!iszero(dp)) + return false; + dp = M[4] * M[12] + M[5] * M[13] + M[6 ] * M[14] + M[7 ] * M[15]; + if (!iszero(dp)) + return false; + dp = M[8] * M[12] + M[9] * M[13] + M[10] * M[14] + M[11] * M[15]; + return (iszero(dp)); + } + + /* doesn't solve floating range problems.. but takes care on +/- 0 on translation because we are changing it.. diff --git a/include/plane3d.h b/include/plane3d.h index 2c5aa608..74c03867 100644 --- a/include/plane3d.h +++ b/include/plane3d.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/position2d.h b/include/position2d.h index 6e8ec8b9..d2854c26 100644 --- a/include/position2d.h +++ b/include/position2d.h @@ -1,120 +1,30 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h +//! As of Irrlicht 1.6, position2d is a synonym for vector2d. +/** You should consider position2d to be deprecated, and use vector2d by preference. */ + #ifndef __IRR_POSITION_H_INCLUDED__ #define __IRR_POSITION_H_INCLUDED__ -#include "irrTypes.h" -#include "dimension2d.h" +#include "vector2d.h" namespace irr { namespace core { +// Use typedefs where possible as they are more explicit... - //! Simple class for holding 2d coordinates. - /** Not supposed for doing geometric calculations. - use vector2d instead for things like that. - */ - template - class position2d - { - public: - //! Default constructor for (0,0). - position2d() : X(0), Y(0) {} - position2d(T x, T y) : X(x), Y(y) {} - position2d(const position2d& other) - : X(other.X), Y(other.Y) {} +//! \deprecated position2d is now a synonym for vector2d, but vector2d should be used directly. +typedef vector2d position2df; - bool operator == (const position2d& other) const - { - return X == other.X && Y == other.Y; - } +//! \deprecated position2d is now a synonym for vector2d, but vector2d should be used directly. +typedef vector2d position2di; +}; // namespace core +}; // namespace irr - bool operator != (const position2d& other) const - { - return X != other.X || Y != other.Y; - } - - const position2d& operator+=(const position2d& other) - { - X += other.X; - Y += other.Y; - return *this; - } - - const position2d& operator-=(const position2d& other) - { - X -= other.X; - Y -= other.Y; - return *this; - } - - const position2d& operator+=(const dimension2d& other) - { - X += other.Width; - Y += other.Height; - return *this; - } - - const position2d& operator-=(const dimension2d& other) - { - X -= other.Width; - Y -= other.Height; - return *this; - } - - position2d operator-(const position2d& other) const - { - return position2d(X-other.X, Y-other.Y); - } - - position2d operator+(const position2d& other) const - { - return position2d(X+other.X, Y+other.Y); - } - - position2d operator*(const position2d& other) const - { - return position2d(X*other.X, Y*other.Y); - } - - position2d operator*(const T& scalar) const - { - return position2d(X*scalar, Y*scalar); - } - - position2d operator+(const dimension2d& other) const - { - return position2d(X+other.Width, Y+other.Height); - } - - position2d operator-(const dimension2d& other) const - { - return position2d(X-other.Width, Y-other.Height); - } - - const position2d& operator=(const position2d& other) - { - X = other.X; - Y = other.Y; - return *this; - } - - //! X coordinate of the position. - T X; - //! Y coordinate of the position. - T Y; - }; - - //! Typedef for an f32 position. - typedef position2d position2df; - //! Typedef for an integer position. - typedef position2d position2di; - -} // end namespace core -} // end namespace irr - -#endif +// ...and use a #define to catch the rest, for (e.g.) position2d +#define position2d vector2d +#endif // __IRR_POSITION_H_INCLUDED__ diff --git a/include/quaternion.h b/include/quaternion.h index e4040b63..a4a9e9a3 100644 --- a/include/quaternion.h +++ b/include/quaternion.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -115,7 +115,10 @@ class quaternion quaternion& rotationFromTo(const vector3df& from, const vector3df& to); //! Quaternion elements. - f32 X, Y, Z, W; + f32 X; // vectorial (imaginary) part + f32 Y; + f32 Z; + f32 W; // real part }; diff --git a/include/rect.h b/include/rect.h index 43847c79..bf2ec35d 100644 --- a/include/rect.h +++ b/include/rect.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -252,6 +252,8 @@ namespace core position2d LowerRightCorner; }; + typedef rect rectf; + typedef rect recti; } // end namespace core } // end namespace irr diff --git a/include/triangle3d.h b/include/triangle3d.h index 9559383a..9fcc2535 100644 --- a/include/triangle3d.h +++ b/include/triangle3d.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/include/vector2d.h b/include/vector2d.h index 9f55626a..83a92de5 100644 --- a/include/vector2d.h +++ b/include/vector2d.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -6,6 +6,7 @@ #define __IRR_POINT_2D_H_INCLUDED__ #include "irrMath.h" +#include "dimension2d.h" namespace irr { @@ -14,6 +15,8 @@ namespace core //! 2d vector template class with lots of operators and methods. +/** As of Irrlicht 1.6, this class supercedes position2d, which should + be considered deprecated. */ template class vector2d { @@ -27,21 +30,28 @@ public: //! Copy constructor vector2d(const vector2d& other) : X(other.X), Y(other.Y) {} + vector2d(const dimension2d& other) : X(other.Width), Y(other.Height) {} + // operators vector2d operator-() const { return vector2d(-X, -Y); } vector2d& operator=(const vector2d& other) { X = other.X; Y = other.Y; return *this; } + vector2d& operator=(const dimension2d& other) { X = other.Width; Y = other.Width; return *this; } vector2d operator+(const vector2d& other) const { return vector2d(X + other.X, Y + other.Y); } + vector2d operator+(const dimension2d& other) const { return vector2d(X + other.Width, Y + other.Height); } vector2d& operator+=(const vector2d& other) { X+=other.X; Y+=other.Y; return *this; } vector2d operator+(const T v) const { return vector2d(X + v, Y + v); } vector2d& operator+=(const T v) { X+=v; Y+=v; return *this; } + vector2d& operator+=(const dimension2d& other) { X += other.Width; Y += other.Height; return *this; } vector2d operator-(const vector2d& other) const { return vector2d(X - other.X, Y - other.Y); } + vector2d operator-(const dimension2d& other) const { return vector2d(X - other.Width, Y - other.Height); } vector2d& operator-=(const vector2d& other) { X-=other.X; Y-=other.Y; return *this; } vector2d operator-(const T v) const { return vector2d(X - v, Y - v); } vector2d& operator-=(const T v) { X-=v; Y-=v; return *this; } + vector2d& operator-=(const dimension2d& other) { X -= other.Width; Y -= other.Height; return *this; } vector2d operator*(const vector2d& other) const { return vector2d(X * other.X, Y * other.Y); } vector2d& operator*=(const vector2d& other) { X*=other.X; Y*=other.Y; return *this; } @@ -289,6 +299,13 @@ public: template vector2d operator*(const S scalar, const vector2d& vector) { return vector*scalar; } + // These methods are declared in dimension2d, but need definitions of vector2d + template + dimension2d::dimension2d(const vector2d& other) : Width(other.X), Height(other.Y) { } + + template + bool dimension2d::operator==(const vector2d& other) const { return Width == other.X && Height == other.Y; } + } // end namespace core } // end namespace irr diff --git a/include/vector3d.h b/include/vector3d.h index 1cc026ce..0c501934 100644 --- a/include/vector3d.h +++ b/include/vector3d.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/media/017shot.jpg b/media/017shot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..cbb58ea3cf0a42224d0cb78b4152a178252d53b8 GIT binary patch literal 4704 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 literal 0 HcmV?d00001 diff --git a/media/019shot.jpg b/media/019shot.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8faa915767550acd13b42d845814e86540783b6a GIT binary patch literal 4554 zcmeH}X;4#H8ip@~04kzkQ<1>PriQIq#Gz$rnvjTqG)q7>ZNd^rKqLqPg0$F;1SFb3 zSb~BC2qYj7AV@&46$Ft@maxd?!Y;dP%92TUPxq8H(^J(yrsj`t)wy-g`M&eiciwyI z+{5eVy$1H5L0BLF0RaKP6F>t1?+qYh9_Hr*0M^z33;+O8e&dTb2$%t2kdTlN2+V(g z!C+w#F;Nk|_U+lTOANA4LISc60+E!FJ0K|~D-D4hJaSML3RO^0kUXHMtSGN6C$Av? z3q*iFRYX`sTvSwCUJ4>5|Ch!48Gwii00MB3fFd9W5dc91cn!eeUzY&lFXIn^g#|$( z0z&+t@qR!6Bq%5%3>Fj;68SYjKoBGZ7KTX39MO*{>y(t%wspvnQbc(q>zIBUbe$w( zm(5aA*40A?FY@Qh^6mLmf3N{QNdP3wk7+{qwFrViAdrwC=(jkZ4UyEb4U#xQ64JI) zH1z;WbuOZ>XFpluy#mBQ0{p5$5WoZ=+{9gKyD94WHns^zDeczw>85+;22&(Y`qZht z;{nZ;Z5j*WZF!0V>T`tXXq+_*BK)6sL#*`o43{p+Z3to;X&a9 zmtI5z4*$_LB|2m?tAF=_Uf7cP>Ht&+4>%fruhe~h(W%GD9JL2iz=)wELyxl; z8>Vu0;`&NH7|hhZx+?pM7T^NBaX_%MwSzn?%-+#K+zyp#4-29{Dd_O7$zr(^* zFFf|;w&AVH-8$MriCk=6UO`Ez^P2$6T-?DK--^!8+H)(8<5ZXdGu97RtOlYv`=PpQ zpCQ#B?{4osM?06I7hKkcpY^obO1g;I!?q6SMOa)SXJT~d5y@A+kE^ynGkrcie{q`A zk~+ja@UHl4`YnUo(V&0JR)4^#m+fZbnw71?_jOXH9fO3Rh z%WfmZ%f5_dPHj;}=nlKXC>?)ezdPd)nm7ux%Oew3dOEtD4BD@L2q@K?RkmU#ARO9X>HLMS>_nw&=xiOZaNR1ZG2v| zk<5Vi#}SeXnCYsmTto4|TK8e(1$cA8o7^gcj=~riLdRfe46k-KF2m`h8Yvp1gwkmi zj&kjsFsW;F2yi0!d1P0%#M(o2>M<^0iU%_9u+vc`>JY`YTI1E)96r0zMO2YVCcCMa zLal;|h}V09l&QyxtyZLUFTCUdgBvKT1bX@!76)g2*I{X?HhzqE2Rr}t*qEw8-6!9 zw;nFTife=|sZsQ+rVFxMjrZU8HVi7dP4a!)`~Z%lIAK1X=kAo^KUSgS4 zXH~8e0#B;311{^B1`_GcUS9iIOj2mlGu?Z6wD`%w`!`R*!gQaA?Yu2Q8{gK#dyejY zq?UI=B+AZttlqJzP)$DZr`x#%$Uv=gX1F)mpxAubk*O7v78^<*l_Ln)N+d!RNqM2(B3?F(cT0)LZ`;Y$Ha&pq0{pt?J6Ug64@Oo2B;TY ztdgyQ6qdlYwSN};eB%A~yP5)qM4r2bQTx?gw#}7}6Yw~WrZv11Q8*F$Y}*b-Cn7LC z>vzBYswr%(FE5-P^Q z^j&^qq_5cQ5}YUg+lrtyB9c>(kV0%Fwc)3|lbm$5oUYcPUQEy6zE24Wu_Qa$KeTuZ z*=+_>q=l);j>`4v)0mT)QOO&zn>MyaaA^lti$f#Qaji=m>d-s2RW|#v)3zW!;ca{! z7GqpwG_|}A(=U8FrnmO6St_v9`7JpD)6>mbVNL3~D)=qa6z76N9~zQ^tx~a2nNN35 z>WMQ`nti>$R<)+A1m#E%(A(6@TJN+Ba}U7>^1RIgD$30Q6R$aTSD)@OG6ACyG{qc< zEr%XmJ*i5}guy*&M4uPEzM;vhmLSUG5JYiwx7I=h*NIUaPxDF3YG|7LQ2+d)9#;~g zyOWp8sPdS((m3F+|9tZt*-<%J9b1S(LGX?nFgAYEE96Sup-(4rmXxM^=-K|=Upq_a zGiMR31Lll(WDK>Ki~3DVe_!`M?;Gk|GmVaW&(xk!*gaLlHPUOBv$Pr6z)bbtZn%Aa zAyRh*hkT2C*?NVad#X}P&zMtpdtBb*Rt*n0w4`Bj^-Wfei;0BsjoQVI&Ibwv1vBko zR`~t-{zor;KA9wk-_Ya%jgkMAc<2}4_brc?vLw3Kf3N)1sMxk_=LTs-7dm)=Dn6Ic zCLEaa5t*j5u!U);*j|Xemgu{6`jhy2y$Pb?nsSs_Q|Pma8#U+;rWsQ^wi9B1tvqwN zlxa_YLSQA$NRK2DBbH?1G{I2PnM%eT|_VJ ziDFNPvV}Bi9?!9_H{=22Xiu`8k?LHRtXHaqdp>oNNJ$e4p@geQ+XGlhxA~#<@qnzKR3a6 zi~}2I?fdC8E+CmzIjW?fPT7kJewEmQ8FpH0y{GHa?AB{yT~Gs^_%XWsu~UBEdCtXS z)Cf#Pt4-MG(&*emtYn>Jt-^zvYt;-6mZ>z7o`q#JiFsaJ(*BVLXv+cMpZ0(D8AYwzQk_*=X1xMM4b^rV+GT_xzF_X2vqX-?z?=^of6W|f+W)+-h@3j2`X!gzL zobWZx5!qsK#Px)Sv4uBC_a6kpFWo!O|JVO>OP+aps@Afp{VhXhf-^phNCSiqe-8N1 zy)Rh4FJDaf|C!)ZIyW<5;gg?Vz<5cjcBbD*RUcwz*cv8h7lj5o&zWQ!k5^A{W@l;D z5uVirDmZ9H?^T^gBOAA&(u*Ccv@oqaqZeQisx4s z#pN7@1_d=G6%`dF^;JeqO?~6$?OQjm;4U2<&25IejEoF-85o#Y9%x0FKmywW^CEvCZCK3i|qbYUH1P=_5Vxve|4#-uTTOE|7-6$ z<^N6pPutfRu5&X=J*8wapyILj{vXlHS&G~L`+|XzfkK_)v{h#7u?wC0BiX!85 z6fJj_`b`0u)c<<=yCSMdk2`fj(c=Znnpq`cu!N+3vuuh7-2HF3&gb<5}$X z-`NHBymZ!k=c1y|CZ?il_p^VnS?v4{>Fai%>xVkdPh#f`UgjqfE>B&T`~%~p{X2O6 z^Uu9Xf$vzXRW;%Ofpk(cOJaSluMHgQz8=@iELob7zK+{|I|KyAsZ;7R)d6xP)0~&! zD`dzWg8J>5_aWcj#Tup_{Mg4!V}) z-+pngo(+8JBD){ibH$*1u4Htslv zf;4AdzbfcI_NzYM`SwrJuI>ic)Ee5E!)$!e^5MC&H164xL3v4k5aS-J&}{d*csx9< zQ3}g4DJPj`cBAj$o?FDD?MBuJa^Ak>4U+oOG$AJ;@6l|?V*~nvp?-7tOwbMDYJV>g zf1uB#McfYT=~v>P-jBwN^!9&4as1QPc=?^R_Rl?m_j1IWF`gPsHx60v&TBkvXAm;J zHuE=WsciZ?EBqJROG7sL9#-vNHL75((XSjG;MXmZDpilV@nIjkJEtX{*2`z!*&6WA zyvg+f8avca+av|uAiFQeVy@3LcOVz4{jFI~?Typ>YM_>z4b7`G-dDV5%xO(ySZaI;3xS@ilJnm1PrOB>7NyX`o3XJLy(}0!OO!zdzE`% zwhd{f**L5zuV(KhgF*==6^&>GVr_CZ)Xf4Sn6D>D!(#cEAMpcq$FD)uh65ly84%?H#C3OhAw8EcB4ZoPY4*Z%G7@%7#l>#dY7kZ z+ToOrQtMN#z?h4&^&N>dI0g>XUH{qtrIJqHOW(Qqo|W(~n!>5C?-j~iuGr1H&Agv7exzn2^~Qyi&9lf8=^7E{bxEVQ$# zRn(Dd+<%>V#nU$ga=W6jxQuA5z@8D>;jZpk#Xa zy^ZecY{);FXrhk*hwji)bE{!Xpr)+Hi3aQR!k*24tel@ayZj_~qjM5zA5v>9g;-xw zL~eB{KaHR!X$@fCOH`}kY+vJnF)a;KG zS=~Fft4>ut)@)zw6K!bcj*`C<8h@3f?Q2xbC1taKHyctZXUDwMs@5D(9TcG_H?Dtr z$xb0nCv`hI((S#A5$X9rv1ilajS``z0oJ=n^4l9z%PicAmlXRn_3jZnJnqONR%~NV z>Erj{V)%(;p;l3y*Gtm_LS;NXUCModDW@Kj(gFL7ucYA2{FR`LAEn$Yxz4Bf4}ry> zEL!H$^7dFk#zs?Q+fiUG;(|Fx!ueIVes;PXjyUcpI$i54`2hDuQX1rfD5;p$=Gb z=<<%Hi{hy2@7?ftGHn{eRJeo_JcRy-ZiaTrP><3}XVDi3)zOL(ZWMHtzHkE&W%>S@ zr(;ZO_}8KzHcpxz1G(!dtG^QeQOGCgS$xROU}mG!Dvh9;vmkuLM)tRgIstD?rD+r? zRdLJn7{j(pMvOa8nbSQme|c5{Lf^5TI@4HxWU*s81#*|1$KUxXxh>lrpoO}HzwS>* zZ^dCQF6nOXHEtV;Sl&62!`{4?X;%|*M8}!>NE$}Rp!ZsC*3Pkxrm^MriZc)#n<0@L zjn3$|W))a{aRNX?d!D^Sz?ude%q%^uKXy-_Cs@I-{VnueQDfcQrAv=sTBJ*gJ<^GY z{UrsJIHEMNfKci91>vfc z!}xWY^3P~pNjgdD>%iP^DcCezg5J0yy{ci|5}W)qVyRVwa{k{_%&zVY|6UQ2=CC>Z z??LrG^1mEUUZ#FbN$fZNukCfHz)OmHT=Jbd{SP0%f(;BSukW~Q8U>{~^z>J$iwUHD z{}RGKqhi!7J!}O|z~7!Wao!M>D#O_4Tb=@{%VoRk0K+|+kZUD~uJSwIK{Fh74#+>!uGunuj{!mT| zkt$GHs9Tj>?9Qv}AO9DLm|#Yli8TOGZ)QU51a$*7p82L;Q+^JQA{WKsV!Uhoa=_a4 zvl+g!vpIEv8jwDE65v_EX3{_7x1|I}U+A)T7k zcPP=Ri^Ct7)3fe@iQ>}!H3dJ{5`_7TCivQzP4e#$Z*U~2UsGe5wP9D$Z0;-g;4QKS zeis>-KI+WjCMS*lFwtXBP3$r7ED*>guofBsg$!t3PKzKbC2elx$Trk4U)*YjsNeF% z1vIOG=l^obtiwodIN!$5>j+mKl{C$&XNs#a+MOpzgMs$ars)P-yYfJipM zCf@RW$x^2fuQ=>J+G}r#Xh`ch#$Hmu{WOXu4U&QKz|5lENOK2|!I7~eb`J|c*t_xB zU(_}CKes;0)P6J$60*yvZ~x$<`;q9Ql?t2D9qO+BI?Vb~LGd+FLw5YFOiEhE^Qq+B z8#u|hB%TCbjzfqwoYvH7!lIC``o6M_593!w{wVRU-L;S87pZ&drsX*-v<5;`s#0GL zp7M-S&sPQIMQS4igdVvnNVI<(ko9m0wkehWL(Qlpc z)NizS$ZrTs^WfJ;&6GrERy)C$l&`_}$O-z4zJnRDVUKRY8xFPCFR!%mg zhe>hU9T~k$QM@z0{ev)TR@ivhQ~9K_TCw_9;UIk3tA0tZ7ptQFB0;hVa51yY247`T zMC;#ph(^h;8Sfl*pK$Fbo_XogV#S;Xq1N#+Yu^E&-&W6H9QTchlSMnQtfU1q#M=Fh z@l=pxs%JL`6K8$9f~ktSC*o8lsJ9QIu2bQGAgDX44*;^=JRfSUUQ%qo`pp;RPji_P_(%Koj+au?6T1C~-Gay}8cH&a+bc}G6sOM8nzJEz^JGfn! zAC!3XZ%ekbrAjELsp14YQ8MO-Ff2+j4M??J3ewux7Bhzg8`&8cZPkhPW zV;e*~yasvVWL3O#&U#y|;J(|*EqUsV)rZ{5z66P`Y`vEmS+|i)inh0P?@U7(tpWX6 zFLvqgTu|3HNyWPh>{=msG{1sPH}ISv@DO^&sV_k0NH@VQQ#X%ljg5b>kyf0q~ zKCnGA>l~Ss43~z)(O*k`fbSpB!z2MB^I~#B;!|HMJ9+FKl!Gu90Bg2_rE1J6agZwR zO96UdZDu39*mSJ8&sesH$@ldeRd`+#)JD@p$IX|<+{Gzp4!`~Y1(2+|majWxMciao zN=U$5aom_E*41L)mqc2WvU5Lmc9VrpFy${_QaF_5mh(jhJFI;1E?PU$(EB&5rgA_9 zdaJ29h{9_rYeZfx;6_vZ;QoAwEhS7vXe_?)zaV;t@3H3uZaIU|p^I{KZP`Jhl7=zp zUFMDP5+1l5KA+>ZC1v4WCX=vR?Yh?h%f-$=r}$^emj8L)<#k%O{TW(kvoTe>=6sL!UQyMwzqmve-9nc5)c zmae*#{=fCvN!7uLW#JY=yu&|Ud#q*%iN6$4-Yxsibyfr!Y-~R(fZicZVK}Vdb0p%X z?;lgN*4ToMq4t&=FLwi1Zq|4S3U4( zf#r9D#U;h){JP#N()mry#0!rMoHokzL-Rs}p^e*&jYsDtMe+BVqN2^g#+ah4*gr%c z+gpnV-q1w}adBg%XNyMGXy}h(A$KrFu@fhE&J2~*kBfqHs_otTo>TrNt6)kGz5+_s zoY?n+qMoZL&Y=9VlDfQ^T&Nnn{9r3XA2Oh8)`I#=g1Wv7)i%k%+kAzt^XSp(!R8DW z&F$>)YwsEYY2MW?Lkv5gzzXENLXh43So-8`5q`EqCUbD&V35Ou=t)n>wPY5PR{_A= z=<60j?>VIN-A`y{Q{hjmIIV#- z4~gf&wqgiw@;Vm`h<-Hd4^IFPXv3rtj#>rtRrc7MpLMP9jsP^+SI#@Cq`8x51lQ74 z;W4y6a~;mTy<_?r*F{)EvKtlCvFarT8O8*de@W4#^)q^5?I;dgbA+FFJL_qdVVM|2 z;))pP=V{VBXp<1@<~nr`slkOak=N56RkL)xOs2JT1H>al4^5DQ9O*oQ4{!0uXIl>r z3mZC`vJcAJ9S$e34~Evkju;DHIcu1D{Fl&Ylc!Ic-ge5r9_LiKX_G-CR`(dbviZJ< z*f5hP^K}tRjP%bq=0Yy5XJ7?^E<1a1KLTZo$@Qk2t^7Z7#Use$fD0PNS7od0o#3|@ zleV`y;43?$8yll3>2nPW@iq{h8tsadjUF4|I~!WndV>L*(wyV6us49(9UUK(5W^2u0tm!bZrp#COV+q4CJTpT3&Z6G&((~a^jBU>lxHNndOIim>U;TuZ$ZLZQ;qjX#I1F25A>*m2 z!iKVh=aJ%2k3^1h?4g{n&?wASd{2mzSu;xkuW65XLG%RmgnuVj3~uQA497QYXU#J4D!^>O zjuxeUF0PDIE?I^`9YHct!D(_$CQf}2q;gG4b z$H}d9@w3w%gS|JAaurc}0OADSzFjLPZ7G_YC!h0z*;~%HCN#g~r>}hN`}+l2p3o{y zJrR_fai8iIGut3W*REvHAZy6U#N7;UuY&n9cGuewoTfPlua6xkzH)ynEL`6M`oq7* zf1p_$PGC#;wZ?J3H0XL-D$V=Ai!X)-$f(=SLZNhiK0F3Z&tx2x_EWIcdHnH{(lK5d zSZnot;N1ew>_@)_TXd^*G_Yxyc5_~q29*$tmnB76N)Xn>6#Y2L-s}QaWsTzSx2$zW zs22NB2WPf?-0HnqjmGk?3L`gU%m=D<4FtOL>+i&__wotHTHP~p%A=A(+|iGEN7lq$ zEm4^B81@=^{%GUw+GgJ8LdOs=hxYyRRFkKQU6o?Ag9azEG2Y?V?9B^&Yeo2GOXKtO z%135}7koZU*N8cnGk=(D#Lx|}GH;9(GXhO&K_Ua0Y>OHFD7G60TPsb7X|1gtd&=J>JFN9w z{bL;#n&;+VC9EaJ%H*gdn#s7*M(wh6&XK@PbTe@id>#wKRvNW4Vc+U{iOLt~P6I}s zx<7eBt(EMoAOOq2Pu^2anvdA08Xq*J)?5uA5;1{(Bt9YcI%go|rO{d+P(26l5|Evm zhsQs%J=Zf^@05)evxy0Pnn(ro`nWVz;$gMim7kz_-p$sQX-oV*q+MR)(Zg|z6+UeVE!M~- z*x`>o{re4!hqEzWac|L;=okJkMVJN7YEnzXdxUlB2?#jhZ5X9R5A+C&Y?H3#~PfQ&swg7APDny6-P~tu8?|SAN(gv3%iv zK@EPM=cLD0z0A+m#Ik5{&}9v5ozMjImn~6b#>EIyo!)b?AC4t)wS#h0W0%jxNGBnB^7s^C*Ff%9e zJ1jU$*8nthKQ!A>K}I{S_hNTaLM%Z$DDnCaweW&v2cmR}+slFj7E@YkPW;_6tMOZ);JmWz(70afv!HIo-{fp5G91@CyJMb=6D1N!pBKfgLleXT z{=Fgz8+zlEy~8av5P^?9r^3LbjftctbwAbZ(1QK+^yk0fXYESh3uRMVv8i`wxdwBX zBX==uzG8{G690h-$Y@)A+#H{>G zEF-O}RhPB?=+S4*$42M6zv?n?LpCCz&OSboG5C#pV#5w&*+rq!l-oXVlh%5YBp zlWIT@$vI1fmC2&-$&?0r0~qW%>)bq>!-v12JzDG$`)LD99Hbl_(*}Z0fJp_TW1kCI zTcpa@gAYqz;X`!M0b0O^9u9Gk>i)x58q#H1282~(tk*M z!60-I|Easkz)>nHMVP&QOs*XK7iH+7jZ}nbmfc$&keuN6coP?Im6OuSmYIkTradry z(aGxKA?|B9YFt4_0FwRHM57yXjn-EA9sWL;z-0Gr zULq~gAY_J>D`vGf1c(F-N>__KN1(C9rPOK+WbsC-0Zi44%FxusQ+KDSkx7FY?q z6^F0S3T3(pVHJwTBu`NlRfF(V2=S%#f@LV}VDE<(LsJtC28`k#%B4hUhI zE7KRB?4U6%)|{I=6uqS2d+<9B`WtzMV%2KV)fQHXHJ*y!fDTHfp71>nC*8_r!5IuCUPN^HCfC0N4WH-M{0p zrQjm^3RQWQQpVQ=rXBeTaWqh2Vl@-$)hquStc)Q8(Z|ZQzS{Xtvfd~Tu zE=4ixNuQ2%x8PGRDnzQ0IQayqRA_XZF}rCL!q6vSC&Z?ApWu#KI0=~G1Pr=Qe9z;s z**<4m?``)D{-ZBVPDtmR#zIv*#{*ZGMFs$8as%C-(8S`g2c5<=x);4eU zDukfptJAc3l}N(mtoPTn`gF8;F#?2zxM(keRa1nCmz zgn=Flzb>Gr=?&@%H*sg!#0s64f`WYyXb>mQmrHPMphx*ml<-Do40)wrFR# zVt{BdoRo)Bs||oI3TisTiosO9jw11#UqS9mxS&gl=RR--6=&hbJ%qo&pQjZX8ua>n zeJb!?hQNf{PU^V(1?RM_*w0R}FP<9jWSHJ{q6tuj7-NK3z7m)1rF3b^JZ1p0ay=Z1-1?~*($ z8Lu(5AYjgTt|YLFy|-5|B{_t5571+f1g9k2$94T1XX1BO_C2SUmc(g`)nejv^K#=h zQexnap5xIub;pf0JG5T@dr!Y9xb|ofF!nH?(EDctl@QEv$@tt@78BGW)1Eu7`JKT) z*?jZ2)B=>&ZKsR|WpqLux$y^|wUNVWmB#Mg9(K&tonUQ(6`RhDa|BV`sFK z=CV`!zwIoN$B$%j4YVwsT{61fy;a8TGrEm!y%`_&{RzesDAcLkrhv{&u-09@Dh#Yb z;;1~O;q0HD#bO*@#>>)CqG+(6m|gJsmuM8h4{2!7MI)^!G6gby>Qz|jy)6Aa&L-br zf7d*0h=)v?8cD^M1zhRL2kghpYSUt=|(3Nsd5@--)b+jP>A5!%mW>7EPE{4vd^<0IlneLw3E6UQl3WX6w9w>b| zjK-ZaWHHnF2YB1|BjxIdYL+0zsBi`a_963#QKWII(dN^k-o7-O)wknnqLu{_7riu3 zgKCO0tg;^Xd>F?G$ntXjM}I#@zV(Ekzc2K{6Nc;4FODsSsuoq{Z94W?tF9>pM`H|N zS!u-*V!3QVQ<;_q7EB>O*#nT@3B_!ESz&i^CT|fVMG6s!UYEK-GZ$n-UN_*Z&Nh$s&;D-qbzwv&%QH~j!mfFNS+s?@^UpVM^ z;|M4giQd%&-ZE0rY z+5f4}&1##_z)f(Et^&78U;_-5q+-8?aHstN_xB#iC2Gd+##s>)aANG+f*(6Z7Zqum zLCcQMiygii88FEe8AmI8@_?(xgNKjZ9+vCoAKkj@Qsc^qQRrnZXX?I8=X^fFV4semg^`3zuC#?yso#g8&2&!H@;cZ>VBBUGNLz!dIRu_I5M@a>SFrY;2&cKL&(*&Qz4! zD5^^y`pmIUyOfiQ!b~v#aPxr;K`QlEMxxJ9QylwXuEFfTlEvist&xen9Uq%?EAPMQ zL1GG;rJ!>v#gX&J*C(3znw_<}Tdm}~@v=wx0w}Xz;I&rs_Vx&HnVRaw@SS{uX~%&2 zw)n*18APBqw{&bg1n;iZk=a9k(YdF7lx5S0=^5WtBAw4xG#!HfsIRAwNJ|BoehdE5 zc@<1yiqkiwA@f7Wj22acPFpHfozX$(KAWOO6%ih(mZVRvDujUeUix_AoXof7q59Ld=v z_QMN70j=Hvwqr{z;SH;Ot3Q#XH0;`e42>BmE#pbOxNL=gg4Eg|hC{M8&9}AniS>-=DoHy<07Rogh8 z@_dUhH#@_{@owEIp$HBL;q@PY&XY=4Rjp#1C(hDl|6M=as46iwRx~WY5cvMe@XUK} zW{ZF}rQ$Q_b#4?Y{>W?9@{B^SbY+r~hkuWN6QDDL5OnGd@m5q8yb>lozRN|(K}&;R zZ->k2cCy>tO_=#Io=R#hFuV2s4P{8K`+_jm&W<#% z;AyNyKF%VQOi~(R_w%yojfREq+Y6cRX~MN(R+7q=CU_TJrrl2dUUi=hdt9oWP*3d! z->32T^~C4pc@j}(Xzw@?alEqwtq2f$u7jS?JX85-?f)tJ&e@vdaYE4Zh9}!1mr01bj$uPt(Y6Hh zLcm6t!I)(M@7WNYc^AlC)x#-*ZYcaa9$EzYOwe5$KZ2j8wUDXq9bdqyK&ImG$f{JR)x53NY-DR&?WPt;*f@J-{gT2F)jT&lF-0^a&Gc=aNHuu>4jw42 z4Pj39+Elz~QL@8T;K)U%F9jNW8O^wHFJ207w| ztenqoE<>ctm@RUaVM;C$P#Bcx-PYn15YBrpQ*;#Au4S}b_F@i@{HynpA~j?E?|05n zzYFy{CPB8I{|OTc%E`tZ8%->2a$SdEZHo`BPxN)j6ZTExho#0$XI5xZ5ocj?o{+ zQ`4PWBUDk=BK5nmHUE)qOq>CRg>H-s)}8=+wY;YAP)d3}p-i1GmNWu+R2r>2AGEqn z?2LDJ#xxA-ngKS0UrT$NycuWfb7HfMvNX*m^Y}!;5)^u5t#?A?mDqGd4qvkDe;U|K zIR|T=T`a<%8xfuHM&z&pcfFVY;=1UZ37+}c^O&MlpQ;!U1%bD-&+FhQ6yH>kQHORW;T+WrxV!fruxdWS9M8g!vui*kY~*NfD(xsmI5)62!S72SxuM|XJ^CsDNA@9afR&P{EQLQx}0h;Rh7MA`Fq`PDx zY!FU^H4c&fM{EDrU6kroR*mfKd&C_wk?Vsntffj=K6snTQge}6iZBS?EU)@s<_*r4krIHIUMMg zM=1#}8sZ`Q0j+n>_7U5Mf5$+GqCMz-MEeurbVXXqwk#W5o}(?*~e64DA{g{Okp2-6GbLG1zo=!+RURCPQ_%l(tYQ|9f(oRtSPj97A|f` zKf?+d!?PG}uJ8hbPNGS}kimXR|8RSCDzhWH(EaUzuRZ8RYMBB{b+T;jcoXw`FNX)S z|8%3uk#^(n>CZUTtT1Xu>$fmnLmA|_<;n%y;xlX7 z)CB$j=1i5$e_)G$3d37vN=69j5EJ?VI`6?vv*!PH7*kwo_+S`e0@-^lH;z_BGDXkA zd#AyIJS$nNt>S6Gw@C6grz@OId*v&~WBbM>W_OCMEG~eiQ7+OmKLMPu{7`75%#5(W zdiE^Pw`1HY-WrPp>jjd^u2{WbB&uOW-o z*tSQB3920Y98ek_t^R}$&5itBHpe`&@xVC7vF%2qCSxdLqMk9z`6G-zuxI32!2;DE znxc>YNo6-Xl?fi^QY+AYY0?qSxFIPxQi!8QP+w+@?LCc zhJhS+z~MBaKsIZ+I(I=%_7&-wOm-pM-XCHcpR?m1n^GO%*6dsARi^NgpucVXwMw5< z55oy;?Z!KzX5#v@EF(xq!X8CUqKEPlC||?F3)31{QEFUddsT{?{1hKjS2cru!IS37 z*mv0Y!ylJH4-N=Lf56idimU?Rdjk&p>q+_sr4>+iXB z)^{VRLrwGl9v;yHaaxcN&zqveldT0Dr%cXLW!rRe*4^))^BeDz!e69gmLD{575I2# z7PW?vq}*VU6tpqZJd(X(f_2)l@+l%fO=!hL{)v~I+y?=>TPj?2b*mLKOltTl`U=v_-abwVLSbKR+ z%E{xrpFL5ZPUkNvJWN^-mCp`wB6Y?HL+^USoR7Gb$@DBwgM1xM4XBI{4b~K zfK^o&#qFkIcXe$HEZ!B=t~6ZMY%?hp;kKUcySP8U5M~VFR}!<%Qw~p8%kJz;_j_^p z0x_xGiLSe(_-5Wtt=KiI;L@2pJA6sOHBhD8gz?#&OwsjQ`la6gy)Z*!C}ZmV=3f4d z33==Yac(E+LFjI!bZUUI?z<|Hc8*4~VXvuza{zQJu|o8*1{9HY&LBz?#$V(rEdAU> z<|ErUYGr#6nbTUcBg(GM9qjU7m7YtgnaD|9D8s!2mZz_CGrxVD>XXnX zuGFcoSs>?Ts3ASXi_+bFU4Exx+mKsobkGfp)a)#9^PbnbU#0TS_?Z@`3A)^3PFSo^ zdcb7A>ci2MW1@`w8#a%DRH;_AY^)BN{d7)Z&eGS+oA@Hpk(-NVIBzvX{JOOs)+Er! zRhmAtx0^6j?qVW5vyj#>2C7gTP|B8I?Cp8Z(rNahd(%Y?Q`q>{=fgJYN2Hn#H&>I=Z0Ar0zlCS0iD^FH5PwY*IRLcx z9RVWHEg~DB%7jU9)cVS|JD!cwUwTw1`4t&Q7!0AU3D+ zg`SA7KrY9Vd4E{q^m*!ih&&Z0;7x^Gg36($6(YAL+^WePfgtEVkFnM3 zJFIe)G5g6BeJvSzal&c9_^vGyJIpBdzHtNh?7b4tPl$sxec7Sbv563aoSLxqvMFB* z75=^FHTh@Wde@~)xyw>Ps?1gKmH}*NzFAv-wvksNCLWVgjs4SobDvc7>(oxt>uWUDac7NOuo7&{!=j0AcpiO(=O6}kIS)X+< z_&v4{I=?JR_-Uis5MR^Pf^mfSGD*N4GWfN+p%U*MRzNtYA^25`lxJ9uVk;`6m>fJn zKDs|!LexKz8j36CGCR8vT(R&ot%2q#S{;l$R?Sg}jo8}FMkgp1{~ilPs?k2Kf*E_{ ziP=}>AEuXLU=5}MdvCcGbv~zAKkt3wD8EXUt;xof49nv6e*dnuL9e<87`%*~o6 z4^aoQCN)0BZv8VcAnqIg%Lw&B9%P4h&Jn}sw=?_Z*8IYYH}7u|WGY~ciH82Jq`ah` zIXZ7oTPz5j<)C_hV^CqIDr?dm)iAD$ruO9->(*X4p+n5Ol`R8bcLEahEA1zbK1g;6?x z0<{L;RLW3N?{u$(-9IglCcP-1jA%M@gT~ckumNixg0T^z`(1K4_K`>{a~carWvTER z7-tcwXGGuky8bb^-2%+r+ei~7QNyd*G|@1m_$o5~M^yauoDQx6o4aX<%$n{4N;mbS zKdvISKeH$mc@-kacJM3p+fY(m<LVo5#W1y)BK*{1>Ix%jO{zZ{W|X{iRt0!YlDev)!% z|0aQD#`g^(ZLQgyKNew_TIcpD1#d5s5*c4KYt|wG`3s9m89*5;K_#N4IE_jN&!>kI zLITD>x+)Bu@3ap9YOV z9wt6G!N_v_h(T7MeH?7V$YU~Ml(8TfUcPXB{IAJQY_*&JfI*HHUkr0pc5=P;&j{|D zclm7+y-k*{7b5rVMvgN>uC_Kj+!_8y1-5)9)3{UHly%!y zh)gm?u?zFNuGuIDsi{c^e^6k-$e$m?uYCWG&3LNFFT9u~!xz@MoWLvy_R~^1oYI!i z*lm~50%hNygLQCL2X)#K&l2Xt728yen1J zEo_r*?w!uA#^*oPk>5Kk4Np4FVR=nO7$^fcQ}$29{Nes31ykaV>*;}0&}^sm1j2VW zzGO5uqD5!Zc3?Ia#lBs)mA>0l_Ty$)BFejjE_)jK1ajtNpNI6)Kq_`T7LIR|=%;m=d}XOCL|daE=} zxRtf4;<%nQ{D`x+F@|r?+DJR~KsHC^5RJyaR3yxwKRETCvQglQx-cMqPIJgY=CurZ zHFSyvKE{-$mtx6;VY^>_iHZm74ZVE3p62bXvJ5F9jTf1T;BM{NlD{~hRk?%jL?UgP zD~*LNHle0vY$VNJi|}U~E}$#~FNURh$D#1g)9VRFPFX&Q#1ZW}xS&^NfgBf55BZ7& zGDP)Haa=USx2!*M!E?JJy_|Vlbzt77+7>ACXm(L2Bz|ee2))w7{H>&9zJ-m}mXc_a z;lI|AaAFFkDpVRMrvYTJ|BY`REHp20v;oIYtJRw>H7Be>A?)MU0QwFC6H^c=>;p%> zlLq6)fwf*&16FHT$@=pocjxQD2cWB?860IBjc+wfXn~qEpMx#dDT-nRUp|`a{m_p2 zf=wSQ%h!a*!p-9A5WO#}jne+qO4KVIXioZM$*~k1_;7v7vcA{kM!@&S4vR@Kk@B3d zCrjT~RXUPp;0JN|1a6&8Q%Yh!D5anhHBiPgA$w|~IbN$HUkqKCtHJ5ynPl6K>6i0O zy-q*wt}(Sr9TEe-D4dgZLF=~C%D+?KA7hp&RPmLU9(a+yYNP9lJPwBmU{-jcqT*8U z#2i(%!Rlfz;6S@X@xmFupmw~|{?hNcivGhb1RR0T&T(o40;DPew<6m)Kn6vm*if@E z@&L@@!+3r3-wdXKiDwlryGK*u&Z(@{Xm{rzU7Mm*EAQ#A4P^L{pWW?Q;UFg_LwYHO9qMnSya;!69?$y>5rD-Eu*Xo5ngBOfgW&lvsnF z=Rb#jdnO4Tmi+@(J;bKg+iu$Eed`NBjwm)fj5%tkGq^}hJxIo7b(ArixQr?ze zG}r!C`S&Jvf53PcmYug_Hwk@vNr8NVV)|TxWHSC{sFzDuzT#MHuz_xlA!n@tC2@tF z8s_$f&(E|Dbg#5%lI{$>iuXh@-)S5$F-Vv{F4@^>9={aWuyz%mTkB|})jl1EN0fy! zF@-RqCPsV7cQ;KCtL&~KtgT6uCKw{RhYl!(Yj@(u|4f0Tv-pn~)YZTU$=RqhkNB0r z5`3je;#M0Sw~`4u)^B`Vr1w{o)2G&A3~^$@$alFx@yE6ej2%gg#N`)ND5|K)7L51@ zDfHpy;>HoBsT~uJR>443{D6`fnQh}4qsJKJ;zM#_)Y6Vn{l6FDJ4JkY9_9%+8My#X zy#H>k%h%vpP^zw2Axi^ifKQSTqMu+C0H&IBLjvf548Fp!&^?G;8cuG^6E5(7+Pn6D zrr-a)M4?p95hXbv3vat_7QB1O1xB4W9lniYj)owJ3O{8PbS0< z>z!^b?X+kbXkF-L-plpur#;wwGjT)Fup<)mUU0GhHWi!^5N{!~?Z$1fISiI)vkVS8 z?%hJ$@lCbTFF~Z&>tFX}IXK@Vlu32@rr*|Z3mb2@cBeJFY$}3Du}>_UF}G!>h$Tpv z1#~iGy_P8T$)KRHLD~-QrP~-ObK#n`dS4#vWwM5EokPs4s0+0TB~?-8qQ^G&_rUZ| zC&q@&+O2uI;)@#*YAr{HI(^^Vf5>OFXlpN~K!UAy+3uR|{7l1b4=gs?4Bkk=TSjzT z$j#oE94}e?5XR-bG#D}WTXhq~u~F3w3$VzLb}@+`OhaC3HN59>^^_y_+juQAy~zC| z|CP9`@z|U;?t31BkR5JnBZTN{9M|4{1}|NF#ZIxY2^IF4MRY z_O)TCl*L|}xPln&2rm@ut@ycRSYsha$EZ>{=;4Noot<^c+~;JYD4NHWkMW+$LG*3a z@_5|s$3E8yNyu^Hx21{uQidIu*e#rxBHiiTHsMCOa>Sz8U!2m9n|7~eH`mH7jU=ZC zp5&nFGrh$7SbT20!mPQSHF;Zm(K}S~y`Vle&~pG~D}GsV#?VXh%I8Fuf?h%r$^xPT zE{q|o@jtUrtZ?%R?y{UE4`-`X*V_LW7-~9jd**CT&CA#GABbYo=s0zzU1uS>9We8ZViluLpR&-@-22~n$ppN?I5 z^;Ia2E7XEEPA?+lwuOP%bGvS(!>m6nYZ#nFlksIs(r57`8EZMs^0{t&>W7-}mv4l| zg8ikr4L221CHvLtKJ$x^rvMU_%=OXm?Yq2w;-32VJKbK#BYo~0LtY0fc^If#(@d)4 zjY%Rk=|xwJtViGG85$E<(Cj9sK<}hk47217K$);Lo`(Y^-^b$$NzFi4-XywVXPQNZ ze3+_Dm&aKDdM>E^8!pxeD%%CCBS9W35CW~9=W^)ZDyd976Zx@m20?(7X>!9*v{CO_ z(AsZ}z$F@fPuh_Fmf(RB+L&zm&y@UXAUS9!Z@6(O{z)|=ED_6+x;TYYUOjs>mp~5TmJTMz_-Sr%!$-6?|oU|7*swP z=@>*c664esDH*sgx}VdAFsc1a;7N!B!gg4he?WBT^`9v zBcwHsde3p0_?%okD_5%r9~jsoQ%Sm!-LNR1~-!DmWBD>}%TC4$5}eU74H!J}LVnm?nU>qIIpD^cY3$ zNQz-x+)6M>c!Rx~0ZFx#OT}yAXT>&qi)p>~HyUGr8$*bYLKrLBNse?9;8gDKi(oOE9>8`H<)sPycccpJvl zb@k5Ag27_Jw;3C+rP+fDPbTB#9VTJas=W+T*PTC(d(}ojkppt~l&~%6i0Ed?Rh^^u zxwfu+8R{%f*RWDqOr87)ogCl*8G4X!Q)5GjU0FTNgKd^o8WP!=TJESpJNZUg<*QYN zYxj*H1GCRE=s;@9&0S=5Magf?uE+nyM>b0uiV?9#S0)44RDST?(sb|;v*$wxjbuBJ$*{QS7AG*?tfSN4a1_vDY~c zmKd;am}B*+20yGDZ5)?-qQLiDWw7{Mfy8}PLFqGr^(u}iQ3w0`IbGFU z>5PJMg}9e@Tm)@axeLh&1#>^|*b6sFVq87=@}xkF7BcWHW!4dI3+f%Q4r4XHr-=Q5 z#->{{!JMDY@s|6WLDL3-oIv0VN=XyKp@U)>vF zX_IN$8=A@OW)PgZ5p_BHz-YhEr~%SP&)~c1lzmYGS$PS4UzjFsC#k?59(Jg9x%;=l ztqG&D_VsJu67Ezz+1xWe$ts6Wn-k{F@t1k4h`YRgiK2=?~+3TTK9 zrls+$*;38$39N3n^ZkqNcEIS z8+skw4p@0~@tj1PaapS{IT2y`>UxIh^?(XBqDgfKJyx{Cpykb^ymp(k|G$YC86?Yv|zJQfb2FoO202HDFHT(Jo9Rnz>`0y9PSWYnhGNu|8yP9 zkxQ8u4+HNM`LA?OHtlT06?1H~Gy; zOl$aek~9Jrdwt5G@VOLH)YV-dZG#*cD0J=5kCE=0_(T78N+>$Vc01A%QZ_o-(2`WB zMp@SV!)F%>>`VWHw!}qRo1x6~10$t+musq|1;WzPobyS7VF?$qvL6}Ft4z(a;k4!w zc#96;&i+$r#-l!w&{h1<(kk`P$Hzcu=kWIK*Ulj6hR%}75RKhSL7wyx$ZfPER9<(} z%l=Kbk6e*aQ6R1A@|U+%d?lgn*0bE;Pk-XX%a7?1Np>bSD7kdOk~PNz@F8Z%(TWH~ z$t-OI+UY2|zaihs!hYJQmXXM!a1}(hz7m(Vh`d$E_~>CX(AHMNzQ8;#2)iB9QWH_5 zCA6K-=*|WScAPKuCYedI4QM&wf~+Rh)ihAbaW?XZ3+fJn6FY-Gxh%F2#GbzRUqI6Q z7>t$Tgph>TLm}kBrVkCDt;Mf$hg|LeJ%=}aenYDuO(Z^n@n+)Yi6oY*a)FhYpq-!z z(FuH_Y5KffX3CpUf?}zxch&&!hDsfy236MSgHC?;kGLD~$$FQm^Re`)b3N|(@nt8< z6x;0Ck|+~~oNd=}Mdns^E5pV~;_Iy-Su70FDh5Xx>X+dffWPHRT3V3RDI2YY%iKYe z7ruYyTeBCe&Y@txPHW3d%=soDkPe(4SDvo_=H^vvJ=L&*!m&9m8cIi`@q(Z|AAWP_ zum*E5{CL>Y-(|SySM#LWO*@KQ)8nsYNqlaIQs%XQo3!GesdqrGejxY{NOaN5)ot89 zqD$V{_bQ(7ea^E~u(ArTynYwuNzDiM1Rd}k^ceS43 zN6!#cGvRF$W&Y<^i}MWD2`(Y4>6wJ^0=2EA9FSk)^hIui;M!M0@tkD&h{8BV`$NfL z_N-&=SH$kIqCJcdIf3vGO^$O#w`}ZYS|Ea9yxCmcofkiU68sOheUe{AUEA3jw@Un& zyDW>&oK320&{$s6vKx){crfzlX9$k6)r%z&Fl)vOsw6!Xy;1yv%y#Or%L z!n#75uN`j|O*9EchR_QidH&a!vgT{Pti!4rm%nFvYqoe&Z1Sshc$lN38hG^yOo_;0 zP)ZDS5%W7(wT!VJzhQWf_Vv3g4emJCp~-C*_M)`3lG57QRVgI4(^h8YaHI@N5b32c4zmDFr(~3pp<7%+6ii=s(#W&6sQQu!1e#RXgdiXd+^(vM9ncw>w5np zXM_GLFZ=cOjBXF2d2L?Nf(X_HP0#N?39S0Lf2a|a9a^z?X5laPCUDS*FheKA8x`qYgba>{Pl}kWTghKfi@N0nwfxHMY%91lNg_?EkuQ)_xUi~Q*{I}i0fN8>n$ zQiXKi9`XK$wvEb)+VlI@%f;cPwhC9FVH55L9@$`r@lxu_nSuw_uAgX?28f`gnyyIs z)CqQ_pI~qGok7c@m}gkDlh&I$*S58pU=z|=CBh`rb^4>1mQ zG`|actnp=<{s~kJ!NfVHpk%DV+EIZm;FV8)5jLxByhbZS8a@tU-%8(|Pt=hA81$go z!~owhKQ=D4{KQQS168QFntKZqZdhUbopjl7z6flJp2&8c-W)xVcmt@!CYMA@~u z#Z+kM+qM8(@JY3WAWj&L5QC`PrxI98$_2LVd$M!6% zXT!3(eTn+>oOd%odOO1?7{33W>rL$D`ZHEgS)eJuK((Ow zeu=CH%Z9?a<9<=`d++aBa<7Lz=rBxa8XX7WE{pG0O$H>W#hmFR9=cG7fhZ(+k7Kh8<)`wC2p07;$Cv3H zFQ^U=2<;_Dwf(hPopzJ739CKY1|%qDPJL0U*%>O648lq`RT0yQ0`J#GaTxiLdvqvf z;Fm_U!a%1?^2B8|jJGfk$tC^GI#E6`F5Xd@5alYp0F$^JFlh<#S+Z?cJ(?@3o%;B= zI2(9jFFf(oiCw`6q)- zJ8TBm2JJlAUa*`+=(G|GLCDJD9As<98+}dd=M3?Bds)e?apiD#cK8T%tUIBtP0LXe zh7liIrC4@yJ~{iO?}hGQx}TZukHx{`jt-+&#VDCFYAjwmq%VWgA|0k}dyI%D_*Qyu z$Ih%%kU zl|;UVr-CDG$6u_Olx-sex))kPX9RJbY8#_YOUpa0S4K8o$wgjh93_Qw2GIVXBYeq? z0RtlklC-U*gC~xoR-;o1zY8TMXoW#1|9!e@iACBgJ}6vM_+<6lP^`f@vGTu#3mu4! z(KTtSxEU-CtC1DD{U3TUUaaz>(;jJ6yynh~gR`noI5Fj3-((_owr6-qO1hdImec`5VZU&P( z*=Y`!?HtXMoE0QODp3Vkw>|Nen%T<>Y)dPM9GPqfCp&&YD1=eQFB5F<`|XjS^xz|L znins>rtVTpW))N^R=T98%$8wd;<+ZfG~`_24Z8S(qKL7bNpfr1GT|`kp~5XbR#M$3 z`eY{7LpoS#R^+I!BjR!%sxxR0qf1%X@`OR-UKp-nUJfS*iBue4;qCI!R$r7aCwrpf0y}hxazl+rjla!pWG;X zC=V2d=C+U^P2`z~M323I2JPfWrB)L#qQH-5G2f1gkFxz%Ql_#J?bfVi^e4W6>TG?5 z@_TLD+E6P?l{H=%c`5VfnCz=^88fAx; zF7n_$DUQf3uXs&Xt@P1Cqlol{G-AGt%&Wrz4I}%F;3xZux=?G$#T(y{Mha`3fx7mAP^yLpb}WwkqZKRYYNj{dK#1*SYbt!sGNs1MNE(csV&CP-O?<;xg1ba4I-gT@^SCC zBg}fBO`&>Jk)7qNdYOre{mfS8Y^h*r?!qLxGtaj%&roI?GrLrmqAaV%D)nt6-iPFA zU~~ai?-p{%Xog0+74ziiGCEKZomkiHiDd2NDjhd-P`7~K&b0~mB(NL%wR82cnp`PKv zuU7xQz~%Vr9(b;UHKVRY;SD4WE&==8lH_T@p^WGj@|$6Qadw&Ca!g8d$I*;PF7WG`**5e@t!PQ_Uk>UZ?zk1{yu_2gSI?I#6WUxzA%4ZUEGYG#b&-Sa+v>gDB+QZ42P zvEFGJBN~-jV3C@tIeWjRB~`Y_admg)Rd`CRiz}=1)cy!Aj@Y&NHD1%cQ6LR2?nW7d z`^2@1w1;XBcaQ}id+jYh`D$F93aG!*p3Qx7mXPLrZWKgtZa z^2kv)(ap?m2WjOd48>UN%_Ly`+;eKPwy7u3HeJZx^5X^h_KWtyJRW8iCJp-|%qxx5 z2>0cU)%TM{%hKK}f&s8YtZSN=7Nh=6eQS|Edv}r>GEv4JUyhi%szRSH+*O~P9`~K z#nv1>!HkT2OMlh*N)BCy$iy|BK#f(m@Kw?zAXEIChNz(6yVEa|iM`;~*H?xv*d zZs+2n=U|nhrTAHiFC)0Ppud3L+lNbGB?M1gvWJpwZ+Xd(;|EC6bWacB(xaNn{~jGi ztUjR<3X|M~e+0v)zBh26lrJ9oHg=na{oG~8N6OBEfWkD41>C{@r0)XayCnbX@?CoI zBAgF?EF0@3TeS7~_9t^v38}?uqB={{|Le*K)+c{F{AXbB^{ZOjei>SHN&xwjeq2nl zM0*njPM&Q}9G)aDUWFDH5UfiTSAU{j{Ry`_X_viI8#qUwCPogRp^>KQ%V8&kQj*Qx z%k)iLbA}h|_sO6GVFw2kIEQke?Vt$NYH^<~w&)o^ez58?b@^H~_!%i!Xr=(a0`KX5 zE-`hOesX@+vWK`#@301^4UoFKHYf^5O32^5f|ZJE2EA=rz4g~TBj9@^pL79kHWQ*3 zinH7(U%yLC(TS|(AM z;dM1)Bk0RP3z>^>JH4b}aV(zF`(s76H0K%=PgH}dB}CXiJ<3kocdNQ<1G&=(#a`bt z^3#Mz!DKB;LB*>>QXO_V!4yhyOU|c>V3&+U3JDIBX;m&>Rtkc<48X0qsuC4jFb^lOquQ#+&w0|Ak7%IK^eVRP8E-f|?z0C04~9Sxc_q zB<%w#j`&_VdDxW9OT$q`KQ89n3&-b3zAYV|4w1;0sWVhtL?B*7JWuII?mMIj`UxW% zKtp~4r3o7ursWdrGe(QRE6ta4Ti{=fC$3Zux!va3XIb}MvK*bW^`4Ir9@G?>AHyVf zg^Bf;-Q(kf*B8^89t@REOjzVm(Q-k3h`sgsu0%oV(Kd7l(~yAsI{({2IcWm2`Rz5Y zxcp=zpgiY?XS13tU&!^Sp)-Xc{kRGl&77=8rfnVZF5>+H`Z)H7$EzC#z=znEpS0#bv3skK>n!SUPO0x-kIQbB&qe%GdELwN(In{ zwLT~97DcU(YGM{xUxfE?2!=hEl4$VaS0*N!A#cX*$~x2%Dy8QKCz23 z%P-SSEC;&E#@7hoU%{3$^OXy_KZ6&Cp^VyMSx1DKA)-R(5YZ$(yE95LtGfUxe>f;zo}KRN6UU(x3kugfPVvQ4IZ%Hj(P@dlQ~3> zBHdcrFtb;tiDQ`$+a;yzoS461@vUA3>MV}pjUFeYe0=JZ z1KC=VBdrZX&yT09i4?4a0|T8*Tcv5w<)EK}+`ThcIDrmRs*T&8BXv?1X&Uf3{Zn#;r)(@*uS|L06I*AC&(U58k%F0L# z1@>hVr77V-tL;!8ZPn*eqshpf-*)!$t)Fs-Blhissm~X4Iszw;{oth_>j%T!Xuq|z zk&i1kidK3%!X4LUk{vy4EG>pD;K_$ZOCQ<@j5dJCNJ@_Ug;K&!R!51JP6Xz^P5HD8 zvwKrE#k4Y3x*Jp}JL(1ad23k}=I62El#X*oEPbSC97cVx;%sdcjG9+OTA*ATqI{`; z#87#fjOz{hu5xEE3?I`7H7+sukwadAk)8ohAaw&I?dH4RdwG6bw8Z65X1t5 z_#C~&{@lshP++Sm+fYz_N4@#mHeGG0$@=rKVvkqWJh!>{70g&cCv+9w$T4&v!BqhB zWA2$m=C#bAE&jZcGZWq!nFSqvu1n8VZ&%2fB$3<8`j-c}Anmt-g6#F{6UA+X%2@l} z_YAZbo6B9e>4n2}+?Ii1(>MNm|0tNfo_;JV)?Q9LXc>!0n%GV%L&^+mX|i?czNV0^ z8&xX%5*8ktPe8fa(u~Tzh7k*b{lio4JBia2Y>r?>BabuhuP%1$llKC@yalbR`nR0b9Iv5;U-4#t_nfr> zelKc_6z9#+uC2ZALp7PpFEJL=?tq^GD&%w+-;a&2lS9b6vK+C@Yu295`gx|hc&Vzt z=?$Gk+#8>tmP92XjVP;jynWVIu$Jaq5wAC`%(BvYsw8%H<;BuXzS;|xChy%+0TJdm zkxC$BFI7Ja{S{u5gzX-J{a@+nk;imcrZ$)@8Ny^oq{c}5KyLUt7|GTS6J7( z8&owF+>?V>9-OsIObHHFVklJ7O_DwTP5j#bzH>k$z?Ddl0m-K@J3l|)utWTF=*_}9 zWW(lwDlozUvAVW$jzk10oXmPQF^plTyOBOpe*%gcW+wHw>_%SoX-lJaIZn#7=9eaw zpMZ9cZ&gU-LIYsgIDFK(47*S3#FD=NGY@q;HO6Z_X;6spE-c$HF)`_*Yq*JI3?ZBBpsfo@u ziQE_c?%5b!v{Z|%XeFbB)wk)Ct@S8)cKN(P;!FCp z@U6J`L06iSiDL)ms#Ufc!>8T*J2iV}rp1~^*SfYd=HPwC%41wuSfpb8_eqATa(pw< zVsX&NKbb*Vn)E&I_;jvfa*}4^>r-EWF-d9bgb3P@uzO=kv-|Qjd79U(SFLt`64fUI zW5r`LDIfC&P_OLhhy)zbGNK~tz>_E~bbzk+)>cEc&1Gju&(`83B@?#=+EfSGXC9v_E`^)BEK(@d}=jET;NIdO3Q5&fGc76OOD*1b( ztkTZv*i=lC3T|l)o#pdNRx{a22f53^t6}Ago8@iTa6Dkh*~d>B6`XSx>4U_b88ULl z+vs9)Zx#Le`{c^Q3HqTYMy1e0?JB~=;TL*2)bY`mg8|Kmy~YV)Q0dJW^Vx>Ufye6_ zP+d;qI2C75N(+Fh)ozD$5)q4EeEja36%k4HYZ|gA>4D3KbG}jb_9!yd+V$;taVK)| zS@y<^$?f~)li`@CIV^^LGrL$L-zmFc9P4v+6NS=HgyMsPf_Ck5R4_KJHa5zk+ja+( z&r{ZgHgIAPttmvUFXu433DWnQ5sl^Mbwfjm40U1Ff3CxlL{-&B zwD`8w=?`14ox5<;>3n@t8OKC|g&9S;OyZT#PA}Qj!3&KH$uu&?KlhBMn$x>J4pX1#L+>LpnH~C}jj15>+f9&^L>!pxCS^PWczF)hl(!~5QB za$164Yi3)S!{d8CAQi$L^@s72;y-(>=ydPi?UH5Pb^AffE^|iCSFzFaVR-WBhP>%2 zZEn$h>KUx=akHA3Z;i>FvTks+%9n81}-IR11oOs4ySVMxb>d zqrTcQJ*S(a3uKsGruGY8n!@K}8DsWtTaxXxeSXxStX46hchYpS<|{hs@iJN~eTxqC zzOyB(=d$g*n~Cvd2n1`5GVg#{kHfBfYJ ze|ig4_>lzz39W^5Cyu9OOc*|Q)OnAy^%!_vA`whVHX+0+5FyCn6FF1@qW4y!CwaIr z#@pxB-dV3*kDnQSg<fG1K20b6)YrfnKjchDOX7-up<2m>carXU}b_or`g=C76Xa2?=r(hh1#WiAm@M{ zA5&oySL|OvtY2|Nj>;DjKK#D!QkG~aVvX z8Aqj?$%}0TM)8aygYfirhzhBx!@lJtW*doaoW0m1n24lK!(cNR%?$eNi@%d_#j;37 zA?XhMH^at6tL)8*S<=20!vnTZ+yZHjkI)xVRn)fY{S&5}H*wDz3X5$o+443TWMm;G ziFE-TL|T=jeB!hj=i;Ne$CXAFyBbp9*}^mF4Emw=agGvcjhA2+tgT{IH8>ldp$Yl= zeOwZOVbs1v_Gs}fY-Ix9m+u1kWrC!-*-pMy{slCRY@n5%n}v-$bW=ExOyiGnWNX%O zZR#)yP6FYigTKt=1t4t&)ldRzUc#=0MoVB6kA_d`jH2RS=3LD^>^FU9f- z%1Mf5{tQ{f)z;iT*fN4FqK}4`LVb2By#`3S4T2+971wd_C!1z zwmqdqrZ7}N#V`DQ0(64Rrq#IBa?9_zO?9H;Mq&ECTbioeimiP_!!Y!HpF~>j9A`ch z+t~ZCxA6u(yL6(Q+L!JZAU8ST*3%d{pm3yx$_<*|#GP1lWVU3m?T0vIxO!9|*Sw^P zaKpCW>n^Qr;%b(*t|uCw;$u7r+1f-RQW z6@yI`Mlytj$r(?XVUxVeIo;ncZ(_?cOL`}F=ta#-w2efRy&_BW=d(%4chH;Zs6w-v zJD>oFGvhD__j@Ir)1ItW;=MXP%|TMeZMJM3E#_HPQfW!~JHJvmJxGtuUdgn?hQgB4 zehv+rK5kxSP({l3d3nA7c_sNhA$Hv3Klyp;+_^cVod(6m4ey2F((1&0RX`P>&HG=}}8u-RLaWgit1 zP(<&MWxTsDIwcqmwP`N*bQ)TdA^1#5DB|u`Sa&!XxgMw{ri_#tKwwx^#D#TQljBQB z?ROmtggC;o4OYp{d{p=`m@~(g!PoLXeoe9>TW%=XwxBFv4zguw7bQyfAcL6VQp=<# zJIJ%GiAfL=EU8s+=wkv|yYYkHo0tXfUDa)|^uo;s(t-m%cF&^NiPA~XzS?xCv_;7=;N=a~ORMvp&zKpur4viaG<_MivI|ghg*j-;Aym}V!=5IT zH{ofU0n7%%(rO(9<%5gXdL;ha6s7BD2Pl9^9uJo4f(Dm{@=PH7mLG9M_0}269LwQK z6;v||?P^t_LR+s2K4$a2F$(<&GO@jObBg*5T@&WuAvqnQ08h=hR>4KvqP@3(=Rnph z_Loo&287#d&~_Wt*QJT}j2c5r%THoQb9I=<6BHRMtVclmg~YZH=pdP`$aFSo(#zh_O13PTvq@8Xl;D6@we z!TbVtg0)(I0aiIOWLly6jBKALp*J)jlvkDl8mRAB(GK#s^2015?H793mhm?SUPdj^ zXqMd*-%uoKVY9xOPT?OxBsv2nG5alirKQQ0hP|NnV0ns<+UM5u9@^ts*y33?%bQ>4 z9LLU-SpefIy>NDwHi&@IPizM@K6F>vH5pZ`PoJmjAsX6lD6uRt6x6xf1M{_3Gx0}J z`RYmK*sleL%7Ww(M166yk1Z)wIVP##H>5KWGiL$>N_X|`6vr>y^dwr5I*a)`bHU5V z$0Oy-PQ>OcS;PSMN$FyViJf9I&`W^(cKy-;BqAMM-Nv|L03Yy0{=+8uxx7BEAprek zt$B^|sN+PSXy%QzIrNu%d*04`Sb7U7_Ze(Qd%7F%pfVt<$_ueNt|wfczE~y}NSlCV z!4r*Y0yyY|M-=z<;nCwJqcKu=eA(8`Ea#KS&ZqG>|58%x=A1SrsB_4%b>{uKOW);( zlC0lbJgm)~I*6SZ*vRH8FMm172I6p9`=ZQ+C#RWY*4RNPN?#w)v~3{Tu1WGb9;h3d z_5cY}f6LD4U}2>6gEr(1V)w!I z+g`URz8gh@GU%6qCR-{LOi0N@!9><0hRxaWn!J6Arg;4p1cc2M{tLjoxenueFYo9G zI+En=;vRkOIDVLu(Lc^OAPG*=8woAjK(teuv}DS;@&&0m>N2)Bo{Ic)pxkI`T9lK` zr=#xzLx=c&8VEpi&-%{)w>F(`1Jbn%sY>z?-1)8P&)=(xrKW6N+XiNP!73!u50QJ~ zleM>kAI!eN4#2)sYinz?#W3O%DeJYQc7yS+?!!a$+yf0K%ZElj{=Vg#@RX_MN>578_>rf~&46}jb zm_S{OaSgI8oi(Msk>TY&HWBzRv_5a#^V1gRUnRExy3pP-r@0xQLk>>6RA*uxc|E_o zaPhozVHdfv7wMFxD$7Vwt3Q#}z+;jQdk zbu}`Ai|0vq{RUh`LF=V)F?9PSrgth;L(`{RSzLsp6CIaM^(|w;cTCDySOBaN!Y`!_ zB@7%ax8DWWEk7UgOXuTuzV7dHhL6T+0e^oVVyG(ugD6}+y^{DG`hgQtUlGE~)f)2f zd=akO6|p4JILGwvCg5)MgI3o209!bF$dbqte}vk6mj#UP$g$<>Wu%U~GlKzMa;LH>j6%Sc{moZr|1!;0f(~wc?ax(Yj>n~o^BamyZH8!Ia4aP+*59*%kGRx z-WL+!qmm!|%tSdzK~|M7V=LZr)`QQy?t)e2a~iTem1ARyMll1T zr8rpR-tts48)LoXGD|78?7hX8g|^=bSPj^@{$aYzxug<*D!cYhcJ#3Axvlf(i$v0y zM?}E=-bzg3(aPz7VGp>UL~JzUc?CFJ*bNS)&Q$AZJyjY20QdyEP8;&X2(F*0J$?Kk zA6qoYDOYfrRq9k9^ILaT0GrlD_w}3M(tf=dF0_N!MI^h%(Q@UQ$7nZUV zHj4t0lBWR!B4kXmD9c-E7eIa=Q#q`Q^MTA)W0e<%vJbewsu5qGp|!}^80f=CS!cwb z8Gk0(jJ_<0eV5MsR1X*f(BnB1lWxv#%OnO;PB)$KkYjPPJbxk7<$S4oc}?Wg^Q_x~ z2GPTIBEx!KaxD9CXJD7WOkSztODdVCxZVj20=$&U)YA0z7|(k?u9`(OlIOIo$W^^e z_h`U54wt6|33oU`PTQS2`D#vqdAv-wIM2)jSd1}OVg@k3J!2tf_*{;)$Q%F|5U_a= zQI%^y*?%FcF)=4;3e(9o!X{{cBC9Ya;%upn*^;CH@gMgOukXHHtmWpFy2LyCU2`~Ye z%uh?Di*~0o!=wNJ_oTA=I~M&sts>V9eYyVvuIrs%71v4Ckv{!phcN=iRSC_Hg5tYinDgIRCe+Y1i z<C2DAg8vZcL0oojnqCR0|<+2t;iR@`ewM2wYF1qM$=U4M#=<$9O7 z#1_gSp=VHi2K`RpztW+l(NsoQPG2uSWt?ZofU2{p5_Td0ruViY4+>K6Iz~_GJ!!%! zVKZIDv5bqg0qUQz=br*jNu9!iIq!p+qLA%hr6;>t@F!B>{}5%SUR7H#t6+k}< z0FxYJfYqrbwsc0EswY_mrHU?1xd2nIZHk{KNZ7`ETzYp$?}EDcX%RgD2;jl>!4~!| z!H|JTuW=zSWi*&F+)uAobU#^=0z@(s$IteNMCe4{(PP&$tz|Z4z5l-*S<83X{19+H zx|#(50FK_ZJ3k?p@%5UA6ze6PT9!Umc?W+`GAE0{xfBzYa;*0ydB%FPTu|qAO=nHK zW5ac)=(e=IULI$=)=O2w7_3ErI z7TL9)WzsIPf^S>`2LT?I;vR|XtSEsB|g2gZu37VN+Hn=1~MCTCFl(naL$Ss|{c zsUiSzfKt4xoV1IfXf)uAF{RajSLi9Y_S6pii|#fLKqtnMe)?;w&NV%ew=5zOc1#k? zH~Sfr*qu8s6$v<_XUh}~5L~@p9*0Z^Z(Xd#GPAPVF)haORjP{{y^JYf=@W~Y1gX5_ zizY-fy%1ur0W%xEEsGZ!7v`yWYxZ&>*We0lmE_3DX0LbSK|05c7=p9DXaYBr?Z0H@ zU$XKqS^1Z&{7Y8;B`g1um4C^~zhvbfv+|Ew`NypMV^;n#EB~04f6U51X5}BV@=pf( aCj
The Irrlicht - Engine Documentation © 2003-2008 by Nikolaus Gebhardt. Generated + Engine Documentation © 2003-2009 by Nikolaus Gebhardt. Generated on $datetime by Doxygen ($doxygenversion)
diff --git a/source/Irrlicht/BuiltInFont.h b/source/Irrlicht/BuiltInFont.h index 551d1f8a..9da9d0af 100644 --- a/source/Irrlicht/BuiltInFont.h +++ b/source/Irrlicht/BuiltInFont.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/C3DSMeshFileLoader.cpp b/source/Irrlicht/C3DSMeshFileLoader.cpp index f5fedffc..cd25ec19 100644 --- a/source/Irrlicht/C3DSMeshFileLoader.cpp +++ b/source/Irrlicht/C3DSMeshFileLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/C3DSMeshFileLoader.h b/source/Irrlicht/C3DSMeshFileLoader.h index 478fd838..9add65fb 100644 --- a/source/Irrlicht/C3DSMeshFileLoader.h +++ b/source/Irrlicht/C3DSMeshFileLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CAnimatedMeshMD2.cpp b/source/Irrlicht/CAnimatedMeshMD2.cpp index 0742dcb9..01de7b79 100644 --- a/source/Irrlicht/CAnimatedMeshMD2.cpp +++ b/source/Irrlicht/CAnimatedMeshMD2.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -6,9 +6,7 @@ #ifdef _IRR_COMPILE_WITH_MD2_LOADER_ #include "CAnimatedMeshMD2.h" -#include "os.h" #include "SColor.h" -#include "IReadFile.h" #include "irrMath.h" namespace irr @@ -16,85 +14,8 @@ namespace irr namespace scene { -#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) -# pragma pack( push, packing ) -# pragma pack( 1 ) -# define PACK_STRUCT -#elif defined( __GNUC__ ) -# define PACK_STRUCT __attribute__((packed)) -#else -# error compiler not supported -#endif - - // structs needed to load the md2-format - - const s32 MD2_MAGIC_NUMBER = 844121161; - const s32 MD2_VERSION = 8; - const s32 MD2_MAX_VERTS = 2048; - - // TA: private - const s32 MD2_FRAME_SHIFT = 2; - const f32 MD2_FRAME_SHIFT_RECIPROCAL = 1.f / ( 1 << MD2_FRAME_SHIFT ); - - struct SMD2Header - { - s32 magic; - s32 version; - s32 skinWidth; - s32 skinHeight; - s32 frameSize; - s32 numSkins; - s32 numVertices; - s32 numTexcoords; - s32 numTriangles; - s32 numGlCommands; - s32 numFrames; - s32 offsetSkins; - s32 offsetTexcoords; - s32 offsetTriangles; - s32 offsetFrames; - s32 offsetGlCommands; - s32 offsetEnd; - } PACK_STRUCT; - - struct SMD2Vertex - { - u8 vertex[3]; - u8 lightNormalIndex; - } PACK_STRUCT; - - struct SMD2Frame - { - f32 scale[3]; - f32 translate[3]; - c8 name[16]; - SMD2Vertex vertices[1]; - } PACK_STRUCT; - - struct SMD2Triangle - { - u16 vertexIndices[3]; - u16 textureIndices[3]; - } PACK_STRUCT; - - struct SMD2TextureCoordinate - { - s16 s; - s16 t; - } PACK_STRUCT; - - struct SMD2GLCommand - { - f32 s, t; - s32 vertexIndex; - } PACK_STRUCT; - -// Default alignment -#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) -# pragma pack( pop, packing ) -#endif - -#undef PACK_STRUCT +const s32 MD2_FRAME_SHIFT = 2; +const f32 MD2_FRAME_SHIFT_RECIPROCAL = 1.f / ( 1 << MD2_FRAME_SHIFT ); const s32 Q2_VERTEX_NORMAL_TABLE_SIZE = 162; @@ -299,7 +220,7 @@ static const SMD2AnimationType MD2AnimationTypeList[21] = //! constructor CAnimatedMeshMD2::CAnimatedMeshMD2() -: InterpolationBuffer(0), FrameList(0), FrameCount(0), TriangleCount(0) +: InterpolationBuffer(0), FrameList(0), FrameCount(0) { #ifdef _DEBUG IAnimatedMesh::setDebugName("CAnimatedMeshMD2 IAnimatedMesh"); @@ -317,7 +238,6 @@ CAnimatedMeshMD2::~CAnimatedMeshMD2() InterpolationBuffer->drop(); } - //! returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh. u32 CAnimatedMeshMD2::getFrameCount() const { @@ -342,7 +262,7 @@ IMesh* CAnimatedMeshMD2::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, } -//! returns amount of mesh buffers. +//! returns amount of mesh buffers. MD2 meshes only have one buffer u32 CAnimatedMeshMD2::getMeshBufferCount() const { return 1; @@ -352,7 +272,10 @@ u32 CAnimatedMeshMD2::getMeshBufferCount() const //! returns pointer to a mesh buffer IMeshBuffer* CAnimatedMeshMD2::getMeshBuffer(u32 nr) const { - return InterpolationBuffer; + if (nr == 0) + return InterpolationBuffer; + else + return 0; } @@ -371,6 +294,7 @@ void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop, { u32 firstFrame, secondFrame; f32 div; + core::vector3df* NormalTable = (core::vector3df*)&Q2_VERTEX_NORMAL_TABLE; // TA: resolve missing ipol in loop between end-start @@ -398,16 +322,24 @@ void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop, } video::S3DVertex* target = static_cast(InterpolationBuffer->getVertices()); - video::S3DVertex* first = FrameList[firstFrame].pointer(); - video::S3DVertex* second = FrameList[secondFrame].pointer(); + SMD2Vert* first = FrameList[firstFrame].pointer(); + SMD2Vert* second = FrameList[secondFrame].pointer(); // interpolate both frames const u32 count = FrameList[firstFrame].size(); for (u32 i=0; iPos = (second->Pos - first->Pos) * div + first->Pos; - target->Normal = (second->Normal - first->Normal) * div + first->Normal; + core::vector3df one, two; + one.X = f32(first->Pos.X) * FrameTransforms[firstFrame].scale.X + FrameTransforms[firstFrame].translate.X; + one.Y = f32(first->Pos.Y) * FrameTransforms[firstFrame].scale.Y + FrameTransforms[firstFrame].translate.Y; + one.Z = f32(first->Pos.Z) * FrameTransforms[firstFrame].scale.Z + FrameTransforms[firstFrame].translate.Z; + two.X = f32(second->Pos.X) * FrameTransforms[secondFrame].scale.X + FrameTransforms[secondFrame].translate.X; + two.Y = f32(second->Pos.Y) * FrameTransforms[secondFrame].scale.Y + FrameTransforms[secondFrame].translate.Y; + two.Z = f32(second->Pos.Z) * FrameTransforms[secondFrame].scale.Z + FrameTransforms[secondFrame].translate.Z; + target->Pos = (two - one) * div + one; + target->Normal = (NormalTable[second->NormalIdx] - NormalTable[first->NormalIdx]) * div + + NormalTable[first->NormalIdx]; ++target; ++first; ++second; @@ -418,242 +350,6 @@ void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop, InterpolationBuffer->setDirty(); } - -//! loads an md2 file -bool CAnimatedMeshMD2::loadFile(io::IReadFile* file) -{ - if (!file) - return false; - - SMD2Header header; - - file->read(&header, sizeof(SMD2Header)); - -#ifdef __BIG_ENDIAN__ - header.magic = os::Byteswap::byteswap(header.magic); - header.version = os::Byteswap::byteswap(header.version); - header.skinWidth = os::Byteswap::byteswap(header.skinWidth); - header.skinHeight = os::Byteswap::byteswap(header.skinHeight); - header.frameSize = os::Byteswap::byteswap(header.frameSize); - header.numSkins = os::Byteswap::byteswap(header.numSkins); - header.numVertices = os::Byteswap::byteswap(header.numVertices); - header.numTexcoords = os::Byteswap::byteswap(header.numTexcoords); - header.numTriangles = os::Byteswap::byteswap(header.numTriangles); - header.numGlCommands = os::Byteswap::byteswap(header.numGlCommands); - header.numFrames = os::Byteswap::byteswap(header.numFrames); - header.offsetSkins = os::Byteswap::byteswap(header.offsetSkins); - header.offsetTexcoords = os::Byteswap::byteswap(header.offsetTexcoords); - header.offsetTriangles = os::Byteswap::byteswap(header.offsetTriangles); - header.offsetFrames = os::Byteswap::byteswap(header.offsetFrames); - header.offsetGlCommands = os::Byteswap::byteswap(header.offsetGlCommands); - header.offsetEnd = os::Byteswap::byteswap(header.offsetEnd); -#endif - - if (header.magic != MD2_MAGIC_NUMBER || header.version != MD2_VERSION) - { - os::Printer::log("MD2 Loader: Wrong file header", file->getFileName(), ELL_WARNING); - return false; - } - - // create Memory for indices and frames - - TriangleCount = header.numTriangles; - if (FrameList) - delete [] FrameList; - FrameList = new core::array[header.numFrames]; - FrameCount = header.numFrames; - - s32 i; - - for (i=0; iseek(header.offsetTexcoords); - SMD2TextureCoordinate* textureCoords = new SMD2TextureCoordinate[header.numTexcoords]; - - if (!file->read(textureCoords, sizeof(SMD2TextureCoordinate)*header.numTexcoords)) - { - os::Printer::log("MD2 Loader: Error reading TextureCoords.", file->getFileName(), ELL_ERROR); - return false; - } - -#ifdef __BIG_ENDIAN__ - for (i=0; iseek(header.offsetTriangles); - - SMD2Triangle *triangles = new SMD2Triangle[header.numTriangles]; - if (!file->read(triangles, header.numTriangles *sizeof(SMD2Triangle))) - { - os::Printer::log("MD2 Loader: Error reading triangles.", file->getFileName(), ELL_ERROR); - return false; - } - -#ifdef __BIG_ENDIAN__ - for (i=0; i* vertices = new core::array< core::vector3df >[header.numFrames]; - core::array< core::vector3df >* normals = new core::array< core::vector3df >[header.numFrames]; - - file->seek(header.offsetFrames); - - for (i = 0; iread(frame, header.frameSize); - -#ifdef __BIG_ENDIAN__ - frame->scale[0] = os::Byteswap::byteswap(frame->scale[0]); - frame->scale[1] = os::Byteswap::byteswap(frame->scale[1]); - frame->scale[2] = os::Byteswap::byteswap(frame->scale[2]); - frame->translate[0] = os::Byteswap::byteswap(frame->translate[0]); - frame->translate[1] = os::Byteswap::byteswap(frame->translate[1]); - frame->translate[2] = os::Byteswap::byteswap(frame->translate[2]); -#endif - // store frame data - - SFrameData fdata; - fdata.begin = i; - fdata.end = i; - fdata.fps = 7; - - if (frame->name[0]) - { - for (s32 s = 0; frame->name[s]!=0 && (frame->name[s] < '0' || - frame->name[s] > '9'); ++s) - fdata.name += frame->name[s]; - - if (!FrameData.empty() && FrameData[FrameData.size()-1].name == fdata.name) - ++FrameData[FrameData.size()-1].end; - else - FrameData.push_back(fdata); - } - - // add vertices - - vertices[i].reallocate(header.numVertices); - for (s32 j=0; jvertices[j].vertex[0] * frame->scale[0] + frame->translate[0]; - v.Z = frame->vertices[j].vertex[1] * frame->scale[1] + frame->translate[1]; - v.Y = frame->vertices[j].vertex[2] * frame->scale[2] + frame->translate[2]; - - vertices[i].push_back(v); - - u8 normalidx = frame->vertices[j].lightNormalIndex; - if (normalidx < Q2_VERTEX_NORMAL_TABLE_SIZE) - { - v.X = Q2_VERTEX_NORMAL_TABLE[normalidx][0]; - v.Z = Q2_VERTEX_NORMAL_TABLE[normalidx][1]; - v.Y = Q2_VERTEX_NORMAL_TABLE[normalidx][2]; - } - - normals[i].push_back(v); - } - - // calculate bounding boxes - if (header.numVertices) - { - core::aabbox3d box; - box.reset(vertices[i][0]); - - for (s32 j=1; j& vert = vertices[f]; - - for (s32 t=0; tIndices.reallocate(header.numVertices); - const u32 count = TriangleCount*3; - for (u32 n=0; nIndices.push_back(n); - InterpolationBuffer->Indices.push_back(n+1); - InterpolationBuffer->Indices.push_back(n+2); - } - - // reallocate interpolate buffer - if (header.numFrames) - { - const u32 currCount = FrameList[0].size(); - InterpolationBuffer->Vertices.set_used(currCount); - - for (u32 num=0; numVertices[num].TCoords = FrameList[0].pointer()[num].TCoords; - InterpolationBuffer->Vertices[num].Color = vtx.Color; - } - } - - // clean up - - delete [] normals; - delete [] vertices; - delete [] triangles; - delete [] textureCoords; - - // return - - calculateBoundingBox(); - - return true; -} - - //! calculates the bounding box void CAnimatedMeshMD2::calculateBoundingBox() { @@ -666,8 +362,8 @@ void CAnimatedMeshMD2::calculateBoundingBox() if (defaultFrame>=FrameCount) defaultFrame = 0; - for (u32 j=0; jBoundingBox.addInternalPoint(FrameList[defaultFrame].pointer()[j].Pos); +// for (u32 j=0; jBoundingBox.addInternalPoint(FrameList[defaultFrame].pointer()[j].Pos); } } @@ -736,14 +432,14 @@ void CAnimatedMeshMD2::getFrameLoop(EMD2_ANIMATION_TYPE l, bool CAnimatedMeshMD2::getFrameLoop(const c8* name, s32& outBegin, s32&outEnd, s32& outFPS) const { - for (u32 i=0; i= FrameData.size()) + if ((u32)nr >= AnimationData.size()) return 0; - return FrameData[nr].name.c_str(); + return AnimationData[nr].name.c_str(); } diff --git a/source/Irrlicht/CAnimatedMeshMD2.h b/source/Irrlicht/CAnimatedMeshMD2.h index 9307f45c..8b552b51 100644 --- a/source/Irrlicht/CAnimatedMeshMD2.h +++ b/source/Irrlicht/CAnimatedMeshMD2.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -28,9 +28,6 @@ namespace scene //! destructor virtual ~CAnimatedMeshMD2(); - //! loads an md2 file - virtual bool loadFile(io::IReadFile* file); - //! returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh. virtual u32 getFrameCount() const; @@ -82,19 +79,16 @@ namespace scene //! \param nr: Zero based index of animation. virtual const c8* getAnimationName(s32 nr) const; - private: - //! updates the interpolation buffer - void updateInterpolationBuffer(s32 frame, s32 startFrame, s32 endFrame); - - //! calculates the bounding box - virtual void calculateBoundingBox(); + // + // exposed for loader + // + //! the buffer that contains the most recent animation SMeshBuffer* InterpolationBuffer; - core::array *FrameList; - core::array > BoxList; - struct SFrameData + //! named animations + struct SAnimationData { core::stringc name; s32 begin; @@ -102,10 +96,44 @@ namespace scene s32 fps; }; - core::array< SFrameData > FrameData; + //! scale and translations for keyframes + struct SKeyFrameTransform + { + core::vector3df scale; + core::vector3df translate; + }; + + //! md2 vertex data + struct SMD2Vert + { + core::vector3d Pos; + u8 NormalIdx; + }; + + //! keyframe transformations + core::array FrameTransforms; + + //! keyframe vertex data + core::array *FrameList; + + //! bounding boxes for each keyframe + core::array > BoxList; + + //! named animations + core::array< SAnimationData > AnimationData; + + //! calculates the bounding box + virtual void calculateBoundingBox(); u32 FrameCount; s32 TriangleCount; + + private: + + //! updates the interpolation buffer + void updateInterpolationBuffer(s32 frame, s32 startFrame, s32 endFrame); + + }; } // end namespace scene diff --git a/source/Irrlicht/CAnimatedMeshMD3.cpp b/source/Irrlicht/CAnimatedMeshMD3.cpp index 27e1045a..28391fb1 100644 --- a/source/Irrlicht/CAnimatedMeshMD3.cpp +++ b/source/Irrlicht/CAnimatedMeshMD3.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Fabio Concas / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Fabio Concas / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CAnimatedMeshMD3.h b/source/Irrlicht/CAnimatedMeshMD3.h index cafafb75..c5c84456 100644 --- a/source/Irrlicht/CAnimatedMeshMD3.h +++ b/source/Irrlicht/CAnimatedMeshMD3.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CAnimatedMeshSceneNode.cpp b/source/Irrlicht/CAnimatedMeshSceneNode.cpp index a818a554..6e3d2e31 100644 --- a/source/Irrlicht/CAnimatedMeshSceneNode.cpp +++ b/source/Irrlicht/CAnimatedMeshSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -32,9 +32,8 @@ CAnimatedMeshSceneNode::CAnimatedMeshSceneNode(IAnimatedMesh* mesh, const core::vector3df& rotation, const core::vector3df& scale) : IAnimatedMeshSceneNode(parent, mgr, id, position, rotation, scale), Mesh(0), - MeshForCurrentFrame(0), BeginFrameTime(0), StartFrame(0), EndFrame(0), FramesPerSecond(0.f), - CurrentFrameNr(0.f), FrameWhenCurrentMeshWasGenerated(0.f), + CurrentFrameNr(0.f), JointMode(EJUOR_NONE), JointsUsed(false), TransitionTime(0), Transiting(0.f), TransitingBlend(0.f), Looping(true), ReadOnlyMaterials(false), RenderFromIdentity(0), @@ -205,8 +204,7 @@ IMesh * CAnimatedMeshSceneNode::getMeshForCurrentFrame(void) { if(Mesh->getMeshType() != EAMT_SKINNED) { - if(!MeshForCurrentFrame || !core::equals(CurrentFrameNr, FrameWhenCurrentMeshWasGenerated)) - MeshForCurrentFrame = Mesh->getMesh((s32)getFrameNr(), 255, StartFrame, EndFrame); + return Mesh->getMesh((s32)getFrameNr(), 255, StartFrame, EndFrame); } else { @@ -241,11 +239,8 @@ IMesh * CAnimatedMeshSceneNode::getMeshForCurrentFrame(void) skinnedMesh->updateBoundingBox(); } - MeshForCurrentFrame = skinnedMesh; + return skinnedMesh; } - - FrameWhenCurrentMeshWasGenerated = CurrentFrameNr; - return MeshForCurrentFrame; } @@ -399,7 +394,7 @@ void CAnimatedMeshSceneNode::render() driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); } - debug_mat.ZBuffer = false; + debug_mat.ZBuffer = video::ECFN_NEVER; debug_mat.Lighting = false; driver->setMaterial(debug_mat); @@ -481,7 +476,7 @@ void CAnimatedMeshSceneNode::render() { debug_mat.Lighting = false; debug_mat.Wireframe = true; - debug_mat.ZBuffer = true; + debug_mat.ZBuffer = video::ECFN_NEVER; driver->setMaterial(debug_mat); for (u32 g=0; ggetMeshBufferCount(); ++g) @@ -822,9 +817,6 @@ void CAnimatedMeshSceneNode::setMesh(IAnimatedMesh* mesh) Mesh = mesh; - // Forget about the stored frame of any existing mesh. - MeshForCurrentFrame = 0; - // get materials and bounding box Box = Mesh->getBoundingBox(); diff --git a/source/Irrlicht/CAnimatedMeshSceneNode.h b/source/Irrlicht/CAnimatedMeshSceneNode.h index efb67f7e..3d4e864d 100644 --- a/source/Irrlicht/CAnimatedMeshSceneNode.h +++ b/source/Irrlicht/CAnimatedMeshSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -171,14 +171,12 @@ namespace scene core::array Materials; core::aabbox3d Box; IAnimatedMesh* Mesh; - IMesh* MeshForCurrentFrame; u32 BeginFrameTime; s32 StartFrame; s32 EndFrame; f32 FramesPerSecond; f32 CurrentFrameNr; - f32 FrameWhenCurrentMeshWasGenerated; //0-unused, 1-get joints only, 2-set joints only, 3-move and set E_JOINT_UPDATE_ON_RENDER JointMode; diff --git a/source/Irrlicht/CAttributeImpl.h b/source/Irrlicht/CAttributeImpl.h index 9654e83e..37b477af 100644 --- a/source/Irrlicht/CAttributeImpl.h +++ b/source/Irrlicht/CAttributeImpl.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -186,7 +186,7 @@ public: Value = core::fast_atof(text); } - virtual E_ATTRIBUTE_TYPE getType() const + virtual E_ATTRIBUTE_TYPE getType() const { return EAT_FLOAT; } @@ -212,7 +212,7 @@ class CNumbersAttribute : public IAttribute { public: - CNumbersAttribute(const char* name, video::SColorf value) : + CNumbersAttribute(const char* name, video::SColorf value) : ValueI(), ValueF(), Count(4), IsFloat(true) { Name = name; @@ -233,7 +233,7 @@ public: } - CNumbersAttribute(const char* name, core::vector3df value) : + CNumbersAttribute(const char* name, core::vector3df value) : ValueI(), ValueF(), Count(3), IsFloat(true) { Name = name; @@ -242,23 +242,7 @@ public: ValueF.push_back(value.Z); } - CNumbersAttribute(const char* name, core::position2df value) : - ValueI(), ValueF(), Count(2), IsFloat(true) - { - Name = name; - ValueF.push_back(value.X); - ValueF.push_back(value.Y); - } - - CNumbersAttribute(const char* name, core::position2di value) : - ValueI(), ValueF(), Count(2), IsFloat(false) - { - Name = name; - ValueI.push_back(value.X); - ValueI.push_back(value.Y); - } - - CNumbersAttribute(const char* name, core::rect value) : + CNumbersAttribute(const char* name, core::rect value) : ValueI(), ValueF(), Count(4), IsFloat(false) { Name = name; @@ -268,7 +252,7 @@ public: ValueI.push_back(value.LowerRightCorner.Y); } - CNumbersAttribute(const char* name, core::rect value) : + CNumbersAttribute(const char* name, core::rect value) : ValueI(), ValueF(), Count(4), IsFloat(true) { Name = name; @@ -278,7 +262,7 @@ public: ValueF.push_back(value.LowerRightCorner.Y); } - CNumbersAttribute(const char* name, core::matrix4 value) : + CNumbersAttribute(const char* name, core::matrix4 value) : ValueI(), ValueF(), Count(16), IsFloat(true) { Name = name; @@ -287,7 +271,7 @@ public: ValueF.push_back(value(r,c)); } - CNumbersAttribute(const char* name, core::quaternion value) : + CNumbersAttribute(const char* name, core::quaternion value) : ValueI(), ValueF(), Count(4), IsFloat(true) { Name = name; @@ -297,7 +281,7 @@ public: ValueF.push_back(value.W); } - CNumbersAttribute(const char* name, core::aabbox3d value) : + CNumbersAttribute(const char* name, core::aabbox3d value) : ValueI(), ValueF(), Count(6), IsFloat(true) { Name = name; @@ -309,7 +293,7 @@ public: ValueF.push_back(value.MaxEdge.Z); } - CNumbersAttribute(const char* name, core::plane3df value) : + CNumbersAttribute(const char* name, core::plane3df value) : ValueI(), ValueF(), Count(4), IsFloat(true) { Name = name; @@ -319,7 +303,7 @@ public: ValueF.push_back(value.D); } - CNumbersAttribute(const char* name, core::triangle3df value) : + CNumbersAttribute(const char* name, core::triangle3df value) : ValueI(), ValueF(), Count(9), IsFloat(true) { Name = name; @@ -334,7 +318,7 @@ public: ValueF.push_back(value.pointC.Z); } - CNumbersAttribute(const char* name, core::vector2df value) : + CNumbersAttribute(const char* name, core::vector2df value) : ValueI(), ValueF(), Count(2), IsFloat(true) { Name = name; @@ -342,7 +326,7 @@ public: ValueF.push_back(value.Y); } - CNumbersAttribute(const char* name, core::vector2di value) : + CNumbersAttribute(const char* name, core::vector2di value) : ValueI(), ValueF(), Count(2), IsFloat(false) { Name = name; @@ -350,7 +334,7 @@ public: ValueI.push_back(value.Y); } - CNumbersAttribute(const char* name, core::line2di value) : + CNumbersAttribute(const char* name, core::line2di value) : ValueI(), ValueF(), Count(4), IsFloat(false) { Name = name; @@ -360,7 +344,7 @@ public: ValueI.push_back(value.end.Y); } - CNumbersAttribute(const char* name, core::line2df value) : + CNumbersAttribute(const char* name, core::line2df value) : ValueI(), ValueF(), Count(4), IsFloat(true) { Name = name; @@ -370,7 +354,7 @@ public: ValueF.push_back(value.end.Y); } - CNumbersAttribute(const char* name, core::line3df value) : + CNumbersAttribute(const char* name, core::line3df value) : ValueI(), ValueF(), Count(6), IsFloat(true) { Name = name; @@ -382,7 +366,7 @@ public: ValueF.push_back(value.end.Z); } - CNumbersAttribute(const char* name, core::dimension2di value) : + CNumbersAttribute(const char* name, core::dimension2du value) : ValueI(), ValueF(), Count(2), IsFloat(false) { Name = name; @@ -391,7 +375,7 @@ public: } - CNumbersAttribute(const char* name, core::dimension2df value) : + CNumbersAttribute(const char* name, core::dimension2df value) : ValueI(), ValueF(), Count(2), IsFloat(true) { Name = name; @@ -400,7 +384,7 @@ public: } - + // getting values virtual s32 getInt() { @@ -415,20 +399,20 @@ public: virtual f32 getFloat() { - if (Count==0) + if (Count==0) return 0.0f; if (IsFloat) return ValueF[0]; else - return (f32)ValueI[0]; + return (f32)ValueI[0]; } virtual bool getBool() { // return true if any number is nonzero bool ret=false; - + for (u32 i=0; i < Count; ++i) if ( IsFloat ? (ValueF[i] != 0) : (ValueI[i] != 0) ) { @@ -437,14 +421,14 @@ public: } return ret; - + } virtual core::stringc getString() { core::stringc outstr; - + for (u32 i=0; i c+r*4) + if (Count > c+r*4) ret(r,c) = ValueF[c+r*4]; } else { for (u32 r=0; r<4; ++r) for (u32 c=0; c<4; ++c) - if (Count > c+r*4) + if (Count > c+r*4) ret(r,c) = (f32)ValueI[c+r*4]; } return ret; @@ -747,7 +731,7 @@ public: return ValueI; } - + // setting values virtual void setInt(s32 intValue) { @@ -804,14 +788,14 @@ public: f32 c = 0; P = core::fast_atof_move(P, c); ValueI[i] = (s32)c; - + } } } // todo: warning message //if (i < Count-1) //{ - // + // //} } @@ -912,14 +896,14 @@ public: { for (u32 r=0; r<4; ++r) for (u32 c=0; c<4; ++c) - if (Count > c+r*4) + if (Count > c+r*4) ValueF[c+r*4] = value(r,c); } else { for (u32 r=0; r<4; ++r) for (u32 c=0; c<4; ++c) - if (Count > c+r*4) + if (Count > c+r*4) ValueI[c+r*4] = (s32)value(r,c); } } @@ -1082,7 +1066,7 @@ public: } } - virtual void setDimension2d(core::dimension2di v) + virtual void setDimension2d(core::dimension2du v) { reset(); if (IsFloat) @@ -1205,7 +1189,7 @@ public: setInt((s32)floatValue); } - virtual E_ATTRIBUTE_TYPE getType() const + virtual E_ATTRIBUTE_TYPE getType() const { return EAT_COLORF; } @@ -1488,9 +1472,9 @@ public: // vector2df -// dimension2di +// dimension2du -/* +/* Special attributes */ @@ -1607,7 +1591,7 @@ public: Name = name; setString(value); } - + CStringAttribute(const char* name, const wchar_t* value) { IsStringW = true; @@ -1626,7 +1610,7 @@ public: { if (IsStringW) return atoi(core::stringc(ValueW.c_str()).c_str()); - else + else return atoi(Value.c_str()); } @@ -1940,22 +1924,22 @@ public: Value = value; } - virtual s32 getInt() - { + virtual s32 getInt() + { return *(s32*)(&Value); } virtual bool getBool() - { + { return (Value != 0); } - virtual void getString(char* target) + virtual void getString(char* target) { sprintf(target, "0x%x", *(int*)(&Value)); } - virtual void setString(const char* text) + virtual void setString(const char* text) { sscanf(text, "0x%x", (unsigned int*)(&Value)); } @@ -1975,7 +1959,7 @@ public: return Value; } - + virtual const wchar_t* getTypeString() const { return L"userPointer"; diff --git a/source/Irrlicht/CAttributes.cpp b/source/Irrlicht/CAttributes.cpp index 21443ef8..62cb9d3b 100644 --- a/source/Irrlicht/CAttributes.cpp +++ b/source/Irrlicht/CAttributes.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CAttributes.h b/source/Irrlicht/CAttributes.h index c001a88b..c08d1ee2 100644 --- a/source/Irrlicht/CAttributes.h +++ b/source/Irrlicht/CAttributes.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -30,7 +30,7 @@ public: //! Returns amount of attributes in this collection of attributes. virtual u32 getAttributeCount() const; - //! Returns attribute name by index. + //! Returns attribute name by index. //! \param index: Index value, must be between 0 and getAttributeCount()-1. virtual const c8* getAttributeName(s32 index); @@ -38,7 +38,7 @@ public: //! \param attributeName: Name for the attribute virtual E_ATTRIBUTE_TYPE getAttributeType(const c8* attributeName); - //! Returns attribute type by index. + //! Returns attribute type by index. //! \param index: Index value, must be between 0 and getAttributeCount()-1. virtual E_ATTRIBUTE_TYPE getAttributeType(s32 index); @@ -46,7 +46,7 @@ public: //! \param attributeName: String for the attribute type virtual const wchar_t* getAttributeTypeString(const c8* attributeName); - //! Returns the type string of the attribute by index. + //! Returns the type string of the attribute by index. //! \param index: Index value, must be between 0 and getAttributeCount()-1. virtual const wchar_t* getAttributeTypeString(s32 index); @@ -126,14 +126,14 @@ public: //! Adds an attribute as string virtual void addString(const c8* attributeName, const c8* value); - //! Sets an attribute value as string. + //! Sets an attribute value as string. //! \param attributeName: Name for the attribute //! \param value: Value for the attribute. Set this to 0 to delete the attribute virtual void setAttribute(const c8* attributeName, const c8* value); //! Gets an attribute as string. //! \param attributeName: Name of the attribute to get. - //! \return Returns value of the attribute previously set by setAttribute() + //! \return Returns value of the attribute previously set by setAttribute() //! or 0 if attribute is not set. virtual core::stringc getAttributeAsString(const c8* attributeName); @@ -142,11 +142,11 @@ public: //! \param target: Buffer where the string is copied to. virtual void getAttributeAsString(const c8* attributeName, c8* target); - //! Returns attribute value as string by index. + //! Returns attribute value as string by index. //! \param index: Index value, must be between 0 and getAttributeCount()-1. virtual core::stringc getAttributeAsString(s32 index); - //! Sets an attribute value as string. + //! Sets an attribute value as string. //! \param attributeName: Name for the attribute virtual void setAttribute(s32 index, const c8* value); @@ -155,14 +155,14 @@ public: //! Adds an attribute as string virtual void addString(const c8* attributeName, const wchar_t* value); - //! Sets an attribute value as string. + //! Sets an attribute value as string. //! \param attributeName: Name for the attribute //! \param value: Value for the attribute. Set this to 0 to delete the attribute virtual void setAttribute(const c8* attributeName, const wchar_t* value); //! Gets an attribute as string. //! \param attributeName: Name of the attribute to get. - //! \return Returns value of the attribute previously set by setAttribute() + //! \return Returns value of the attribute previously set by setAttribute() //! or 0 if attribute is not set. virtual core::stringw getAttributeAsStringW(const c8* attributeName); @@ -171,11 +171,11 @@ public: //! \param target: Buffer where the string is copied to. virtual void getAttributeAsStringW(const c8* attributeName, wchar_t* target); - //! Returns attribute value as string by index. + //! Returns attribute value as string by index. //! \param index: Index value, must be between 0 and getAttributeCount()-1. virtual core::stringw getAttributeAsStringW(s32 index); - //! Sets an attribute value as string. + //! Sets an attribute value as string. //! \param attributeName: Name for the attribute virtual void setAttribute(s32 index, const wchar_t* value); @@ -212,18 +212,18 @@ public: //! Adds an attribute as wide string array virtual void addArray(const c8* attributeName, core::array value); - //! Sets an attribute value as a wide string array. + //! Sets an attribute value as a wide string array. //! \param attributeName: Name for the attribute //! \param value: Value for the attribute. Set this to 0 to delete the attribute virtual void setAttribute(const c8* attributeName, const core::array value); //! Gets an attribute as an array of wide strings. //! \param attributeName: Name of the attribute to get. - //! \return Returns value of the attribute previously set by setAttribute() + //! \return Returns value of the attribute previously set by setAttribute() //! or 0 if attribute is not set. virtual core::array getAttributeAsArray(const c8* attributeName); - //! Returns attribute value as an array of wide strings by index. + //! Returns attribute value as an array of wide strings by index. //! \param index: Index value, must be between 0 and getAttributeCount()-1. virtual core::array getAttributeAsArray(s32 index); @@ -244,7 +244,7 @@ public: //! Gets an attribute as boolean value //! \param attributeName: Name of the attribute to get. - //! \return Returns value of the attribute previously set by setAttribute() + //! \return Returns value of the attribute previously set by setAttribute() virtual bool getAttributeAsBool(const c8* attributeName); //! Gets an attribute as boolean value @@ -290,11 +290,11 @@ public: //! \param index: Index value, must be between 0 and getAttributeCount()-1. virtual const c8* getAttributeAsEnumeration(s32 index); - //! Gets the list of enumeration literals of an enumeration attribute + //! Gets the list of enumeration literals of an enumeration attribute //! \param attributeName: Name of the attribute to get. virtual void getAttributeEnumerationLiteralsOfEnumeration(const c8* attributeName, core::array& outLiterals); - //! Gets the list of enumeration literals of an enumeration attribute + //! Gets the list of enumeration literals of an enumeration attribute //! \param index: Index value, must be between 0 and getAttributeCount()-1. virtual void getAttributeEnumerationLiteralsOfEnumeration(s32 index, core::array& outLiterals); @@ -371,7 +371,7 @@ public: //! Gets an attribute as 3d vector //! \param index: Index value, must be between 0 and getAttributeCount()-1. virtual core::vector3df getAttributeAsVector3d(s32 index); - + //! Sets an attribute as vector virtual void setAttribute(s32 index, core::vector3df v); @@ -428,7 +428,7 @@ public: matrix attribute - */ + */ //! Adds an attribute as matrix virtual void addMatrix(const c8* attributeName, const core::matrix4& v); @@ -619,7 +619,7 @@ public: virtual void setAttribute(s32 index, video::ITexture* texture); - + /* User Pointer Attribute @@ -682,7 +682,7 @@ public: virtual core::line2di getLine2di() { return core::line2di(); } virtual core::line3df getLine3d() { return core::line3df(); } virtual core::line3di getLine3di() { return core::line3di(); } - virtual core::dimension2di getDimension2d() { return core::dimension2di(); } + virtual core::dimension2du getDimension2d() { return core::dimension2du(); } virtual core::aabbox3d getBBox() { return core::aabbox3d(); } virtual core::plane3df getPlane() { return core::plane3df(); } @@ -711,7 +711,7 @@ public: virtual void setLine2d(core::line2di v) {}; virtual void setLine3d(core::line3df v) {}; virtual void setLine3d(core::line3di v) {}; - virtual void setDimension2d(core::dimension2di v) {}; + virtual void setDimension2d(core::dimension2du v) {}; virtual void setBBox(core::aabbox3d v) {}; virtual void setPlane(core::plane3df v) {}; virtual void setUserPointer(void* v) {}; diff --git a/source/Irrlicht/CB3DMeshFileLoader.cpp b/source/Irrlicht/CB3DMeshFileLoader.cpp index 1fd74222..c7cc5829 100644 --- a/source/Irrlicht/CB3DMeshFileLoader.cpp +++ b/source/Irrlicht/CB3DMeshFileLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2006-2008 Luke Hoschke +// Copyright (C) 2006-2009 Luke Hoschke // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -907,7 +907,8 @@ void CB3DMeshFileLoader::loadTextures(SB3dMaterial& material) const SB3dTexture* B3dTexture = material.Textures[i]; if (B3dTexture && B3dTexture->TextureName.size() && !material.Material.getTexture(i)) { - SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, (B3dTexture->Flags & 0x8) ? true:false); + if (!SceneManager->getParameters()->getAttributeAsBool(B3D_LOADER_IGNORE_MIPMAP_FLAG)) + SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, (B3dTexture->Flags & 0x8) ? true:false); material.Material.setTexture(i, SceneManager->getVideoDriver()->getTexture( B3dTexture->TextureName.c_str() )); if (material.Textures[i]->Flags & 0x10) // Clamp U material.Material.TextureLayer[i].TextureWrap=video::ETC_CLAMP; diff --git a/source/Irrlicht/CB3DMeshFileLoader.h b/source/Irrlicht/CB3DMeshFileLoader.h index 151ea1c1..5f9099e7 100644 --- a/source/Irrlicht/CB3DMeshFileLoader.h +++ b/source/Irrlicht/CB3DMeshFileLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2006-2008 Luke Hoschke +// Copyright (C) 2006-2009 Luke Hoschke // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CBSPMeshFileLoader.cpp b/source/Irrlicht/CBSPMeshFileLoader.cpp index 11553fc9..daedbffe 100644 --- a/source/Irrlicht/CBSPMeshFileLoader.cpp +++ b/source/Irrlicht/CBSPMeshFileLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CBSPMeshFileLoader.h b/source/Irrlicht/CBSPMeshFileLoader.h index 88e36123..db17392b 100644 --- a/source/Irrlicht/CBSPMeshFileLoader.h +++ b/source/Irrlicht/CBSPMeshFileLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CBillboardSceneNode.cpp b/source/Irrlicht/CBillboardSceneNode.cpp index 86cd70dd..2e079896 100644 --- a/source/Irrlicht/CBillboardSceneNode.cpp +++ b/source/Irrlicht/CBillboardSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CBillboardSceneNode.h b/source/Irrlicht/CBillboardSceneNode.h index d4f96a91..ae705269 100644 --- a/source/Irrlicht/CBillboardSceneNode.h +++ b/source/Irrlicht/CBillboardSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CBoneSceneNode.cpp b/source/Irrlicht/CBoneSceneNode.cpp index a12563da..3363cd2f 100644 --- a/source/Irrlicht/CBoneSceneNode.cpp +++ b/source/Irrlicht/CBoneSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CBoneSceneNode.h b/source/Irrlicht/CBoneSceneNode.h index 263e91f9..f6528e70 100644 --- a/source/Irrlicht/CBoneSceneNode.h +++ b/source/Irrlicht/CBoneSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CBurningShader_Raster_Reference.cpp b/source/Irrlicht/CBurningShader_Raster_Reference.cpp index 3706f473..9abaeda6 100644 --- a/source/Irrlicht/CBurningShader_Raster_Reference.cpp +++ b/source/Irrlicht/CBurningShader_Raster_Reference.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -625,13 +625,37 @@ void CBurningShader_Raster_Reference::setMaterial ( const SBurningShaderMaterial ShaderParam.SetRenderState( BD3DRS_SPECULARMATERIALSOURCE, BD3DMCS_MATERIAL); // depth buffer enable and compare - ShaderParam.SetRenderState( BD3DRS_ZENABLE, material.org.ZBuffer ? BD3DZB_USEW : BD3DZB_FALSE); - ShaderParam.SetRenderState( BD3DRS_ZFUNC, material.org.ZBuffer == 2 ? BD3DCMP_EQUAL : BD3DCMP_LESSEQUAL ); + ShaderParam.SetRenderState( BD3DRS_ZENABLE, (material.org.ZBuffer==video::ECFN_NEVER) ? BD3DZB_FALSE : BD3DZB_USEW); + switch (material.org.ZBuffer) + { + case ECFN_NEVER: + ShaderParam.SetRenderState(BD3DRS_ZFUNC, BD3DCMP_NEVER); + break; + case ECFN_LESSEQUAL: + ShaderParam.SetRenderState(BD3DRS_ZFUNC, BD3DCMP_LESSEQUAL); + break; + case ECFN_EQUAL: + ShaderParam.SetRenderState(BD3DRS_ZFUNC, BD3DCMP_EQUAL); + break; + case ECFN_LESS: + ShaderParam.SetRenderState(BD3DRS_ZFUNC, BD3DCMP_LESSEQUAL); + break; + case ECFN_NOTEQUAL: + ShaderParam.SetRenderState(BD3DRS_ZFUNC, BD3DCMP_NOTEQUAL); + break; + case ECFN_GREATEREQUAL: + ShaderParam.SetRenderState(BD3DRS_ZFUNC, BD3DCMP_GREATEREQUAL); + break; + case ECFN_GREATER: + ShaderParam.SetRenderState(BD3DRS_ZFUNC, BD3DCMP_GREATER); + break; + case ECFN_ALWAYS: + ShaderParam.SetRenderState(BD3DRS_ZFUNC, BD3DCMP_ALWAYS); + break; + } // depth buffer write ShaderParam.SetRenderState( BD3DRS_ZWRITEENABLE, m.ZWriteEnable ); - - } /*! diff --git a/source/Irrlicht/CCSMLoader.cpp b/source/Irrlicht/CCSMLoader.cpp index 8ec2aeda..823613b0 100644 --- a/source/Irrlicht/CCSMLoader.cpp +++ b/source/Irrlicht/CCSMLoader.cpp @@ -1,11 +1,11 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // // This file was written by Saurav Mohapatra and modified by Nikolaus Gebhardt. // See CCSMLoader.h for details. -#include "IrrCompileConfig.h" +#include "IrrCompileConfig.h" #ifdef _IRR_COMPILE_WITH_CSM_LOADER_ #include "CCSMLoader.h" @@ -433,7 +433,7 @@ namespace scene video::IImage* lmapImg = driver->createImageFromData( video::ECF_A8R8G8B8, - core::dimension2d(lmap->getWidth(),lmap->getHeight()), + core::dimension2d(lmap->getWidth(),lmap->getHeight()), (void *)(lmap->getPixelData())); driver->addTexture(lmapName.c_str(), lmapImg); diff --git a/source/Irrlicht/CCSMLoader.h b/source/Irrlicht/CCSMLoader.h index cb87167d..bfa27353 100644 --- a/source/Irrlicht/CCSMLoader.h +++ b/source/Irrlicht/CCSMLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // diff --git a/source/Irrlicht/CCameraSceneNode.cpp b/source/Irrlicht/CCameraSceneNode.cpp index 93545b8f..25865fa9 100644 --- a/source/Irrlicht/CCameraSceneNode.cpp +++ b/source/Irrlicht/CCameraSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CCameraSceneNode.h b/source/Irrlicht/CCameraSceneNode.h index d4bdd46c..b18e5425 100644 --- a/source/Irrlicht/CCameraSceneNode.h +++ b/source/Irrlicht/CCameraSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CColladaFileLoader.cpp b/source/Irrlicht/CColladaFileLoader.cpp index 0ba5b89a..06d0ab2e 100644 --- a/source/Irrlicht/CColladaFileLoader.cpp +++ b/source/Irrlicht/CColladaFileLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CColladaFileLoader.h b/source/Irrlicht/CColladaFileLoader.h index 84db1751..c253346d 100644 --- a/source/Irrlicht/CColladaFileLoader.h +++ b/source/Irrlicht/CColladaFileLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -101,7 +101,7 @@ struct SColladaImage { core::stringc Id; core::stringc Source; - core::dimension2di Dimension; + core::dimension2du Dimension; bool SourceIsFilename; }; @@ -121,7 +121,7 @@ struct SColladaMaterial core::stringc Id; core::stringc InstanceEffectId; f32 Transparency; - + inline bool operator< (const SColladaMaterial & other) const { return Id < other.Id; @@ -134,7 +134,7 @@ struct SColladaEffect video::SMaterial Mat; core::stringc Id; f32 Transparency; - + inline bool operator< (const SColladaEffect & other) const { return Id < other.Id; @@ -317,10 +317,10 @@ private: void readPolygonSection(io::IXMLReaderUTF8* reader, const core::stringc& vertexPositionSource, core::array& sources, scene::SMesh* mesh, const core::stringc& geometryId); - + //! finds a material, possible instancing it const SColladaMaterial * findMaterial(const core::stringc & materialName); - + //! reads and bind materials as given by the symbol->target bind mapping void readBindMaterialSection(io::IXMLReaderUTF8* reader, const core::stringc & id); diff --git a/source/Irrlicht/CColladaMeshWriter.cpp b/source/Irrlicht/CColladaMeshWriter.cpp index f8b230fa..0e3ba009 100644 --- a/source/Irrlicht/CColladaMeshWriter.cpp +++ b/source/Irrlicht/CColladaMeshWriter.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CColladaMeshWriter.h b/source/Irrlicht/CColladaMeshWriter.h index a0dc99b9..694c73e4 100644 --- a/source/Irrlicht/CColladaMeshWriter.h +++ b/source/Irrlicht/CColladaMeshWriter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CColorConverter.cpp b/source/Irrlicht/CColorConverter.cpp index e2573af5..65e50dd8 100644 --- a/source/Irrlicht/CColorConverter.cpp +++ b/source/Irrlicht/CColorConverter.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CColorConverter.h b/source/Irrlicht/CColorConverter.h index e457e6b4..e7ef5f70 100644 --- a/source/Irrlicht/CColorConverter.h +++ b/source/Irrlicht/CColorConverter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CCubeSceneNode.cpp b/source/Irrlicht/CCubeSceneNode.cpp index 29ee1e87..65928b02 100644 --- a/source/Irrlicht/CCubeSceneNode.cpp +++ b/source/Irrlicht/CCubeSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CCubeSceneNode.h b/source/Irrlicht/CCubeSceneNode.h index 658b0610..15db5550 100644 --- a/source/Irrlicht/CCubeSceneNode.h +++ b/source/Irrlicht/CCubeSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CD3D8Driver.cpp b/source/Irrlicht/CD3D8Driver.cpp index cc6371a9..33f85e70 100644 --- a/source/Irrlicht/CD3D8Driver.cpp +++ b/source/Irrlicht/CD3D8Driver.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -25,7 +25,7 @@ namespace video //! constructor -CD3D8Driver::CD3D8Driver(const core::dimension2d& screenSize, HWND window, +CD3D8Driver::CD3D8Driver(const core::dimension2d& screenSize, HWND window, bool fullscreen, bool stencilbuffer, io::IFileSystem* io, bool pureSoftware, bool vsync) : CNullDriver(io, screenSize), CurrentRenderMode(ERM_NONE), @@ -138,14 +138,13 @@ void CD3D8Driver::createMaterialRenderers() // add basic 1 texture blending addAndDropMaterialRenderer(new CD3D8MaterialRenderer_ONETEXTURE_BLEND(pID3DDevice, this)); - } //! initialises the Direct3D API -bool CD3D8Driver::initDriver(const core::dimension2d& screenSize, +bool CD3D8Driver::initDriver(const core::dimension2d& screenSize, HWND hwnd, u32 bits, bool fullScreen, bool pureSoftware, - bool highPrecisionFPU, bool vsync, bool antiAlias) + bool highPrecisionFPU, bool vsync, u8 antiAlias) { HRESULT hr; D3DLibrary = LoadLibrary( "d3d8.dll" ); @@ -190,8 +189,6 @@ bool CD3D8Driver::initDriver(const core::dimension2d& screenSize, os::Printer::log(tmp, ELL_INFORMATION); } - - D3DDISPLAYMODE d3ddm; hr = pID3D->GetAdapterDisplayMode(D3DADAPTER_DEFAULT, &d3ddm); if (FAILED(hr)) @@ -200,10 +197,9 @@ bool CD3D8Driver::initDriver(const core::dimension2d& screenSize, return false; } - ZeroMemory(&present, sizeof(present)); - present.SwapEffect = D3DSWAPEFFECT_COPY; + present.SwapEffect = D3DSWAPEFFECT_DISCARD; present.Windowed = TRUE; present.BackBufferFormat = d3ddm.Format; present.EnableAutoDepthStencil = TRUE; @@ -229,21 +225,26 @@ bool CD3D8Driver::initDriver(const core::dimension2d& screenSize, #endif // enable anti alias if possible and whished - if (antiAlias) + if (antiAlias > 0) { - if (!FAILED(pID3D->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, + if(antiAlias > 16) + antiAlias = 16; + + while(antiAlias > 0) + { + if(!FAILED(pID3D->CheckDeviceMultiSampleType(D3DADAPTER_DEFAULT, devtype , present.BackBufferFormat, !fullScreen, - D3DMULTISAMPLE_2_SAMPLES))) - { - // enable multi sampling - present.SwapEffect = D3DSWAPEFFECT_DISCARD; - present.MultiSampleType = D3DMULTISAMPLE_2_SAMPLES; + (D3DMULTISAMPLE_TYPE)antiAlias))) + { + present.MultiSampleType = (D3DMULTISAMPLE_TYPE)antiAlias; + present.SwapEffect = D3DSWAPEFFECT_DISCARD; + break; + } + --antiAlias; } - else - { + + if(antiAlias==0) os::Printer::log("Anti aliasing disabled because hardware/driver lacks necessary caps.", ELL_WARNING); - antiAlias = false; - } } // check stencil buffer compatibility @@ -350,7 +351,7 @@ bool CD3D8Driver::initDriver(const core::dimension2d& screenSize, setVertexShader(EVT_STANDARD); // enable antialiasing - if (antiAlias) + if (antiAlias>0) pID3DDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); // set fog mode @@ -372,12 +373,6 @@ bool CD3D8Driver::initDriver(const core::dimension2d& screenSize, // set the renderstates setRenderStates3DMode(); - // set max anisotropy - pID3DDevice->SetTextureStageState(0, D3DTSS_MAXANISOTROPY, core::min_( (DWORD) 16, Caps.MaxAnisotropy)); - pID3DDevice->SetTextureStageState(1, D3DTSS_MAXANISOTROPY, core::min_( (DWORD) 16, Caps.MaxAnisotropy)); - pID3DDevice->SetTextureStageState(2, D3DTSS_MAXANISOTROPY, core::min_( (DWORD) 16, Caps.MaxAnisotropy)); - pID3DDevice->SetTextureStageState(3, D3DTSS_MAXANISOTROPY, core::min_( (DWORD) 16, Caps.MaxAnisotropy)); - // so far so good. return true; } @@ -571,6 +566,8 @@ bool CD3D8Driver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const return (Caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) == 0; case EVDF_TEXTURE_NPOT: return (Caps.TextureCaps & D3DPTEXTURECAPS_POW2) == 0; + case EVDF_COLOR_MASK: + return (Caps.PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE) != 0; default: return false; }; @@ -649,7 +646,6 @@ void CD3D8Driver::setMaterial(const SMaterial& material) setTransform((E_TRANSFORMATION_STATE) ( ETS_TEXTURE_0 + i ), material.getTextureMatrix(i)); } - } @@ -668,7 +664,6 @@ void CD3D8Driver::setTextureCreationFlag(E_TEXTURE_CREATION_FLAG flag, if (flag == video::ETCF_CREATE_MIP_MAPS && !queryFeature(EVDF_MIP_MAP)) enabled = false; - CNullDriver::setTextureCreationFlag(flag, enabled); } @@ -722,7 +717,7 @@ bool CD3D8Driver::setRenderTarget(video::ITexture* texture, if (dss) dss->Release(); - CurrentRendertargetSize = core::dimension2d(0,0); + CurrentRendertargetSize = core::dimension2d(0,0); PrevRenderTarget->Release(); PrevRenderTarget = 0; } @@ -733,12 +728,11 @@ bool CD3D8Driver::setRenderTarget(video::ITexture* texture, // store previous target - if (!PrevRenderTarget) - if (FAILED(pID3DDevice->GetRenderTarget(&PrevRenderTarget))) - { - os::Printer::log("Could not get previous render target.", ELL_ERROR); - return false; - } + if (!PrevRenderTarget && (FAILED(pID3DDevice->GetRenderTarget(&PrevRenderTarget)))) + { + os::Printer::log("Could not get previous render target.", ELL_ERROR); + return false; + } // set new render target @@ -776,7 +770,7 @@ bool CD3D8Driver::setRenderTarget(video::ITexture* texture, //! Creates a render target texture. ITexture* CD3D8Driver::addRenderTargetTexture( - const core::dimension2d& size, const c8* name) + const core::dimension2d& size, const c8* name) { if (!name) name="rt"; @@ -914,8 +908,9 @@ void CD3D8Driver::draw2DImage(const video::ITexture* texture, core::position2d targetPos = pos; core::position2d sourcePos = sourceRect.UpperLeftCorner; + // This needs to be signed as it may go negative. core::dimension2d sourceSize(sourceRect.getSize()); - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); if (clipRect) { @@ -929,7 +924,7 @@ void CD3D8Driver::draw2DImage(const video::ITexture* texture, targetPos.X = clipRect->UpperLeftCorner.X; } - if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X) + if (targetPos.X + (s32)sourceSize.Width > clipRect->LowerRightCorner.X) { sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X; if (sourceSize.Width <= 0) @@ -946,7 +941,7 @@ void CD3D8Driver::draw2DImage(const video::ITexture* texture, targetPos.Y = clipRect->UpperLeftCorner.Y; } - if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y) + if (targetPos.Y + (s32)sourceSize.Height > clipRect->LowerRightCorner.Y) { sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y; if (sourceSize.Height <= 0) @@ -966,7 +961,7 @@ void CD3D8Driver::draw2DImage(const video::ITexture* texture, targetPos.X = 0; } - if (targetPos.X + sourceSize.Width > renderTargetSize.Width) + if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width) { sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; if (sourceSize.Width <= 0) @@ -983,7 +978,7 @@ void CD3D8Driver::draw2DImage(const video::ITexture* texture, targetPos.Y = 0; } - if (targetPos.Y + sourceSize.Height > renderTargetSize.Height) + if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height) { sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; if (sourceSize.Height <= 0) @@ -993,20 +988,20 @@ void CD3D8Driver::draw2DImage(const video::ITexture* texture, // ok, we've clipped everything. // now draw it. - s32 xPlus = -(renderTargetSize.Width>>1); + s32 xPlus = -(s32)(renderTargetSize.Width>>1); f32 xFact = 1.0f / (renderTargetSize.Width>>1); s32 yPlus = renderTargetSize.Height-(renderTargetSize.Height>>1); f32 yFact = 1.0f / (renderTargetSize.Height>>1); - const core::dimension2d sourceSurfaceSize = texture->getOriginalSize(); + const core::dimension2d sourceSurfaceSize = texture->getOriginalSize(); core::rect tcoords; tcoords.UpperLeftCorner.X = (((f32)sourcePos.X)+0.5f) / texture->getOriginalSize().Width ; tcoords.UpperLeftCorner.Y = (((f32)sourcePos.Y)+0.5f) / texture->getOriginalSize().Height; tcoords.LowerRightCorner.X = (((f32)sourcePos.X +0.5f + (f32)sourceSize.Width)) / texture->getOriginalSize().Width; tcoords.LowerRightCorner.Y = (((f32)sourcePos.Y +0.5f + (f32)sourceSize.Height)) / texture->getOriginalSize().Height; - core::rect poss(targetPos, sourceSize); + core::rect poss(targetPos, core::dimension2d(sourceSize)); setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); @@ -1047,7 +1042,7 @@ void CD3D8Driver::draw2DImage(const video::ITexture* texture, if(!texture) return; - const core::dimension2d& ss = texture->getOriginalSize(); + const core::dimension2d& ss = texture->getOriginalSize(); core::rect tcoords; tcoords.UpperLeftCorner.X = (f32)sourceRect.UpperLeftCorner.X / (f32)ss.Width; tcoords.UpperLeftCorner.Y = (f32)sourceRect.UpperLeftCorner.Y / (f32)ss.Height; @@ -1076,7 +1071,7 @@ void CD3D8Driver::draw2DImage(const video::ITexture* texture, tcoords.LowerRightCorner.Y -= scale * tcHeight; } - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); core::rect npos; f32 xFact = 2.0f / ( renderTargetSize.Width ); f32 yFact = 2.0f / ( renderTargetSize.Height ); @@ -1137,8 +1132,8 @@ void CD3D8Driver::draw2DRectangle(const core::rect& position, if (!pos.isValid()) return; - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); - s32 xPlus = -(renderTargetSize.Width>>1); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + s32 xPlus = -(s32)(renderTargetSize.Width>>1); f32 xFact = 1.0f / (renderTargetSize.Width>>1); s32 yPlus = renderTargetSize.Height-(renderTargetSize.Height>>1); @@ -1168,11 +1163,9 @@ void CD3D8Driver::draw2DRectangle(const core::rect& position, pID3DDevice->DrawIndexedPrimitiveUP(D3DPT_TRIANGLELIST, 0, 4, 2, &indices[0], D3DFMT_INDEX16, &vtx[0], sizeof(S3DVertex)); - } - //! Draws a 2d line. void CD3D8Driver::draw2DLine(const core::position2d& start, const core::position2d& end, @@ -1180,8 +1173,8 @@ void CD3D8Driver::draw2DLine(const core::position2d& start, { // thanks to Vash TheStampede who sent in his implementation - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); - const s32 xPlus = -(renderTargetSize.Width>>1); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + const s32 xPlus = -(s32)(renderTargetSize.Width>>1); const f32 xFact = 1.0f / (renderTargetSize.Width>>1); const s32 yPlus = @@ -1211,10 +1204,11 @@ void CD3D8Driver::draw2DLine(const core::position2d& start, pID3DDevice->DrawPrimitiveUP(D3DPT_LINELIST, 1, &vtx[0], sizeof(S3DVertex)); } + //! Draws a pixel void CD3D8Driver::drawPixel(u32 x, u32 y, const SColor & color) { - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); if(x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height) return; @@ -1223,7 +1217,7 @@ void CD3D8Driver::drawPixel(u32 x, u32 y, const SColor & color) setVertexShader(EVT_STANDARD); - const s32 xPlus = -renderTargetSize.Width / 2; + const s32 xPlus = -((s32)renderTargetSize.Width) / 2; const f32 xFact = 2.0f / renderTargetSize.Width; const s32 yPlus = renderTargetSize.Height / 2; const f32 yFact = 2.0f / renderTargetSize.Height; @@ -1235,7 +1229,6 @@ void CD3D8Driver::drawPixel(u32 x, u32 y, const SColor & color) } - //! sets right vertex shader void CD3D8Driver::setVertexShader(E_VERTEX_TYPE newType) { @@ -1354,7 +1347,6 @@ void CD3D8Driver::setBasicRenderStates(const SMaterial& material, const SMateria } // shademode - if (resetAllRenderstates || lastmaterial.GouraudShading != material.GouraudShading) { if (material.GouraudShading) @@ -1364,7 +1356,6 @@ void CD3D8Driver::setBasicRenderStates(const SMaterial& material, const SMateria } // lighting - if (resetAllRenderstates || lastmaterial.Lighting != material.Lighting) { if (material.Lighting) @@ -1373,28 +1364,45 @@ void CD3D8Driver::setBasicRenderStates(const SMaterial& material, const SMateria pID3DDevice->SetRenderState(D3DRS_LIGHTING, FALSE); } - // zbuffer - if (resetAllRenderstates || lastmaterial.ZBuffer != material.ZBuffer) { switch (material.ZBuffer) { - case 0: - pID3DDevice->SetRenderState(D3DRS_ZENABLE, FALSE); - break; - case 1: - pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); - pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); - break; - case 2: - pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); - pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_EQUAL); - break; + case ECFN_NEVER: + pID3DDevice->SetRenderState(D3DRS_ZENABLE, FALSE); + break; + case ECFN_LESSEQUAL: + pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); + break; + case ECFN_EQUAL: + pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_EQUAL); + break; + case ECFN_LESS: + pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS); + break; + case ECFN_NOTEQUAL: + pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_NOTEQUAL); + break; + case ECFN_GREATEREQUAL: + pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATEREQUAL); + break; + case ECFN_GREATER: + pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATER); + break; + case ECFN_ALWAYS: + pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); + break; } } - // zwrite // if (resetAllRenderstates || lastmaterial.ZWriteEnable != material.ZWriteEnable) { @@ -1405,8 +1413,6 @@ void CD3D8Driver::setBasicRenderStates(const SMaterial& material, const SMateria } // back face culling - - if (resetAllRenderstates || (lastmaterial.FrontfaceCulling != material.FrontfaceCulling) || (lastmaterial.BackfaceCulling != material.BackfaceCulling)) { // if (material.FrontfaceCulling && material.BackfaceCulling) @@ -1442,6 +1448,18 @@ void CD3D8Driver::setBasicRenderStates(const SMaterial& material, const SMateria pID3DDevice->SetRenderState(D3DRS_NORMALIZENORMALS, material.NormalizeNormals); } + // Color Mask + if (queryFeature(EVDF_COLOR_MASK) && + (resetAllRenderstates || lastmaterial.ColorMask != material.ColorMask)) + { + const DWORD flag = + ((material.ColorMask & ECP_RED)?D3DCOLORWRITEENABLE_RED:0) | + ((material.ColorMask & ECP_GREEN)?D3DCOLORWRITEENABLE_GREEN:0) | + ((material.ColorMask & ECP_BLUE)?D3DCOLORWRITEENABLE_BLUE:0) | + ((material.ColorMask & ECP_ALPHA)?D3DCOLORWRITEENABLE_ALPHA:0); + pID3DDevice->SetRenderState(D3DRS_COLORWRITEENABLE, flag); + } + // thickness if (resetAllRenderstates || lastmaterial.Thickness != material.Thickness) { @@ -1451,6 +1469,12 @@ void CD3D8Driver::setBasicRenderStates(const SMaterial& material, const SMateria // texture address mode for (u32 st=0; stSetTextureStageState(st, D3DSAMP_MIPMAPLODBIAS, *(DWORD*)(&tmp)); + } + if (resetAllRenderstates || lastmaterial.TextureLayer[st].TextureWrap != material.TextureLayer[st].TextureWrap) { u32 mode = D3DTADDRESS_WRAP; @@ -1481,7 +1505,7 @@ void CD3D8Driver::setBasicRenderStates(const SMaterial& material, const SMateria lastmaterial.TextureLayer[st].TrilinearFilter != material.TextureLayer[st].TrilinearFilter || lastmaterial.TextureLayer[st].AnisotropicFilter != material.TextureLayer[st].AnisotropicFilter ) { - if (material.TextureLayer[st].BilinearFilter || material.TextureLayer[st].TrilinearFilter || material.TextureLayer[st].AnisotropicFilter) + if (material.TextureLayer[st].BilinearFilter || material.TextureLayer[st].TrilinearFilter || material.TextureLayer[st].AnisotropicFilter>1) { D3DTEXTUREFILTERTYPE tftMag = ((Caps.TextureFilterCaps & D3DPTFILTERCAPS_MAGFANISOTROPIC) && material.TextureLayer[st].AnisotropicFilter) ? D3DTEXF_ANISOTROPIC : D3DTEXF_LINEAR; @@ -1489,6 +1513,8 @@ void CD3D8Driver::setBasicRenderStates(const SMaterial& material, const SMateria material.TextureLayer[st].AnisotropicFilter) ? D3DTEXF_ANISOTROPIC : D3DTEXF_LINEAR; D3DTEXTUREFILTERTYPE tftMip = material.TextureLayer[st].TrilinearFilter ? D3DTEXF_LINEAR : D3DTEXF_POINT; + if (tftMag==D3DTEXF_ANISOTROPIC || tftMin == D3DTEXF_ANISOTROPIC) + pID3DDevice->SetTextureStageState(st, D3DTSS_MAXANISOTROPY, core::min_((DWORD)material.TextureLayer[st].AnisotropicFilter, Caps.MaxAnisotropy)); pID3DDevice->SetTextureStageState(st, D3DTSS_MAGFILTER, tftMag); pID3DDevice->SetTextureStageState(st, D3DTSS_MINFILTER, tftMin); pID3DDevice->SetTextureStageState(st, D3DTSS_MIPFILTER, tftMip); @@ -1504,7 +1530,6 @@ void CD3D8Driver::setBasicRenderStates(const SMaterial& material, const SMateria } - //! sets the needed renderstates void CD3D8Driver::setRenderStatesStencilShadowMode(bool zfail) { @@ -1588,7 +1613,6 @@ void CD3D8Driver::setRenderStatesStencilShadowMode(bool zfail) } - //! sets the needed renderstates void CD3D8Driver::setRenderStatesStencilFillMode(bool alpha) { @@ -1646,7 +1670,6 @@ void CD3D8Driver::setRenderStatesStencilFillMode(bool alpha) } - //! sets the needed renderstates void CD3D8Driver::setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel) { @@ -1784,13 +1807,9 @@ void CD3D8Driver::deleteAllDynamicLights() } - //! adds a dynamic light -void CD3D8Driver::addDynamicLight(const SLight& dl) +s32 CD3D8Driver::addDynamicLight(const SLight& dl) { - if ((u32)LastSetLight == Caps.MaxActiveLights-1) - return; - CNullDriver::addDynamicLight(dl); D3DLIGHT8 light; @@ -1826,11 +1845,26 @@ void CD3D8Driver::addDynamicLight(const SLight& dl) light.Phi = dl.OuterCone * 2.0f * core::DEGTORAD; ++LastSetLight; - pID3DDevice->SetLight(LastSetLight, &light); - pID3DDevice->LightEnable(LastSetLight, true); + + if(D3D_OK == pID3DDevice->SetLight(LastSetLight, &light)) + { + // I don't care if this succeeds + (void)pID3DDevice->LightEnable(LastSetLight, true); + return LastSetLight; + } + + return -1; } +void CD3D8Driver::turnLightOn(s32 lightIndex, bool turnOn) +{ + if(lightIndex < 0 || lightIndex > LastSetLight) + return; + + (void)pID3DDevice->LightEnable(lightIndex, turnOn); +} + //! returns the maximal amount of dynamic lights the device can handle u32 CD3D8Driver::getMaximalDynamicLightAmount() const @@ -1839,7 +1873,6 @@ u32 CD3D8Driver::getMaximalDynamicLightAmount() const } - //! Sets the dynamic ambient light color. The default color is //! (0,0,0,0) which means it is dark. //! \param color: New color of the ambient light. @@ -1854,7 +1887,6 @@ void CD3D8Driver::setAmbientLight(const SColorf& color) } - //! \return Returns the name of the video driver. Example: In case of the DIRECT3D8 //! driver, it would return "Direct3D8.1". const wchar_t* CD3D8Driver::getName() const @@ -1863,7 +1895,6 @@ const wchar_t* CD3D8Driver::getName() const } - //! Draws a shadow volume into the stencil buffer. To draw a stencil shadow, do //! this: Frist, draw all geometry. Then use this method, to draw the shadow //! volume. Then, use IVideoDriver::drawStencilShadow() to visualize the shadow. @@ -1905,7 +1936,6 @@ void CD3D8Driver::drawStencilShadowVolume(const core::vector3df* triangles, s32 } - //! Fills the stencil shadow with color. After the shadow volume has been drawn //! into the stencil buffer using IVideoDriver::drawStencilShadowVolume(), use this //! to draw the color of the shadow. @@ -1941,7 +1971,6 @@ void CD3D8Driver::drawStencilShadow(bool clearStencilBuffer, video::SColor leftU } - //! Returns the maximum amount of primitives (mostly vertices) which //! the device is able to render with one drawIndexedTriangleList //! call. @@ -1978,6 +2007,7 @@ void CD3D8Driver::setFog(SColor color, bool linearFog, f32 start, pID3DDevice->SetRenderState (D3DRS_RANGEFOGENABLE, rangeFog); } + //! Draws a 3d line. void CD3D8Driver::draw3DLine(const core::vector3df& start, const core::vector3df& end, SColor color) @@ -1994,7 +2024,7 @@ void CD3D8Driver::draw3DLine(const core::vector3df& start, } -void CD3D8Driver::OnResize(const core::dimension2d& size) +void CD3D8Driver::OnResize(const core::dimension2d& size) { if (!pID3DDevice) return; @@ -2003,18 +2033,21 @@ void CD3D8Driver::OnResize(const core::dimension2d& size) reset(); } + //! Returns type of video driver E_DRIVER_TYPE CD3D8Driver::getDriverType() const { return EDT_DIRECT3D8; } + //! Returns the transformation set by setTransform const core::matrix4& CD3D8Driver::getTransform(E_TRANSFORMATION_STATE state) const { return Matrices[state]; } + //! Sets a vertex shader constant. void CD3D8Driver::setVertexShaderConstant(const f32* data, s32 startRegister, s32 constantAmount) { @@ -2022,6 +2055,7 @@ void CD3D8Driver::setVertexShaderConstant(const f32* data, s32 startRegister, s3 pID3DDevice->SetVertexShaderConstant(startRegister, data, constantAmount); } + //! Sets a pixel shader constant. void CD3D8Driver::setPixelShaderConstant(const f32* data, s32 startRegister, s32 constantAmount) { @@ -2029,6 +2063,7 @@ void CD3D8Driver::setPixelShaderConstant(const f32* data, s32 startRegister, s32 pID3DDevice->SetPixelShaderConstant(startRegister, data, constantAmount); } + //! Sets a constant for the vertex shader based on a name. bool CD3D8Driver::setVertexShaderConstant(const c8* name, const f32* floats, int count) { @@ -2036,6 +2071,7 @@ bool CD3D8Driver::setVertexShaderConstant(const c8* name, const f32* floats, int return false; } + //! Sets a constant for the pixel shader based on a name. bool CD3D8Driver::setPixelShaderConstant(const c8* name, const f32* floats, int count) { @@ -2043,6 +2079,7 @@ bool CD3D8Driver::setPixelShaderConstant(const c8* name, const f32* floats, int return false; } + //! Returns pointer to the IGPUProgrammingServices interface. IGPUProgrammingServices* CD3D8Driver::getGPUProgrammingServices() { @@ -2075,7 +2112,6 @@ IVideoDriver* CD3D8Driver::getVideoDriver() } - //! Clears the ZBuffer. void CD3D8Driver::clearZBuffer() { @@ -2085,6 +2121,7 @@ void CD3D8Driver::clearZBuffer() os::Printer::log("CD3D8Driver clearZBuffer() failed.", ELL_WARNING); } + //! Returns an image created from the last rendered frame. IImage* CD3D8Driver::createScreenShot() { @@ -2136,13 +2173,13 @@ IImage* CD3D8Driver::createScreenShot() u8 * sP = (u8 *)lockedRect.pBits; // If the display mode format doesn't promise anything about the Alpha value - // and it appears that it's not presenting 255, then we should manually + // and it appears that it's not presenting 255, then we should manually // set each pixel alpha value to 255. if(D3DFMT_X8R8G8B8 == displayMode.Format && (0xFF000000 != (*dP & 0xFF000000))) { - for (s32 y = 0; y < ScreenSize.Height; ++y) + for (u32 y = 0; y < ScreenSize.Height; ++y) { - for(s32 x = 0; x < ScreenSize.Width; ++x) + for(u32 x = 0; x < ScreenSize.Width; ++x) { *dP = *((u32*)sP) | 0xFF000000; dP++; @@ -2154,7 +2191,7 @@ IImage* CD3D8Driver::createScreenShot() } else { - for (s32 y = 0; y < ScreenSize.Height; ++y) + for (u32 y = 0; y < ScreenSize.Height; ++y) { memcpy(dP, sP, ScreenSize.Width * 4); @@ -2176,9 +2213,8 @@ IImage* CD3D8Driver::createScreenShot() } - // returns the current size of the screen or rendertarget -const core::dimension2d& CD3D8Driver::getCurrentRenderTargetSize() const +const core::dimension2d& CD3D8Driver::getCurrentRenderTargetSize() const { if ( CurrentRendertargetSize.Width == 0 ) return ScreenSize; @@ -2187,7 +2223,6 @@ const core::dimension2d& CD3D8Driver::getCurrentRenderTargetSize() const } - // Set/unset a clipping plane. bool CD3D8Driver::setClipPlane(u32 index, const core::plane3df& plane, bool enable) { @@ -2228,10 +2263,10 @@ namespace video #ifdef _IRR_COMPILE_WITH_DIRECT3D_8_ //! creates a video driver -IVideoDriver* createDirectX8Driver(const core::dimension2d& screenSize, HWND window, - u32 bits, bool fullscreen, bool stencilbuffer, - io::IFileSystem* io, bool pureSoftware, bool highPrecisionFPU, - bool vsync, bool antiAlias) +IVideoDriver* createDirectX8Driver(const core::dimension2d& screenSize, + HWND window, u32 bits, bool fullscreen, bool stencilbuffer, + io::IFileSystem* io, bool pureSoftware, bool highPrecisionFPU, + bool vsync, u8 antiAlias) { CD3D8Driver* dx8 = new CD3D8Driver(screenSize, window, fullscreen, stencilbuffer, io, pureSoftware); @@ -2250,4 +2285,3 @@ IVideoDriver* createDirectX8Driver(const core::dimension2d& screenSize, HWN } // end namespace video } // end namespace irr - diff --git a/source/Irrlicht/CD3D8Driver.h b/source/Irrlicht/CD3D8Driver.h index 0891a942..11c0f724 100644 --- a/source/Irrlicht/CD3D8Driver.h +++ b/source/Irrlicht/CD3D8Driver.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -33,7 +33,7 @@ namespace video public: //! constructor - CD3D8Driver(const core::dimension2d& screenSize, HWND window, bool fullscreen, + CD3D8Driver(const core::dimension2d& screenSize, HWND window, bool fullscreen, bool stencibuffer, io::IFileSystem* io, bool pureSoftware=false, bool vsync=false); //! destructor @@ -101,9 +101,9 @@ namespace video const core::vector3df& end, SColor color = SColor(255,255,255,255)); //! initialises the Direct3D API - bool initDriver(const core::dimension2d& screenSize, HWND hwnd, + bool initDriver(const core::dimension2d& screenSize, HWND hwnd, u32 bits, bool fullScreen, bool pureSoftware, - bool highPrecisionFPU, bool vsync, bool antiAlias); + bool highPrecisionFPU, bool vsync, u8 antiAlias); //! \return Returns the name of the video driver. Example: In case of the DIRECT3D8 //! driver, it would return "Direct3D8.1". @@ -112,8 +112,15 @@ namespace video //! deletes all dynamic lights there are virtual void deleteAllDynamicLights(); - //! adds a dynamic light - virtual void addDynamicLight(const SLight& light); + //! adds a dynamic light, returning an index to the light + //! \param light: the light data to use to create the light + //! \return An index to the light, or -1 if an error occurs + virtual s32 addDynamicLight(const SLight& light); + + //! Turns a dynamic light on or off + //! \param lightIndex: the index returned by addDynamicLight + //! \param turnOn: true to turn the light on, false to turn it off + virtual void turnLightOn(s32 lightIndex, bool turnOn); //! returns the maximal amount of dynamic lights the device can handle virtual u32 getMaximalDynamicLightAmount() const; @@ -151,7 +158,7 @@ namespace video //! Only used by the internal engine. Used to notify the driver that //! the window was resized. - virtual void OnResize(const core::dimension2d& size); + virtual void OnResize(const core::dimension2d& size); //! Returns type of video driver virtual E_DRIVER_TYPE getDriverType() const; @@ -183,7 +190,7 @@ namespace video virtual IVideoDriver* getVideoDriver(); //! Creates a render target texture. - virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, const c8* name); //! Clears the ZBuffer. @@ -245,7 +252,7 @@ namespace video virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const char* name); // returns the current size of the screen or rendertarget - virtual const core::dimension2d& getCurrentRenderTargetSize() const; + virtual const core::dimension2d& getCurrentRenderTargetSize() const; //! Adds a new material renderer to the VideoDriver, using pixel and/or //! vertex shaders to render geometry. @@ -281,7 +288,7 @@ namespace video IDirect3DDevice8* pID3DDevice; IDirect3DSurface8* PrevRenderTarget; - core::dimension2d CurrentRendertargetSize; + core::dimension2d CurrentRendertargetSize; void* WindowId; core::rect* SceneSourceRect; diff --git a/source/Irrlicht/CD3D8MaterialRenderer.h b/source/Irrlicht/CD3D8MaterialRenderer.h index 6189563a..c3fd8573 100644 --- a/source/Irrlicht/CD3D8MaterialRenderer.h +++ b/source/Irrlicht/CD3D8MaterialRenderer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -338,7 +338,8 @@ public: pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); - pID3DDevice->SetRenderState(D3DRS_ALPHAREF, core::floor32(material.MaterialTypeParam * 255.f)); + // 127 is required by EMT_TRANSPARENT_ALPHA_CHANNEL_REF + pID3DDevice->SetRenderState(D3DRS_ALPHAREF, 127); pID3DDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); } diff --git a/source/Irrlicht/CD3D8NormalMapRenderer.cpp b/source/Irrlicht/CD3D8NormalMapRenderer.cpp index f924962d..5f03131c 100644 --- a/source/Irrlicht/CD3D8NormalMapRenderer.cpp +++ b/source/Irrlicht/CD3D8NormalMapRenderer.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CD3D8NormalMapRenderer.h b/source/Irrlicht/CD3D8NormalMapRenderer.h index 9189cf65..c4eb5265 100644 --- a/source/Irrlicht/CD3D8NormalMapRenderer.h +++ b/source/Irrlicht/CD3D8NormalMapRenderer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CD3D8ParallaxMapRenderer.cpp b/source/Irrlicht/CD3D8ParallaxMapRenderer.cpp index d8922321..abe64a7e 100644 --- a/source/Irrlicht/CD3D8ParallaxMapRenderer.cpp +++ b/source/Irrlicht/CD3D8ParallaxMapRenderer.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CD3D8ParallaxMapRenderer.h b/source/Irrlicht/CD3D8ParallaxMapRenderer.h index f06bc329..53bd89ac 100644 --- a/source/Irrlicht/CD3D8ParallaxMapRenderer.h +++ b/source/Irrlicht/CD3D8ParallaxMapRenderer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CD3D8ShaderMaterialRenderer.cpp b/source/Irrlicht/CD3D8ShaderMaterialRenderer.cpp index e08d4e1b..88c3a1b3 100644 --- a/source/Irrlicht/CD3D8ShaderMaterialRenderer.cpp +++ b/source/Irrlicht/CD3D8ShaderMaterialRenderer.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CD3D8ShaderMaterialRenderer.h b/source/Irrlicht/CD3D8ShaderMaterialRenderer.h index 79a695e0..a50573d3 100644 --- a/source/Irrlicht/CD3D8ShaderMaterialRenderer.h +++ b/source/Irrlicht/CD3D8ShaderMaterialRenderer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CD3D8Texture.cpp b/source/Irrlicht/CD3D8Texture.cpp index e87b61b0..62d25b41 100644 --- a/source/Irrlicht/CD3D8Texture.cpp +++ b/source/Irrlicht/CD3D8Texture.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -31,7 +31,7 @@ namespace video { //! rendertarget constructor -CD3D8Texture::CD3D8Texture(CD3D8Driver* driver, core::dimension2d size, const char* name) +CD3D8Texture::CD3D8Texture(CD3D8Driver* driver, core::dimension2d size, const char* name) : ITexture(name), Texture(0), RTTSurface(0), Driver(driver), TextureSize(size), ImageSize(size), Pitch(0), HasMipMaps(false), IsRenderTarget(true) @@ -112,7 +112,7 @@ CD3D8Texture::~CD3D8Texture() //! creates the hardware texture bool CD3D8Texture::createTexture(video::IImage* image, u32 flags) { - core::dimension2d optSize; + core::dimension2d optSize; ImageSize = image->getDimension(); if (Driver->queryFeature(EVDF_TEXTURE_NPOT)) @@ -288,14 +288,14 @@ void CD3D8Texture::unlock() //! Returns original size of the texture. -const core::dimension2d& CD3D8Texture::getOriginalSize() const +const core::dimension2d& CD3D8Texture::getOriginalSize() const { return ImageSize; } //! Returns (=size) of the texture. -const core::dimension2d& CD3D8Texture::getSize() const +const core::dimension2d& CD3D8Texture::getSize() const { return TextureSize; } diff --git a/source/Irrlicht/CD3D8Texture.h b/source/Irrlicht/CD3D8Texture.h index 21a054ed..221dba98 100644 --- a/source/Irrlicht/CD3D8Texture.h +++ b/source/Irrlicht/CD3D8Texture.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -31,7 +31,7 @@ public: u32 flags, const char* name); //! rendertarget constructor - CD3D8Texture(CD3D8Driver* driver, core::dimension2d size, const char* name); + CD3D8Texture(CD3D8Driver* driver, core::dimension2d size, const char* name); //! destructor virtual ~CD3D8Texture(); @@ -43,10 +43,10 @@ public: virtual void unlock(); //! Returns original size of the texture. - virtual const core::dimension2d& getOriginalSize() const; + virtual const core::dimension2d& getOriginalSize() const; //! Returns (=size) of the texture. - virtual const core::dimension2d& getSize() const; + virtual const core::dimension2d& getSize() const; //! returns driver type of texture (=the driver, who created the texture) virtual E_DRIVER_TYPE getDriverType() const; @@ -102,8 +102,8 @@ private: IDirect3DTexture8* Texture; IDirect3DSurface8* RTTSurface; CD3D8Driver* Driver; - core::dimension2d TextureSize; - core::dimension2d ImageSize; + core::dimension2d TextureSize; + core::dimension2d ImageSize; s32 Pitch; ECOLOR_FORMAT ColorFormat; bool HasMipMaps; diff --git a/source/Irrlicht/CD3D9Driver.cpp b/source/Irrlicht/CD3D9Driver.cpp index 0d297058..24bc4723 100644 --- a/source/Irrlicht/CD3D9Driver.cpp +++ b/source/Irrlicht/CD3D9Driver.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -24,16 +24,17 @@ namespace video { //! constructor -CD3D9Driver::CD3D9Driver(const core::dimension2d& screenSize, HWND window, +CD3D9Driver::CD3D9Driver(const core::dimension2d& screenSize, HWND window, bool fullscreen, bool stencilbuffer, io::IFileSystem* io, bool pureSoftware) : CNullDriver(io, screenSize), CurrentRenderMode(ERM_NONE), - ResetRenderStates(true), Transformation3DChanged(false), StencilBuffer(stencilbuffer), + ResetRenderStates(true), Transformation3DChanged(false), + StencilBuffer(stencilbuffer), AntiAliasing(0), D3DLibrary(0), pID3D(0), pID3DDevice(0), PrevRenderTarget(0), WindowId(0), SceneSourceRect(0), LastVertexType((video::E_VERTEX_TYPE)-1), MaxTextureUnits(0), MaxUserClipPlanes(0), - MaxLightDistance(sqrtf(FLT_MAX)), LastSetLight(-1), ColorFormat(ECF_A8R8G8B8), DeviceLost(false), - Fullscreen(fullscreen), DriverWasReset(true) + MaxLightDistance(0.f), LastSetLight(-1), ColorFormat(ECF_A8R8G8B8), DeviceLost(false), + Fullscreen(fullscreen), DriverWasReset(true), AlphaToCoverageSupport(false) { #ifdef _DEBUG setDebugName("CD3D9Driver"); @@ -46,7 +47,7 @@ CD3D9Driver::CD3D9Driver(const core::dimension2d& screenSize, HWND window, CurrentTexture[i] = 0; LastTextureMipMapsAvailable[i] = false; } - + MaxLightDistance = sqrtf(FLT_MAX); // create sphere map matrix SphereMapMatrixD3D9._11 = 0.5f; SphereMapMatrixD3D9._12 = 0.0f; @@ -130,7 +131,6 @@ void CD3D9Driver::createMaterialRenderers() MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer); renderer->drop(); - // add parallax map renderers renderer = new CD3D9ParallaxMapRenderer(pID3DDevice, this, tmp, @@ -145,17 +145,15 @@ void CD3D9Driver::createMaterialRenderers() MaterialRenderers[EMT_TRANSPARENT_VERTEX_ALPHA].Renderer); renderer->drop(); - // add basic 1 texture blending addAndDropMaterialRenderer(new CD3D9MaterialRenderer_ONETEXTURE_BLEND(pID3DDevice, this)); - } //! initialises the Direct3D API -bool CD3D9Driver::initDriver(const core::dimension2d& screenSize, +bool CD3D9Driver::initDriver(const core::dimension2d& screenSize, HWND hwnd, u32 bits, bool fullScreen, bool pureSoftware, - bool highPrecisionFPU, bool vsync, bool antiAlias) + bool highPrecisionFPU, bool vsync, u8 antiAlias) { HRESULT hr; Fullscreen = fullScreen; @@ -206,15 +204,16 @@ bool CD3D9Driver::initDriver(const core::dimension2d& screenSize, os::Printer::log(tmp, ELL_INFORMATION); // Assign vendor name based on vendor id. + VendorID= static_cast(dai.VendorId); switch(dai.VendorId) { - case 0x1002 : vendorName = "ATI Technologies Inc."; break; - case 0x10DE : vendorName = "NVIDIA Corporation"; break; - case 0x102B : vendorName = "Matrox Electronic Systems Ltd."; break; - case 0x121A : vendorName = "3dfx Interactive Inc"; break; - case 0x5333 : vendorName = "S3 Graphics Co., Ltd."; break; - case 0x8086 : vendorName = "Intel Corporation"; break; - default: vendorName = "Unknown VendorId: ";vendorName += (u32)dai.VendorId; break; + case 0x1002 : VendorName = "ATI Technologies Inc."; break; + case 0x10DE : VendorName = "NVIDIA Corporation"; break; + case 0x102B : VendorName = "Matrox Electronic Systems Ltd."; break; + case 0x121A : VendorName = "3dfx Interactive Inc"; break; + case 0x5333 : VendorName = "S3 Graphics Co., Ltd."; break; + case 0x8086 : VendorName = "Intel Corporation"; break; + default: VendorName = "Unknown VendorId: ";VendorName += (u32)dai.VendorId; break; } } @@ -251,7 +250,7 @@ bool CD3D9Driver::initDriver(const core::dimension2d& screenSize, else { present.BackBufferFormat = d3ddm.Format; - present.SwapEffect = D3DSWAPEFFECT_COPY; + present.SwapEffect = D3DSWAPEFFECT_DISCARD; present.Windowed = TRUE; } @@ -274,45 +273,33 @@ bool CD3D9Driver::initDriver(const core::dimension2d& screenSize, #endif // enable anti alias if possible and desired - if (antiAlias) + if (antiAlias > 0) { + if(antiAlias > 16) + antiAlias = 16; + DWORD qualityLevels = 0; - if (SUCCEEDED(pID3D->CheckDeviceMultiSampleType(adapter, + while(antiAlias > 0) + { + if(SUCCEEDED(pID3D->CheckDeviceMultiSampleType(adapter, devtype, present.BackBufferFormat, !fullScreen, - D3DMULTISAMPLE_4_SAMPLES, &qualityLevels))) - { - // enable multi sampling - present.MultiSampleType = D3DMULTISAMPLE_4_SAMPLES; - present.MultiSampleQuality = qualityLevels-1; - present.SwapEffect = D3DSWAPEFFECT_DISCARD; + (D3DMULTISAMPLE_TYPE)antiAlias, &qualityLevels))) + { + present.MultiSampleType = (D3DMULTISAMPLE_TYPE)antiAlias; + present.MultiSampleQuality = qualityLevels-1; + present.SwapEffect = D3DSWAPEFFECT_DISCARD; + break; + } + --antiAlias; } - else - if (SUCCEEDED(pID3D->CheckDeviceMultiSampleType(adapter, - devtype, present.BackBufferFormat, !fullScreen, - D3DMULTISAMPLE_2_SAMPLES, &qualityLevels))) - { - // enable multi sampling - present.MultiSampleType = D3DMULTISAMPLE_2_SAMPLES; - present.MultiSampleQuality = qualityLevels-1; - present.SwapEffect = D3DSWAPEFFECT_DISCARD; - } - else - if (SUCCEEDED(pID3D->CheckDeviceMultiSampleType(adapter, - devtype, present.BackBufferFormat, !fullScreen, - D3DMULTISAMPLE_NONMASKABLE, &qualityLevels))) - { - // enable non maskable multi sampling - present.SwapEffect = D3DSWAPEFFECT_DISCARD; - present.MultiSampleType = D3DMULTISAMPLE_NONMASKABLE; - present.MultiSampleQuality = qualityLevels-1; - } - else + + if(antiAlias==0) { os::Printer::log("Anti aliasing disabled because hardware/driver lacks necessary caps.", ELL_WARNING); - antiAlias = false; } } + AntiAliasing = antiAlias; // check stencil buffer compatibility if (StencilBuffer) @@ -420,10 +407,6 @@ bool CD3D9Driver::initDriver(const core::dimension2d& screenSize, // set default vertex shader setVertexShader(EVT_STANDARD); - // enable antialiasing - if (antiAlias) - pID3DDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); - // set fog mode setFog(FogColor, LinearFog, FogStart, FogEnd, FogDensity, PixelFog, RangeFog); @@ -440,15 +423,20 @@ bool CD3D9Driver::initDriver(const core::dimension2d& screenSize, MaxTextureUnits = core::min_((u32)Caps.MaxSimultaneousTextures, MATERIAL_MAX_TEXTURES); MaxUserClipPlanes = (u32)Caps.MaxUserClipPlanes; + if (VendorID==0x10DE)//NVidia + AlphaToCoverageSupport = (pID3D->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, + D3DFMT_X8R8G8B8, 0,D3DRTYPE_SURFACE, + (D3DFORMAT)MAKEFOURCC('A', 'T', 'O', 'C')) == S_OK); + else if (VendorID=0x1002)//ATI + AlphaToCoverageSupport = true; // TODO: Check unknown +#if 0 + AlphaToCoverageSupport = (pID3D->CheckDeviceFormat(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, + D3DFMT_X8R8G8B8, 0,D3DRTYPE_SURFACE, + (D3DFORMAT)MAKEFOURCC('A','2','M','1')) == S_OK); +#endif // set the renderstates setRenderStates3DMode(); - // set maximal anisotropy - pID3DDevice->SetSamplerState(0, D3DSAMP_MAXANISOTROPY, min(16ul, Caps.MaxAnisotropy)); - pID3DDevice->SetSamplerState(1, D3DSAMP_MAXANISOTROPY, min(16ul, Caps.MaxAnisotropy)); - pID3DDevice->SetSamplerState(2, D3DSAMP_MAXANISOTROPY, min(16ul, Caps.MaxAnisotropy)); - pID3DDevice->SetSamplerState(3, D3DSAMP_MAXANISOTROPY, min(16ul, Caps.MaxAnisotropy)); - // store the screen's depth buffer DepthBuffers.push_back(new SDepthSurface()); pID3DDevice->GetDepthStencilSurface(&(DepthBuffers[0]->Surface)); @@ -626,6 +614,8 @@ bool CD3D9Driver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const return (Caps.TextureCaps & D3DPTEXTURECAPS_SQUAREONLY) == 0; case EVDF_TEXTURE_NPOT: return (Caps.TextureCaps & D3DPTEXTURECAPS_POW2) == 0; + case EVDF_COLOR_MASK: + return (Caps.PrimitiveMiscCaps & D3DPMISCCAPS_COLORWRITEENABLE) != 0; default: return false; }; @@ -765,7 +755,7 @@ bool CD3D9Driver::setRenderTarget(video::ITexture* texture, os::Printer::log("Error: Could not set main depth buffer.", ELL_ERROR); } - CurrentRendertargetSize = core::dimension2d(0,0); + CurrentRendertargetSize = core::dimension2d(0,0); PrevRenderTarget->Release(); PrevRenderTarget = 0; } @@ -1244,14 +1234,14 @@ void CD3D9Driver::draw2DImage(const video::ITexture* texture, if(!texture) return; - const core::dimension2d& ss = texture->getOriginalSize(); + const core::dimension2d& ss = texture->getOriginalSize(); core::rect tcoords; tcoords.UpperLeftCorner.X = (f32)sourceRect.UpperLeftCorner.X / (f32)ss.Width; tcoords.UpperLeftCorner.Y = (f32)sourceRect.UpperLeftCorner.Y / (f32)ss.Height; tcoords.LowerRightCorner.X = (f32)sourceRect.LowerRightCorner.X / (f32)ss.Width; tcoords.LowerRightCorner.Y = (f32)sourceRect.LowerRightCorner.Y / (f32)ss.Height; - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); core::rect npos; f32 xFact = 2.0f / ( renderTargetSize.Width ); f32 yFact = 2.0f / ( renderTargetSize.Height ); @@ -1332,6 +1322,7 @@ void CD3D9Driver::draw2DImage(const video::ITexture* texture, core::position2d targetPos = pos; core::position2d sourcePos = sourceRect.UpperLeftCorner; + // This needs to be signed as it may go negative. core::dimension2d sourceSize(sourceRect.getSize()); if (clipRect) @@ -1346,7 +1337,7 @@ void CD3D9Driver::draw2DImage(const video::ITexture* texture, targetPos.X = clipRect->UpperLeftCorner.X; } - if (targetPos.X + sourceSize.Width > clipRect->LowerRightCorner.X) + if (targetPos.X + (s32)sourceSize.Width > clipRect->LowerRightCorner.X) { sourceSize.Width -= (targetPos.X + sourceSize.Width) - clipRect->LowerRightCorner.X; if (sourceSize.Width <= 0) @@ -1363,7 +1354,7 @@ void CD3D9Driver::draw2DImage(const video::ITexture* texture, targetPos.Y = clipRect->UpperLeftCorner.Y; } - if (targetPos.Y + sourceSize.Height > clipRect->LowerRightCorner.Y) + if (targetPos.Y + (s32)sourceSize.Height > clipRect->LowerRightCorner.Y) { sourceSize.Height -= (targetPos.Y + sourceSize.Height) - clipRect->LowerRightCorner.Y; if (sourceSize.Height <= 0) @@ -1383,9 +1374,9 @@ void CD3D9Driver::draw2DImage(const video::ITexture* texture, targetPos.X = 0; } - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); - if (targetPos.X + sourceSize.Width > renderTargetSize.Width) + if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width) { sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; if (sourceSize.Width <= 0) @@ -1402,7 +1393,7 @@ void CD3D9Driver::draw2DImage(const video::ITexture* texture, targetPos.Y = 0; } - if (targetPos.Y + sourceSize.Height > renderTargetSize.Height) + if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height) { sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; if (sourceSize.Height <= 0) @@ -1412,7 +1403,7 @@ void CD3D9Driver::draw2DImage(const video::ITexture* texture, // ok, we've clipped everything. // now draw it. - s32 xPlus = -renderTargetSize.Width / 2; + s32 xPlus = -(s32)(renderTargetSize.Width) / 2; f32 xFact = 2.0f / renderTargetSize.Width; s32 yPlus = renderTargetSize.Height / 2; @@ -1424,7 +1415,7 @@ void CD3D9Driver::draw2DImage(const video::ITexture* texture, tcoords.LowerRightCorner.X = (((f32)sourcePos.X +0.5f + (f32)sourceSize.Width)) / texture->getOriginalSize().Width; tcoords.LowerRightCorner.Y = (((f32)sourcePos.Y +0.5f + (f32)sourceSize.Height)) / texture->getOriginalSize().Height; - core::rect poss(targetPos, sourceSize); + core::rect poss(targetPos, core::dimension2d(sourceSize)); setRenderStates2DMode(color.getAlpha()<255, true, useAlphaChannelOfTexture); @@ -1464,9 +1455,9 @@ void CD3D9Driver::draw2DRectangle(const core::rect& position, if (!pos.isValid()) return; - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); - s32 xPlus = -renderTargetSize.Width / 2; + s32 xPlus = -((s32)renderTargetSize.Width) / 2; f32 xFact = 2.0f / renderTargetSize.Width; s32 yPlus = renderTargetSize.Height / 2; @@ -1508,8 +1499,8 @@ void CD3D9Driver::draw2DLine(const core::position2d& start, { // thanks to Vash TheStampede who sent in his implementation - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); - const s32 xPlus = -renderTargetSize.Width / 2; + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + const s32 xPlus = -((s32)renderTargetSize.Width) / 2; const f32 xFact = 2.0f / renderTargetSize.Width; const s32 yPlus = renderTargetSize.Height / 2; @@ -1542,7 +1533,7 @@ void CD3D9Driver::draw2DLine(const core::position2d& start, //! Draws a pixel void CD3D9Driver::drawPixel(u32 x, u32 y, const SColor & color) { - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); if(x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height) return; @@ -1551,7 +1542,7 @@ void CD3D9Driver::drawPixel(u32 x, u32 y, const SColor & color) setVertexShader(EVT_STANDARD); - const s32 xPlus = -renderTargetSize.Width / 2; + const s32 xPlus = -((s32)renderTargetSize.Width) / 2; const f32 xFact = 2.0f / renderTargetSize.Width; const s32 yPlus = renderTargetSize.Height / 2; const f32 yFact = 2.0f / renderTargetSize.Height; @@ -1704,17 +1695,37 @@ void CD3D9Driver::setBasicRenderStates(const SMaterial& material, const SMateria { switch (material.ZBuffer) { - case 0: - pID3DDevice->SetRenderState(D3DRS_ZENABLE, FALSE); - break; - case 1: - pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); - pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); - break; - case 2: - pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); - pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_EQUAL); - break; + case ECFN_NEVER: + pID3DDevice->SetRenderState(D3DRS_ZENABLE, FALSE); + break; + case ECFN_LESSEQUAL: + pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESSEQUAL); + break; + case ECFN_EQUAL: + pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_EQUAL); + break; + case ECFN_LESS: + pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_LESS); + break; + case ECFN_NOTEQUAL: + pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_NOTEQUAL); + break; + case ECFN_GREATEREQUAL: + pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATEREQUAL); + break; + case ECFN_GREATER: + pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_GREATER); + break; + case ECFN_ALWAYS: + pID3DDevice->SetRenderState(D3DRS_ZENABLE, TRUE); + pID3DDevice->SetRenderState(D3DRS_ZFUNC, D3DCMP_ALWAYS); + break; } } @@ -1763,6 +1774,51 @@ void CD3D9Driver::setBasicRenderStates(const SMaterial& material, const SMateria pID3DDevice->SetRenderState(D3DRS_NORMALIZENORMALS, material.NormalizeNormals); } + // Color Mask + if (queryFeature(EVDF_COLOR_MASK) && + (resetAllRenderstates || lastmaterial.ColorMask != material.ColorMask)) + { + const DWORD flag = + ((material.ColorMask & ECP_RED)?D3DCOLORWRITEENABLE_RED:0) | + ((material.ColorMask & ECP_GREEN)?D3DCOLORWRITEENABLE_GREEN:0) | + ((material.ColorMask & ECP_BLUE)?D3DCOLORWRITEENABLE_BLUE:0) | + ((material.ColorMask & ECP_ALPHA)?D3DCOLORWRITEENABLE_ALPHA:0); + pID3DDevice->SetRenderState(D3DRS_COLORWRITEENABLE, flag); + } + + // Anti Aliasing + if (resetAllRenderstates || lastmaterial.AntiAliasing != material.AntiAliasing) + { + if (AlphaToCoverageSupport && (material.AntiAliasing & EAAM_ALPHA_TO_COVERAGE)) + { + if (VendorID==0x10DE)//NVidia + pID3DDevice->SetRenderState(D3DRS_ADAPTIVETESS_Y, MAKEFOURCC('A','T','O','C')); + // SSAA could give better results on NVidia cards + else if (VendorID==0x1002)//ATI + pID3DDevice->SetRenderState(D3DRS_POINTSIZE, MAKEFOURCC('A','2','M','1')); + } + else if (AlphaToCoverageSupport && (lastmaterial.AntiAliasing & EAAM_ALPHA_TO_COVERAGE)) + { + if (VendorID==0x10DE) + pID3DDevice->SetRenderState(D3DRS_ADAPTIVETESS_Y, D3DFMT_UNKNOWN); + else if (VendorID==0x1002) + pID3DDevice->SetRenderState(D3DRS_POINTSIZE, MAKEFOURCC('A','2','M','0')); + } + + // enable antialiasing + if (AntiAliasing) + { + if (material.AntiAliasing & (EAAM_SIMPLE|EAAM_QUALITY)) + pID3DDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, TRUE); + else if (lastmaterial.AntiAliasing & (EAAM_SIMPLE|EAAM_QUALITY)) + pID3DDevice->SetRenderState(D3DRS_MULTISAMPLEANTIALIAS, FALSE); + if (material.AntiAliasing & (EAAM_LINE_SMOOTH)) + pID3DDevice->SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, TRUE); + else if (lastmaterial.AntiAliasing & (EAAM_LINE_SMOOTH)) + pID3DDevice->SetRenderState(D3DRS_ANTIALIASEDLINEENABLE, FALSE); + } + } + // thickness if (resetAllRenderstates || lastmaterial.Thickness != material.Thickness) { @@ -1772,6 +1828,12 @@ void CD3D9Driver::setBasicRenderStates(const SMaterial& material, const SMateria // texture address mode for (u32 st=0; stSetSamplerState(st, D3DSAMP_MIPMAPLODBIAS, *(DWORD*)(&tmp)); + } + if (resetAllRenderstates || lastmaterial.TextureLayer[st].TextureWrap != material.TextureLayer[st].TextureWrap) { u32 mode = D3DTADDRESS_WRAP; @@ -1810,6 +1872,8 @@ void CD3D9Driver::setBasicRenderStates(const SMaterial& material, const SMateria material.TextureLayer[st].AnisotropicFilter) ? D3DTEXF_ANISOTROPIC : D3DTEXF_LINEAR; D3DTEXTUREFILTERTYPE tftMip = material.TextureLayer[st].TrilinearFilter ? D3DTEXF_LINEAR : D3DTEXF_POINT; + if (tftMag==D3DTEXF_ANISOTROPIC || tftMin == D3DTEXF_ANISOTROPIC) + pID3DDevice->SetSamplerState(st, D3DSAMP_MAXANISOTROPY, core::min_((DWORD)material.TextureLayer[st].AnisotropicFilter, Caps.MaxAnisotropy)); pID3DDevice->SetSamplerState(st, D3DSAMP_MAGFILTER, tftMag); pID3DDevice->SetSamplerState(st, D3DSAMP_MINFILTER, tftMin); pID3DDevice->SetSamplerState(st, D3DSAMP_MIPFILTER, tftMip); @@ -2098,11 +2162,8 @@ void CD3D9Driver::deleteAllDynamicLights() //! adds a dynamic light -void CD3D9Driver::addDynamicLight(const SLight& dl) +s32 CD3D9Driver::addDynamicLight(const SLight& dl) { - if ((u32)LastSetLight == Caps.MaxActiveLights-1) - return; - CNullDriver::addDynamicLight(dl); D3DLIGHT9 light; @@ -2138,8 +2199,26 @@ void CD3D9Driver::addDynamicLight(const SLight& dl) light.Phi = dl.OuterCone * 2.0f * core::DEGTORAD; ++LastSetLight; - pID3DDevice->SetLight(LastSetLight, &light); - pID3DDevice->LightEnable(LastSetLight, true); + + if(D3D_OK == pID3DDevice->SetLight(LastSetLight, &light)) + { + // I don't care if this succeeds + (void)pID3DDevice->LightEnable(LastSetLight, true); + return LastSetLight; + } + + return -1; +} + +//! Turns a dynamic light on or off +//! \param lightIndex: the index returned by addDynamicLight +//! \param turnOn: true to turn the light on, false to turn it off +void CD3D9Driver::turnLightOn(s32 lightIndex, bool turnOn) +{ + if(lightIndex < 0 || lightIndex > LastSetLight) + return; + + (void)pID3DDevice->LightEnable(lightIndex, turnOn); } @@ -2321,6 +2400,9 @@ bool CD3D9Driver::reset() if(DepthBuffers[i]->Surface) DepthBuffers[i]->Surface->Release(); } + // this does not require a restore in the reset method, it's updated + // automatically in the next render cycle. + removeAllHardwareBuffers(); DriverWasReset=true; @@ -2340,7 +2422,7 @@ bool CD3D9Driver::reset() desc.MultiSampleQuality, TRUE, &(DepthBuffers[i]->Surface), - NULL); + NULL); } // restore RTTs @@ -2402,7 +2484,7 @@ bool CD3D9Driver::reset() } -void CD3D9Driver::OnResize(const core::dimension2d& size) +void CD3D9Driver::OnResize(const core::dimension2d& size) { if (!pID3DDevice) return; @@ -2536,7 +2618,7 @@ IVideoDriver* CD3D9Driver::getVideoDriver() //! Creates a render target texture. ITexture* CD3D9Driver::addRenderTargetTexture( - const core::dimension2d& size, + const core::dimension2d& size, const c8* name) { if (!name) @@ -2613,13 +2695,13 @@ IImage* CD3D9Driver::createScreenShot() u8 * sP = (u8 *)lockedRect.pBits; // If the display mode format doesn't promise anything about the Alpha value - // and it appears that it's not presenting 255, then we should manually + // and it appears that it's not presenting 255, then we should manually // set each pixel alpha value to 255. if(D3DFMT_X8R8G8B8 == displayMode.Format && (0xFF000000 != (*dP & 0xFF000000))) { - for (s32 y = 0; y < ScreenSize.Height; ++y) + for (u32 y = 0; y < ScreenSize.Height; ++y) { - for(s32 x = 0; x < ScreenSize.Width; ++x) + for(u32 x = 0; x < ScreenSize.Width; ++x) { *dP = *((u32*)sP) | 0xFF000000; dP++; @@ -2631,7 +2713,7 @@ IImage* CD3D9Driver::createScreenShot() } else { - for (s32 y = 0; y < ScreenSize.Height; ++y) + for (u32 y = 0; y < ScreenSize.Height; ++y) { memcpy(dP, sP, ScreenSize.Width * 4); @@ -2668,7 +2750,7 @@ D3DFORMAT CD3D9Driver::getD3DColorFormat() const // returns the current size of the screen or rendertarget -const core::dimension2d& CD3D9Driver::getCurrentRenderTargetSize() const +const core::dimension2d& CD3D9Driver::getCurrentRenderTargetSize() const { if ( CurrentRendertargetSize.Width == 0 ) return ScreenSize; @@ -2746,11 +2828,11 @@ void CD3D9Driver::checkDepthBuffer(ITexture* tex) { if (!tex) return; - const core::dimension2di optSize = tex->getSize().getOptimalSize( + const core::dimension2du optSize = tex->getSize().getOptimalSize( !queryFeature(EVDF_TEXTURE_NPOT), !queryFeature(EVDF_TEXTURE_NSQUARE), true); SDepthSurface* depth=0; - core::dimension2di destSize(0x7fffffff, 0x7fffffff); + core::dimension2du destSize(0x7fffffff, 0x7fffffff); for (u32 i=0; iSize.Width>=optSize.Width) && @@ -2776,7 +2858,7 @@ void CD3D9Driver::checkDepthBuffer(ITexture* tex) desc.MultiSampleQuality, TRUE, &(DepthBuffers.getLast()->Surface), - NULL); + NULL); if (SUCCEEDED(hr)) { depth=DepthBuffers.getLast(); @@ -2793,7 +2875,7 @@ void CD3D9Driver::checkDepthBuffer(ITexture* tex) char buffer[128]; sprintf(buffer,"Could not create DepthBuffer of %ix%i",destSize.Width,destSize.Height); os::Printer::log(buffer,ELL_ERROR); - } + } DepthBuffers.erase(DepthBuffers.size()-1); } } @@ -2831,10 +2913,10 @@ namespace video #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ //! creates a video driver -IVideoDriver* createDirectX9Driver(const core::dimension2d& screenSize, +IVideoDriver* createDirectX9Driver(const core::dimension2d& screenSize, HWND window, u32 bits, bool fullscreen, bool stencilbuffer, io::IFileSystem* io, bool pureSoftware, bool highPrecisionFPU, - bool vsync, bool antiAlias) + bool vsync, u8 antiAlias) { CD3D9Driver* dx9 = new CD3D9Driver(screenSize, window, fullscreen, stencilbuffer, io, pureSoftware); if (!dx9->initDriver(screenSize, window, bits, fullscreen, pureSoftware, highPrecisionFPU, vsync, antiAlias)) diff --git a/source/Irrlicht/CD3D9Driver.h b/source/Irrlicht/CD3D9Driver.h index 0f9dce57..d77335ca 100644 --- a/source/Irrlicht/CD3D9Driver.h +++ b/source/Irrlicht/CD3D9Driver.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -32,7 +32,7 @@ namespace video } IDirect3DSurface9* Surface; - core::dimension2di Size; + core::dimension2du Size; }; class CD3D9Driver : public CNullDriver, IMaterialRendererServices @@ -40,7 +40,7 @@ namespace video public: //! constructor - CD3D9Driver(const core::dimension2d& screenSize, HWND window, bool fullscreen, + CD3D9Driver(const core::dimension2d& screenSize, HWND window, bool fullscreen, bool stencibuffer, io::IFileSystem* io, bool pureSoftware=false); //! destructor @@ -134,9 +134,9 @@ namespace video const core::vector3df& end, SColor color = SColor(255,255,255,255)); //! initialises the Direct3D API - bool initDriver(const core::dimension2d& screenSize, HWND hwnd, + bool initDriver(const core::dimension2d& screenSize, HWND hwnd, u32 bits, bool fullScreen, bool pureSoftware, - bool highPrecisionFPU, bool vsync, bool antiAlias); + bool highPrecisionFPU, bool vsync, u8 antiAlias); //! \return Returns the name of the video driver. Example: In case of the DIRECT3D8 //! driver, it would return "Direct3D8.1". @@ -145,8 +145,15 @@ namespace video //! deletes all dynamic lights there are virtual void deleteAllDynamicLights(); - //! adds a dynamic light - virtual void addDynamicLight(const SLight& light); + //! adds a dynamic light, returning an index to the light + //! \param light: the light data to use to create the light + //! \return An index to the light, or -1 if an error occurs + virtual s32 addDynamicLight(const SLight& light); + + //! Turns a dynamic light on or off + //! \param lightIndex: the index returned by addDynamicLight + //! \param turnOn: true to turn the light on, false to turn it off + virtual void turnLightOn(s32 lightIndex, bool turnOn); //! returns the maximal amount of dynamic lights the device can handle virtual u32 getMaximalDynamicLightAmount() const; @@ -180,7 +187,7 @@ namespace video //! Only used by the internal engine. Used to notify the driver that //! the window was resized. - virtual void OnResize(const core::dimension2d& size); + virtual void OnResize(const core::dimension2d& size); //! Can be called by an IMaterialRenderer to make its work easier. virtual void setBasicRenderStates(const SMaterial& material, const SMaterial& lastMaterial, @@ -212,7 +219,7 @@ namespace video virtual IVideoDriver* getVideoDriver(); //! Creates a render target texture. - virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, const c8* name); //! Clears the ZBuffer. @@ -228,7 +235,7 @@ namespace video virtual void enableClipPlane(u32 index, bool enable); //! Returns the graphics card vendor name. - virtual core::stringc getVendorInfo() {return vendorName;} + virtual core::stringc getVendorInfo() {return VendorName;} //! Check if the driver was recently reset. virtual bool checkDriverReset() {return DriverWasReset;} @@ -289,11 +296,11 @@ namespace video virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const char* name); //! returns the current size of the screen or rendertarget - virtual const core::dimension2d& getCurrentRenderTargetSize() const; + virtual const core::dimension2d& getCurrentRenderTargetSize() const; //! Check if a proper depth buffer for the RTT is available, otherwise create it. void checkDepthBuffer(ITexture* tex); - + //! Adds a new material renderer to the VideoDriver, using pixel and/or //! vertex shaders to render geometry. s32 addShaderMaterial(const c8* vertexShaderProgram, const c8* pixelShaderProgram, @@ -333,6 +340,7 @@ namespace video bool ResetRenderStates; // bool to make all renderstates be reseted if set. bool Transformation3DChanged; bool StencilBuffer; + u8 AntiAliasing; const ITexture* CurrentTexture[MATERIAL_MAX_TEXTURES]; bool LastTextureMipMapsAvailable[MATERIAL_MAX_TEXTURES]; core::matrix4 Matrices[ETS_COUNT]; // matrizes of the 3d mode we need to restore when we switch back from the 2d mode. @@ -342,8 +350,8 @@ namespace video IDirect3DDevice9* pID3DDevice; IDirect3DSurface9* PrevRenderTarget; - core::dimension2d CurrentRendertargetSize; - core::dimension2d CurrentDepthBufferSize; + core::dimension2d CurrentRendertargetSize; + core::dimension2d CurrentDepthBufferSize; void* WindowId; core::rect* SceneSourceRect; @@ -354,7 +362,8 @@ namespace video SColorf AmbientLight; - core::stringc vendorName; + core::stringc VendorName; + u16 VendorID; core::array DepthBuffers; @@ -368,6 +377,7 @@ namespace video bool DeviceLost; bool Fullscreen; bool DriverWasReset; + bool AlphaToCoverageSupport; }; diff --git a/source/Irrlicht/CD3D9HLSLMaterialRenderer.cpp b/source/Irrlicht/CD3D9HLSLMaterialRenderer.cpp index 46cdeafc..0d5bc202 100644 --- a/source/Irrlicht/CD3D9HLSLMaterialRenderer.cpp +++ b/source/Irrlicht/CD3D9HLSLMaterialRenderer.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -18,20 +18,20 @@ namespace irr { -namespace video +namespace video { //! Public constructor CD3D9HLSLMaterialRenderer::CD3D9HLSLMaterialRenderer(IDirect3DDevice9* d3ddev, - video::IVideoDriver* driver, s32& outMaterialTypeNr, + video::IVideoDriver* driver, s32& outMaterialTypeNr, const c8* vertexShaderProgram, const c8* vertexShaderEntryPointName, E_VERTEX_SHADER_TYPE vsCompileTarget, - const c8* pixelShaderProgram, + const c8* pixelShaderProgram, const c8* pixelShaderEntryPointName, E_PIXEL_SHADER_TYPE psCompileTarget, - IShaderConstantSetCallBack* callback, + IShaderConstantSetCallBack* callback, IMaterialRenderer* baseMaterial, s32 userData) : CD3D9ShaderMaterialRenderer(d3ddev, driver, callback, baseMaterial, userData), @@ -52,11 +52,11 @@ CD3D9HLSLMaterialRenderer::CD3D9HLSLMaterialRenderer(IDirect3DDevice9* d3ddev, return; } - if (!createHLSLVertexShader(vertexShaderProgram, + if (!createHLSLVertexShader(vertexShaderProgram, vertexShaderEntryPointName, VERTEX_SHADER_TYPE_NAMES[vsCompileTarget])) return; - if (!createHLSLPixelShader(pixelShaderProgram, + if (!createHLSLPixelShader(pixelShaderProgram, pixelShaderEntryPointName, PIXEL_SHADER_TYPE_NAMES[psCompileTarget])) return; @@ -64,7 +64,8 @@ CD3D9HLSLMaterialRenderer::CD3D9HLSLMaterialRenderer(IDirect3DDevice9* d3ddev, outMaterialTypeNr = Driver->addMaterialRenderer(this); } - //! Destructor + +//! Destructor CD3D9HLSLMaterialRenderer::~CD3D9HLSLMaterialRenderer() { if (VSConstantsTable) @@ -76,8 +77,8 @@ CD3D9HLSLMaterialRenderer::~CD3D9HLSLMaterialRenderer() bool CD3D9HLSLMaterialRenderer::createHLSLVertexShader(const char* vertexShaderProgram, - const char* shaderEntryPointName, - const char* shaderTargetName) + const char* shaderEntryPointName, + const char* shaderTargetName) { if (!vertexShaderProgram) return true; @@ -85,49 +86,48 @@ bool CD3D9HLSLMaterialRenderer::createHLSLVertexShader(const char* vertexShaderP LPD3DXBUFFER buffer = 0; LPD3DXBUFFER errors = 0; - #ifdef _IRR_D3D_NO_SHADER_DEBUGGING +#ifdef _IRR_D3D_NO_SHADER_DEBUGGING - // compile without debug info - - HRESULT h = stubD3DXCompileShader( - vertexShaderProgram, - strlen(vertexShaderProgram), - 0, // macros - 0, // no includes - shaderEntryPointName, - shaderTargetName, - 0, // no flags - &buffer, - &errors, - &VSConstantsTable); + // compile without debug info + HRESULT h = stubD3DXCompileShader( + vertexShaderProgram, + strlen(vertexShaderProgram), + 0, // macros + 0, // no includes + shaderEntryPointName, + shaderTargetName, + 0, // no flags + &buffer, + &errors, + &VSConstantsTable); - #else +#else - // compile shader and emitt some debug informations to - // make it possible to debug the shader in visual studio + // compile shader and emitt some debug informations to + // make it possible to debug the shader in visual studio - static int irr_dbg_hlsl_file_nr = 0; - ++irr_dbg_hlsl_file_nr; - char tmp[32]; - sprintf(tmp, "irr_d3d9_dbg_hlsl_%d.vsh", irr_dbg_hlsl_file_nr); + static int irr_dbg_hlsl_file_nr = 0; + ++irr_dbg_hlsl_file_nr; + char tmp[32]; + sprintf(tmp, "irr_d3d9_dbg_hlsl_%d.vsh", irr_dbg_hlsl_file_nr); - FILE* f = fopen(tmp, "wb"); - fwrite(vertexShaderProgram, strlen(vertexShaderProgram), 1, f); - fflush(f); - fclose(f); + FILE* f = fopen(tmp, "wb"); + fwrite(vertexShaderProgram, strlen(vertexShaderProgram), 1, f); + fflush(f); + fclose(f); - HRESULT h = stubD3DXCompileShaderFromFile( - tmp, - 0, // macros - 0, // no includes - shaderEntryPointName, - shaderTargetName, - D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION, - &buffer, - &errors, - &VSConstantsTable); + HRESULT h = stubD3DXCompileShaderFromFile( + tmp, + 0, // macros + 0, // no includes + shaderEntryPointName, + shaderTargetName, + D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION, + &buffer, + &errors, + &VSConstantsTable); - #endif +#endif if (FAILED(h)) { @@ -163,7 +163,7 @@ bool CD3D9HLSLMaterialRenderer::createHLSLVertexShader(const char* vertexShaderP } -bool CD3D9HLSLMaterialRenderer::createHLSLPixelShader(const char* pixelShaderProgram, +bool CD3D9HLSLMaterialRenderer::createHLSLPixelShader(const char* pixelShaderProgram, const char* shaderEntryPointName, const char* shaderTargetName) { @@ -172,10 +172,13 @@ bool CD3D9HLSLMaterialRenderer::createHLSLPixelShader(const char* pixelShaderPro LPD3DXBUFFER buffer = 0; LPD3DXBUFFER errors = 0; - + +#ifdef _IRR_D3D_NO_SHADER_DEBUGGING + + // compile without debug info HRESULT h = stubD3DXCompileShader( pixelShaderProgram, - strlen(pixelShaderProgram), + strlen(pixelShaderProgram), 0, // macros 0, // no includes shaderEntryPointName, @@ -185,6 +188,34 @@ bool CD3D9HLSLMaterialRenderer::createHLSLPixelShader(const char* pixelShaderPro &errors, &PSConstantsTable); +#else + + // compile shader and emitt some debug informations to + // make it possible to debug the shader in visual studio + + static int irr_dbg_hlsl_file_nr = 0; + ++irr_dbg_hlsl_file_nr; + char tmp[32]; + sprintf(tmp, "irr_d3d9_dbg_hlsl_%d.psh", irr_dbg_hlsl_file_nr); + + FILE* f = fopen(tmp, "wb"); + fwrite(pixelShaderProgram, strlen(pixelShaderProgram), 1, f); + fflush(f); + fclose(f); + + HRESULT h = stubD3DXCompileShaderFromFile( + tmp, + 0, // macros + 0, // no includes + shaderEntryPointName, + shaderTargetName, + D3DXSHADER_DEBUG | D3DXSHADER_SKIPOPTIMIZATION, + &buffer, + &errors, + &PSConstantsTable); + +#endif + if (FAILED(h)) { os::Printer::log("HLSL pixel shader compilation failed:"); @@ -219,14 +250,14 @@ bool CD3D9HLSLMaterialRenderer::createHLSLPixelShader(const char* pixelShaderPro } -bool CD3D9HLSLMaterialRenderer::setVariable(bool vertexShader, const c8* name, - const f32* floats, int count) +bool CD3D9HLSLMaterialRenderer::setVariable(bool vertexShader, const c8* name, + const f32* floats, int count) { LPD3DXCONSTANTTABLE tbl = vertexShader ? VSConstantsTable : PSConstantsTable; if (!tbl) return false; - // currently we only support top level parameters. + // currently we only support top level parameters. // Should be enough for the beginning. (TODO) D3DXHANDLE hndl = tbl->GetConstantByName(NULL, name); @@ -250,6 +281,7 @@ bool CD3D9HLSLMaterialRenderer::setVariable(bool vertexShader, const c8* name, return true; } + bool CD3D9HLSLMaterialRenderer::OnRender(IMaterialRendererServices* service, E_VERTEX_TYPE vtxtype) { if (VSConstantsTable) @@ -258,9 +290,10 @@ bool CD3D9HLSLMaterialRenderer::OnRender(IMaterialRendererServices* service, E_V return CD3D9ShaderMaterialRenderer::OnRender(service, vtxtype); } + void CD3D9HLSLMaterialRenderer::printHLSLVariables(LPD3DXCONSTANTTABLE table) { - // currently we only support top level parameters. + // currently we only support top level parameters. // Should be enough for the beginning. (TODO) // print out constant names @@ -268,7 +301,7 @@ void CD3D9HLSLMaterialRenderer::printHLSLVariables(LPD3DXCONSTANTTABLE table) HRESULT hr = table->GetDesc(&tblDesc); if (!FAILED(hr)) { - for (int i=0; i<(int)tblDesc.Constants; ++i) + for (int i=0; i<(int)tblDesc.Constants; ++i) { D3DXCONSTANT_DESC d; UINT n = 1; diff --git a/source/Irrlicht/CD3D9HLSLMaterialRenderer.h b/source/Irrlicht/CD3D9HLSLMaterialRenderer.h index ed63b097..91744739 100644 --- a/source/Irrlicht/CD3D9HLSLMaterialRenderer.h +++ b/source/Irrlicht/CD3D9HLSLMaterialRenderer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CD3D9MaterialRenderer.h b/source/Irrlicht/CD3D9MaterialRenderer.h index 4ffe9522..ca65eb38 100644 --- a/source/Irrlicht/CD3D9MaterialRenderer.h +++ b/source/Irrlicht/CD3D9MaterialRenderer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -365,7 +365,8 @@ public: pID3DDevice->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE); - pID3DDevice->SetRenderState(D3DRS_ALPHAREF, core::floor32(material.MaterialTypeParam * 255)); + // 127 is required by EMT_TRANSPARENT_ALPHA_CHANNEL_REF + pID3DDevice->SetRenderState(D3DRS_ALPHAREF, 127); pID3DDevice->SetRenderState(D3DRS_ALPHAFUNC, D3DCMP_GREATEREQUAL); pID3DDevice->SetRenderState(D3DRS_ALPHATESTENABLE, TRUE); } diff --git a/source/Irrlicht/CD3D9NormalMapRenderer.cpp b/source/Irrlicht/CD3D9NormalMapRenderer.cpp index 3565aeeb..c175d931 100644 --- a/source/Irrlicht/CD3D9NormalMapRenderer.cpp +++ b/source/Irrlicht/CD3D9NormalMapRenderer.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CD3D9NormalMapRenderer.h b/source/Irrlicht/CD3D9NormalMapRenderer.h index f67f6fd6..7f9f88b8 100644 --- a/source/Irrlicht/CD3D9NormalMapRenderer.h +++ b/source/Irrlicht/CD3D9NormalMapRenderer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CD3D9ParallaxMapRenderer.cpp b/source/Irrlicht/CD3D9ParallaxMapRenderer.cpp index 2e216be2..e4920d29 100644 --- a/source/Irrlicht/CD3D9ParallaxMapRenderer.cpp +++ b/source/Irrlicht/CD3D9ParallaxMapRenderer.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CD3D9ParallaxMapRenderer.h b/source/Irrlicht/CD3D9ParallaxMapRenderer.h index 1074ca78..54719e7f 100644 --- a/source/Irrlicht/CD3D9ParallaxMapRenderer.h +++ b/source/Irrlicht/CD3D9ParallaxMapRenderer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CD3D9ShaderMaterialRenderer.cpp b/source/Irrlicht/CD3D9ShaderMaterialRenderer.cpp index 03cf69ab..89127b92 100644 --- a/source/Irrlicht/CD3D9ShaderMaterialRenderer.cpp +++ b/source/Irrlicht/CD3D9ShaderMaterialRenderer.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CD3D9ShaderMaterialRenderer.h b/source/Irrlicht/CD3D9ShaderMaterialRenderer.h index 621d82a3..b035eb64 100644 --- a/source/Irrlicht/CD3D9ShaderMaterialRenderer.h +++ b/source/Irrlicht/CD3D9ShaderMaterialRenderer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CD3D9Texture.cpp b/source/Irrlicht/CD3D9Texture.cpp index dea1753d..ec7bb45e 100644 --- a/source/Irrlicht/CD3D9Texture.cpp +++ b/source/Irrlicht/CD3D9Texture.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -30,7 +30,7 @@ namespace video { //! rendertarget constructor -CD3D9Texture::CD3D9Texture(CD3D9Driver* driver, const core::dimension2d& size, const char* name) +CD3D9Texture::CD3D9Texture(CD3D9Driver* driver, const core::dimension2d& size, const char* name) : ITexture(name), Texture(0), RTTSurface(0), Driver(driver), DepthSurface(0), TextureSize(size), ImageSize(size), Pitch(0), HasMipMaps(false), HardwareMipMaps(false), IsRenderTarget(true) @@ -258,7 +258,7 @@ bool CD3D9Texture::createMipMaps(u32 level) //! creates the hardware texture bool CD3D9Texture::createTexture(u32 flags, IImage * image) { - core::dimension2d optSize; + core::dimension2d optSize; ImageSize = image->getDimension(); if (Driver->queryFeature(EVDF_TEXTURE_NPOT)) @@ -456,14 +456,14 @@ void CD3D9Texture::unlock() //! Returns original size of the texture. -const core::dimension2d& CD3D9Texture::getOriginalSize() const +const core::dimension2d& CD3D9Texture::getOriginalSize() const { return ImageSize; } //! Returns (=size) of the texture. -const core::dimension2d& CD3D9Texture::getSize() const +const core::dimension2d& CD3D9Texture::getSize() const { return TextureSize; } diff --git a/source/Irrlicht/CD3D9Texture.h b/source/Irrlicht/CD3D9Texture.h index 3a64a760..ca93389a 100644 --- a/source/Irrlicht/CD3D9Texture.h +++ b/source/Irrlicht/CD3D9Texture.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -32,7 +32,7 @@ public: u32 flags, const char* name); //! rendertarget constructor - CD3D9Texture(CD3D9Driver* driver, const core::dimension2d& size, const char* name); + CD3D9Texture(CD3D9Driver* driver, const core::dimension2d& size, const char* name); //! destructor virtual ~CD3D9Texture(); @@ -44,10 +44,10 @@ public: virtual void unlock(); //! Returns original size of the texture. - virtual const core::dimension2d& getOriginalSize() const; + virtual const core::dimension2d& getOriginalSize() const; //! Returns (=size) of the texture. - virtual const core::dimension2d& getSize() const; + virtual const core::dimension2d& getSize() const; //! returns driver type of texture (=the driver, who created the texture) virtual E_DRIVER_TYPE getDriverType() const; @@ -107,8 +107,8 @@ private: IDirect3DSurface9* RTTSurface; CD3D9Driver* Driver; SDepthSurface* DepthSurface; - core::dimension2d TextureSize; - core::dimension2d ImageSize; + core::dimension2d TextureSize; + core::dimension2d ImageSize; s32 Pitch; ECOLOR_FORMAT ColorFormat; diff --git a/source/Irrlicht/CDMFLoader.cpp b/source/Irrlicht/CDMFLoader.cpp index dc4147be..c95b5095 100644 --- a/source/Irrlicht/CDMFLoader.cpp +++ b/source/Irrlicht/CDMFLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // @@ -13,7 +13,7 @@ See the header file for additional information including use and distribution rights. */ -#include "IrrCompileConfig.h" +#include "IrrCompileConfig.h" #ifdef _IRR_COMPILE_WITH_DMF_LOADER_ #ifdef _DEBUG @@ -219,7 +219,7 @@ IAnimatedMesh* CDMFLoader::createMesh(io::IReadFile* file) driver->setTextureCreationFlag(ETCF_ALWAYS_32_BIT,true); CImage *immagine= new CImage(ECF_A8R8G8B8, - core::dimension2d(8,8)); + core::dimension2d(8,8)); immagine->fill(color); tex = driver->addTexture("", immagine); immagine->drop(); @@ -252,7 +252,7 @@ IAnimatedMesh* CDMFLoader::createMesh(io::IReadFile* file) //if texture is present mirror vertically owing to DeleD representation if (tex && header.dmfVersion<1.1) { - const core::dimension2d texsize = tex->getSize(); + const core::dimension2d texsize = tex->getSize(); void* pp = tex->lock(); if (pp) { @@ -261,8 +261,8 @@ IAnimatedMesh* CDMFLoader::createMesh(io::IReadFile* file) { s16* p = (s16*)pp; s16 tmp=0; - for (s32 x=0; x ligsize=lig->getSize(); + const core::dimension2d ligsize=lig->getSize(); void* pp = lig->lock(); if (pp) { @@ -299,9 +299,9 @@ IAnimatedMesh* CDMFLoader::createMesh(io::IReadFile* file) { s16* p = (s16*)pp; s16 tmp=0; - for (s32 x=0; x& size) +CDepthBuffer::CDepthBuffer(const core::dimension2d& size) : Buffer(0), Size(0,0) { #ifdef _DEBUG @@ -55,7 +55,7 @@ void CDepthBuffer::clear() //! sets the new size of the zbuffer -void CDepthBuffer::setSize(const core::dimension2d& size) +void CDepthBuffer::setSize(const core::dimension2d& size) { if (size == Size) return; @@ -73,7 +73,7 @@ void CDepthBuffer::setSize(const core::dimension2d& size) //! returns the size of the zbuffer -const core::dimension2d& CDepthBuffer::getSize() const +const core::dimension2d& CDepthBuffer::getSize() const { return Size; } @@ -91,7 +91,7 @@ namespace video { //! creates a ZBuffer -IDepthBuffer* createDepthBuffer(const core::dimension2d& size) +IDepthBuffer* createDepthBuffer(const core::dimension2d& size) { #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ return new CDepthBuffer(size); @@ -99,7 +99,7 @@ IDepthBuffer* createDepthBuffer(const core::dimension2d& size) return 0; #endif // _IRR_COMPILE_WITH_BURNINGSVIDEO_ } - + } // end namespace video } // end namespace irr diff --git a/source/Irrlicht/CDepthBuffer.h b/source/Irrlicht/CDepthBuffer.h index 951ea3db..258a61c2 100644 --- a/source/Irrlicht/CDepthBuffer.h +++ b/source/Irrlicht/CDepthBuffer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -17,7 +17,7 @@ namespace video public: //! constructor - CDepthBuffer(const core::dimension2d& size); + CDepthBuffer(const core::dimension2d& size); //! destructor virtual ~CDepthBuffer(); @@ -26,10 +26,10 @@ namespace video virtual void clear(); //! sets the new size of the zbuffer - virtual void setSize(const core::dimension2d& size); + virtual void setSize(const core::dimension2d& size); //! returns the size of the zbuffer - virtual const core::dimension2d& getSize() const; + virtual const core::dimension2d& getSize() const; //! locks the zbuffer virtual void* lock() @@ -52,11 +52,11 @@ namespace video private: u8* Buffer; - core::dimension2d Size; + core::dimension2d Size; u32 TotalSize; u32 Pitch; }; - + } // end namespace video } // end namespace irr diff --git a/source/Irrlicht/CDummyTransformationSceneNode.cpp b/source/Irrlicht/CDummyTransformationSceneNode.cpp index cfca942b..64cb1799 100644 --- a/source/Irrlicht/CDummyTransformationSceneNode.cpp +++ b/source/Irrlicht/CDummyTransformationSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CDummyTransformationSceneNode.h b/source/Irrlicht/CDummyTransformationSceneNode.h index 42103e03..379a4857 100644 --- a/source/Irrlicht/CDummyTransformationSceneNode.h +++ b/source/Irrlicht/CDummyTransformationSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CEmptySceneNode.cpp b/source/Irrlicht/CEmptySceneNode.cpp index 23d02714..473425f9 100644 --- a/source/Irrlicht/CEmptySceneNode.cpp +++ b/source/Irrlicht/CEmptySceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CEmptySceneNode.h b/source/Irrlicht/CEmptySceneNode.h index 87729a64..9f5c33b0 100644 --- a/source/Irrlicht/CEmptySceneNode.h +++ b/source/Irrlicht/CEmptySceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CFPSCounter.cpp b/source/Irrlicht/CFPSCounter.cpp index 21e4bb26..2466f75c 100644 --- a/source/Irrlicht/CFPSCounter.cpp +++ b/source/Irrlicht/CFPSCounter.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CFPSCounter.h b/source/Irrlicht/CFPSCounter.h index 19f71a78..358ee6df 100644 --- a/source/Irrlicht/CFPSCounter.h +++ b/source/Irrlicht/CFPSCounter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CFileList.cpp b/source/Irrlicht/CFileList.cpp index cf1fc8aa..7fee16e4 100644 --- a/source/Irrlicht/CFileList.cpp +++ b/source/Irrlicht/CFileList.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CFileList.h b/source/Irrlicht/CFileList.h index 1ba11955..1940ecb3 100644 --- a/source/Irrlicht/CFileList.h +++ b/source/Irrlicht/CFileList.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CFileSystem.cpp b/source/Irrlicht/CFileSystem.cpp index 52899db6..495b0363 100644 --- a/source/Irrlicht/CFileSystem.cpp +++ b/source/Irrlicht/CFileSystem.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -14,7 +14,7 @@ #include "os.h" #include "IrrCompileConfig.h" #include "CAttributes.h" -#include "CMemoryReadFile.h" +#include "CMemoryFile.h" #if defined (_IRR_WINDOWS_API_) #if !defined ( _WIN32_WCE ) @@ -97,7 +97,17 @@ IReadFile* CFileSystem::createMemoryReadFile(void* memory, s32 len, if (!memory) return 0; else - return new CMemoryReadFile(memory, len, fileName, deleteMemoryWhenDropped); + return new CMemoryFile(memory, len, fileName, deleteMemoryWhenDropped); +} + +//! Creates an IReadFile interface for treating memory like a file. +IWriteFile* CFileSystem::createMemoryWriteFile(void* memory, s32 len, + const c8* fileName, bool deleteMemoryWhenDropped) +{ + if (!memory) + return 0; + else + return new CMemoryFile(memory, len, fileName, deleteMemoryWhenDropped); } diff --git a/source/Irrlicht/CFileSystem.h b/source/Irrlicht/CFileSystem.h index 467d9dc4..645b2259 100644 --- a/source/Irrlicht/CFileSystem.h +++ b/source/Irrlicht/CFileSystem.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -37,6 +37,9 @@ public: //! Creates an IReadFile interface for accessing memory like a file. virtual IReadFile* createMemoryReadFile(void* memory, s32 len, const c8* fileName, bool deleteMemoryWhenDropped = false); + //! Creates an IWriteFile interface for accessing memory like a file. + virtual IWriteFile* createMemoryWriteFile(void* memory, s32 len, const c8* fileName, bool deleteMemoryWhenDropped=false); + //! Opens a file for write access. virtual IWriteFile* createAndWriteFile(const c8* filename, bool append=false); diff --git a/source/Irrlicht/CGUIButton.cpp b/source/Irrlicht/CGUIButton.cpp index b4aedf4d..798504b6 100644 --- a/source/Irrlicht/CGUIButton.cpp +++ b/source/Irrlicht/CGUIButton.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -18,7 +18,7 @@ namespace gui //! constructor CGUIButton::CGUIButton(IGUIEnvironment* environment, IGUIElement* parent, - s32 id, core::rect rectangle, bool noclip) + s32 id, core::rect rectangle, bool noclip) : IGUIButton(environment, parent, id, rectangle), Pressed(false), IsPushButton(false), UseAlphaChannel(false), Border(true), ClickTime(0), SpriteBank(0), OverrideFont(0), Image(0), PressedImage(0) @@ -99,8 +99,7 @@ bool CGUIButton::OnEvent(const SEvent& event) { case EET_KEY_INPUT_EVENT: if (event.KeyInput.PressedDown && - (event.KeyInput.Key == KEY_RETURN || - event.KeyInput.Key == KEY_SPACE)) + (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE)) { if (!IsPushButton) setPressed(true); @@ -116,14 +115,13 @@ bool CGUIButton::OnEvent(const SEvent& event) } else if (!event.KeyInput.PressedDown && Pressed && - (event.KeyInput.Key == KEY_RETURN || - event.KeyInput.Key == KEY_SPACE)) + (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE)) { //Environment->removeFocus(this); if (!IsPushButton) setPressed(false); - + if (Parent) { SEvent newEvent; @@ -147,7 +145,7 @@ bool CGUIButton::OnEvent(const SEvent& event) if (event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) { if (Environment->hasFocus(this) && - !AbsoluteClippingRect.isPointInside(core::position2d(event.MouseInput.X, event.MouseInput.Y))) + !AbsoluteClippingRect.isPointInside(core::position2d(event.MouseInput.X, event.MouseInput.Y))) { Environment->removeFocus(this); return false; @@ -155,7 +153,7 @@ bool CGUIButton::OnEvent(const SEvent& event) if (!IsPushButton) setPressed(true); - + Environment->setFocus(this); return true; } @@ -178,7 +176,7 @@ bool CGUIButton::OnEvent(const SEvent& event) { setPressed(!Pressed); } - + if ((!IsPushButton && wasPressed && Parent) || (IsPushButton && wasPressed != Pressed)) { @@ -217,7 +215,7 @@ void CGUIButton::draw() core::rect rect = AbsoluteRect; // todo: move sprite up and text down if the pressed state has a sprite - // draw sprites for focused and mouse-over + // draw sprites for focused and mouse-over core::position2di spritePos = AbsoluteRect.getCenter(); if (!Pressed) @@ -231,14 +229,14 @@ void CGUIButton::draw() pos.X -= ImageRect.getWidth() / 2; pos.Y -= ImageRect.getHeight() / 2; - driver->draw2DImage(Image, pos, ImageRect, &AbsoluteClippingRect, + driver->draw2DImage(Image, pos, ImageRect, &AbsoluteClippingRect, video::SColor(255,255,255,255), UseAlphaChannel); } if (SpriteBank && ButtonSprites[EGBS_BUTTON_UP].Index != -1) { // draw pressed sprite - SpriteBank->draw2DSprite(ButtonSprites[EGBS_BUTTON_UP].Index, spritePos, - &AbsoluteClippingRect, ButtonSprites[EGBS_BUTTON_UP].Color, ClickTime, os::Timer::getTime(), + SpriteBank->draw2DSprite(ButtonSprites[EGBS_BUTTON_UP].Index, spritePos, + &AbsoluteClippingRect, ButtonSprites[EGBS_BUTTON_UP].Color, ClickTime, os::Timer::getTime(), ButtonSprites[EGBS_BUTTON_UP].Loop, true); } } @@ -265,8 +263,8 @@ void CGUIButton::draw() if (SpriteBank && ButtonSprites[EGBS_BUTTON_DOWN].Index != -1) { // draw sprite - SpriteBank->draw2DSprite(ButtonSprites[EGBS_BUTTON_DOWN].Index, spritePos, - &AbsoluteClippingRect, ButtonSprites[EGBS_BUTTON_DOWN].Color, ClickTime, os::Timer::getTime(), + SpriteBank->draw2DSprite(ButtonSprites[EGBS_BUTTON_DOWN].Index, spritePos, + &AbsoluteClippingRect, ButtonSprites[EGBS_BUTTON_DOWN].Color, ClickTime, os::Timer::getTime(), ButtonSprites[EGBS_BUTTON_DOWN].Loop, true); } @@ -280,7 +278,7 @@ void CGUIButton::draw() if (font) font->draw(Text.c_str(), rect, - skin->getColor(IsEnabled ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT), true, true, + skin->getColor(IsEnabled ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT), true, true, &AbsoluteClippingRect); } @@ -291,6 +289,9 @@ void CGUIButton::draw() //! sets another skin independent font. if this is set to zero, the button uses the font of the skin. void CGUIButton::setOverrideFont(IGUIFont* font) { + if (OverrideFont == font) + return; + if (OverrideFont) OverrideFont->drop(); @@ -301,7 +302,7 @@ void CGUIButton::setOverrideFont(IGUIFont* font) } -//! Sets an image which should be displayed on the button when it is in normal state. +//! Sets an image which should be displayed on the button when it is in normal state. void CGUIButton::setImage(video::ITexture* image) { if (Image) @@ -309,7 +310,10 @@ void CGUIButton::setImage(video::ITexture* image) Image = image; if (image) - ImageRect = core::rect(core::position2d(0,0), image->getOriginalSize()); + { + core::dimension2di signedSize(image->getOriginalSize()); + ImageRect = core::rect(core::position2d(0,0), signedSize); + } if (Image) Image->grab(); @@ -336,7 +340,7 @@ void CGUIButton::setImage(video::ITexture* image, const core::rect& pos) } -//! Sets an image which should be displayed on the button when it is in pressed state. +//! Sets an image which should be displayed on the button when it is in pressed state. void CGUIButton::setPressedImage(video::ITexture* image) { if (PressedImage) @@ -344,7 +348,10 @@ void CGUIButton::setPressedImage(video::ITexture* image) PressedImage = image; if (image) - PressedImageRect = core::rect(core::position2d(0,0), image->getOriginalSize()); + { + core::dimension2di signedSize(image->getOriginalSize()); + PressedImageRect = core::rect(core::position2d(0,0), signedSize); + } if (PressedImage) PressedImage->grab(); diff --git a/source/Irrlicht/CGUIButton.h b/source/Irrlicht/CGUIButton.h index f38f31ea..5b7530e6 100644 --- a/source/Irrlicht/CGUIButton.h +++ b/source/Irrlicht/CGUIButton.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -37,16 +37,16 @@ namespace gui //! sets another skin independent font. if this is set to zero, the button uses the font of the skin. virtual void setOverrideFont(IGUIFont* font=0); - //! Sets an image which should be displayed on the button when it is in normal state. + //! Sets an image which should be displayed on the button when it is in normal state. virtual void setImage(video::ITexture* image); - //! Sets an image which should be displayed on the button when it is in normal state. + //! Sets an image which should be displayed on the button when it is in normal state. virtual void setImage(video::ITexture* image, const core::rect& pos); - //! Sets an image which should be displayed on the button when it is in pressed state. + //! Sets an image which should be displayed on the button when it is in pressed state. virtual void setPressedImage(video::ITexture* image); - //! Sets an image which should be displayed on the button when it is in pressed state. + //! Sets an image which should be displayed on the button when it is in pressed state. virtual void setPressedImage(video::ITexture* image, const core::rect& pos); //! Sets the sprite bank used by the button @@ -58,7 +58,7 @@ namespace gui \param index: The sprite number from the current sprite bank \param color: The color of the sprite */ - virtual void setSprite(EGUI_BUTTON_STATE state, s32 index, + virtual void setSprite(EGUI_BUTTON_STATE state, s32 index, video::SColor color=video::SColor(255,255,255,255), bool loop=false); //! Sets if the button should behave like a push button. Which means it @@ -74,7 +74,7 @@ namespace gui //! Sets if the button should use the skin to draw its border virtual void setDrawBorder(bool border); - + //! Sets if the alpha channel should be used for drawing images on the button (default is false) virtual void setUseAlphaChannel(bool useAlphaChannel); @@ -105,7 +105,6 @@ namespace gui bool Pressed; bool IsPushButton; bool UseAlphaChannel; - bool Border; u32 ClickTime; diff --git a/source/Irrlicht/CGUICheckBox.cpp b/source/Irrlicht/CGUICheckBox.cpp index bdb086ea..f1791ccc 100644 --- a/source/Irrlicht/CGUICheckBox.cpp +++ b/source/Irrlicht/CGUICheckBox.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -19,7 +19,7 @@ namespace gui //! constructor CGUICheckBox::CGUICheckBox(bool checked, IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) -: IGUICheckBox(environment, parent, id, rectangle), Pressed(false), Checked(checked), checkTime(0) +: IGUICheckBox(environment, parent, id, rectangle), checkTime(0), Pressed(false), Checked(checked) { #ifdef _DEBUG setDebugName("CGUICheckBox"); @@ -31,7 +31,6 @@ CGUICheckBox::CGUICheckBox(bool checked, IGUIEnvironment* environment, IGUIEleme } - //! called if an event happened. bool CGUICheckBox::OnEvent(const SEvent& event) { @@ -41,8 +40,7 @@ bool CGUICheckBox::OnEvent(const SEvent& event) { case EET_KEY_INPUT_EVENT: if (event.KeyInput.PressedDown && - (event.KeyInput.Key == KEY_RETURN || - event.KeyInput.Key == KEY_SPACE)) + (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE)) { Pressed = true; return true; @@ -55,8 +53,7 @@ bool CGUICheckBox::OnEvent(const SEvent& event) } else if (!event.KeyInput.PressedDown && Pressed && - (event.KeyInput.Key == KEY_RETURN || - event.KeyInput.Key == KEY_SPACE)) + (event.KeyInput.Key == KEY_RETURN || event.KeyInput.Key == KEY_SPACE)) { Pressed = false; if (Parent) @@ -123,7 +120,6 @@ bool CGUICheckBox::OnEvent(const SEvent& event) } - //! draws the element and its children void CGUICheckBox::draw() { @@ -137,8 +133,8 @@ void CGUICheckBox::draw() s32 height = skin->getSize(EGDS_CHECK_BOX_WIDTH); core::rect checkRect(AbsoluteRect.UpperLeftCorner.X, - ((AbsoluteRect.getHeight() - height) / 2) + AbsoluteRect.UpperLeftCorner.Y, - 0, 0); + ((AbsoluteRect.getHeight() - height) / 2) + AbsoluteRect.UpperLeftCorner.Y, + 0, 0); checkRect.LowerRightCorner.X = checkRect.UpperLeftCorner.X + height; checkRect.LowerRightCorner.Y = checkRect.UpperLeftCorner.Y + height; @@ -147,7 +143,7 @@ void CGUICheckBox::draw() false, true, checkRect, &AbsoluteClippingRect); if (Checked && Environment->getSkin()) - Environment->getSkin()->drawIcon(this, EGDI_CHECK_BOX_CHECKED, checkRect.getCenter(), + Environment->getSkin()->drawIcon(this, EGDI_CHECK_BOX_CHECKED, checkRect.getCenter(), checkTime, os::Timer::getTime(), false, &AbsoluteClippingRect); if (Text.size()) @@ -157,7 +153,7 @@ void CGUICheckBox::draw() IGUIFont* font = skin->getFont(); if (font) - font->draw(Text.c_str(), checkRect, + font->draw(Text.c_str(), checkRect, skin->getColor(EGDC_BUTTON_TEXT), false, true, &AbsoluteClippingRect); } @@ -179,13 +175,15 @@ bool CGUICheckBox::isChecked() const return Checked; } + //! Writes attributes of the element. void CGUICheckBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const { IGUICheckBox::serializeAttributes(out,options); - out->addBool ("Checked", Checked ); + out->addBool("Checked", Checked); } + //! Reads attributes of the element void CGUICheckBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) { @@ -199,3 +197,4 @@ void CGUICheckBox::deserializeAttributes(io::IAttributes* in, io::SAttributeRead } // end namespace irr #endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUICheckBox.h b/source/Irrlicht/CGUICheckBox.h index 83706801..ced97bf0 100644 --- a/source/Irrlicht/CGUICheckBox.h +++ b/source/Irrlicht/CGUICheckBox.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -42,9 +42,9 @@ namespace gui private: + u32 checkTime; bool Pressed; bool Checked; - u32 checkTime; }; } // end namespace gui diff --git a/source/Irrlicht/CGUIColorSelectDialog.cpp b/source/Irrlicht/CGUIColorSelectDialog.cpp index 2667b979..ee660898 100644 --- a/source/Irrlicht/CGUIColorSelectDialog.cpp +++ b/source/Irrlicht/CGUIColorSelectDialog.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -98,7 +98,7 @@ CGUIColorSelectDialog::CGUIColorSelectDialog(const wchar_t* title, IGUIEnvironme ColorRing.Texture = driver->getTexture ( "#colorring" ); if ( 0 == ColorRing.Texture ) { - buildColorRing(core::dimension2d(128, 128), 1, + buildColorRing(core::dimension2d(128, 128), 1, Environment->getSkin()->getColor(EGDC_3D_SHADOW).color); } @@ -184,9 +184,9 @@ CGUIColorSelectDialog::~CGUIColorSelectDialog() //! renders a antialiased, colored ring -void CGUIColorSelectDialog::buildColorRing( const core::dimension2d & dim, s32 supersample, const u32 borderColor ) +void CGUIColorSelectDialog::buildColorRing( const core::dimension2d & dim, s32 supersample, const u32 borderColor ) { - const core::dimension2d d(dim.Width * supersample, dim.Height * supersample); + const core::dimension2d d(dim.Width * supersample, dim.Height * supersample); video::CImage *RawTexture = new video::CImage(video::ECF_A8R8G8B8, d); RawTexture->fill ( 0x00808080 ); diff --git a/source/Irrlicht/CGUIColorSelectDialog.h b/source/Irrlicht/CGUIColorSelectDialog.h index d033cf86..376d35c0 100644 --- a/source/Irrlicht/CGUIColorSelectDialog.h +++ b/source/Irrlicht/CGUIColorSelectDialog.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -67,8 +67,7 @@ namespace gui }; SColorCircle ColorRing; - void buildColorRing( const core::dimension2d & dim, s32 supersample, const u32 borderColor ); - + void buildColorRing( const core::dimension2d & dim, s32 supersample, const u32 borderColor ); }; @@ -78,3 +77,4 @@ namespace gui #endif // _IRR_COMPILE_WITH_GUI_ #endif // __C_GUI_COLOR_SELECT_DIALOG_H_INCLUDED__ + diff --git a/source/Irrlicht/CGUIComboBox.cpp b/source/Irrlicht/CGUIComboBox.cpp index f5220eb8..6f0fd317 100644 --- a/source/Irrlicht/CGUIComboBox.cpp +++ b/source/Irrlicht/CGUIComboBox.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -23,8 +23,8 @@ namespace gui CGUIComboBox::CGUIComboBox(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) : IGUIComboBox(environment, parent, id, rectangle), - ListButton(0), SelectedText(0), ListBox(0), Selected(-1), HasFocus(false), LastFocus(0), - HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER) + ListButton(0), SelectedText(0), ListBox(0), LastFocus(0), + Selected(-1), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER), HasFocus(false) { #ifdef _DEBUG setDebugName("CGUIComboBox"); @@ -39,7 +39,7 @@ CGUIComboBox::CGUIComboBox(IGUIEnvironment* environment, IGUIElement* parent, core::rect r; r.UpperLeftCorner.X = rectangle.getWidth() - width - 2; r.LowerRightCorner.X = rectangle.getWidth() - 2; - + r.UpperLeftCorner.Y = 2; r.LowerRightCorner.Y = rectangle.getHeight() - 2; @@ -72,6 +72,7 @@ CGUIComboBox::CGUIComboBox(IGUIEnvironment* environment, IGUIElement* parent, setTabOrder(-1); } + void CGUIComboBox::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical) { HAlign = horizontal; @@ -79,6 +80,7 @@ void CGUIComboBox::setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT ve SelectedText->setTextAlignment(horizontal, vertical); } + //! Returns amount of items in box u32 CGUIComboBox::getItemCount() const { @@ -108,6 +110,7 @@ void CGUIComboBox::removeItem(u32 idx) Items.erase(idx); } + //! Returns caption of this element. const wchar_t* CGUIComboBox::getText() const { @@ -127,7 +130,6 @@ u32 CGUIComboBox::addItem(const wchar_t* text) } - //! deletes all items in the combo box void CGUIComboBox::clear() { @@ -136,7 +138,6 @@ void CGUIComboBox::clear() } - //! returns id of selected item. returns -1 if no item is selected. s32 CGUIComboBox::getSelected() const { @@ -144,7 +145,6 @@ s32 CGUIComboBox::getSelected() const } - //! sets the selected item. Set this to -1 if no item should be selected void CGUIComboBox::setSelected(s32 idx) { @@ -153,11 +153,12 @@ void CGUIComboBox::setSelected(s32 idx) Selected = idx; if (Selected == -1) - SelectedText->setText(L""); + SelectedText->setText(L""); else SelectedText->setText(Items[Selected].c_str()); } + //! called if an event happened. bool CGUIComboBox::OnEvent(const SEvent& event) { @@ -190,10 +191,10 @@ bool CGUIComboBox::OnEvent(const SEvent& event) bool absorb = true; switch (event.KeyInput.Key) { - case KEY_DOWN: - setSelected(Selected+1); + case KEY_DOWN: + setSelected(Selected+1); break; - case KEY_UP: + case KEY_UP: setSelected(Selected-1); break; case KEY_HOME: @@ -227,11 +228,11 @@ bool CGUIComboBox::OnEvent(const SEvent& event) switch(event.GUIEvent.EventType) { case EGET_ELEMENT_FOCUS_LOST: - if (ListBox && - (Environment->hasFocus(ListBox) || ListBox->isMyChild(event.GUIEvent.Caller) ) && - event.GUIEvent.Element != this && - event.GUIEvent.Element != ListButton && - event.GUIEvent.Element != ListBox && + if (ListBox && + (Environment->hasFocus(ListBox) || ListBox->isMyChild(event.GUIEvent.Caller) ) && + event.GUIEvent.Element != this && + event.GUIEvent.Element != ListButton && + event.GUIEvent.Element != ListBox && !ListBox->isMyChild(event.GUIEvent.Element)) { openCloseMenu(); @@ -267,7 +268,7 @@ bool CGUIComboBox::OnEvent(const SEvent& event) case EMIE_LMOUSE_PRESSED_DOWN: { core::position2d p(event.MouseInput.X, event.MouseInput.Y); - + // send to list box if (ListBox && ListBox->isPointInside(p) && ListBox->OnEvent(event)) return true; @@ -312,7 +313,6 @@ bool CGUIComboBox::OnEvent(const SEvent& event) } - void CGUIComboBox::sendSelectionChangedEvent() { if (Parent) @@ -328,7 +328,6 @@ void CGUIComboBox::sendSelectionChangedEvent() } - //! draws the element and its children void CGUIComboBox::draw() { @@ -343,8 +342,17 @@ void CGUIComboBox::draw() LastFocus = currentFocus; SelectedText->setBackgroundColor(skin->getColor(EGDC_HIGH_LIGHT)); - SelectedText->setDrawBackground(HasFocus); - SelectedText->setOverrideColor(skin->getColor(HasFocus ? EGDC_HIGH_LIGHT_TEXT : EGDC_BUTTON_TEXT)); + + if(isEnabled()) + { + SelectedText->setDrawBackground(HasFocus); + SelectedText->setOverrideColor(skin->getColor(HasFocus ? EGDC_HIGH_LIGHT_TEXT : EGDC_BUTTON_TEXT)); + } + else + { + SelectedText->setDrawBackground(false); + SelectedText->setOverrideColor(skin->getColor(EGDC_GRAY_TEXT)); + } } core::rect frameRect(AbsoluteRect); @@ -373,7 +381,7 @@ void CGUIComboBox::openCloseMenu() if (Parent) Parent->bringToFront(this); - IGUISkin* skin = Environment->getSkin(); + IGUISkin* skin = Environment->getSkin(); s32 h = Items.size(); if (h > 5) @@ -403,6 +411,7 @@ void CGUIComboBox::openCloseMenu() } } + //! Writes attributes of the element. void CGUIComboBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const { @@ -422,6 +431,7 @@ void CGUIComboBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadW } } + //! Reads attributes of the element void CGUIComboBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) { diff --git a/source/Irrlicht/CGUIComboBox.h b/source/Irrlicht/CGUIComboBox.h index c79755c7..ac8b4aee 100644 --- a/source/Irrlicht/CGUIComboBox.h +++ b/source/Irrlicht/CGUIComboBox.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -76,11 +76,11 @@ namespace gui IGUIButton* ListButton; IGUIStaticText* SelectedText; IGUIListBox* ListBox; + IGUIElement *LastFocus; core::array< core::stringw > Items; s32 Selected; - bool HasFocus; - IGUIElement *LastFocus; EGUI_ALIGNMENT HAlign, VAlign; + bool HasFocus; }; diff --git a/source/Irrlicht/CGUIContextMenu.cpp b/source/Irrlicht/CGUIContextMenu.cpp index fc7e59cc..cf03ace7 100644 --- a/source/Irrlicht/CGUIContextMenu.cpp +++ b/source/Irrlicht/CGUIContextMenu.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -23,8 +23,8 @@ namespace gui CGUIContextMenu::CGUIContextMenu(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle, bool getFocus, bool allowFocus) - : IGUIContextMenu(environment, parent, id, rectangle), HighLighted(-1), - ChangeTime(0), EventParent(0), AllowFocus(allowFocus), LastFont(0) + : IGUIContextMenu(environment, parent, id, rectangle), EventParent(0), LastFont(0), + HighLighted(-1), ChangeTime(0), AllowFocus(allowFocus) { #ifdef _DEBUG setDebugName("CGUIContextMenu"); @@ -242,7 +242,7 @@ bool CGUIContextMenu::OnEvent(const SEvent& event) } break; default: - break; + break; } break; case EET_MOUSE_INPUT_EVENT: @@ -265,7 +265,7 @@ bool CGUIContextMenu::OnEvent(const SEvent& event) highlight(core::position2d(event.MouseInput.X, event.MouseInput.Y), true); return true; default: - break; + break; } break; default: @@ -530,16 +530,15 @@ void CGUIContextMenu::draw() void CGUIContextMenu::recalculateSize() { - IGUISkin* skin = Environment->getSkin(); - IGUIFont* font = skin->getFont(EGDF_MENU); + IGUIFont* font = Environment->getSkin()->getFont(EGDF_MENU); if (!font) return; core::rect rect; rect.UpperLeftCorner = RelativeRect.UpperLeftCorner; - s32 width = 100; - s32 height = 3; + u32 width = 100; + u32 height = 3; u32 i; for (i=0; i Dim; + core::dimension2d Dim; s32 PosY; CGUIContextMenu* SubMenu; s32 CommandId; @@ -132,13 +132,13 @@ namespace gui void setEventParent(IGUIElement *parent); - s32 HighLighted; core::array Items; core::position2d Pos; - u32 ChangeTime; IGUIElement* EventParent; - bool AllowFocus; IGUIFont *LastFont; + s32 HighLighted; + u32 ChangeTime; + bool AllowFocus; }; diff --git a/source/Irrlicht/CGUIEditBox.cpp b/source/Irrlicht/CGUIEditBox.cpp index 39ef4f26..b542ca13 100644 --- a/source/Irrlicht/CGUIEditBox.cpp +++ b/source/Irrlicht/CGUIEditBox.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -33,13 +33,11 @@ CGUIEditBox::CGUIEditBox(const wchar_t* text, bool border, IGUIEnvironment* envi const core::rect& rectangle) : IGUIEditBox(environment, parent, id, rectangle), MouseMarking(false), Border(border), OverrideColorEnabled(false), MarkBegin(0), MarkEnd(0), - OverrideColor(video::SColor(101,255,255,255)), - OverrideFont(0), LastBreakFont(0), CursorPos(0), HScrollPos(0), VScrollPos(0), Max(0), + OverrideColor(video::SColor(101,255,255,255)), OverrideFont(0), LastBreakFont(0), + Operator(0), BlinkStartTime(0), CursorPos(0), HScrollPos(0), VScrollPos(0), Max(0), WordWrap(false), MultiLine(false), AutoScroll(true), PasswordBox(false), - PasswordChar(L'*'), - HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER), + PasswordChar(L'*'), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_CENTER), CurrentTextRect(0,0,1,1), FrameRect(rectangle) - { #ifdef _DEBUG setDebugName("CGUIEditBox"); @@ -47,7 +45,8 @@ CGUIEditBox::CGUIEditBox(const wchar_t* text, bool border, IGUIEnvironment* envi Text = text; - Operator = environment->getOSOperator(); + if (Environment) + Operator = Environment->getOSOperator(); if (Operator) Operator->grab(); @@ -56,7 +55,9 @@ CGUIEditBox::CGUIEditBox(const wchar_t* text, bool border, IGUIEnvironment* envi setTabStop(true); setTabOrder(-1); - IGUISkin *skin = Environment->getSkin(); + IGUISkin *skin = 0; + if (Environment) + skin = Environment->getSkin(); if (Border && skin) { FrameRect.UpperLeftCorner.X += skin->getSize(EGDS_TEXT_DISTANCE_X)+1; @@ -84,6 +85,9 @@ CGUIEditBox::~CGUIEditBox() //! Sets another skin independent font. void CGUIEditBox::setOverrideFont(IGUIFont* font) { + if (OverrideFont == font) + return; + if (OverrideFont) OverrideFont->drop(); @@ -661,6 +665,7 @@ bool CGUIEditBox::processKey(const SEvent& event) return true; } + //! draws the element and its children void CGUIEditBox::draw() { @@ -874,9 +879,10 @@ bool CGUIEditBox::isAutoScrollEnabled() const return AutoScroll; } + //! Gets the area of the text in the edit box //! \return Returns the size in pixels of the text -core::dimension2di CGUIEditBox::getTextDimension() +core::dimension2du CGUIEditBox::getTextDimension() { core::rect ret; @@ -890,7 +896,7 @@ core::dimension2di CGUIEditBox::getTextDimension() ret.addInternalPoint(CurrentTextRect.LowerRightCorner); } - return ret.getSize(); + return core::dimension2du(ret.getSize()); } @@ -1143,7 +1149,7 @@ void CGUIEditBox::breakText() void CGUIEditBox::setTextRect(s32 line) { - core::dimension2di d; + core::dimension2du d; s32 lineCount = 1; IGUIFont* font = OverrideFont; @@ -1362,7 +1368,7 @@ void CGUIEditBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadW setPasswordBox(in->getAttributeAsBool("PasswordBox"), ch[0]); setTextAlignment( (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("HTextAlign", GUIAlignmentNames), - (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames)); + (EGUI_ALIGNMENT) in->getAttributeAsEnumeration("VTextAlign", GUIAlignmentNames)); // setOverrideFont(in->getAttributeAsFont("OverrideFont")); } diff --git a/source/Irrlicht/CGUIEditBox.h b/source/Irrlicht/CGUIEditBox.h index 4bace920..bdad4a93 100644 --- a/source/Irrlicht/CGUIEditBox.h +++ b/source/Irrlicht/CGUIEditBox.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -66,7 +66,7 @@ namespace gui //! Gets the size area of the text in the edit box //! \return Returns the size in pixels of the text - virtual core::dimension2di getTextDimension(); + virtual core::dimension2du getTextDimension(); //! Sets text justification virtual void setTextAlignment(EGUI_ALIGNMENT horizontal, EGUI_ALIGNMENT vertical); @@ -81,14 +81,14 @@ namespace gui virtual void setText(const wchar_t* text); //! Sets the maximum amount of characters which may be entered in the box. - //! \param max: Maximum amount of characters. If 0, the character amount is + //! \param max: Maximum amount of characters. If 0, the character amount is //! infinity. virtual void setMax(u32 max); //! Returns maximum amount of characters, previously set by setMax(); virtual u32 getMax() const; - //! Sets whether the edit box is a password box. Setting this to true will + //! Sets whether the edit box is a password box. Setting this to true will /** disable MultiLine, WordWrap and the ability to copy with ctrl+c or ctrl+x \param passwordBox: true to enable password, false to disable \param passwordChar: the character that is displayed instead of letters */ diff --git a/source/Irrlicht/CGUIEnvironment.cpp b/source/Irrlicht/CGUIEnvironment.cpp index c923a3e4..f9d05013 100644 --- a/source/Irrlicht/CGUIEnvironment.cpp +++ b/source/Irrlicht/CGUIEnvironment.cpp @@ -1,5 +1,5 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -52,7 +52,7 @@ const wchar_t* IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE = L"type"; //! constructor CGUIEnvironment::CGUIEnvironment(io::IFileSystem* fs, video::IVideoDriver* driver, IOSOperator* op) -: IGUIElement(EGUIET_ELEMENT, 0, 0, 0, core::rect(core::position2d(0,0), driver ? driver->getScreenSize() : core::dimension2d(0,0))), +: IGUIElement(EGUIET_ELEMENT, 0, 0, 0, core::rect(core::position2d(0,0), driver ? core::dimension2d(driver->getScreenSize()) : core::dimension2d(0,0))), Driver(driver), Hovered(0), Focus(0), LastHoveredMousePos(0,0), CurrentSkin(0), FileSystem(fs), UserReceiver(0), Operator(op) { @@ -182,7 +182,7 @@ void CGUIEnvironment::drawAll() { if (Driver) { - core::dimension2d dim = Driver->getScreenSize(); + core::dimension2d dim(Driver->getScreenSize()); if (AbsoluteRect.LowerRightCorner.X != dim.Width || AbsoluteRect.LowerRightCorner.Y != dim.Height) { @@ -192,7 +192,7 @@ void CGUIEnvironment::drawAll() AbsoluteClippingRect = DesiredRect; AbsoluteRect = DesiredRect; updateAbsolutePosition(); - } + } } // make sure tooltip is always on top @@ -243,7 +243,7 @@ bool CGUIEnvironment::setFocus(IGUIElement* element) currentFocus->drop(); currentFocus = 0; } - + if (element) { currentFocus = Focus; @@ -275,7 +275,7 @@ bool CGUIEnvironment::setFocus(IGUIElement* element) // element is the new focus so it doesn't have to be dropped Focus = element; - + return true; } @@ -308,7 +308,7 @@ bool CGUIEnvironment::removeFocus(IGUIElement* element) Focus->drop(); Focus = 0; } - + return true; } @@ -317,7 +317,7 @@ bool CGUIEnvironment::removeFocus(IGUIElement* element) bool CGUIEnvironment::hasFocus(IGUIElement* element) const { _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - return (element == Focus); + return (element == Focus); } @@ -327,18 +327,21 @@ video::IVideoDriver* CGUIEnvironment::getVideoDriver() const return Driver; } + //! returns the current file system io::IFileSystem* CGUIEnvironment::getFileSystem() const { return FileSystem; } + //! returns the current file system IOSOperator* CGUIEnvironment::getOSOperator() const { return Operator; } + //! clear all GUI elements void CGUIEnvironment::clear() { @@ -370,7 +373,7 @@ bool CGUIEnvironment::OnEvent(const SEvent& event) if (UserReceiver && (event.EventType != EET_MOUSE_INPUT_EVENT) && (event.EventType != EET_KEY_INPUT_EVENT) - && (event.EventType != EET_GUI_EVENT || event.GUIEvent.Caller != this)) + && (event.EventType != EET_GUI_EVENT || event.GUIEvent.Caller != this)) { ret = UserReceiver->OnEvent(event); } @@ -391,14 +394,14 @@ void CGUIEnvironment::OnPostRender( u32 time ) ToolTip.Element == 0 && Hovered != ToolTip.Element && Hovered->getToolTipText().size() && - getSkin() && + getSkin() && getSkin()->getFont(EGDF_TOOLTIP) ) { core::rect pos; pos.UpperLeftCorner = LastHoveredMousePos; - core::dimension2di dim = getSkin()->getFont(EGDF_TOOLTIP)->getDimension(Hovered->getToolTipText().c_str()); + core::dimension2du dim = getSkin()->getFont(EGDF_TOOLTIP)->getDimension(Hovered->getToolTipText().c_str()); dim.Width += getSkin()->getSize(EGDS_TEXT_DISTANCE_X)*2; dim.Height += getSkin()->getSize(EGDS_TEXT_DISTANCE_Y)*2; @@ -443,7 +446,7 @@ void CGUIEnvironment::updateHoveredElement(core::position2d mousePos) if (Hovered != lastHovered) { - SEvent event; + SEvent event; event.EventType = EET_GUI_EVENT; if (lastHovered) @@ -478,7 +481,7 @@ void CGUIEnvironment::updateHoveredElement(core::position2d mousePos) event.GUIEvent.EventType = EGET_ELEMENT_HOVERED; Hovered->OnEvent(event); } - } + } if (lastHovered && lastHovered != this) lastHovered->drop(); @@ -526,8 +529,8 @@ bool CGUIEnvironment::postEventFromUser(const SEvent& event) case EET_KEY_INPUT_EVENT: { // send focus changing event - if (event.EventType == EET_KEY_INPUT_EVENT && - event.KeyInput.PressedDown && + if (event.EventType == EET_KEY_INPUT_EVENT && + event.KeyInput.PressedDown && event.KeyInput.Key == KEY_TAB) { IGUIElement *next = getNextElement(event.KeyInput.Shift, event.KeyInput.Control); @@ -732,7 +735,7 @@ bool CGUIEnvironment::loadGUI(io::IReadFile* file, IGUIElement* parent) _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; return false; } - + // read file while(reader->read()) { @@ -741,34 +744,33 @@ bool CGUIEnvironment::loadGUI(io::IReadFile* file, IGUIElement* parent) // finish up - reader->drop(); - return true; + reader->drop(); + return true; } //! reads an element -void CGUIEnvironment::readGUIElement(io::IXMLReader* reader, IGUIElement* parent) +void CGUIEnvironment::readGUIElement(io::IXMLReader* reader, IGUIElement* node) { if (!reader) return; - gui::IGUIElement* node = 0; - io::EXML_NODE nodeType = reader->getNodeType(); if (nodeType == io::EXN_NONE || nodeType == io::EXN_UNKNOWN || nodeType == io::EXN_ELEMENT_END) return; - if (!parent && !wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName())) + if (!wcscmp(IRR_XML_FORMAT_GUI_ENV, reader->getNodeName())) { - node = this; // root + if (!node) + node = this; // root } else if (!wcscmp(IRR_XML_FORMAT_GUI_ELEMENT, reader->getNodeName())) { // find node type and create it - core::stringc attrName = reader->getAttributeValue(IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE); + const core::stringc attrName = reader->getAttributeValue(IRR_XML_FORMAT_GUI_ELEMENT_ATTR_TYPE); - node = addGUIElement(attrName.c_str(), parent); + node = addGUIElement(attrName.c_str(), node); if (!node) os::Printer::log("Could not create GUI element of unknown type", attrName.c_str()); @@ -810,7 +812,7 @@ void CGUIEnvironment::readGUIElement(io::IXMLReader* reader, IGUIElement* parent else { os::Printer::log("Found unknown element in irrlicht GUI file", - core::stringc(reader->getNodeName()).c_str()); + core::stringc(reader->getNodeName()).c_str()); } break; @@ -918,9 +920,9 @@ void CGUIEnvironment::deserializeAttributes(io::IAttributes* in, io::SAttributeR } - RelativeRect = AbsoluteRect = - core::rect(core::position2d(0,0), - Driver ? Driver->getScreenSize() : core::dimension2d(0,0)); + RelativeRect = AbsoluteRect = + core::rect(core::position2d(0,0), + Driver ? core::dimension2di(Driver->getScreenSize()) : core::dimension2d(0,0)); } @@ -940,7 +942,7 @@ IGUIButton* CGUIEnvironment::addButton(const core::rect& rectangle, IGUIEle //! adds a window. The returned pointer must not be dropped. -IGUIWindow* CGUIEnvironment::addWindow(const core::rect& rectangle, bool modal, +IGUIWindow* CGUIEnvironment::addWindow(const core::rect& rectangle, bool modal, const wchar_t* text, IGUIElement* parent, s32 id) { parent = parent ? parent : this; @@ -982,7 +984,7 @@ IGUIWindow* CGUIEnvironment::addMessageBox(const wchar_t* caption, const wchar_t parent = parent ? parent : this; core::rect rect; - core::dimension2d screenDim, msgBoxDim; + core::dimension2d screenDim, msgBoxDim; screenDim.Width = parent->getAbsolutePosition().getWidth(); screenDim.Height = parent->getAbsolutePosition().getHeight(); @@ -1016,6 +1018,7 @@ IGUIScrollBar* CGUIEnvironment::addScrollBar(bool horizontal, const core::rect& rectangle, IGUIElement* parent, s32 id, bool drawBackground) { CGUITable* b = new CGUITable(this, parent ? parent : this, id, rectangle, true, drawBackground, false); @@ -1023,13 +1026,14 @@ IGUITable* CGUIEnvironment::addTable(const core::rect& rectangle, IGUIEleme return b; } -//! Adds an image element. + +//! Adds an image element. IGUIImage* CGUIEnvironment::addImage(video::ITexture* image, core::position2d pos, bool useAlphaChannel, IGUIElement* parent, s32 id, const wchar_t* text) { core::dimension2d sz(0,0); if (image) - sz = image->getOriginalSize(); + sz = core::dimension2d(image->getOriginalSize()); IGUIImage* img = new CGUIImage(this, parent ? parent : this, id, core::rect(pos, sz)); @@ -1079,7 +1083,7 @@ IGUIMeshViewer* CGUIEnvironment::addMeshViewer(const core::rect& rectangle, //! adds a checkbox IGUICheckBox* CGUIEnvironment::addCheckBox(bool checked, const core::rect& rectangle, IGUIElement* parent, s32 id, const wchar_t* text) { - IGUICheckBox* b = new CGUICheckBox(checked, this, + IGUICheckBox* b = new CGUICheckBox(checked, this, parent ? parent : this , id , rectangle); if (text) @@ -1091,9 +1095,8 @@ IGUICheckBox* CGUIEnvironment::addCheckBox(bool checked, const core::rect& //! adds a list box -IGUIListBox* CGUIEnvironment::addListBox(const core::rect& rectangle, - IGUIElement* parent, s32 id, - bool drawBackground) +IGUIListBox* CGUIEnvironment::addListBox(const core::rect& rectangle, + IGUIElement* parent, s32 id, bool drawBackground) { IGUIListBox* b = new CGUIListBox(this, parent ? parent : this, id, rectangle, true, drawBackground, false); @@ -1113,9 +1116,8 @@ IGUIListBox* CGUIEnvironment::addListBox(const core::rect& rectangle, //! adds a file open dialog. The returned pointer must not be dropped. -IGUIFileOpenDialog* CGUIEnvironment::addFileOpenDialog(const wchar_t* title, - bool modal, - IGUIElement* parent, s32 id) +IGUIFileOpenDialog* CGUIEnvironment::addFileOpenDialog(const wchar_t* title, + bool modal, IGUIElement* parent, s32 id) { parent = parent ? parent : this; @@ -1133,9 +1135,8 @@ IGUIFileOpenDialog* CGUIEnvironment::addFileOpenDialog(const wchar_t* title, //! adds a color select dialog. The returned pointer must not be dropped. -IGUIColorSelectDialog* CGUIEnvironment::addColorSelectDialog(const wchar_t* title, - bool modal, - IGUIElement* parent, s32 id) +IGUIColorSelectDialog* CGUIEnvironment::addColorSelectDialog(const wchar_t* title, + bool modal, IGUIElement* parent, s32 id) { parent = parent ? parent : this; @@ -1154,11 +1155,10 @@ IGUIColorSelectDialog* CGUIEnvironment::addColorSelectDialog(const wchar_t* titl //! adds a static text. The returned pointer must not be dropped. -IGUIStaticText* CGUIEnvironment::addStaticText(const wchar_t* text, - const core::rect& rectangle, - bool border, bool wordWrap, - IGUIElement* parent, s32 id, - bool background) +IGUIStaticText* CGUIEnvironment::addStaticText(const wchar_t* text, + const core::rect& rectangle, + bool border, bool wordWrap, + IGUIElement* parent, s32 id, bool background) { IGUIStaticText* d = new CGUIStaticText(text, border, this, parent ? parent : this, id, rectangle, background); @@ -1171,10 +1171,9 @@ IGUIStaticText* CGUIEnvironment::addStaticText(const wchar_t* text, //! Adds an edit box. The returned pointer must not be dropped. -IGUIEditBox* CGUIEnvironment::addEditBox(const wchar_t* text, - const core::rect& rectangle, - bool border, IGUIElement* parent, - s32 id) +IGUIEditBox* CGUIEnvironment::addEditBox(const wchar_t* text, + const core::rect& rectangle, bool border, + IGUIElement* parent, s32 id) { IGUIEditBox* d = new CGUIEditBox(text, border, this, parent ? parent : this, id, rectangle); @@ -1185,9 +1184,9 @@ IGUIEditBox* CGUIEnvironment::addEditBox(const wchar_t* text, //! Adds a spin box to the environment -IGUISpinBox* CGUIEnvironment::addSpinBox(const wchar_t* text, - const core::rect &rectangle, - IGUIElement* parent, s32 id) +IGUISpinBox* CGUIEnvironment::addSpinBox(const wchar_t* text, + const core::rect &rectangle, + IGUIElement* parent, s32 id) { IGUISpinBox* d = new CGUISpinBox(text, this, parent ? parent : this, id, rectangle); @@ -1207,7 +1206,7 @@ IGUITabControl* CGUIEnvironment::addTabControl(const core::rect& rectangle, } -//! Adds tab to the environment. +//! Adds tab to the environment. IGUITab* CGUIEnvironment::addTab(const core::rect& rectangle, IGUIElement* parent, s32 id) { @@ -1222,7 +1221,7 @@ IGUITab* CGUIEnvironment::addTab(const core::rect& rectangle, IGUIContextMenu* CGUIEnvironment::addContextMenu(const core::rect& rectangle, IGUIElement* parent, s32 id) { - IGUIContextMenu* c = new CGUIContextMenu(this, + IGUIContextMenu* c = new CGUIContextMenu(this, parent ? parent : this, id, rectangle, true); c->drop(); return c; @@ -1235,7 +1234,7 @@ IGUIContextMenu* CGUIEnvironment::addMenu(IGUIElement* parent, s32 id) if (!parent) parent = this; - IGUIContextMenu* c = new CGUIMenu(this, + IGUIContextMenu* c = new CGUIMenu(this, parent, id, core::rect(0,0, parent->getAbsolutePosition().getWidth(), parent->getAbsolutePosition().getHeight())); @@ -1265,9 +1264,8 @@ IGUIInOutFader* CGUIEnvironment::addInOutFader(const core::rect* rectangle, if (rectangle) rect = *rectangle; - else - if (Driver) - rect = core::rect(core::position2d(0,0), Driver->getScreenSize()); + else if (Driver) + rect = core::rect(core::position2d(0,0), core::dimension2di(Driver->getScreenSize())); if (!parent) parent = this; @@ -1439,7 +1437,7 @@ IGUISpriteBank* CGUIEnvironment::addEmptySpriteBank(const c8 *name) const s32 index = Banks.binary_search(b); if (index != -1) - return 0; + return 0; // create a new sprite bank @@ -1461,7 +1459,7 @@ IGUIFont* CGUIEnvironment::getBuiltInFont() const } -//! Returns the root gui element. +//! Returns the root gui element. IGUIElement* CGUIEnvironment::getRootGUIElement() { return this; @@ -1480,13 +1478,13 @@ IGUIElement* CGUIEnvironment::getNextElement(bool reverse, bool group) { startOrder = startPos->getTabOrder(); } - else + else if (!group && Focus && !Focus->isTabGroup()) { startOrder = Focus->getTabOrder(); if (startOrder == -1) { - // this element is not part of the tab cycle, + // this element is not part of the tab cycle, // but its parent might be... IGUIElement *el = Focus; while (el && el->getParent() && startOrder == -1) @@ -1531,4 +1529,3 @@ IGUIEnvironment* createGUIEnvironment(io::IFileSystem* fs, #endif // _IRR_COMPILE_WITH_GUI_ - diff --git a/source/Irrlicht/CGUIEnvironment.h b/source/Irrlicht/CGUIEnvironment.h index dac1c362..8e9c3051 100644 --- a/source/Irrlicht/CGUIEnvironment.h +++ b/source/Irrlicht/CGUIEnvironment.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -83,7 +83,7 @@ public: virtual IGUIButton* addButton(const core::rect& rectangle, IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0,const wchar_t* tooltiptext = 0); //! adds a window. The returned pointer must not be dropped. - virtual IGUIWindow* addWindow(const core::rect& rectangle, bool modal = false, + virtual IGUIWindow* addWindow(const core::rect& rectangle, bool modal = false, const wchar_t* text=0, IGUIElement* parent=0, s32 id=-1); //! adds a modal screen. The returned pointer must not be dropped. @@ -96,12 +96,12 @@ public: //! adds a scrollbar. The returned pointer must not be dropped. virtual IGUIScrollBar* addScrollBar(bool horizontal, const core::rect& rectangle, IGUIElement* parent=0, s32 id=-1); - //! Adds an image element. + //! Adds an image element. virtual IGUIImage* addImage(video::ITexture* image, core::position2d pos, bool useAlphaChannel=true, IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0); //! adds an image. The returned pointer must not be dropped. - virtual IGUIImage* addImage(const core::rect& rectangle, + virtual IGUIImage* addImage(const core::rect& rectangle, IGUIElement* parent=0, s32 id=-1, const wchar_t* text=0); //! adds a checkbox @@ -125,18 +125,18 @@ public: bool border=false, bool wordWrap=true, IGUIElement* parent=0, s32 id=-1, bool drawBackground = false); //! Adds an edit box. The returned pointer must not be dropped. - virtual IGUIEditBox* addEditBox(const wchar_t* text, const core::rect& rectangle, + virtual IGUIEditBox* addEditBox(const wchar_t* text, const core::rect& rectangle, bool border=false, IGUIElement* parent=0, s32 id=-1); //! Adds a spin box to the environment - virtual IGUISpinBox* addSpinBox(const wchar_t* text, const core::rect& rectangle, + virtual IGUISpinBox* addSpinBox(const wchar_t* text, const core::rect& rectangle, IGUIElement* parent=0, s32 id=-1); //! Adds a tab control to the environment. virtual IGUITabControl* addTabControl(const core::rect& rectangle, IGUIElement* parent=0, bool fillbackground=false, bool border=true, s32 id=-1); - //! Adds tab to the environment. + //! Adds tab to the environment. virtual IGUITab* addTab(const core::rect& rectangle, IGUIElement* parent=0, s32 id=-1); @@ -156,7 +156,7 @@ public: IGUIElement* parent=0, s32 id=-1); //! Adds a table element. - virtual IGUITable* addTable(const core::rect& rectangle, + virtual IGUITable* addTable(const core::rect& rectangle, IGUIElement* parent=0, s32 id=-1, bool drawBackground=false); //! sets the focus to an element @@ -177,7 +177,7 @@ public: //! Adds an element for fading in or out. virtual IGUIInOutFader* addInOutFader(const core::rect* rectangle=0, IGUIElement* parent=0, s32 id=-1); - //! Returns the root gui element. + //! Returns the root gui element. virtual IGUIElement* getRootGUIElement(); virtual void OnPostRender( u32 time ); @@ -201,27 +201,27 @@ public: //! Saves the current gui into a file. /** \param filename: Name of the file. - \param start: The element to start saving from. - if not specified, the root element will be used */ + \param start: The element to start saving from. + if not specified, the root element will be used */ virtual bool saveGUI(const c8* filename, IGUIElement* start=0); //! Saves the current gui into a file. /** \param file: The file to save the GUI to. - \param start: The element to start saving from. + \param start: The element to start saving from. if not specified, the root element will be used */ virtual bool saveGUI(io::IWriteFile* file, IGUIElement* start=0); //! Loads the gui. Note that the current gui is not cleared before. /** \param filename: Name of the file. - \param parent: The parent of all loaded GUI elements, + \param parent: The parent of all loaded GUI elements, if not specified, the root element will be used */ virtual bool loadGUI(const c8* filename, IGUIElement* parent=0); //! Loads the gui. Note that the current gui is not cleared before. /** \param file: IReadFile to load the GUI from - \param parent: The parent of all loaded GUI elements, + \param parent: The parent of all loaded GUI elements, if not specified, the root element will be used */ - virtual bool loadGUI(io::IReadFile* file, IGUIElement* parent=0); + virtual bool loadGUI(io::IReadFile* file, IGUIElement* parent=0); //! Writes attributes of the environment virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const; @@ -233,8 +233,7 @@ public: virtual void writeGUIElement(io::IXMLWriter* writer, IGUIElement* node); //! reads an element - virtual void readGUIElement(io::IXMLReader* reader, IGUIElement* parent); - + virtual void readGUIElement(io::IXMLReader* reader, IGUIElement* node); private: @@ -268,9 +267,9 @@ private: struct SToolTip { + IGUIStaticText* Element; u32 LastTime; u32 LaunchTime; - IGUIStaticText* Element; }; SToolTip ToolTip; diff --git a/source/Irrlicht/CGUIFileOpenDialog.cpp b/source/Irrlicht/CGUIFileOpenDialog.cpp index 3c7a1835..5b6a41d0 100644 --- a/source/Irrlicht/CGUIFileOpenDialog.cpp +++ b/source/Irrlicht/CGUIFileOpenDialog.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -32,7 +32,7 @@ CGUIFileOpenDialog::CGUIFileOpenDialog(const wchar_t* title, (parent->getAbsolutePosition().getHeight()-FOD_HEIGHT)/2, (parent->getAbsolutePosition().getWidth()-FOD_WIDTH)/2+FOD_WIDTH, (parent->getAbsolutePosition().getHeight()-FOD_HEIGHT)/2+FOD_HEIGHT)), - Dragging(false), FileNameText(0), FileList(0) + FileNameText(0), FileList(0), Dragging(false) { #ifdef _DEBUG IGUIElement::setDebugName("CGUIFileOpenDialog"); @@ -49,8 +49,8 @@ CGUIFileOpenDialog::CGUIFileOpenDialog(const wchar_t* title, color = skin->getColor(EGDC_WINDOW_SYMBOL); } - s32 buttonw = environment->getSkin()->getSize(EGDS_WINDOW_BUTTON_WIDTH); - s32 posx = RelativeRect.getWidth() - buttonw - 4; + const s32 buttonw = environment->getSkin()->getSize(EGDS_WINDOW_BUTTON_WIDTH); + const s32 posx = RelativeRect.getWidth() - buttonw - 4; CloseButton = Environment->addButton(core::rect(posx, 3, posx + buttonw, 3 + buttonw), this, -1, L"", skin ? skin->getDefaultText(EGDT_WINDOW_CLOSE) : L"Close"); diff --git a/source/Irrlicht/CGUIFileOpenDialog.h b/source/Irrlicht/CGUIFileOpenDialog.h index 3af2ece4..43d7a9f2 100644 --- a/source/Irrlicht/CGUIFileOpenDialog.h +++ b/source/Irrlicht/CGUIFileOpenDialog.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -50,7 +50,6 @@ namespace gui core::position2d DragStart; core::stringw FileName; - bool Dragging; IGUIButton* CloseButton; IGUIButton* OKButton; IGUIButton* CancelButton; @@ -58,8 +57,8 @@ namespace gui IGUIElement* FileNameText; IGUIElement* EventParent; io::IFileSystem* FileSystem; - io::IFileList* FileList; + bool Dragging; }; diff --git a/source/Irrlicht/CGUIFont.cpp b/source/Irrlicht/CGUIFont.cpp index d07da50d..650c862c 100644 --- a/source/Irrlicht/CGUIFont.cpp +++ b/source/Irrlicht/CGUIFont.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -96,7 +96,7 @@ bool CGUIFont::load(io::IXMLReader* xml) if (alpha == core::stringw("false")) Driver->makeColorKeyTexture(SpriteBank->getTexture(i), core::position2di(0,0)); } - } + } else if (core::stringw(L"c") == xml->getNodeName()) { // adding a character to this font @@ -112,45 +112,45 @@ bool CGUIFont::load(io::IXMLReader* xml) // parse rectangle core::stringc rectstr = xml->getAttributeValue(L"r"); - wchar_t ch = xml->getAttributeValue(L"c")[0]; + wchar_t ch = xml->getAttributeValue(L"c")[0]; const c8 *c = rectstr.c_str(); s32 val; val = 0; - while (*c >= '0' && *c <= '9') - { - val *= 10; - val += *c - '0'; + while (*c >= '0' && *c <= '9') + { + val *= 10; + val += *c - '0'; c++; } rectangle.UpperLeftCorner.X = val; while (*c == L' ' || *c == L',') c++; val = 0; - while (*c >= '0' && *c <= '9') - { - val *= 10; - val += *c - '0'; + while (*c >= '0' && *c <= '9') + { + val *= 10; + val += *c - '0'; c++; } rectangle.UpperLeftCorner.Y = val; while (*c == L' ' || *c == L',') c++; val = 0; - while (*c >= '0' && *c <= '9') - { - val *= 10; - val += *c - '0'; + while (*c >= '0' && *c <= '9') + { + val *= 10; + val += *c - '0'; c++; } rectangle.LowerRightCorner.X = val; while (*c == L' ' || *c == L',') c++; val = 0; - while (*c >= '0' && *c <= '9') - { - val *= 10; - val += *c - '0'; + while (*c >= '0' && *c <= '9') + { + val *= 10; + val += *c - '0'; c++; } rectangle.LowerRightCorner.Y = val; @@ -158,7 +158,7 @@ bool CGUIFont::load(io::IXMLReader* xml) CharacterMap.insert(ch,Areas.size()); // make frame - f.rectNumber = SpriteBank->getPositions().size(); + f.rectNumber = SpriteBank->getPositions().size(); f.textureNumber = texno; // add frame to sprite @@ -279,7 +279,7 @@ bool CGUIFont::loadTexture(video::IImage* image, const c8* name) void CGUIFont::readPositions32bit(video::IImage* image, s32& lowerRightPositions) { - const core::dimension2d& size = image->getDimension(); + const core::dimension2d& size = image->getDimension(); s32* p = (s32*)image->lock(); if (!p) @@ -301,9 +301,9 @@ void CGUIFont::readPositions32bit(video::IImage* image, s32& lowerRightPositions // start parsing core::position2d pos(0,0); - for (pos.Y=0; pos.Y size = image->getDimension(); + core::dimension2d size = image->getDimension(); s16* p = (s16*)image->lock(); if (!p) @@ -382,9 +382,9 @@ void CGUIFont::readPositions16bit(video::IImage* image, s32& lowerRightPositions // start parsing core::position2d pos(0,0); - for (pos.Y=0; pos.Y CGUIFont::getDimension(const wchar_t* text) const +core::dimension2d CGUIFont::getDimension(const wchar_t* text) const { - core::dimension2d dim(0, 0); - core::dimension2d thisLine(0, MaxHeight); + core::dimension2d dim(0, 0); + core::dimension2d thisLine(0, MaxHeight); for (const wchar_t* p = text; *p; ++p) { @@ -481,7 +481,7 @@ core::dimension2d CGUIFont::getDimension(const wchar_t* text) const //! set an Pixel Offset on Drawing ( scale position on width ) -void CGUIFont::setKerningWidth ( s32 kerning ) +void CGUIFont::setKerningWidth(s32 kerning) { GlobalKerningWidth = kerning; } @@ -507,7 +507,7 @@ s32 CGUIFont::getKerningWidth(const wchar_t* thisLetter, const wchar_t* previous //! set an Pixel Offset on Drawing ( scale position on height ) -void CGUIFont::setKerningHeight ( s32 kerning ) +void CGUIFont::setKerningHeight(s32 kerning) { GlobalKerningHeight = kerning; } @@ -544,7 +544,7 @@ void CGUIFont::draw(const wchar_t* text, const core::rect& position, video: if (!Driver) return; - core::dimension2d textDimension; + core::dimension2d textDimension; core::position2d offset = position.UpperLeftCorner; if (hcenter || vcenter) @@ -580,7 +580,7 @@ void CGUIFont::draw(const wchar_t* text, const core::rect& position, video: if (!Driver) return; - core::dimension2d textDimension; + core::dimension2d textDimension; core::position2d offset = position.UpperLeftCorner; if (hcenter || vcenter || clip) @@ -594,7 +594,7 @@ void CGUIFont::draw(const wchar_t* text, const core::rect& position, video: if (clip) { - core::rect clippedRect(offset, textDimension); + core::rect clippedRect(offset, core::dimension2d(textDimension)); clippedRect.clipAgainst(*clip); if (!clippedRect.isValid()) return; @@ -646,3 +646,4 @@ IGUISpriteBank* CGUIFont::getSpriteBank() const } // end namespace irr #endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIFont.h b/source/Irrlicht/CGUIFont.h index 9884d02d..cb6abf6a 100644 --- a/source/Irrlicht/CGUIFont.h +++ b/source/Irrlicht/CGUIFont.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -54,7 +54,7 @@ public: bool vcenter=false, const core::rect* clip=0); //! returns the dimension of a text - virtual core::dimension2d getDimension(const wchar_t* text) const; + virtual core::dimension2d getDimension(const wchar_t* text) const; //! Calculates the index of the character in the text which is on a specific position. virtual s32 getCharacterFromPos(const wchar_t* text, s32 pixel_x) const; diff --git a/source/Irrlicht/CGUIImage.cpp b/source/Irrlicht/CGUIImage.cpp index 1a112323..0bf3dd89 100644 --- a/source/Irrlicht/CGUIImage.cpp +++ b/source/Irrlicht/CGUIImage.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -15,11 +15,10 @@ namespace gui { - //! constructor CGUIImage::CGUIImage(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle) -: IGUIImage(environment, parent, id, rectangle), Color(255,255,255,255), - Texture(0), UseAlphaChannel(false), ScaleImage(false) +: IGUIImage(environment, parent, id, rectangle), Texture(0), Color(255,255,255,255), + UseAlphaChannel(false), ScaleImage(false) { #ifdef _DEBUG setDebugName("CGUIImage"); @@ -27,7 +26,6 @@ CGUIImage::CGUIImage(IGUIEnvironment* environment, IGUIElement* parent, s32 id, } - //! destructor CGUIImage::~CGUIImage() { @@ -36,7 +34,6 @@ CGUIImage::~CGUIImage() } - //! sets an image void CGUIImage::setImage(video::ITexture* image) { @@ -77,14 +74,14 @@ void CGUIImage::draw() { const video::SColor Colors[] = {Color,Color,Color,Color}; - driver->draw2DImage(Texture, AbsoluteRect, - core::rect(core::position2d(0,0), Texture->getOriginalSize()), + driver->draw2DImage(Texture, AbsoluteRect, + core::rect(core::position2d(0,0), core::dimension2di(Texture->getOriginalSize())), &AbsoluteClippingRect, Colors, UseAlphaChannel); } else { - driver->draw2DImage(Texture, AbsoluteRect.UpperLeftCorner, - core::rect(core::position2d(0,0), Texture->getOriginalSize()), + driver->draw2DImage(Texture, AbsoluteRect.UpperLeftCorner, + core::rect(core::position2d(0,0), core::dimension2di(Texture->getOriginalSize())), &AbsoluteClippingRect, Color, UseAlphaChannel); } } @@ -103,12 +100,14 @@ void CGUIImage::setUseAlphaChannel(bool use) UseAlphaChannel = use; } + //! sets if the image should use its alpha channel to draw itself void CGUIImage::setScaleImage(bool scale) { ScaleImage = scale; } + //! Returns true if the image is scaled to fit, false if not bool CGUIImage::isImageScaled() const { @@ -136,6 +135,7 @@ void CGUIImage::serializeAttributes(io::IAttributes* out, io::SAttributeReadWrit } + //! Reads attributes of the element void CGUIImage::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) { @@ -148,10 +148,9 @@ void CGUIImage::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWri } - - } // end namespace gui } // end namespace irr #endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIImage.h b/source/Irrlicht/CGUIImage.h index 171cef50..f0a9d699 100644 --- a/source/Irrlicht/CGUIImage.h +++ b/source/Irrlicht/CGUIImage.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -52,10 +52,9 @@ namespace gui //! Reads attributes of the element virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options); - private: - video::SColor Color; video::ITexture* Texture; + video::SColor Color; bool UseAlphaChannel; bool ScaleImage; diff --git a/source/Irrlicht/CGUIInOutFader.cpp b/source/Irrlicht/CGUIInOutFader.cpp index e89304f6..bf513ad2 100644 --- a/source/Irrlicht/CGUIInOutFader.cpp +++ b/source/Irrlicht/CGUIInOutFader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -63,7 +63,6 @@ void CGUIInOutFader::draw() } - //! Gets the color to fade out to or to fade in from. video::SColor CGUIInOutFader::getColor() const { @@ -71,7 +70,6 @@ video::SColor CGUIInOutFader::getColor() const } - //! Sets the color to fade out to or to fade in from. void CGUIInOutFader::setColor(video::SColor color) { @@ -90,7 +88,7 @@ void CGUIInOutFader::setColor(video::SColor color) if (Action == EFA_FADE_OUT) { - FullColor.setAlpha(0); + FullColor.setAlpha(0); TransColor.setAlpha(255); } else @@ -102,6 +100,7 @@ void CGUIInOutFader::setColor(video::SColor color) */ } + void CGUIInOutFader::setColor(video::SColor source, video::SColor dest) { Color[0] = source; @@ -123,7 +122,7 @@ void CGUIInOutFader::setColor(video::SColor source, video::SColor dest) //! Returns if the fade in or out process is done. -bool CGUIInOutFader::isReady() const +bool CGUIInOutFader::isReady() const { u32 now = os::Timer::getTime(); bool ret = (now > EndTime); @@ -132,7 +131,6 @@ bool CGUIInOutFader::isReady() const } - //! Starts the fade in process. void CGUIInOutFader::fadeIn(u32 time) { @@ -152,6 +150,7 @@ void CGUIInOutFader::fadeOut(u32 time) setColor(Color[0],Color[1]); } + //! Writes attributes of the element. void CGUIInOutFader::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const { @@ -162,6 +161,7 @@ void CGUIInOutFader::serializeAttributes(io::IAttributes* out, io::SAttributeRea } + //! Reads attributes of the element void CGUIInOutFader::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) { @@ -172,7 +172,6 @@ void CGUIInOutFader::deserializeAttributes(io::IAttributes* in, io::SAttributeRe } - } // end namespace gui } // end namespace irr diff --git a/source/Irrlicht/CGUIInOutFader.h b/source/Irrlicht/CGUIInOutFader.h index 7cf58b0e..6e9ba3e8 100644 --- a/source/Irrlicht/CGUIInOutFader.h +++ b/source/Irrlicht/CGUIInOutFader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -59,12 +59,11 @@ namespace gui u32 StartTime; u32 EndTime; - EFadeAction Action; + EFadeAction Action; video::SColor Color[2]; video::SColor FullColor; video::SColor TransColor; - }; } // end namespace gui diff --git a/source/Irrlicht/CGUIListBox.cpp b/source/Irrlicht/CGUIListBox.cpp index 6f88037b..61132901 100644 --- a/source/Irrlicht/CGUIListBox.cpp +++ b/source/Irrlicht/CGUIListBox.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -25,9 +25,8 @@ CGUIListBox::CGUIListBox(IGUIEnvironment* environment, IGUIElement* parent, bool drawBack, bool moveOverSelect) : IGUIListBox(environment, parent, id, rectangle), Selected(-1), ItemHeight(0), TotalItemHeight(0), ItemsIconWidth(0), Font(0), IconBank(0), - ScrollBar(0), Selecting(false), DrawBack(drawBack), - MoveOverSelect(moveOverSelect), selectTime(0), AutoScroll(true), - KeyBuffer(), LastKeyTime(0), HighlightWhenNotFocused(true) + ScrollBar(0), selectTime(0), LastKeyTime(0), Selecting(false), DrawBack(drawBack), + MoveOverSelect(moveOverSelect), AutoScroll(true), HighlightWhenNotFocused(true) { #ifdef _DEBUG setDebugName("CGUIListBox"); diff --git a/source/Irrlicht/CGUIListBox.h b/source/Irrlicht/CGUIListBox.h index 88e51f8c..798e561d 100644 --- a/source/Irrlicht/CGUIListBox.h +++ b/source/Irrlicht/CGUIListBox.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -23,7 +23,7 @@ namespace gui { public: //! constructor - CGUIListBox(IGUIEnvironment* environment, IGUIElement* parent, + CGUIListBox(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle, bool clip=true, bool drawBack=false, bool moveOverSelect=false); @@ -72,7 +72,7 @@ namespace gui //! An icon is an index within the icon sprite bank. Several default icons are available in the //! skin through getIcon virtual void setSpriteBank(IGUISpriteBank* bank); - + //! sets if automatic scrolling is enabled or not. Default is true. virtual void setAutoScrollEnabled(bool scroll); @@ -97,22 +97,22 @@ namespace gui //! clear all item colors at index virtual void clearItemOverrideColor(u32 index); - //! clear item color at index for given colortype + //! clear item color at index for given colortype virtual void clearItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType); //! has the item at index its color overwritten? virtual bool hasItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const; - //! return the overwrite color at given item index. + //! return the overwrite color at given item index. virtual video::SColor getItemOverrideColor(u32 index, EGUI_LISTBOX_COLOR colorType) const; //! return the default color which is used for the given colorType virtual video::SColor getItemDefaultColor(EGUI_LISTBOX_COLOR colorType) const; - //! set the item at the given index + //! set the item at the given index virtual void setItem(u32 index, const wchar_t* text, s32 icon); - //! Insert the item at the given index + //! Insert the item at the given index //! Return the index on success or -1 on failure. virtual s32 insertItem(u32 index, const wchar_t* text, s32 icon); @@ -123,7 +123,7 @@ namespace gui struct ListItem { - ListItem() : icon(-1) + ListItem() : icon(-1) {} core::stringw text; @@ -157,13 +157,13 @@ namespace gui gui::IGUIFont* Font; gui::IGUISpriteBank* IconBank; gui::IGUIScrollBar* ScrollBar; + u32 selectTime; + u32 LastKeyTime; + core::stringw KeyBuffer; bool Selecting; bool DrawBack; bool MoveOverSelect; - u32 selectTime; bool AutoScroll; - core::stringw KeyBuffer; - u32 LastKeyTime; bool HighlightWhenNotFocused; }; diff --git a/source/Irrlicht/CGUIMenu.cpp b/source/Irrlicht/CGUIMenu.cpp index 542fed00..1993037d 100644 --- a/source/Irrlicht/CGUIMenu.cpp +++ b/source/Irrlicht/CGUIMenu.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -19,8 +19,8 @@ namespace gui //! constructor CGUIMenu::CGUIMenu(IGUIEnvironment* environment, IGUIElement* parent, - s32 id, core::rect rectangle) - : CGUIContextMenu(environment, parent, id, rectangle, false, true) + s32 id, core::rect rectangle) + : CGUIContextMenu(environment, parent, id, rectangle, false, true) { #ifdef _DEBUG setDebugName("CGUIMenu"); @@ -42,7 +42,7 @@ void CGUIMenu::draw() IGUISkin* skin = Environment->getSkin(); IGUIFont* font = skin->getFont(EGDF_MENU); - + if (font != LastFont) { if (LastFont) @@ -87,7 +87,7 @@ void CGUIMenu::draw() c = EGDC_GRAY_TEXT; if (font) - font->draw(Items[i].Text.c_str(), rect, + font->draw(Items[i].Text.c_str(), rect, skin->getColor(c), true, true, &AbsoluteClippingRect); } } @@ -135,7 +135,7 @@ bool CGUIMenu::OnEvent(const SEvent& event) } if (Parent) - Parent->bringToFront(this); + Parent->bringToFront(this); core::position2d p(event.MouseInput.X, event.MouseInput.Y); bool shouldCloseSubMenu = hasOpenSubMenu(); @@ -241,12 +241,14 @@ core::rect CGUIMenu::getHRect(const SItem& i, const core::rect& absolu return r; } + //! Gets drawing rect of Item core::rect CGUIMenu::getRect(const SItem& i, const core::rect& absolute) const { return getHRect(i, absolute); } + void CGUIMenu::updateAbsolutePosition() { if (Parent) diff --git a/source/Irrlicht/CGUIMenu.h b/source/Irrlicht/CGUIMenu.h index 391dd866..c7168f76 100644 --- a/source/Irrlicht/CGUIMenu.h +++ b/source/Irrlicht/CGUIMenu.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -49,3 +49,4 @@ namespace gui #endif // __C_GUI_MENU_H_INCLUDED__ #endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIMeshViewer.cpp b/source/Irrlicht/CGUIMeshViewer.cpp index 99685da1..501218dc 100644 --- a/source/Irrlicht/CGUIMeshViewer.cpp +++ b/source/Irrlicht/CGUIMeshViewer.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -172,4 +172,3 @@ void CGUIMeshViewer::draw() #endif // _IRR_COMPILE_WITH_GUI_ - diff --git a/source/Irrlicht/CGUIMeshViewer.h b/source/Irrlicht/CGUIMeshViewer.h index ee0b3edf..cf6d148c 100644 --- a/source/Irrlicht/CGUIMeshViewer.h +++ b/source/Irrlicht/CGUIMeshViewer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CGUIMessageBox.cpp b/source/Irrlicht/CGUIMessageBox.cpp index 8073e358..57e524a0 100644 --- a/source/Irrlicht/CGUIMessageBox.cpp +++ b/source/Irrlicht/CGUIMessageBox.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -295,8 +295,8 @@ bool CGUIMessageBox::OnEvent(const SEvent& event) { // cancel press if (OkButton) OkButton->setPressed(false); - if (YesButton) OkButton->setPressed(false); - if (NoButton) OkButton->setPressed(false); + if (YesButton) YesButton->setPressed(false); + if (NoButton) NoButton->setPressed(false); Pressed = false; } else @@ -397,6 +397,7 @@ bool CGUIMessageBox::OnEvent(const SEvent& event) return CGUIWindow::OnEvent(event); } + //! Writes attributes of the element. void CGUIMessageBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const { @@ -410,6 +411,7 @@ void CGUIMessageBox::serializeAttributes(io::IAttributes* out, io::SAttributeRea out->addString ("MessageText", MessageText.c_str()); } + //! Reads attributes of the element void CGUIMessageBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0) { @@ -431,6 +433,5 @@ void CGUIMessageBox::deserializeAttributes(io::IAttributes* in, io::SAttributeRe } // end namespace gui } // end namespace irr - #endif // _IRR_COMPILE_WITH_GUI_ diff --git a/source/Irrlicht/CGUIMessageBox.h b/source/Irrlicht/CGUIMessageBox.h index 80cde846..5686e028 100644 --- a/source/Irrlicht/CGUIMessageBox.h +++ b/source/Irrlicht/CGUIMessageBox.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -57,4 +57,4 @@ namespace gui #endif // _IRR_COMPILE_WITH_GUI_ -#endif +#endif diff --git a/source/Irrlicht/CGUIModalScreen.cpp b/source/Irrlicht/CGUIModalScreen.cpp index 084ef401..e69c8437 100644 --- a/source/Irrlicht/CGUIModalScreen.cpp +++ b/source/Irrlicht/CGUIModalScreen.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -24,7 +24,7 @@ CGUIModalScreen::CGUIModalScreen(IGUIEnvironment* environment, IGUIElement* pare setDebugName("CGUIModalScreen"); #endif setAlignment(EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_LOWERRIGHT); - + // this element is a tab group setTabGroup(true); } @@ -69,7 +69,7 @@ bool CGUIModalScreen::OnEvent(const SEvent& event) default: break; } - + IGUIElement::OnEvent(event); return true; // absorb everything else @@ -110,7 +110,6 @@ void CGUIModalScreen::draw() } - //! Removes a child. void CGUIModalScreen::removeChild(IGUIElement* child) { @@ -120,6 +119,7 @@ void CGUIModalScreen::removeChild(IGUIElement* child) remove(); } + //! adds a child void CGUIModalScreen::addChild(IGUIElement* child) { @@ -144,6 +144,7 @@ void CGUIModalScreen::updateAbsolutePosition() IGUIElement::updateAbsolutePosition(); } + //! Writes attributes of the element. void CGUIModalScreen::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const { @@ -161,3 +162,4 @@ void CGUIModalScreen::deserializeAttributes(io::IAttributes* in, io::SAttributeR } // end namespace irr #endif // _IRR_COMPILE_WITH_GUI_ + diff --git a/source/Irrlicht/CGUIModalScreen.h b/source/Irrlicht/CGUIModalScreen.h index 38e339b0..d87da732 100644 --- a/source/Irrlicht/CGUIModalScreen.h +++ b/source/Irrlicht/CGUIModalScreen.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -56,3 +56,4 @@ namespace gui #endif // _IRR_COMPILE_WITH_GUI_ #endif + diff --git a/source/Irrlicht/CGUIScrollBar.cpp b/source/Irrlicht/CGUIScrollBar.cpp index b5959d5c..09bee5b6 100644 --- a/source/Irrlicht/CGUIScrollBar.cpp +++ b/source/Irrlicht/CGUIScrollBar.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -185,7 +185,7 @@ bool CGUIScrollBar::OnEvent(const SEvent& event) return true; } } - + if (DraggedBySlider) { setPos(newPos); @@ -219,6 +219,7 @@ bool CGUIScrollBar::OnEvent(const SEvent& event) return IGUIElement::OnEvent(event); } + //! draws the element and its children void CGUIScrollBar::draw() { @@ -239,10 +240,10 @@ void CGUIScrollBar::draw() if (DesiredPos >= Pos + LargeStep) setPos(Pos + LargeStep); - else + else if (DesiredPos <= Pos - LargeStep) setPos(Pos - LargeStep); - else + else if (DesiredPos >= Pos - LargeStep && DesiredPos <= Pos + LargeStep) setPos(DesiredPos); @@ -283,6 +284,7 @@ void CGUIScrollBar::draw() IGUIElement::draw(); } + void CGUIScrollBar::updateAbsolutePosition() { IGUIElement::updateAbsolutePosition(); @@ -323,7 +325,6 @@ s32 CGUIScrollBar::getPosFromMousePos(s32 x, s32 y) const } - //! sets the position of the scrollbar void CGUIScrollBar::setPos(s32 pos) { @@ -368,6 +369,7 @@ void CGUIScrollBar::setSmallStep(s32 step) SmallStep = 10; } + //! gets the small step value s32 CGUIScrollBar::getLargeStep() const { @@ -385,7 +387,6 @@ void CGUIScrollBar::setLargeStep(s32 step) } - //! gets the maximum value of the scrollbar. s32 CGUIScrollBar::getMax() const { diff --git a/source/Irrlicht/CGUIScrollBar.h b/source/Irrlicht/CGUIScrollBar.h index 6bcdc505..258e273c 100644 --- a/source/Irrlicht/CGUIScrollBar.h +++ b/source/Irrlicht/CGUIScrollBar.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CGUISkin.cpp b/source/Irrlicht/CGUISkin.cpp index d63bcb8d..95edab88 100644 --- a/source/Irrlicht/CGUISkin.cpp +++ b/source/Irrlicht/CGUISkin.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -23,9 +23,7 @@ CGUISkin::CGUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver) setDebugName("CGUISkin"); #endif - if ( (Type == EGST_WINDOWS_CLASSIC) | - (Type == EGST_WINDOWS_METALLIC) - ) + if ((Type == EGST_WINDOWS_CLASSIC) || (Type == EGST_WINDOWS_METALLIC)) { Colors[EGDC_3D_DARK_SHADOW] = video::SColor(101,50,50,50); Colors[EGDC_3D_SHADOW] = video::SColor(101,130,130,130); @@ -57,7 +55,7 @@ CGUISkin::CGUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver) Sizes[EGDS_MESSAGE_BOX_HEIGHT] = 200; Sizes[EGDS_BUTTON_WIDTH] = 80; Sizes[EGDS_BUTTON_HEIGHT] = 30; - + Sizes[EGDS_TEXT_DISTANCE_X] = 2; Sizes[EGDS_TEXT_DISTANCE_Y] = 0; } @@ -68,7 +66,7 @@ CGUISkin::CGUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver) //Colors[EGDC_3D_FACE] = 0xc0c9ccd4; // tab background Colors[EGDC_3D_FACE] = 0xc0cbd2d9; // tab background Colors[EGDC_3D_SHADOW] = 0x50e4e8f1; // tab background, and left-top highlight - Colors[EGDC_3D_HIGH_LIGHT] = 0x40c7ccdc; + Colors[EGDC_3D_HIGH_LIGHT] = 0x40c7ccdc; Colors[EGDC_3D_LIGHT] = 0x802e313a; Colors[EGDC_ACTIVE_BORDER] = 0x80404040; // window title Colors[EGDC_ACTIVE_CAPTION] = 0xf0d0d0d0; @@ -137,8 +135,7 @@ CGUISkin::CGUISkin(EGUI_SKIN_TYPE type, video::IVideoDriver* driver) for (u32 i=0; i rect = r; if ( Type == EGST_BURNING_SKIN ) - { + { rect.UpperLeftCorner.Y -= 3; draw3DButtonPaneStandard(element, rect, clip); return; @@ -693,7 +692,7 @@ void CGUISkin::draw3DTabButton(IGUIElement* element, bool active, tr.LowerRightCorner.Y = tr.UpperLeftCorner.Y + 1; tr.UpperLeftCorner.X += 1; Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); - + // draw left highlight tr = frameRect; tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1; @@ -707,17 +706,15 @@ void CGUISkin::draw3DTabButton(IGUIElement* element, bool active, tr.LowerRightCorner.X -= 2; Driver->draw2DRectangle(getColor(EGDC_3D_FACE), tr, clip); - // draw right middle gray shadow tr.LowerRightCorner.X += 1; tr.UpperLeftCorner.X = tr.LowerRightCorner.X - 1; Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), tr, clip); - tr.LowerRightCorner.X += 1; tr.UpperLeftCorner.X += 1; tr.UpperLeftCorner.Y += 1; - Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), tr, clip); + Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), tr, clip); } else { @@ -725,7 +722,7 @@ void CGUISkin::draw3DTabButton(IGUIElement* element, bool active, tr.UpperLeftCorner.Y = tr.LowerRightCorner.Y - 1; tr.UpperLeftCorner.X += 1; Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); - + // draw left highlight tr = frameRect; tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1; @@ -739,20 +736,18 @@ void CGUISkin::draw3DTabButton(IGUIElement* element, bool active, tr.LowerRightCorner.X -= 2; tr.LowerRightCorner.Y -= 1; Driver->draw2DRectangle(getColor(EGDC_3D_FACE), tr, clip); - + // draw right middle gray shadow tr.LowerRightCorner.X += 1; tr.UpperLeftCorner.X = tr.LowerRightCorner.X - 1; //tr.LowerRightCorner.Y -= 1; Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), tr, clip); - tr.LowerRightCorner.X += 1; tr.UpperLeftCorner.X += 1; tr.LowerRightCorner.Y -= 1; - Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), tr, clip); + Driver->draw2DRectangle(getColor(EGDC_3D_DARK_SHADOW), tr, clip); } - } @@ -785,7 +780,6 @@ void CGUISkin::draw3DTabBody(IGUIElement* element, bool border, bool background, tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1; Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); - // draw right shadow tr.UpperLeftCorner.X = rect.LowerRightCorner.X - 1; tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1; @@ -795,7 +789,6 @@ void CGUISkin::draw3DTabBody(IGUIElement* element, bool border, bool background, tr = rect; tr.UpperLeftCorner.Y = tr.LowerRightCorner.Y - 1; Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), tr, clip); - } else { @@ -803,23 +796,21 @@ void CGUISkin::draw3DTabBody(IGUIElement* element, bool border, bool background, tr.LowerRightCorner.Y -= tabHeight + 2; tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1; Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); - + // draw right shadow tr.UpperLeftCorner.X = rect.LowerRightCorner.X - 1; tr.LowerRightCorner.X = tr.UpperLeftCorner.X + 1; Driver->draw2DRectangle(getColor(EGDC_3D_SHADOW), tr, clip); - + // draw lower shadow tr = rect; tr.LowerRightCorner.Y = tr.UpperLeftCorner.Y + 1; Driver->draw2DRectangle(getColor(EGDC_3D_HIGH_LIGHT), tr, clip); - } } if (background) { - if ( alignment == EGUIA_UPPERLEFT ) { tr = rect; @@ -851,9 +842,9 @@ void CGUISkin::draw3DTabBody(IGUIElement* element, bool border, bool background, //! draws an icon, usually from the skin's sprite bank -/** \param parent: Pointer to the element which wishes to draw this icon. -This parameter is usually not used by IGUISkin, but can be used for example -by more complex implementations to find out how to draw the part exactly. +/** \param parent: Pointer to the element which wishes to draw this icon. +This parameter is usually not used by IGUISkin, but can be used for example +by more complex implementations to find out how to draw the part exactly. \param icon: Specifies the icon to be drawn. \param position: The position to draw the icon \param starttime: The time at the start of the animation @@ -862,13 +853,13 @@ by more complex implementations to find out how to draw the part exactly. \param clip: Clip area. */ void CGUISkin::drawIcon(IGUIElement* element, EGUI_DEFAULT_ICON icon, const core::position2di position, - u32 starttime, u32 currenttime, + u32 starttime, u32 currenttime, bool loop, const core::rect* clip) { if (!SpriteBank) return; - SpriteBank->draw2DSprite(Icons[icon], position, clip, + SpriteBank->draw2DSprite(Icons[icon], position, clip, video::SColor(255,0,0,0), starttime, currenttime, loop, true); } @@ -889,7 +880,7 @@ void CGUISkin::draw2DRectangle(IGUIElement* element, //! Writes attributes of the object. -//! Implement this to expose the attributes of your scene node animator for +//! Implement this to expose the attributes of your scene node animator for //! scripting languages, editors, debuggers or xml serialization purposes. void CGUISkin::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const { @@ -909,7 +900,7 @@ void CGUISkin::serializeAttributes(io::IAttributes* out, io::SAttributeReadWrite //! Reads attributes of the object. -//! Implement this to set the attributes of your scene node animator for +//! Implement this to set the attributes of your scene node animator for //! scripting languages, editors, debuggers or xml deserialization purposes. void CGUISkin::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) { @@ -933,4 +924,3 @@ void CGUISkin::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWrit #endif // _IRR_COMPILE_WITH_GUI_ - diff --git a/source/Irrlicht/CGUISkin.h b/source/Irrlicht/CGUISkin.h index 7d7b56ac..8ac2c208 100644 --- a/source/Irrlicht/CGUISkin.h +++ b/source/Irrlicht/CGUISkin.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -58,56 +58,56 @@ namespace gui virtual u32 getIcon(EGUI_DEFAULT_ICON icon) const; //! Sets a default icon - /** Sets the sprite index used for drawing icons like arrows, - close buttons and ticks in checkboxes + /** Sets the sprite index used for drawing icons like arrows, + close buttons and ticks in checkboxes \param icon: Enum specifying which icon to change \param index: The sprite index used to draw this icon */ virtual void setIcon(EGUI_DEFAULT_ICON icon, u32 index); //! Returns a default text. /** For example for Message box button captions: - "OK", "Cancel", "Yes", "No" and so on. */ + "OK", "Cancel", "Yes", "No" and so on. */ virtual const wchar_t* getDefaultText(EGUI_DEFAULT_TEXT text) const; - //! Sets a default text. + //! Sets a default text. /** For example for Message box button captions: - "OK", "Cancel", "Yes", "No" and so on. */ + "OK", "Cancel", "Yes", "No" and so on. */ virtual void setDefaultText(EGUI_DEFAULT_TEXT which, const wchar_t* newText); //! draws a standard 3d button pane - /** Used for drawing for example buttons in normal state. + /** Used for drawing for example buttons in normal state. It uses the colors EGDC_3D_DARK_SHADOW, EGDC_3D_HIGH_LIGHT, EGDC_3D_SHADOW and - EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details. + EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details. \param rect: Defining area where to draw. \param clip: Clip area. \param element: Pointer to the element which wishes to draw this. This parameter - is usually not used by ISkin, but can be used for example by more complex + is usually not used by ISkin, but can be used for example by more complex implementations to find out how to draw the part exactly. */ - virtual void draw3DButtonPaneStandard(IGUIElement* element, + virtual void draw3DButtonPaneStandard(IGUIElement* element, const core::rect& rect, const core::rect* clip=0); //! draws a pressed 3d button pane - /** Used for drawing for example buttons in pressed state. + /** Used for drawing for example buttons in pressed state. It uses the colors EGDC_3D_DARK_SHADOW, EGDC_3D_HIGH_LIGHT, EGDC_3D_SHADOW and - EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details. + EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details. \param rect: Defining area where to draw. \param clip: Clip area. \param element: Pointer to the element which wishes to draw this. This parameter - is usually not used by ISkin, but can be used for example by more complex + is usually not used by ISkin, but can be used for example by more complex implementations to find out how to draw the part exactly. */ - virtual void draw3DButtonPanePressed(IGUIElement* element, + virtual void draw3DButtonPanePressed(IGUIElement* element, const core::rect& rect, const core::rect* clip=0); //! draws a sunken 3d pane /** Used for drawing the background of edit, combo or check boxes. \param element: Pointer to the element which wishes to draw this. This parameter - is usually not used by ISkin, but can be used for example by more complex - implementations to find out how to draw the part exactly. + is usually not used by ISkin, but can be used for example by more complex + implementations to find out how to draw the part exactly. \param bgcolor: Background color. - \param flat: Specifies if the sunken pane should be flat or displayed as sunken - deep into the ground. + \param flat: Specifies if the sunken pane should be flat or displayed as sunken + deep into the ground. \param rect: Defining area where to draw. \param clip: Clip area. */ virtual void draw3DSunkenPane(IGUIElement* element, @@ -119,8 +119,8 @@ namespace gui //! draws a window background /** Used for drawing the background of dialogs and windows. \param element: Pointer to the element which wishes to draw this. This parameter - is usually not used by ISkin, but can be used for example by more complex - implementations to find out how to draw the part exactly. + is usually not used by ISkin, but can be used for example by more complex + implementations to find out how to draw the part exactly. \param titleBarColor: Title color. \param drawTitleBar: True to enable title drawing. \param rect: Defining area where to draw. @@ -132,12 +132,12 @@ namespace gui const core::rect* clip=0); //! draws a standard 3d menu pane - /** Used for drawing for menus and context menus. + /** Used for drawing for menus and context menus. It uses the colors EGDC_3D_DARK_SHADOW, EGDC_3D_HIGH_LIGHT, EGDC_3D_SHADOW and - EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details. + EGDC_3D_FACE for this. See EGUI_DEFAULT_COLOR for details. \param element: Pointer to the element which wishes to draw this. This parameter - is usually not used by ISkin, but can be used for example by more complex - implementations to find out how to draw the part exactly. + is usually not used by ISkin, but can be used for example by more complex + implementations to find out how to draw the part exactly. \param rect: Defining area where to draw. \param clip: Clip area. */ virtual void draw3DMenuPane(IGUIElement* element, @@ -145,10 +145,10 @@ namespace gui const core::rect* clip=0); //! draws a standard 3d tool bar - /** Used for drawing for toolbars and menus. + /** Used for drawing for toolbars and menus. \param element: Pointer to the element which wishes to draw this. This parameter - is usually not used by ISkin, but can be used for example by more complex - implementations to find out how to draw the part exactly. + is usually not used by ISkin, but can be used for example by more complex + implementations to find out how to draw the part exactly. \param rect: Defining area where to draw. \param clip: Clip area. */ virtual void draw3DToolBar(IGUIElement* element, @@ -156,10 +156,10 @@ namespace gui const core::rect* clip=0); //! draws a tab button - /** Used for drawing for tab buttons on top of tabs. + /** Used for drawing for tab buttons on top of tabs. \param element: Pointer to the element which wishes to draw this. This parameter - is usually not used by ISkin, but can be used for example by more complex - implementations to find out how to draw the part exactly. + is usually not used by ISkin, but can be used for example by more complex + implementations to find out how to draw the part exactly. \param active: Specifies if the tab is currently active. \param rect: Defining area where to draw. \param clip: Clip area. */ @@ -167,9 +167,9 @@ namespace gui const core::rect& rect, const core::rect* clip=0, EGUI_ALIGNMENT alignment=EGUIA_UPPERLEFT); //! draws a tab control body - /** \param element: Pointer to the element which wishes to draw this. This parameter - is usually not used by ISkin, but can be used for example by more complex - implementations to find out how to draw the part exactly. + /** \param element: Pointer to the element which wishes to draw this. This parameter + is usually not used by ISkin, but can be used for example by more complex + implementations to find out how to draw the part exactly. \param border: Specifies if the border should be drawn. \param background: Specifies if the background should be drawn. \param rect: Defining area where to draw. @@ -178,9 +178,9 @@ namespace gui const core::rect& rect, const core::rect* clip=0, s32 tabHeight=-1, EGUI_ALIGNMENT alignment=EGUIA_UPPERLEFT); //! draws an icon, usually from the skin's sprite bank - /** \param element: Pointer to the element which wishes to draw this icon. - This parameter is usually not used by IGUISkin, but can be used for example - by more complex implementations to find out how to draw the part exactly. + /** \param element: Pointer to the element which wishes to draw this icon. + This parameter is usually not used by IGUISkin, but can be used for example + by more complex implementations to find out how to draw the part exactly. \param icon: Specifies the icon to be drawn. \param position: The position to draw the icon \param starttime: The time at the start of the animation @@ -189,20 +189,20 @@ namespace gui \param clip: Clip area. */ virtual void drawIcon(IGUIElement* element, EGUI_DEFAULT_ICON icon, const core::position2di position, - u32 starttime=0, u32 currenttime=0, + u32 starttime=0, u32 currenttime=0, bool loop=false, const core::rect* clip=0); //! draws a 2d rectangle. - /** \param element: Pointer to the element which wishes to draw this icon. - This parameter is usually not used by IGUISkin, but can be used for example - by more complex implementations to find out how to draw the part exactly. - \param color: Color of the rectangle to draw. The alpha component specifies how + /** \param element: Pointer to the element which wishes to draw this icon. + This parameter is usually not used by IGUISkin, but can be used for example + by more complex implementations to find out how to draw the part exactly. + \param color: Color of the rectangle to draw. The alpha component specifies how transparent the rectangle will be. \param pos: Position of the rectangle. \param clip: Pointer to rectangle against which the rectangle will be clipped. If the pointer is null, no clipping will be performed. */ - virtual void draw2DRectangle(IGUIElement* element, const video::SColor &color, + virtual void draw2DRectangle(IGUIElement* element, const video::SColor &color, const core::rect& pos, const core::rect* clip = 0); @@ -210,12 +210,12 @@ namespace gui virtual EGUI_SKIN_TYPE getType() const; //! Writes attributes of the object. - //! Implement this to expose the attributes of your scene node animator for + //! Implement this to expose the attributes of your scene node animator for //! scripting languages, editors, debuggers or xml serialization purposes. virtual void serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const; //! Reads attributes of the object. - //! Implement this to set the attributes of your scene node animator for + //! Implement this to set the attributes of your scene node animator for //! scripting languages, editors, debuggers or xml deserialization purposes. virtual void deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options=0); diff --git a/source/Irrlicht/CGUISpinBox.cpp b/source/Irrlicht/CGUISpinBox.cpp index 107c9c1a..1aeeadc0 100644 --- a/source/Irrlicht/CGUISpinBox.cpp +++ b/source/Irrlicht/CGUISpinBox.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2006-2008 Michael Zeilfelder +// Copyright (C) 2006-2009 Michael Zeilfelder // This file uses the licence of the Irrlicht Engine. #include "CGUISpinBox.h" @@ -255,6 +255,7 @@ void CGUISpinBox::serializeAttributes(io::IAttributes* out, io::SAttributeReadWr out->addInt("DecimalPlaces", DecimalPlaces); } + //! Reads attributes of the element void CGUISpinBox::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) { diff --git a/source/Irrlicht/CGUISpinBox.h b/source/Irrlicht/CGUISpinBox.h index a16065d8..559ff530 100644 --- a/source/Irrlicht/CGUISpinBox.h +++ b/source/Irrlicht/CGUISpinBox.h @@ -1,4 +1,4 @@ -// Copyright (C) 2006-2008 Michael Zeilfelder +// Copyright (C) 2006-2009 Michael Zeilfelder // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CGUISpriteBank.cpp b/source/Irrlicht/CGUISpriteBank.cpp index ed75ee75..06ffbc53 100644 --- a/source/Irrlicht/CGUISpriteBank.cpp +++ b/source/Irrlicht/CGUISpriteBank.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CGUISpriteBank.h b/source/Irrlicht/CGUISpriteBank.h index 5881e2bd..075b472a 100644 --- a/source/Irrlicht/CGUISpriteBank.h +++ b/source/Irrlicht/CGUISpriteBank.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -47,12 +47,11 @@ public: protected: - core::array Sprites; + core::array Sprites; core::array< core::rect > Rectangles; core::array Textures; IGUIEnvironment* Environment; video::IVideoDriver* Driver; - }; } // end namespace gui @@ -62,4 +61,3 @@ protected: #endif // __C_GUI_SPRITE_BANK_H_INCLUDED__ - diff --git a/source/Irrlicht/CGUIStaticText.cpp b/source/Irrlicht/CGUIStaticText.cpp index 3039fb87..6a4d6240 100644 --- a/source/Irrlicht/CGUIStaticText.cpp +++ b/source/Irrlicht/CGUIStaticText.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -21,9 +21,9 @@ CGUIStaticText::CGUIStaticText(const wchar_t* text, bool border, IGUIEnvironment* environment, IGUIElement* parent, s32 id, const core::rect& rectangle, bool background) -: IGUIStaticText(environment, parent, id, rectangle), Border(border), +: IGUIStaticText(environment, parent, id, rectangle), HAlign(EGUIA_UPPERLEFT), VAlign(EGUIA_UPPERLEFT), - OverrideColorEnabled(false), WordWrap(false), Background(background), + Border(border), OverrideColorEnabled(false), WordWrap(false), Background(background), OverrideColor(video::SColor(101,255,255,255)), BGColor(video::SColor(101,210,210,210)), OverrideFont(0), LastBreakFont(0) { @@ -88,12 +88,12 @@ void CGUIStaticText::draw() { if (VAlign == EGUIA_LOWERRIGHT) { - frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y - + frameRect.UpperLeftCorner.Y = frameRect.LowerRightCorner.Y - font->getDimension(L"A").Height - font->getKerningHeight(); } if (HAlign == EGUIA_LOWERRIGHT) { - frameRect.UpperLeftCorner.X = frameRect.LowerRightCorner.X - + frameRect.UpperLeftCorner.X = frameRect.LowerRightCorner.X - font->getDimension(Text.c_str()).Width; } @@ -122,7 +122,7 @@ void CGUIStaticText::draw() { if (HAlign == EGUIA_LOWERRIGHT) { - r.UpperLeftCorner.X = frameRect.LowerRightCorner.X - + r.UpperLeftCorner.X = frameRect.LowerRightCorner.X - font->getDimension(BrokenText[i].c_str()).Width; } @@ -349,6 +349,7 @@ void CGUIStaticText::setText(const wchar_t* text) breakText(); } + void CGUIStaticText::updateAbsolutePosition() { IGUIElement::updateAbsolutePosition(); diff --git a/source/Irrlicht/CGUIStaticText.h b/source/Irrlicht/CGUIStaticText.h index 9a7f4b94..ec37fa29 100644 --- a/source/Irrlicht/CGUIStaticText.h +++ b/source/Irrlicht/CGUIStaticText.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -91,8 +91,8 @@ namespace gui //! Breaks the single text line. void breakText(); - bool Border; EGUI_ALIGNMENT HAlign, VAlign; + bool Border; bool OverrideColorEnabled; bool WordWrap; bool Background; diff --git a/source/Irrlicht/CGUITabControl.cpp b/source/Irrlicht/CGUITabControl.cpp index 488a3c9a..2c6da282 100644 --- a/source/Irrlicht/CGUITabControl.cpp +++ b/source/Irrlicht/CGUITabControl.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -24,20 +24,19 @@ namespace gui //! constructor CGUITab::CGUITab(s32 number, IGUIEnvironment* environment, - IGUIElement* parent, const core::rect& rectangle, + IGUIElement* parent, const core::rect& rectangle, s32 id) : IGUITab(environment, parent, id, rectangle), Number(number), - DrawBackground(false), BackColor(0,0,0,0) + BackColor(0,0,0,0), TextColor(255,0,0,0), + DrawBackground(false) { #ifdef _DEBUG setDebugName("CGUITab"); #endif - IGUISkin* skin = environment->getSkin(); + const IGUISkin* const skin = environment->getSkin(); if (skin) TextColor = skin->getColor(EGDC_BUTTON_TEXT); - else - TextColor.set(255,0,0,0); } @@ -84,17 +83,20 @@ void CGUITab::setBackgroundColor(video::SColor c) BackColor = c; } + //! sets the color of the text void CGUITab::setTextColor(video::SColor c) { TextColor = c; } + video::SColor CGUITab::getTextColor() const { return TextColor; } + //! returns true if the tab is drawing its background, false if not bool CGUITab::isDrawingBackground() const { @@ -148,7 +150,7 @@ void CGUITab::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWrite //! constructor CGUITabControl::CGUITabControl(IGUIEnvironment* environment, - IGUIElement* parent, const core::rect& rectangle, + IGUIElement* parent, const core::rect& rectangle, bool fillbackground, bool border, s32 id) : IGUITabControl(environment, parent, id, rectangle), ActiveTab(-1), Border(border), FillBackground(fillbackground), ScrollControl(false), TabHeight(0), VerticalAlignment(EGUIA_UPPERLEFT), @@ -156,7 +158,7 @@ CGUITabControl::CGUITabControl(IGUIEnvironment* environment, { #ifdef _DEBUG setDebugName("CGUITabControl"); - #endif + #endif video::SColor color(255,255,255,255); IGUISkin* skin = Environment->getSkin(); @@ -195,7 +197,7 @@ CGUITabControl::CGUITabControl(IGUIEnvironment* environment, DownButton->setVisible(false); DownButton->setSubElement(true); DownButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_UPPERLEFT, EGUIA_UPPERLEFT); - DownButton->setOverrideFont(Environment->getBuiltInFont()); + DownButton->setOverrideFont(Environment->getBuiltInFont()); DownButton->grab(); } @@ -370,6 +372,7 @@ bool CGUITabControl::OnEvent(const SEvent& event) return IGUIElement::OnEvent(event); } + void CGUITabControl::scrollLeft() { if ( CurrentScrollTabIndex > 0 ) @@ -377,6 +380,7 @@ void CGUITabControl::scrollLeft() recalculateScrollBar(); } + void CGUITabControl::scrollRight() { if ( CurrentScrollTabIndex < (s32)(Tabs.size()) - 1 ) @@ -387,6 +391,7 @@ void CGUITabControl::scrollRight() recalculateScrollBar(); } + bool CGUITabControl::needScrollControl(s32 startIndex, bool withScrollControl) { if ( startIndex >= (s32)Tabs.size() ) @@ -437,6 +442,7 @@ bool CGUITabControl::needScrollControl(s32 startIndex, bool withScrollControl) return false; } + bool CGUITabControl::selectTab(core::position2d p) { IGUISkin* skin = Environment->getSkin(); @@ -506,7 +512,7 @@ void CGUITabControl::draw() if (!font) return; - + if ( VerticalAlignment == EGUIA_UPPERLEFT ) { frameRect.UpperLeftCorner.Y += 2; @@ -567,7 +573,7 @@ void CGUITabControl::draw() // draw active tab if (left != 0 && right != 0 && activeTab != 0) - { + { // draw upper highlight frame if ( VerticalAlignment == EGUIA_UPPERLEFT ) { @@ -576,7 +582,7 @@ void CGUITabControl::draw() frameRect.UpperLeftCorner.Y -= 2; skin->draw3DTabButton(this, true, frameRect, &AbsoluteClippingRect, VerticalAlignment); - + // draw text font->draw(activeTab->getText(), frameRect, activeTab->getTextColor(), true, true, &AbsoluteClippingRect); @@ -599,7 +605,7 @@ void CGUITabControl::draw() frameRect.LowerRightCorner.Y += 2; skin->draw3DTabButton(this, true, frameRect, &AbsoluteClippingRect, VerticalAlignment); - + // draw text font->draw(activeTab->getText(), frameRect, activeTab->getTextColor(), true, true, &AbsoluteClippingRect); @@ -640,6 +646,7 @@ void CGUITabControl::draw() IGUIElement::draw(); } + //! Set the height of the tabs void CGUITabControl::setTabHeight( s32 height ) { @@ -653,12 +660,14 @@ void CGUITabControl::setTabHeight( s32 height ) recalculateScrollBar(); } + //! Get the height of the tabs s32 CGUITabControl::getTabHeight() const { return TabHeight; } + //! Set the extra width added to tabs on each side of the text void CGUITabControl::setTabExtraWidth( s32 extraWidth ) { @@ -670,18 +679,20 @@ void CGUITabControl::setTabExtraWidth( s32 extraWidth ) recalculateScrollBar(); } + //! Get the extra width added to tabs on each side of the text s32 CGUITabControl::getTabExtraWidth() const { return TabExtraWidth; } + void CGUITabControl::recalculateScrollBar() { ScrollControl = needScrollControl() || CurrentScrollTabIndex > 0; if (ScrollControl) - { + { UpButton->setVisible( true ); DownButton->setVisible( true ); } @@ -695,6 +706,7 @@ void CGUITabControl::recalculateScrollBar() this->bringToFront( DownButton ); } + //! Set the alignment of the tabs void CGUITabControl::setTabVerticalAlignment( EGUI_ALIGNMENT alignment ) { @@ -725,7 +737,7 @@ void CGUITabControl::setTabVerticalAlignment( EGUI_ALIGNMENT alignment ) UpButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT); DownButton->setAlignment(EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT, EGUIA_LOWERRIGHT); } - + UpButton->setRelativePosition(core::rect(ButtonX, ButtonY, ButtonX+ButtonSize, ButtonY+ButtonSize)); ButtonX += ButtonSize + 1; DownButton->setRelativePosition(core::rect(ButtonX, ButtonY, ButtonX+ButtonSize, ButtonY+ButtonSize)); @@ -733,18 +745,21 @@ void CGUITabControl::setTabVerticalAlignment( EGUI_ALIGNMENT alignment ) recalculateScrollBar(); } + //! Get the alignment of the tabs EGUI_ALIGNMENT CGUITabControl::getTabVerticalAlignment() const { return VerticalAlignment; } + //! Returns which tab is currently active s32 CGUITabControl::getActiveTab() const { return ActiveTab; } + //! Brings a tab to front. bool CGUITabControl::setActiveTab(s32 idx) { @@ -766,12 +781,13 @@ bool CGUITabControl::setActiveTab(s32 idx) event.GUIEvent.Caller = this; event.GUIEvent.Element = 0; event.GUIEvent.EventType = EGET_TAB_CHANGED; - Parent->OnEvent(event); + Parent->OnEvent(event); } return true; } + bool CGUITabControl::setActiveTab(IGUIElement *tab) { for (s32 i=0; i<(s32)Tabs.size(); ++i) @@ -780,6 +796,7 @@ bool CGUITabControl::setActiveTab(IGUIElement *tab) return false; } + //! Removes a child. void CGUITabControl::removeChild(IGUIElement* child) { @@ -813,6 +830,7 @@ void CGUITabControl::removeChild(IGUIElement* child) recalculateScrollBar(); } + //! Update the position of the element, decides scroll button status void CGUITabControl::updateAbsolutePosition() { @@ -820,6 +838,7 @@ void CGUITabControl::updateAbsolutePosition() recalculateScrollBar(); } + //! Writes attributes of the element. void CGUITabControl::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options=0) const { @@ -855,4 +874,3 @@ void CGUITabControl::deserializeAttributes(io::IAttributes* in, io::SAttributeRe #endif // _IRR_COMPILE_WITH_GUI_ - diff --git a/source/Irrlicht/CGUITabControl.h b/source/Irrlicht/CGUITabControl.h index 5a5d6be8..83a7b640 100644 --- a/source/Irrlicht/CGUITabControl.h +++ b/source/Irrlicht/CGUITabControl.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -47,7 +47,7 @@ namespace gui //! sets the color of the background, if it should be drawn. virtual void setBackgroundColor(video::SColor c); - + //! sets the color of the text virtual void setTextColor(video::SColor c); @@ -69,14 +69,12 @@ namespace gui private: s32 Number; - bool DrawBackground; video::SColor BackColor; video::SColor TextColor; - + bool DrawBackground; }; - //! A standard tab control class CGUITabControl : public IGUITabControl { diff --git a/source/Irrlicht/CGUITable.cpp b/source/Irrlicht/CGUITable.cpp index 2feb8749..f98d9244 100644 --- a/source/Irrlicht/CGUITable.cpp +++ b/source/Irrlicht/CGUITable.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -109,6 +109,7 @@ void CGUITable::addColumn(const wchar_t* caption, s32 columnIndex) recalculateWidths(); } + //! remove a column from the table void CGUITable::removeColumn(u32 columnIndex) { @@ -126,16 +127,19 @@ void CGUITable::removeColumn(u32 columnIndex) recalculateWidths(); } + s32 CGUITable::getColumnCount() const { return Columns.size(); } + s32 CGUITable::getRowCount() const { return Rows.size(); } + bool CGUITable::setActiveColumn(s32 idx, bool doOrder ) { if (idx < 0 || idx >= (s32)Columns.size()) @@ -198,16 +202,19 @@ bool CGUITable::setActiveColumn(s32 idx, bool doOrder ) return true; } + s32 CGUITable::getActiveColumn() const { return ActiveTab; } + EGUI_ORDERING_MODE CGUITable::getActiveColumnOrdering() const { return CurrentOrdering; } + void CGUITable::setColumnWidth(u32 columnIndex, u32 width) { if ( columnIndex < Columns.size() ) @@ -260,6 +267,7 @@ void CGUITable::addRow(u32 rowIndex) recalculateHeights(); } + void CGUITable::removeRow(u32 rowIndex) { if ( rowIndex > Rows.size() ) @@ -273,6 +281,7 @@ void CGUITable::removeRow(u32 rowIndex) recalculateHeights(); } + //! adds an list item, returns id of item void CGUITable::setCellText(u32 rowIndex, u32 columnIndex, const wchar_t* text) { @@ -287,6 +296,7 @@ void CGUITable::setCellText(u32 rowIndex, u32 columnIndex, const wchar_t* text) } } + void CGUITable::setCellText(u32 rowIndex, u32 columnIndex, const wchar_t* text, video::SColor color) { if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) @@ -297,6 +307,7 @@ void CGUITable::setCellText(u32 rowIndex, u32 columnIndex, const wchar_t* text, } } + void CGUITable::setCellColor(u32 rowIndex, u32 columnIndex, video::SColor color) { if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) @@ -305,6 +316,7 @@ void CGUITable::setCellColor(u32 rowIndex, u32 columnIndex, video::SColor color) } } + void CGUITable::setCellData(u32 rowIndex, u32 columnIndex, void *data) { if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) @@ -313,6 +325,7 @@ void CGUITable::setCellData(u32 rowIndex, u32 columnIndex, void *data) } } + const wchar_t* CGUITable::getCellText(u32 rowIndex, u32 columnIndex ) const { if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) @@ -323,6 +336,7 @@ const wchar_t* CGUITable::getCellText(u32 rowIndex, u32 columnIndex ) const return 0; } + void* CGUITable::getCellData(u32 rowIndex, u32 columnIndex ) const { if ( rowIndex < Rows.size() && columnIndex < Columns.size() ) @@ -333,6 +347,7 @@ void* CGUITable::getCellData(u32 rowIndex, u32 columnIndex ) const return 0; } + //! clears the list void CGUITable::clear() { @@ -348,6 +363,7 @@ void CGUITable::clear() recalculateWidths(); } + void CGUITable::clearRows() { Rows.clear(); @@ -358,11 +374,13 @@ void CGUITable::clearRows() recalculateHeights(); } + s32 CGUITable::getSelected() const { return Selected; } + void CGUITable::recalculateWidths() { TotalItemWidth=0; @@ -373,6 +391,7 @@ void CGUITable::recalculateWidths() checkScrollbars(); } + void CGUITable::recalculateHeights() { TotalItemHeight = 0; @@ -396,6 +415,7 @@ void CGUITable::recalculateHeights() checkScrollbars(); } + // automatic enabled/disabling and resizing of scrollbars void CGUITable::checkScrollbars() { @@ -484,6 +504,7 @@ void CGUITable::checkScrollbars() } } + void CGUITable::refreshControls() { updateAbsolutePosition(); @@ -657,6 +678,7 @@ void CGUITable::swapRows(u32 rowIndexA, u32 rowIndexB) } + bool CGUITable::dragColumnStart(s32 xpos, s32 ypos) { if ( !ResizableColumns ) @@ -691,6 +713,7 @@ bool CGUITable::dragColumnStart(s32 xpos, s32 ypos) return false; } + bool CGUITable::dragColumnUpdate(s32 xpos) { if ( !ResizableColumns || CurrentResizedColumn < 0 || CurrentResizedColumn >= s32(Columns.size()) ) @@ -708,6 +731,7 @@ bool CGUITable::dragColumnUpdate(s32 xpos) return false; } + bool CGUITable::selectColumnHeader(s32 xpos, s32 ypos) { if ( ypos > ( AbsoluteRect.UpperLeftCorner.Y + ItemHeight ) ) @@ -735,6 +759,7 @@ bool CGUITable::selectColumnHeader(s32 xpos, s32 ypos) return false; } + void CGUITable::orderRows(s32 columnIndex, EGUI_ORDERING_MODE mode) { Row swap; @@ -996,7 +1021,7 @@ void CGUITable::breakText(const core::stringw& text, core::stringw& brokenText, c[1] = L'\0'; const u32 maxLength = cellWidth - (CellWidthPadding * 2); - const s32 maxLengthDots = cellWidth - (CellWidthPadding * 2) - font->getDimension(L"...").Width; + const u32 maxLengthDots = cellWidth - (CellWidthPadding * 2) - font->getDimension(L"...").Width; const u32 size = text.size(); u32 pos = 0; diff --git a/source/Irrlicht/CGUITable.h b/source/Irrlicht/CGUITable.h index 4f02be0d..67684411 100644 --- a/source/Irrlicht/CGUITable.h +++ b/source/Irrlicht/CGUITable.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -26,7 +26,7 @@ namespace gui { public: //! constructor - CGUITable(IGUIEnvironment* environment, IGUIElement* parent, + CGUITable(IGUIEnvironment* environment, IGUIElement* parent, s32 id, core::rect rectangle, bool clip=true, bool drawBack=false, bool moveOverSelect=true); @@ -45,7 +45,7 @@ namespace gui //! Makes a column active. This will trigger an ordering process. /** \param idx: The id of the column to make active. - \return Returns true if successful. */ + \return True if successful. */ virtual bool setActiveColumn(s32 columnIndex, bool doOrder=false); //! Returns which header is currently active @@ -56,18 +56,18 @@ namespace gui //! set a column width virtual void setColumnWidth(u32 columnIndex, u32 width); - + //! columns can be resized by drag 'n drop virtual void setResizableColumns(bool resizable); - + //! can columns be resized by dran 'n drop? virtual bool hasResizableColumns() const; - //! This tells the table control which ordering mode should be used when - //! a column header is clicked. + //! This tells the table control which ordering mode should be used when + //! a column header is clicked. /** \param columnIndex: The index of the column header. \param state: If true, a EGET_TABLE_HEADER_CHANGED message will be sent and you can order the table data as you whish.*/ - //! \param mode: One of the modes defined in EGUI_COLUMN_ORDERING + //! \param mode: One of the modes defined in EGUI_COLUMN_ORDERING virtual void setColumnOrdering(u32 columnIndex, EGUI_COLUMN_ORDERING mode); //! Returns which row is currently selected @@ -99,7 +99,7 @@ namespace gui //! a new row is added or the cells data is changed. This makes //! the system more flexible and doesn't make you pay the cost //! of ordering when adding a lot of rows. - //! \param columnIndex: When set to -1 the active column is used. + //! \param columnIndex: When set to -1 the active column is used. virtual void orderRows(s32 columnIndex=-1, EGUI_ORDERING_MODE mode=EGOM_NONE); diff --git a/source/Irrlicht/CGUIToolBar.cpp b/source/Irrlicht/CGUIToolBar.cpp index f57c1fd2..9c7c4e1a 100644 --- a/source/Irrlicht/CGUIToolBar.cpp +++ b/source/Irrlicht/CGUIToolBar.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -69,7 +69,7 @@ bool CGUIToolBar::OnEvent(const SEvent& event) { if (IsEnabled) { - if (event.EventType == EET_MOUSE_INPUT_EVENT && + if (event.EventType == EET_MOUSE_INPUT_EVENT && event.MouseInput.Event == EMIE_LMOUSE_PRESSED_DOWN) { if (AbsoluteClippingRect.isPointInside(core::position2di(event.MouseInput.X, event.MouseInput.Y))) @@ -116,7 +116,7 @@ void CGUIToolBar::updateAbsolutePosition() //! Adds a button to the tool bar IGUIButton* CGUIToolBar::addButton(s32 id, const wchar_t* text,const wchar_t* tooltiptext, - video::ITexture* img, video::ITexture* pressed, bool isPushButton, + video::ITexture* img, video::ITexture* pressed, bool isPushButton, bool useAlphaChannel) { ButtonX += 3; @@ -124,7 +124,7 @@ IGUIButton* CGUIToolBar::addButton(s32 id, const wchar_t* text,const wchar_t* to core::rect rectangle(ButtonX,2,0,0); if ( img ) { - const core::dimension2di &size = img->getOriginalSize(); + const core::dimension2du &size = img->getOriginalSize(); rectangle.LowerRightCorner.X = rectangle.UpperLeftCorner.X + size.Width + 8; rectangle.LowerRightCorner.Y = rectangle.UpperLeftCorner.Y + size.Height + 6; } @@ -151,10 +151,10 @@ IGUIButton* CGUIToolBar::addButton(s32 id, const wchar_t* text,const wchar_t* to if (useAlphaChannel) button->setUseAlphaChannel(useAlphaChannel); - + return button; } - + } // end namespace gui } // end namespace irr diff --git a/source/Irrlicht/CGUIToolBar.h b/source/Irrlicht/CGUIToolBar.h index 0bacb18d..3f6eaf96 100644 --- a/source/Irrlicht/CGUIToolBar.h +++ b/source/Irrlicht/CGUIToolBar.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CGUIWindow.cpp b/source/Irrlicht/CGUIWindow.cpp index 82104623..ae6a6106 100644 --- a/source/Irrlicht/CGUIWindow.cpp +++ b/source/Irrlicht/CGUIWindow.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -31,7 +31,7 @@ CGUIWindow::CGUIWindow(IGUIEnvironment* environment, IGUIElement* parent, s32 id IGUISpriteBank* sprites = 0; video::SColor color(255,255,255,255); - + s32 buttonw = 15; if (skin) { @@ -41,7 +41,7 @@ CGUIWindow::CGUIWindow(IGUIEnvironment* environment, IGUIElement* parent, s32 id } s32 posx = RelativeRect.getWidth() - buttonw - 4; - CloseButton = Environment->addButton(core::rect(posx, 3, posx + buttonw, 3 + buttonw), this, -1, + CloseButton = Environment->addButton(core::rect(posx, 3, posx + buttonw, 3 + buttonw), this, -1, L"", skin ? skin->getDefaultText(EGDT_WINDOW_CLOSE) : L"Close" ); CloseButton->setSubElement(true); CloseButton->setTabStop(false); @@ -54,7 +54,7 @@ CGUIWindow::CGUIWindow(IGUIEnvironment* environment, IGUIElement* parent, s32 id } posx -= buttonw + 2; - RestoreButton = Environment->addButton(core::rect(posx, 3, posx + buttonw, 3 + buttonw), this, -1, + RestoreButton = Environment->addButton(core::rect(posx, 3, posx + buttonw, 3 + buttonw), this, -1, L"", skin ? skin->getDefaultText(EGDT_WINDOW_RESTORE) : L"Restore" ); RestoreButton->setVisible(false); RestoreButton->setSubElement(true); @@ -68,7 +68,7 @@ CGUIWindow::CGUIWindow(IGUIEnvironment* environment, IGUIElement* parent, s32 id } posx -= buttonw + 2; - MinButton = Environment->addButton(core::rect(posx, 3, posx + buttonw, 3 + buttonw), this, -1, + MinButton = Environment->addButton(core::rect(posx, 3, posx + buttonw, 3 + buttonw), this, -1, L"", skin ? skin->getDefaultText(EGDT_WINDOW_MINIMIZE) : L"Minimize" ); MinButton->setVisible(false); MinButton->setSubElement(true); @@ -171,14 +171,12 @@ bool CGUIWindow::OnEvent(const SEvent& event) if (Dragging) { // gui window should not be dragged outside its parent - if (Parent) - if (event.MouseInput.X < Parent->getAbsolutePosition().UpperLeftCorner.X +1 || + if (Parent && + (event.MouseInput.X < Parent->getAbsolutePosition().UpperLeftCorner.X +1 || event.MouseInput.Y < Parent->getAbsolutePosition().UpperLeftCorner.Y +1 || event.MouseInput.X > Parent->getAbsolutePosition().LowerRightCorner.X -1 || - event.MouseInput.Y > Parent->getAbsolutePosition().LowerRightCorner.Y -1) - - return true; - + event.MouseInput.Y > Parent->getAbsolutePosition().LowerRightCorner.Y -1)) + return true; move(core::position2d(event.MouseInput.X - DragStart.X, event.MouseInput.Y - DragStart.Y)); DragStart.X = event.MouseInput.X; diff --git a/source/Irrlicht/CGUIWindow.h b/source/Irrlicht/CGUIWindow.h index 2573d688..10cdb522 100644 --- a/source/Irrlicht/CGUIWindow.h +++ b/source/Irrlicht/CGUIWindow.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -46,12 +46,12 @@ namespace gui protected: - core::position2d DragStart; - bool Dragging; - IGUIButton* CloseButton; IGUIButton* MinButton; IGUIButton* RestoreButton; + + core::position2d DragStart; + bool Dragging; }; } // end namespace gui @@ -59,5 +59,5 @@ namespace gui #endif // _IRR_COMPILE_WITH_GUI_ -#endif +#endif diff --git a/source/Irrlicht/CGeometryCreator.cpp b/source/Irrlicht/CGeometryCreator.cpp index ccb1982e..54bcf5ae 100644 --- a/source/Irrlicht/CGeometryCreator.cpp +++ b/source/Irrlicht/CGeometryCreator.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -119,7 +119,7 @@ IMesh* CGeometryCreator::createHillPlaneMesh( IMesh* CGeometryCreator::createTerrainMesh(video::IImage* texture, video::IImage* heightmap, const core::dimension2d& stretchSize, f32 maxHeight, video::IVideoDriver* driver, - const core::dimension2d& maxVtxBlockSize, + const core::dimension2d& maxVtxBlockSize, bool debugBorders) { if (!texture || !heightmap) @@ -134,17 +134,17 @@ IMesh* CGeometryCreator::createTerrainMesh(video::IImage* texture, SMesh* mesh = new SMesh(); const u32 tm = os::Timer::getRealTime()/1000; - const core::dimension2d hMapSize= heightmap->getDimension(); - const core::dimension2d tMapSize= texture->getDimension(); + const core::dimension2d hMapSize= heightmap->getDimension(); + const core::dimension2d tMapSize= texture->getDimension(); const core::position2d thRel(static_cast(tMapSize.Width) / hMapSize.Width, static_cast(tMapSize.Height) / hMapSize.Height); maxHeight /= 255.0f; // height step per color value - core::position2d processed(0,0); + core::position2d processed(0,0); while (processed.Y blockSize = maxVtxBlockSize; + core::dimension2d blockSize = maxVtxBlockSize; if (processed.X + blockSize.Width > hMapSize.Width) blockSize.Width = hMapSize.Width - processed.X; if (processed.Y + blockSize.Height > hMapSize.Height) @@ -154,7 +154,7 @@ IMesh* CGeometryCreator::createTerrainMesh(video::IImage* texture, buffer->setHardwareMappingHint(scene::EHM_STATIC); buffer->Vertices.reallocate(blockSize.getArea()); // add vertices of vertex block - s32 y; + u32 y; core::vector2df pos(0.f, processed.Y*stretchSize.Height); const core::vector2df bs(1.f/blockSize.Width, 1.f/blockSize.Height); core::vector2df tc(0.f, 0.5f*bs.Y); @@ -162,7 +162,7 @@ IMesh* CGeometryCreator::createTerrainMesh(video::IImage* texture, { pos.X=processed.X*stretchSize.Width; tc.X=0.5f*bs.X; - for (s32 x=0; xgetPixel(x+processed.X, y+processed.Y).getAverage() * maxHeight; @@ -181,7 +181,7 @@ IMesh* CGeometryCreator::createTerrainMesh(video::IImage* texture, s32 c1 = 0; for (y=0; y(core::floor32(processed.X*thRel.X), core::floor32(processed.Y*thRel.Y)), - core::dimension2d(core::floor32(blockSize.Width*thRel.X), core::floor32(blockSize.Height*thRel.Y))); + core::dimension2d(core::floor32(blockSize.Width*thRel.X), core::floor32(blockSize.Height*thRel.Y))); sprintf(textureName, "terrain%u_%u", tm, mesh->getMeshBufferCount()); diff --git a/source/Irrlicht/CGeometryCreator.h b/source/Irrlicht/CGeometryCreator.h index babe2c2d..f682edd5 100644 --- a/source/Irrlicht/CGeometryCreator.h +++ b/source/Irrlicht/CGeometryCreator.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -34,7 +34,7 @@ public: static IMesh* createTerrainMesh(video::IImage* texture, video::IImage* heightmap, const core::dimension2d& stretchSize, f32 maxHeight, video::IVideoDriver* driver, - const core::dimension2d& defaultVertexBlockSize, + const core::dimension2d& defaultVertexBlockSize, bool debugBorders=false); static IMesh* createArrowMesh(const u32 tesselationCylinder, diff --git a/source/Irrlicht/CImage.cpp b/source/Irrlicht/CImage.cpp index 13233e55..eb971649 100644 --- a/source/Irrlicht/CImage.cpp +++ b/source/Irrlicht/CImage.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -579,7 +579,7 @@ static void executeBlit_TextureCopy_32_to_24( const SBlitJob * job ) src = (u32*) ( (u8*) (src) + job->srcPitch ); dst += job->dstPitch ; } - + } @@ -970,7 +970,7 @@ namespace video { //! constructor -CImage::CImage(ECOLOR_FORMAT format, const core::dimension2d& size) +CImage::CImage(ECOLOR_FORMAT format, const core::dimension2d& size) :Data(0), Size(size), Format(format), DeleteMemory(true) { initData(); @@ -978,7 +978,7 @@ CImage::CImage(ECOLOR_FORMAT format, const core::dimension2d& size) //! constructor -CImage::CImage(ECOLOR_FORMAT format, const core::dimension2d& size, void* data, +CImage::CImage(ECOLOR_FORMAT format, const core::dimension2d& size, void* data, bool ownForeignMemory, bool deleteForeignMemory) : Data(0), Size(size), Format(format), DeleteMemory(deleteForeignMemory) { @@ -1017,7 +1017,7 @@ CImage::CImage(ECOLOR_FORMAT format, IImage* imageToCopy) //! constructor CImage::CImage(IImage* imageToCopy, const core::position2d& pos, - const core::dimension2d& size) + const core::dimension2d& size) : Data(0), Size(0,0), DeleteMemory(true) { if (!imageToCopy) @@ -1058,7 +1058,7 @@ CImage::~CImage() //! Returns width and height of image data. -const core::dimension2d& CImage::getDimension() const +const core::dimension2d& CImage::getDimension() const { return Size; } @@ -1312,6 +1312,8 @@ void CImage::drawLine(const core::position2d& from, const core::position2d< RenderLine32_Blend( this, p[0], p[1], color.color, alpha ); } break; + default: + break; } } } @@ -1321,7 +1323,7 @@ void CImage::drawLine(const core::position2d& from, const core::position2d< //! copies this surface into another, scaling it to the target image size // note: this is very very slow. (i didn't want to write a fast version. // but hopefully, nobody wants to scale surfaces every frame. -void CImage::copyToScaling(void* target, s32 width, s32 height, ECOLOR_FORMAT format, u32 pitch) +void CImage::copyToScaling(void* target, u32 width, u32 height, ECOLOR_FORMAT format, u32 pitch) { if (!target || !width || !height) return; @@ -1342,7 +1344,7 @@ void CImage::copyToScaling(void* target, s32 width, s32 height, ECOLOR_FORMAT fo u8* tgtpos = (u8*) target; u8* dstpos = (u8*) Data; const u32 bwidth = width*bpp; - for (s32 y=0; y& targetSize = target->getDimension(); + const core::dimension2d& targetSize = target->getDimension(); if (targetSize==Size) { @@ -1394,7 +1396,7 @@ void CImage::copyToScaling(IImage* target) //! copies this surface into another, scaling it to fit it. void CImage::copyToScalingBoxFilter(IImage* target, s32 bias) { - const core::dimension2d destSize = target->getDimension(); + const core::dimension2d destSize = target->getDimension(); const f32 sourceXStep = (f32) Size.Width / (f32) destSize.Width; const f32 sourceYStep = (f32) Size.Height / (f32) destSize.Height; @@ -1407,10 +1409,10 @@ void CImage::copyToScalingBoxFilter(IImage* target, s32 bias) f32 sy; sy = 0.f; - for ( s32 y = 0; y != destSize.Height; ++y ) + for ( u32 y = 0; y != destSize.Height; ++y ) { sx = 0.f; - for ( s32 x = 0; x != destSize.Width; ++x ) + for ( u32 x = 0; x != destSize.Width; ++x ) { target->setPixel( x, y, getPixelBox( core::floor32(sx), core::floor32(sy), fx, fy, bias ) ); sx += sourceXStep; diff --git a/source/Irrlicht/CImage.h b/source/Irrlicht/CImage.h index a6c6c4d0..67ead229 100644 --- a/source/Irrlicht/CImage.h +++ b/source/Irrlicht/CImage.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -26,15 +26,15 @@ public: //! \param useForeignMemory: If true, the image will use the data pointer //! directly and own it from now on, which means it will also try to delete [] the //! data when the image will be destructed. If false, the memory will by copied. - CImage(ECOLOR_FORMAT format, const core::dimension2d& size, + CImage(ECOLOR_FORMAT format, const core::dimension2d& size, void* data, bool ownForeignMemory=true, bool deleteMemory = true); //! constructor for empty image - CImage(ECOLOR_FORMAT format, const core::dimension2d& size); + CImage(ECOLOR_FORMAT format, const core::dimension2d& size); //! constructor using a part from another image CImage(IImage* imageToCopy, - const core::position2d& pos, const core::dimension2d& size); + const core::position2d& pos, const core::dimension2d& size); //! destructor virtual ~CImage(); @@ -49,7 +49,7 @@ public: virtual void unlock() {} //! Returns width and height of image data. - virtual const core::dimension2d& getDimension() const; + virtual const core::dimension2d& getDimension() const; //! Returns bits per pixel. virtual u32 getBitsPerPixel() const; @@ -88,7 +88,7 @@ public: virtual u32 getPitch() const { return Pitch; } //! copies this surface into another, scaling it to fit. - virtual void copyToScaling(void* target, s32 width, s32 height, ECOLOR_FORMAT format, u32 pitch=0); + virtual void copyToScaling(void* target, u32 width, u32 height, ECOLOR_FORMAT format, u32 pitch=0); //! copies this surface into another, scaling it to fit. virtual void copyToScaling(IImage* target); @@ -128,7 +128,7 @@ private: inline SColor getPixelBox ( s32 x, s32 y, s32 fx, s32 fy, s32 bias ) const; void* Data; - core::dimension2d Size; + core::dimension2d Size; u32 BitsPerPixel; u32 BytesPerPixel; u32 Pitch; diff --git a/source/Irrlicht/CImageLoaderBMP.cpp b/source/Irrlicht/CImageLoaderBMP.cpp index 7e754418..1224f860 100644 --- a/source/Irrlicht/CImageLoaderBMP.cpp +++ b/source/Irrlicht/CImageLoaderBMP.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -311,32 +311,32 @@ IImage* CImageLoaderBMP::loadImage(io::IReadFile* file) const switch(header.BPP) { case 1: - image = new CImage(ECF_A1R5G5B5, core::dimension2d(header.Width, header.Height)); + image = new CImage(ECF_A1R5G5B5, core::dimension2d(header.Width, header.Height)); if (image) CColorConverter::convert1BitTo16Bit(bmpData, (s16*)image->lock(), header.Width, header.Height, pitch, true); break; case 4: - image = new CImage(ECF_A1R5G5B5, core::dimension2d(header.Width, header.Height)); + image = new CImage(ECF_A1R5G5B5, core::dimension2d(header.Width, header.Height)); if (image) CColorConverter::convert4BitTo16Bit(bmpData, (s16*)image->lock(), header.Width, header.Height, paletteData, pitch, true); break; case 8: - image = new CImage(ECF_A1R5G5B5, core::dimension2d(header.Width, header.Height)); + image = new CImage(ECF_A1R5G5B5, core::dimension2d(header.Width, header.Height)); if (image) CColorConverter::convert8BitTo16Bit(bmpData, (s16*)image->lock(), header.Width, header.Height, paletteData, pitch, true); break; case 16: - image = new CImage(ECF_A1R5G5B5, core::dimension2d(header.Width, header.Height)); + image = new CImage(ECF_A1R5G5B5, core::dimension2d(header.Width, header.Height)); if (image) CColorConverter::convert16BitTo16Bit((s16*)bmpData, (s16*)image->lock(), header.Width, header.Height, pitch, true); break; case 24: - image = new CImage(ECF_R8G8B8, core::dimension2d(header.Width, header.Height)); + image = new CImage(ECF_R8G8B8, core::dimension2d(header.Width, header.Height)); if (image) CColorConverter::convert24BitTo24Bit(bmpData, (u8*)image->lock(), header.Width, header.Height, pitch, true, true); break; case 32: // thx to Reinhard Ostermeier - image = new CImage(ECF_A8R8G8B8, core::dimension2d(header.Width, header.Height)); + image = new CImage(ECF_A8R8G8B8, core::dimension2d(header.Width, header.Height)); if (image) CColorConverter::convert32BitTo32Bit((s32*)bmpData, (s32*)image->lock(), header.Width, header.Height, pitch, true); break; diff --git a/source/Irrlicht/CImageLoaderBMP.h b/source/Irrlicht/CImageLoaderBMP.h index 180e0ce1..e7e4076d 100644 --- a/source/Irrlicht/CImageLoaderBMP.h +++ b/source/Irrlicht/CImageLoaderBMP.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CImageLoaderJPG.cpp b/source/Irrlicht/CImageLoaderJPG.cpp index 63ec1d85..faf9394b 100644 --- a/source/Irrlicht/CImageLoaderJPG.cpp +++ b/source/Irrlicht/CImageLoaderJPG.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -236,7 +236,7 @@ IImage* CImageLoaderJPG::loadImage(io::IReadFile* file) const // convert image IImage* image = new CImage(ECF_R8G8B8, - core::dimension2d(width, height), output); + core::dimension2d(width, height), output); delete [] input; diff --git a/source/Irrlicht/CImageLoaderJPG.h b/source/Irrlicht/CImageLoaderJPG.h index fbc9cac2..472c9b26 100644 --- a/source/Irrlicht/CImageLoaderJPG.h +++ b/source/Irrlicht/CImageLoaderJPG.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CImageLoaderPCX.cpp b/source/Irrlicht/CImageLoaderPCX.cpp index d62e2179..f53c7d86 100644 --- a/source/Irrlicht/CImageLoaderPCX.cpp +++ b/source/Irrlicht/CImageLoaderPCX.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -96,7 +96,7 @@ IImage* CImageLoaderPCX::loadImage(io::IReadFile* file) const for( s32 i=0; i<256; i++ ) { paletteData[i] = (tempPalette[i*3+0] << 16) | - (tempPalette[i*3+1] << 8) | + (tempPalette[i*3+1] << 8) | (tempPalette[i*3+2] ); } @@ -111,7 +111,7 @@ IImage* CImageLoaderPCX::loadImage(io::IReadFile* file) const for( s32 i=0; i<256; i++ ) { paletteData[i] = (header.Palette[i*3+0] << 16) | - (header.Palette[i*3+1] << 8) | + (header.Palette[i*3+1] << 8) | (header.Palette[i*3+2]); } } @@ -169,12 +169,12 @@ IImage* CImageLoaderPCX::loadImage(io::IReadFile* file) const switch(header.Planes) // TODO: Other formats { case 1: - image = new CImage(ECF_A1R5G5B5, core::dimension2d(width, height)); + image = new CImage(ECF_A1R5G5B5, core::dimension2d(width, height)); if (image) CColorConverter::convert8BitTo16Bit(PCXData, (s16*)image->lock(), width, height, paletteData, pad); break; case 3: - image = new CImage(ECF_R8G8B8, core::dimension2d(width, height)); + image = new CImage(ECF_R8G8B8, core::dimension2d(width, height)); if (image) CColorConverter::convert24BitTo24Bit(PCXData, (u8*)image->lock(), width, height, pad); break; @@ -184,7 +184,7 @@ IImage* CImageLoaderPCX::loadImage(io::IReadFile* file) const { if (header.Planes==1) { - image = new CImage(ECF_A1R5G5B5, core::dimension2d(width, height)); + image = new CImage(ECF_A1R5G5B5, core::dimension2d(width, height)); if (image) CColorConverter::convert4BitTo16Bit(PCXData, (s16*)image->lock(), width, height, paletteData, pad); } @@ -193,13 +193,13 @@ IImage* CImageLoaderPCX::loadImage(io::IReadFile* file) const { if (header.Planes==4) { - image = new CImage(ECF_A1R5G5B5, core::dimension2d(width, height)); + image = new CImage(ECF_A1R5G5B5, core::dimension2d(width, height)); if (image) CColorConverter::convert4BitTo16Bit(PCXData, (s16*)image->lock(), width, height, paletteData, pad); } else if (header.Planes==1) { - image = new CImage(ECF_A1R5G5B5, core::dimension2d(width, height)); + image = new CImage(ECF_A1R5G5B5, core::dimension2d(width, height)); if (image) CColorConverter::convert1BitTo16Bit(PCXData, (s16*)image->lock(), width, height, pad); } diff --git a/source/Irrlicht/CImageLoaderPCX.h b/source/Irrlicht/CImageLoaderPCX.h index 8468b2ae..1024e2c2 100644 --- a/source/Irrlicht/CImageLoaderPCX.h +++ b/source/Irrlicht/CImageLoaderPCX.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CImageLoaderPNG.cpp b/source/Irrlicht/CImageLoaderPNG.cpp index 22192fd5..df432b76 100644 --- a/source/Irrlicht/CImageLoaderPNG.cpp +++ b/source/Irrlicht/CImageLoaderPNG.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -184,9 +184,16 @@ IImage* CImageLoaderPng::loadImage(io::IReadFile* file) const // Update the changes png_read_update_info(png_ptr, info_ptr); - png_get_IHDR(png_ptr, info_ptr, - (png_uint_32*)&Width, (png_uint_32*)&Height, - &BitDepth, &ColorType, NULL, NULL, NULL); + { + // Use temporary variables to avoid passing casted pointers + png_uint_32 w,h; + // Extract info + png_get_IHDR(png_ptr, info_ptr, + &w, &h, + &BitDepth, &ColorType, NULL, NULL, NULL); + Width=w; + Height=h; + } // Convert RGBA to BGRA if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA) @@ -199,15 +206,22 @@ IImage* CImageLoaderPng::loadImage(io::IReadFile* file) const } // Update the changes - png_get_IHDR(png_ptr, info_ptr, - (png_uint_32*)&Width, (png_uint_32*)&Height, - &BitDepth, &ColorType, NULL, NULL, NULL); + { + // Use temporary variables to avoid passing casted pointers + png_uint_32 w,h; + // Extract info + png_get_IHDR(png_ptr, info_ptr, + &w, &h, + &BitDepth, &ColorType, NULL, NULL, NULL); + Width=w; + Height=h; + } // Create the image structure to be filled by png data if (ColorType==PNG_COLOR_TYPE_RGB_ALPHA) - image = new CImage(ECF_A8R8G8B8, core::dimension2d(Width, Height)); + image = new CImage(ECF_A8R8G8B8, core::dimension2d(Width, Height)); else - image = new CImage(ECF_R8G8B8, core::dimension2d(Width, Height)); + image = new CImage(ECF_R8G8B8, core::dimension2d(Width, Height)); if (!image) { os::Printer::log("LOAD PNG: Internal PNG create image struct failure\n", file->getFileName(), ELL_ERROR); diff --git a/source/Irrlicht/CImageLoaderPNG.h b/source/Irrlicht/CImageLoaderPNG.h index 1b58c56f..d10d1e6b 100644 --- a/source/Irrlicht/CImageLoaderPNG.h +++ b/source/Irrlicht/CImageLoaderPNG.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CImageLoaderPPM.cpp b/source/Irrlicht/CImageLoaderPPM.cpp index 430e9443..be7804d9 100644 --- a/source/Irrlicht/CImageLoaderPPM.cpp +++ b/source/Irrlicht/CImageLoaderPPM.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2008 Christian Stehno +// Copyright (C) 2007-2009 Christian Stehno // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -39,7 +39,7 @@ bool CImageLoaderPPM::isALoadableFileExtension(const c8* fileName) const //! returns true if the file maybe is able to be loaded by this class bool CImageLoaderPPM::isALoadableFileFormat(io::IReadFile* file) const { - c8 id[2]; + c8 id[2]={0}; file->read(&id, 2); return (id[0]=='P' && id[1]>'0' && id[1]<'7'); } @@ -99,7 +99,7 @@ IImage* CImageLoaderPPM::loadImage(io::IReadFile* file) const shift=0; } } - image = new CImage(ECF_A1R5G5B5, core::dimension2d(width, height)); + image = new CImage(ECF_A1R5G5B5, core::dimension2d(width, height)); if (image) CColorConverter::convert1BitTo16Bit(data, (s16*)image->lock(), width, height); } @@ -120,7 +120,7 @@ IImage* CImageLoaderPPM::loadImage(io::IReadFile* file) const return 0; data = new u8[size]; file->read(data, size); - image = new CImage(ECF_A8R8G8B8, core::dimension2d(width, height)); + image = new CImage(ECF_A8R8G8B8, core::dimension2d(width, height)); if (image) { u8* ptr = (u8*)image->lock(); @@ -137,7 +137,7 @@ IImage* CImageLoaderPPM::loadImage(io::IReadFile* file) const { if (file->getSize()-file->getPos() < (long)(2*size)) // optimistic test return 0; - image = new CImage(ECF_A8R8G8B8, core::dimension2d(width, height)); + image = new CImage(ECF_A8R8G8B8, core::dimension2d(width, height)); if (image) { u8* ptr = (u8*)image->lock(); @@ -162,7 +162,7 @@ IImage* CImageLoaderPPM::loadImage(io::IReadFile* file) const return 0; data = new u8[bytesize]; file->read(data, bytesize); - image = new CImage(ECF_A8R8G8B8, core::dimension2d(width, height)); + image = new CImage(ECF_A8R8G8B8, core::dimension2d(width, height)); if (image) { u8* ptr = (u8*)image->lock(); @@ -179,7 +179,7 @@ IImage* CImageLoaderPPM::loadImage(io::IReadFile* file) const { if (file->getSize()-file->getPos() < (long)(2*bytesize)) // optimistic test return 0; - image = new CImage(ECF_A8R8G8B8, core::dimension2d(width, height)); + image = new CImage(ECF_A8R8G8B8, core::dimension2d(width, height)); if (image) { u8* ptr = (u8*)image->lock(); diff --git a/source/Irrlicht/CImageLoaderPPM.h b/source/Irrlicht/CImageLoaderPPM.h index a3bdcb40..af71299f 100644 --- a/source/Irrlicht/CImageLoaderPPM.h +++ b/source/Irrlicht/CImageLoaderPPM.h @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2008 Christian Stehno +// Copyright (C) 2007-2009 Christian Stehno // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CImageLoaderPSD.cpp b/source/Irrlicht/CImageLoaderPSD.cpp index c6b5e2e1..247c3c20 100644 --- a/source/Irrlicht/CImageLoaderPSD.cpp +++ b/source/Irrlicht/CImageLoaderPSD.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -152,7 +152,7 @@ IImage* CImageLoaderPSD::loadImage(io::IReadFile* file) const { // create surface image = new CImage(ECF_A8R8G8B8, - core::dimension2d(header.width, header.height), imageData); + core::dimension2d(header.width, header.height), imageData); } if (!image) diff --git a/source/Irrlicht/CImageLoaderPSD.h b/source/Irrlicht/CImageLoaderPSD.h index 2d4acd7f..6b6cad06 100644 --- a/source/Irrlicht/CImageLoaderPSD.h +++ b/source/Irrlicht/CImageLoaderPSD.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CImageLoaderTGA.cpp b/source/Irrlicht/CImageLoaderTGA.cpp index be964620..bb2193dd 100644 --- a/source/Irrlicht/CImageLoaderTGA.cpp +++ b/source/Irrlicht/CImageLoaderTGA.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -145,7 +145,7 @@ IImage* CImageLoaderTGA::loadImage(io::IReadFile* file) const case 16: { image = new CImage(ECF_A1R5G5B5, - core::dimension2d(header.ImageWidth, header.ImageHeight)); + core::dimension2d(header.ImageWidth, header.ImageHeight)); if (image) CColorConverter::convert16BitTo16Bit((s16*)data, (s16*)image->lock(), header.ImageWidth, header.ImageHeight, 0, (header.ImageDescriptor&0x20)==0); @@ -154,7 +154,7 @@ IImage* CImageLoaderTGA::loadImage(io::IReadFile* file) const case 24: { image = new CImage(ECF_R8G8B8, - core::dimension2d(header.ImageWidth, header.ImageHeight)); + core::dimension2d(header.ImageWidth, header.ImageHeight)); if (image) CColorConverter::convert24BitTo24Bit( (u8*)data, (u8*)image->lock(), header.ImageWidth, header.ImageHeight, 0, (header.ImageDescriptor&0x20)==0, true); @@ -163,7 +163,7 @@ IImage* CImageLoaderTGA::loadImage(io::IReadFile* file) const case 32: { image = new CImage(ECF_A8R8G8B8, - core::dimension2d(header.ImageWidth, header.ImageHeight)); + core::dimension2d(header.ImageWidth, header.ImageHeight)); if (image) CColorConverter::convert32BitTo32Bit((s32*)data, (s32*)image->lock(), header.ImageWidth, header.ImageHeight, 0, (header.ImageDescriptor&0x20)==0); diff --git a/source/Irrlicht/CImageLoaderTGA.h b/source/Irrlicht/CImageLoaderTGA.h index 2cf5294e..26429d8b 100644 --- a/source/Irrlicht/CImageLoaderTGA.h +++ b/source/Irrlicht/CImageLoaderTGA.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CImageLoaderWAL.cpp b/source/Irrlicht/CImageLoaderWAL.cpp index ddaa9a08..53c9a040 100644 --- a/source/Irrlicht/CImageLoaderWAL.cpp +++ b/source/Irrlicht/CImageLoaderWAL.cpp @@ -1,5 +1,5 @@ // Copyright (C) 2004 Murphy McCauley -// Copyright (C) 2007-2008 Christian Stehno +// Copyright (C) 2007-2009 Christian Stehno // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -123,7 +123,7 @@ IImage* CImageLoaderWAL::loadImage(irr::io::IReadFile* file) const IImage* image = 0; image = new CImage(ECF_A1R5G5B5, - core::dimension2d(header.ImageWidth, header.ImageHeight)); + core::dimension2d(header.ImageWidth, header.ImageHeight)); // I wrote an 8 to 32 converter, but this works with released Irrlicht code. CColorConverter::convert8BitTo16Bit(data, diff --git a/source/Irrlicht/CImageLoaderWAL.h b/source/Irrlicht/CImageLoaderWAL.h index e22e66b6..de6e819d 100644 --- a/source/Irrlicht/CImageLoaderWAL.h +++ b/source/Irrlicht/CImageLoaderWAL.h @@ -1,5 +1,5 @@ // Copyright (C) 2004 Murphy McCauley -// Copyright (C) 2007-2008 Christian Stehno +// Copyright (C) 2007-2009 Christian Stehno // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h /* diff --git a/source/Irrlicht/CImageWriterBMP.cpp b/source/Irrlicht/CImageWriterBMP.cpp index 064c1e6e..f4c7689b 100644 --- a/source/Irrlicht/CImageWriterBMP.cpp +++ b/source/Irrlicht/CImageWriterBMP.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CImageWriterBMP.h b/source/Irrlicht/CImageWriterBMP.h index 3f9deb95..759c1834 100644 --- a/source/Irrlicht/CImageWriterBMP.h +++ b/source/Irrlicht/CImageWriterBMP.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CImageWriterJPG.cpp b/source/Irrlicht/CImageWriterJPG.cpp index 3adbc94c..bf285659 100644 --- a/source/Irrlicht/CImageWriterJPG.cpp +++ b/source/Irrlicht/CImageWriterJPG.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -127,8 +127,8 @@ static bool writeJPEGFile(io::IWriteFile* file, IImage* image, u32 quality) if ( 0 == format ) return false; - const core::dimension2di dim = image->getDimension(); - + const core::dimension2du dim = image->getDimension(); + struct jpeg_compress_struct cinfo; struct jpeg_error_mgr jerr; cinfo.err = jpeg_std_error(&jerr); diff --git a/source/Irrlicht/CImageWriterJPG.h b/source/Irrlicht/CImageWriterJPG.h index db4ffa53..f44cd563 100644 --- a/source/Irrlicht/CImageWriterJPG.h +++ b/source/Irrlicht/CImageWriterJPG.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CImageWriterPCX.cpp b/source/Irrlicht/CImageWriterPCX.cpp index ff0d3d05..31f52d42 100644 --- a/source/Irrlicht/CImageWriterPCX.cpp +++ b/source/Irrlicht/CImageWriterPCX.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -40,7 +40,7 @@ bool CImageWriterPCX::writeImage(io::IWriteFile *file, IImage *image,u32 param) u8 d1; u16 d2; - s32 i; + u32 i; d1 = 10; // Manufacturer file->write(&d1, 1); @@ -113,7 +113,7 @@ bool CImageWriterPCX::writeImage(io::IWriteFile *file, IImage *image,u32 param) value = 0; for (u32 j=0; j<3; ++j) // color planes { - for (s32 k=0; kgetDimension().Width; ++k) + for (u32 k=0; kgetDimension().Width; ++k) { const SColor pix = image->getPixel(k,i); if ((cnt!=0) && (cnt<63) && diff --git a/source/Irrlicht/CImageWriterPCX.h b/source/Irrlicht/CImageWriterPCX.h index 152e7e6a..7cf09f12 100644 --- a/source/Irrlicht/CImageWriterPCX.h +++ b/source/Irrlicht/CImageWriterPCX.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CImageWriterPNG.cpp b/source/Irrlicht/CImageWriterPNG.cpp index 4bd80b96..75704b89 100644 --- a/source/Irrlicht/CImageWriterPNG.cpp +++ b/source/Irrlicht/CImageWriterPNG.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -169,7 +169,7 @@ bool CImageWriterPNG::writeImage(io::IWriteFile* file, IImage* image,u32 param) data=tmpImage; // Fill array of pointers to rows in image data - for (s32 i=0; igetDimension().Height; ++i) + for (u32 i=0; igetDimension().Height; ++i) { RowPointers[i]=data; data += lineWidth; diff --git a/source/Irrlicht/CImageWriterPNG.h b/source/Irrlicht/CImageWriterPNG.h index 133a59c5..0b45ed80 100644 --- a/source/Irrlicht/CImageWriterPNG.h +++ b/source/Irrlicht/CImageWriterPNG.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CImageWriterPPM.cpp b/source/Irrlicht/CImageWriterPPM.cpp index 1de1789f..9610458f 100644 --- a/source/Irrlicht/CImageWriterPPM.cpp +++ b/source/Irrlicht/CImageWriterPPM.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -42,7 +42,7 @@ bool CImageWriterPPM::writeImage(io::IWriteFile *file, IImage *image, u32 param) char cache[70]; int size; - const core::dimension2d& imageSize = image->getDimension(); + const core::dimension2d& imageSize = image->getDimension(); const bool binary = false; @@ -64,9 +64,9 @@ bool CImageWriterPPM::writeImage(io::IWriteFile *file, IImage *image, u32 param) if (binary) { - for (s32 h = 0; h < imageSize.Height; ++h) + for (u32 h = 0; h < imageSize.Height; ++h) { - for (s32 c = 0; c < imageSize.Width; ++c) + for (u32 c = 0; c < imageSize.Width; ++c) { const video::SColor& pixel = image->getPixel(c, h); const u8 r = (u8)(pixel.getRed() & 0xff); @@ -82,12 +82,12 @@ bool CImageWriterPPM::writeImage(io::IWriteFile *file, IImage *image, u32 param) { s32 n = 0; - for (s32 h = 0; h < imageSize.Height; ++h) + for (u32 h = 0; h < imageSize.Height; ++h) { - for (s32 c = 0; c < imageSize.Width; ++c, ++n) + for (u32 c = 0; c < imageSize.Width; ++c, ++n) { const video::SColor& pixel = image->getPixel(c, h); - size = snprintf(cache, 70, "%.3u %.3u %.3u%s", pixel.getRed(), pixel.getGreen(), pixel.getBlue(), n % 5 == 4 ? "\n" : " "); + size = snprintf(cache, 70, "%.3u %.3u %.3u%s", pixel.getRed(), pixel.getGreen(), pixel.getBlue(), n % 5 == 4 ? "\n" : " "); if (file->write(cache, size) != size) return false; } diff --git a/source/Irrlicht/CImageWriterPPM.h b/source/Irrlicht/CImageWriterPPM.h index 82a6ce86..99a68a9e 100644 --- a/source/Irrlicht/CImageWriterPPM.h +++ b/source/Irrlicht/CImageWriterPPM.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CImageWriterPSD.cpp b/source/Irrlicht/CImageWriterPSD.cpp index 42fb4198..25c4d5b7 100644 --- a/source/Irrlicht/CImageWriterPSD.cpp +++ b/source/Irrlicht/CImageWriterPSD.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CImageWriterPSD.h b/source/Irrlicht/CImageWriterPSD.h index b3cd238c..bf0be8d1 100644 --- a/source/Irrlicht/CImageWriterPSD.h +++ b/source/Irrlicht/CImageWriterPSD.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CImageWriterTGA.cpp b/source/Irrlicht/CImageWriterTGA.cpp index da6d94ff..7016c67c 100644 --- a/source/Irrlicht/CImageWriterTGA.cpp +++ b/source/Irrlicht/CImageWriterTGA.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CImageWriterTGA.h b/source/Irrlicht/CImageWriterTGA.h index 983b8ef4..7f24338f 100644 --- a/source/Irrlicht/CImageWriterTGA.h +++ b/source/Irrlicht/CImageWriterTGA.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CIrrDeviceLinux.cpp b/source/Irrlicht/CIrrDeviceLinux.cpp index e2ab2574..3f8b204e 100644 --- a/source/Irrlicht/CIrrDeviceLinux.cpp +++ b/source/Irrlicht/CIrrDeviceLinux.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -306,7 +306,6 @@ bool CIrrDeviceLinux::createWindow() { if (major==1 && minor>2) { - const int MAX_SAMPLES = 16; // attribute array for the draw buffer int visualAttrBuffer[] = { @@ -316,28 +315,29 @@ bool CIrrDeviceLinux::createWindow() GLX_BLUE_SIZE, 4, GLX_ALPHA_SIZE, CreationParams.WithAlphaChannel?1:0, GLX_DEPTH_SIZE, CreationParams.ZBufferBits, - GLX_DOUBLEBUFFER, GL_TRUE, - GLX_STENCIL_SIZE, 1, + GLX_DOUBLEBUFFER, CreationParams.Doublebuffer?True:False, + GLX_STENCIL_SIZE, CreationParams.Stencilbuffer?1:0, GLX_SAMPLE_BUFFERS_ARB, 1, - GLX_SAMPLES_ARB, MAX_SAMPLES, + GLX_SAMPLES_ARB, CreationParams.AntiAlias, + GLX_STEREO, CreationParams.Stereobuffer?True:False, None }; GLXFBConfig *configList=0; int nitems=0; - if (!CreationParams.AntiAlias) + if (CreationParams.AntiAlias<2) { visualAttrBuffer[17] = 0; visualAttrBuffer[19] = 0; } - if (CreationParams.Stencilbuffer) + // first round with unchanged values { configList=glXChooseFBConfig(display, screennr, visualAttrBuffer,&nitems); if (!configList && CreationParams.AntiAlias) { while (!configList && (visualAttrBuffer[19]>1)) { - visualAttrBuffer[19] >>= 1; + visualAttrBuffer[19] -= 1; configList=glXChooseFBConfig(display, screennr, visualAttrBuffer,&nitems); } if (!configList) @@ -348,31 +348,34 @@ bool CIrrDeviceLinux::createWindow() if (configList) { os::Printer::log("No FSAA available.", ELL_WARNING); - CreationParams.AntiAlias=false; + CreationParams.AntiAlias=0; } else { //reenable multisampling visualAttrBuffer[17] = 1; - visualAttrBuffer[19] = MAX_SAMPLES; + visualAttrBuffer[19] = CreationParams.AntiAlias; } } } } - // Next try without stencil buffer + // Next try with flipped stencil buffer value + // If the first round was with stencil flag it's now without + // Other way round also makes sense because some configs + // only have depth buffer combined with stencil buffer if (!configList) { if (CreationParams.Stencilbuffer) os::Printer::log("No stencilbuffer available, disabling stencil shadows.", ELL_WARNING); - CreationParams.Stencilbuffer = false; - visualAttrBuffer[15]=0; + CreationParams.Stencilbuffer = !CreationParams.Stencilbuffer; + visualAttrBuffer[15]=CreationParams.Stencilbuffer?1:0; configList=glXChooseFBConfig(display, screennr, visualAttrBuffer,&nitems); if (!configList && CreationParams.AntiAlias) { while (!configList && (visualAttrBuffer[19]>1)) { - visualAttrBuffer[19] >>= 1; + visualAttrBuffer[19] -= 1; configList=glXChooseFBConfig(display, screennr, visualAttrBuffer,&nitems); } if (!configList) @@ -383,28 +386,31 @@ bool CIrrDeviceLinux::createWindow() if (configList) { os::Printer::log("No FSAA available.", ELL_WARNING); - CreationParams.AntiAlias=false; + CreationParams.AntiAlias=0; } else { //reenable multisampling visualAttrBuffer[17] = 1; - visualAttrBuffer[19] = MAX_SAMPLES; + visualAttrBuffer[19] = CreationParams.AntiAlias; } } } } // Next try without double buffer - if (!configList) + if (!configList && CreationParams.Doublebuffer) { os::Printer::log("No doublebuffering available.", ELL_WARNING); - visualAttrBuffer[13] = GL_FALSE; + CreationParams.Doublebuffer=false; + visualAttrBuffer[13] = GLX_DONT_CARE; + CreationParams.Stencilbuffer = false; + visualAttrBuffer[15]=0; configList=glXChooseFBConfig(display, screennr, visualAttrBuffer,&nitems); if (!configList && CreationParams.AntiAlias) { while (!configList && (visualAttrBuffer[19]>1)) { - visualAttrBuffer[19] >>= 1; + visualAttrBuffer[19] -= 1; configList=glXChooseFBConfig(display, screennr, visualAttrBuffer,&nitems); } if (!configList) @@ -415,13 +421,13 @@ bool CIrrDeviceLinux::createWindow() if (configList) { os::Printer::log("No FSAA available.", ELL_WARNING); - CreationParams.AntiAlias=false; + CreationParams.AntiAlias=0; } else { //reenable multisampling visualAttrBuffer[17] = 1; - visualAttrBuffer[19] = MAX_SAMPLES; + visualAttrBuffer[19] = CreationParams.AntiAlias; } } } @@ -445,27 +451,26 @@ bool CIrrDeviceLinux::createWindow() GLX_BLUE_SIZE, 4, GLX_ALPHA_SIZE, CreationParams.WithAlphaChannel?1:0, GLX_DEPTH_SIZE, CreationParams.ZBufferBits, - GLX_DOUBLEBUFFER, GL_TRUE, - GLX_STENCIL_SIZE, 1, + GLX_DOUBLEBUFFER, CreationParams.Doublebuffer?GL_TRUE:GL_FALSE, + GLX_STENCIL_SIZE, CreationParams.Stencilbuffer?1:0, + GLX_STEREO, CreationParams.Stereobuffer?GL_TRUE:GL_FALSE, None }; - if (CreationParams.Stencilbuffer) - visual=glXChooseVisual(display, screennr, visualAttrBuffer); + visual=glXChooseVisual(display, screennr, visualAttrBuffer); if (!visual) { if (CreationParams.Stencilbuffer) - { os::Printer::log("No stencilbuffer available, disabling.", ELL_WARNING); - CreationParams.Stencilbuffer = false; - } - visualAttrBuffer[15]=0; + CreationParams.Stencilbuffer = !CreationParams.Stencilbuffer; + visualAttrBuffer[15]=CreationParams.Stencilbuffer?1:0; visual=glXChooseVisual(display, screennr, visualAttrBuffer); - if (!visual) + if (!visual && CreationParams.Doublebuffer) { os::Printer::log("No doublebuffering available.", ELL_WARNING); - visualAttrBuffer[13] = GL_FALSE; + CreationParams.Doublebuffer=false; + visualAttrBuffer[13] = GLX_DONT_CARE; visual=glXChooseVisual(display, screennr, visualAttrBuffer); } } @@ -474,12 +479,14 @@ bool CIrrDeviceLinux::createWindow() else os::Printer::log("No GLX support available. OpenGL driver will not work.", ELL_WARNING); } - + // don't use the XVisual with OpenGL, because it ignores all requested + // properties of the CreationParams + else if (!visual) #endif // _IRR_COMPILE_WITH_OPENGL_ // create visual with standard X methods - if (!visual) { + os::Printer::log("Using plain X visual"); XVisualInfo visTempl; //Template to hold requested values int visNumber; // Return value of available visuals @@ -765,7 +772,7 @@ bool CIrrDeviceLinux::run() } if (VideoDriver) - VideoDriver->OnResize(core::dimension2d(Width, Height)); + VideoDriver->OnResize(core::dimension2d(Width, Height)); } break; @@ -970,9 +977,9 @@ bool CIrrDeviceLinux::present(video::IImage* image, void* windowId, core::rectwidth; - const int minWidth = core::min_(image->getDimension().Width, destwidth); - const int destPitch = SoftwareImage->bytes_per_line; + const u32 destwidth = SoftwareImage->width; + const u32 minWidth = core::min_(image->getDimension().Width, destwidth); + const u32 destPitch = SoftwareImage->bytes_per_line; video::ECOLOR_FORMAT destColor; switch (SoftwareImage->bits_per_pixel) @@ -993,10 +1000,10 @@ bool CIrrDeviceLinux::present(video::IImage* image, void* windowId, core::rect(image->lock()); u8* destData = reinterpret_cast(SoftwareImage->data); - const int destheight = SoftwareImage->height; - const int srcheight = core::min_(image->getDimension().Height, destheight); - const int srcPitch = image->getPitch(); - for (int y=0; y!=srcheight; ++y) + const u32 destheight = SoftwareImage->height; + const u32 srcheight = core::min_(image->getDimension().Height, destheight); + const u32 srcPitch = image->getPitch(); + for (u32 y=0; y!=srcheight; ++y) { video::CColorConverter::convert_viaFormat(srcdata,image->getColorFormat(), minWidth, destData, destColor); srcdata+=srcPitch; @@ -1116,11 +1123,11 @@ video::IVideoModeList* CIrrDeviceLinux::getVideoModeList() // find fitting mode - VideoModeList.setDesktop(defaultDepth, core::dimension2d( + VideoModeList.setDesktop(defaultDepth, core::dimension2d( modes[0]->hdisplay, modes[0]->vdisplay)); for (int i = 0; i( + VideoModeList.addMode(core::dimension2d( modes[i]->hdisplay, modes[i]->vdisplay), defaultDepth); } XFree(modes); @@ -1134,11 +1141,11 @@ video::IVideoModeList* CIrrDeviceLinux::getVideoModeList() XRRScreenConfiguration *config=XRRGetScreenInfo(display,DefaultRootWindow(display)); oldRandrMode=XRRConfigCurrentConfiguration(config,&oldRandrRotation); XRRScreenSize *modes=XRRConfigSizes(config,&modeCount); - VideoModeList.setDesktop(defaultDepth, core::dimension2d( + VideoModeList.setDesktop(defaultDepth, core::dimension2d( modes[oldRandrMode].width, modes[oldRandrMode].height)); for (int i = 0; i( + VideoModeList.addMode(core::dimension2d( modes[i].width, modes[i].height), defaultDepth); } XRRFreeScreenConfigInfo(config); @@ -1379,7 +1386,7 @@ bool CIrrDeviceLinux::activateJoysticks(core::array & joystickInf info.fd = open(devName.c_str(), O_RDONLY); if(-1 == info.fd) { - // ...but Ubuntu and possibly other distros + // ...but Ubuntu and possibly other distros // create the devices in /dev/input devName = "/dev/input/js"; devName += joystick; @@ -1412,7 +1419,7 @@ bool CIrrDeviceLinux::activateJoysticks(core::array & joystickInf char name[80]; ioctl( info.fd, JSIOCGNAME(80), name); returnInfo.Name = name; - + joystickInfo.push_back(returnInfo); } @@ -1420,7 +1427,7 @@ bool CIrrDeviceLinux::activateJoysticks(core::array & joystickInf { char logString[256]; (void)sprintf(logString, "Found joystick %u, %u axes, %u buttons '%s'", - joystick, joystickInfo[joystick].Axes, + joystick, joystickInfo[joystick].Axes, joystickInfo[joystick].Buttons, joystickInfo[joystick].Name.c_str()); os::Printer::log(logString, ELL_INFORMATION); } @@ -1468,7 +1475,7 @@ void CIrrDeviceLinux::pollJoysticks() (void)postEventFromUser(info.persistentData); } #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ -} +} IRRLICHT_API IrrlichtDevice* IRRCALLCONV createDeviceEx(const SIrrlichtCreationParameters& param) diff --git a/source/Irrlicht/CIrrDeviceLinux.h b/source/Irrlicht/CIrrDeviceLinux.h index 0ca353be..4e7776a1 100644 --- a/source/Irrlicht/CIrrDeviceLinux.h +++ b/source/Irrlicht/CIrrDeviceLinux.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -147,6 +147,8 @@ namespace irr //! Changes the visible state of the mouse cursor. virtual void setVisible(bool visible) { + if (visible==IsVisible) + return; IsVisible = visible; #ifdef _IRR_COMPILE_WITH_X11_ if (!Null) diff --git a/source/Irrlicht/CIrrDeviceSDL.cpp b/source/Irrlicht/CIrrDeviceSDL.cpp index d5eb71d5..886856db 100644 --- a/source/Irrlicht/CIrrDeviceSDL.cpp +++ b/source/Irrlicht/CIrrDeviceSDL.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -89,7 +89,7 @@ CIrrDeviceSDL::CIrrDeviceSDL(const SIrrlichtCreationParameters& param) SDL_Flags |= SDL_FULLSCREEN; if (CreationParams.DriverType == video::EDT_OPENGL) SDL_Flags |= SDL_OPENGL; - else + else if (CreationParams.Doublebuffer) SDL_Flags |= SDL_DOUBLEBUF; // create window if (CreationParams.DriverType != video::EDT_NULL) @@ -147,11 +147,44 @@ bool CIrrDeviceSDL::createWindow() SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, CreationParams.WithAlphaChannel?8:0 ); } SDL_GL_SetAttribute( SDL_GL_DEPTH_SIZE, CreationParams.ZBufferBits); - SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); + if (CreationParams.Doublebuffer) + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); + if (CreationParams.Stereobuffer) + SDL_GL_SetAttribute( SDL_GL_STEREO, 1 ); + if (CreationParams.AntiAlias>1) + { + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 1 ); + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, CreationParams.AntiAlias ); + } + } if ( !Screen ) Screen = SDL_SetVideoMode( Width, Height, CreationParams.Bits, SDL_Flags ); + if ( !Screen && CreationParams.AntiAlias>1) + { + while (--CreationParams.AntiAlias>1) + { + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, CreationParams.AntiAlias ); + Screen = SDL_SetVideoMode( Width, Height, CreationParams.Bits, SDL_Flags ); + if (Screen) + break; + } + if ( !Screen ) + { + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLEBUFFERS, 0 ); + SDL_GL_SetAttribute( SDL_GL_MULTISAMPLESAMPLES, 0 ); + Screen = SDL_SetVideoMode( Width, Height, CreationParams.Bits, SDL_Flags ); + if (Screen) + os::Printer::log("AntiAliasing disabled due to lack of support!" ); + } + } + if ( !Screen && CreationParams.Doublebuffer) + { + // Try single buffer + SDL_GL_SetAttribute( SDL_GL_DOUBLEBUFFER, 1 ); + Screen = SDL_SetVideoMode( Width, Height, CreationParams.Bits, SDL_Flags ); + } if ( !Screen ) { os::Printer::log( "Could not initialize display!" ); diff --git a/source/Irrlicht/CIrrDeviceSDL.h b/source/Irrlicht/CIrrDeviceSDL.h index 2dcbf533..b6e87cb2 100644 --- a/source/Irrlicht/CIrrDeviceSDL.h +++ b/source/Irrlicht/CIrrDeviceSDL.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // This device code is based on the original SDL device implementation diff --git a/source/Irrlicht/CIrrDeviceStub.cpp b/source/Irrlicht/CIrrDeviceStub.cpp index b420da24..87cd5f12 100644 --- a/source/Irrlicht/CIrrDeviceStub.cpp +++ b/source/Irrlicht/CIrrDeviceStub.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CIrrDeviceStub.h b/source/Irrlicht/CIrrDeviceStub.h index 8cc2c541..e4b5e046 100644 --- a/source/Irrlicht/CIrrDeviceStub.h +++ b/source/Irrlicht/CIrrDeviceStub.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -19,13 +19,13 @@ namespace irr namespace gui { class IGUIEnvironment; - IGUIEnvironment* createGUIEnvironment(io::IFileSystem* fs, + IGUIEnvironment* createGUIEnvironment(io::IFileSystem* fs, video::IVideoDriver* Driver, IOSOperator* op); } namespace scene { - ISceneManager* createSceneManager(video::IVideoDriver* driver, + ISceneManager* createSceneManager(video::IVideoDriver* driver, io::IFileSystem* fs, gui::ICursorControl* cc, gui::IGUIEnvironment *gui); } @@ -36,13 +36,13 @@ namespace irr namespace video { - IVideoDriver* createSoftwareDriver(const core::dimension2d& windowSize, + IVideoDriver* createSoftwareDriver(const core::dimension2d& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter); - IVideoDriver* createSoftwareDriver2(const core::dimension2d& windowSize, + IVideoDriver* createSoftwareDriver2(const core::dimension2d& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter); - IVideoDriver* createNullDriver(io::IFileSystem* io, const core::dimension2d& screenSize); + IVideoDriver* createNullDriver(io::IFileSystem* io, const core::dimension2d& screenSize); } @@ -79,7 +79,7 @@ namespace irr //! Returns a pointer to the ITimer object. With it the current Time can be received. virtual ITimer* getTimer(); - //! Returns the version of the engine. + //! Returns the version of the engine. virtual const char* getVersion() const; //! send the event to the right receiver @@ -91,7 +91,7 @@ namespace irr //! Returns pointer to the current event receiver. Returns 0 if there is none. virtual IEventReceiver* getEventReceiver(); - //! Sets the input receiving scene manager. + //! Sets the input receiving scene manager. /** If set to null, the main scene manager (returned by GetSceneManager()) will receive the input */ virtual void setInputReceivingSceneManager(scene::ISceneManager* sceneManager); diff --git a/source/Irrlicht/CIrrDeviceWin32.cpp b/source/Irrlicht/CIrrDeviceWin32.cpp index 9e1699a9..08286970 100644 --- a/source/Irrlicht/CIrrDeviceWin32.cpp +++ b/source/Irrlicht/CIrrDeviceWin32.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -24,15 +24,15 @@ namespace irr namespace video { #ifdef _IRR_COMPILE_WITH_DIRECT3D_8_ - IVideoDriver* createDirectX8Driver(const core::dimension2d& screenSize, HWND window, + IVideoDriver* createDirectX8Driver(const core::dimension2d& screenSize, HWND window, u32 bits, bool fullscreen, bool stencilbuffer, io::IFileSystem* io, - bool pureSoftware, bool highPrecisionFPU, bool vsync, bool antiAlias); + bool pureSoftware, bool highPrecisionFPU, bool vsync, u8 antiAlias); #endif #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ - IVideoDriver* createDirectX9Driver(const core::dimension2d& screenSize, HWND window, + IVideoDriver* createDirectX9Driver(const core::dimension2d& screenSize, HWND window, u32 bits, bool fullscreen, bool stencilbuffer, io::IFileSystem* io, - bool pureSoftware, bool highPrecisionFPU, bool vsync, bool antiAlias); + bool pureSoftware, bool highPrecisionFPU, bool vsync, u8 antiAlias); #endif #ifdef _IRR_COMPILE_WITH_OPENGL_ @@ -330,7 +330,7 @@ CIrrDeviceWin32::CIrrDeviceWin32(const SIrrlichtCreationParameters& params) wcex.hIconSm = 0; // if there is an icon, load it - wcex.hIcon = (HICON)LoadImage(hInstance, "irrlicht.ico", IMAGE_ICON, 0,0, LR_LOADFROMFILE); + wcex.hIcon = (HICON)LoadImage(hInstance, "irrlicht.ico", IMAGE_ICON, 0,0, LR_LOADFROMFILE); RegisterClassEx(&wcex); @@ -438,9 +438,9 @@ void CIrrDeviceWin32::createDriver() case video::EDT_DIRECT3D8: #ifdef _IRR_COMPILE_WITH_DIRECT3D_8_ - VideoDriver = video::createDirectX8Driver(CreationParams.WindowSize, HWnd, - CreationParams.Bits, CreationParams.Fullscreen, CreationParams.Stencilbuffer, - FileSystem, false, CreationParams.HighPrecisionFPU, CreationParams.Vsync, + VideoDriver = video::createDirectX8Driver(CreationParams.WindowSize, HWnd, + CreationParams.Bits, CreationParams.Fullscreen, CreationParams.Stencilbuffer, + FileSystem, false, CreationParams.HighPrecisionFPU, CreationParams.Vsync, CreationParams.AntiAlias); if (!VideoDriver) @@ -456,9 +456,9 @@ void CIrrDeviceWin32::createDriver() case video::EDT_DIRECT3D9: #ifdef _IRR_COMPILE_WITH_DIRECT3D_9_ - VideoDriver = video::createDirectX9Driver(CreationParams.WindowSize, HWnd, - CreationParams.Bits, CreationParams.Fullscreen, CreationParams.Stencilbuffer, - FileSystem, false, CreationParams.HighPrecisionFPU, CreationParams.Vsync, + VideoDriver = video::createDirectX9Driver(CreationParams.WindowSize, HWnd, + CreationParams.Bits, CreationParams.Fullscreen, CreationParams.Stencilbuffer, + FileSystem, false, CreationParams.HighPrecisionFPU, CreationParams.Vsync, CreationParams.AntiAlias); if (!VideoDriver) @@ -530,7 +530,7 @@ void CIrrDeviceWin32::createDriver() VideoDriver = video::createSoftwareDriver2(CreationParams.WindowSize, CreationParams.Fullscreen, FileSystem, this); #else os::Printer::log("Burning's Video driver was not compiled in.", ELL_ERROR); - #endif + #endif break; case video::EDT_NULL: @@ -582,7 +582,7 @@ bool CIrrDeviceWin32::run() void CIrrDeviceWin32::yield() { Sleep(1); - + } //! Pause execution and let other processes to run for a specified amount of time. @@ -591,7 +591,7 @@ void CIrrDeviceWin32::sleep(u32 timeMs, bool pauseTimer) const bool wasStopped = Timer ? Timer->isStopped() : true; if (pauseTimer && !wasStopped) Timer->stop(); - + Sleep(timeMs); if (pauseTimer && !wasStopped) @@ -619,7 +619,7 @@ void CIrrDeviceWin32::resizeIfNecessary() sprintf(tmp, "Resizing window (%ld %ld)", r.right, r.bottom); os::Printer::log(tmp); - getVideoDriver()->OnResize(irr::core::dimension2d(r.right, r.bottom)); + getVideoDriver()->OnResize(irr::core::dimension2du((u32)r.right, (u32)r.bottom)); } Resized = false; @@ -665,7 +665,7 @@ bool CIrrDeviceWin32::present(video::IImage* image, void* windowId, core::rectgetBitsPerPixel(); bi.bV4Planes = 1; bi.bV4Width = image->getDimension().Width; - bi.bV4Height = -image->getDimension().Height; + bi.bV4Height = -((s32)image->getDimension().Height); bi.bV4V4Compression = BI_BITFIELDS; bi.bV4AlphaMask = image->getAlphaMask(); bi.bV4RedMask = image->getRedMask(); @@ -802,19 +802,19 @@ video::IVideoModeList* CIrrDeviceWin32::getVideoModeList() // enumerate video modes. DWORD i=0; DEVMODE mode; - memset(&mode, 0, sizeof(mode)); + memset(&mode, 0, sizeof(mode)); mode.dmSize = sizeof(mode); while (EnumDisplaySettings(NULL, i, &mode)) { - VideoModeList.addMode(core::dimension2d(mode.dmPelsWidth, mode.dmPelsHeight), + VideoModeList.addMode(core::dimension2d(mode.dmPelsWidth, mode.dmPelsHeight), mode.dmBitsPerPel); ++i; } if (EnumDisplaySettings(NULL, ENUM_CURRENT_SETTINGS, &mode)) - VideoModeList.setDesktop(mode.dmBitsPerPel, core::dimension2d(mode.dmPelsWidth, mode.dmPelsHeight)); + VideoModeList.setDesktop(mode.dmBitsPerPel, core::dimension2d(mode.dmPelsWidth, mode.dmPelsHeight)); } return &VideoModeList; @@ -1011,7 +1011,7 @@ bool CIrrDeviceWin32::activateJoysticks(core::array & joystickInf { if(JOYERR_NOERROR == joyGetPosEx(joystick, &info) && - JOYERR_NOERROR == joyGetDevCaps(joystick, + JOYERR_NOERROR == joyGetDevCaps(joystick, &activeJoystick.Caps, sizeof(activeJoystick.Caps))) { @@ -1033,7 +1033,7 @@ bool CIrrDeviceWin32::activateJoysticks(core::array & joystickInf { char logString[256]; (void)sprintf(logString, "Found joystick %d, %d axes, %d buttons '%s'", - joystick, joystickInfo[joystick].Axes, + joystick, joystickInfo[joystick].Axes, joystickInfo[joystick].Buttons, joystickInfo[joystick].Name.c_str()); os::Printer::log(logString, ELL_INFORMATION); } @@ -1076,11 +1076,11 @@ void CIrrDeviceWin32::pollJoysticks() { default: case 6: - event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_V] = + event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_V] = (s16)((65535 * (info.dwVpos - caps.wVmin)) / (caps.wVmax - caps.wVmin) - 32768); case 5: - event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_U] = + event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_U] = (s16)((65535 * (info.dwUpos - caps.wUmin)) / (caps.wUmax - caps.wUmin) - 32768); case 4: @@ -1088,25 +1088,25 @@ void CIrrDeviceWin32::pollJoysticks() (s16)((65535 * (info.dwRpos - caps.wRmin)) / (caps.wRmax - caps.wRmin) - 32768); case 3: - event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Z] = + event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Z] = (s16)((65535 * (info.dwZpos - caps.wZmin)) / (caps.wZmax - caps.wZmin) - 32768); - + case 2: event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_Y] = (s16)((65535 * (info.dwYpos - caps.wYmin)) / (caps.wYmax - caps.wYmin) - 32768); case 1: - event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_X] = + event.JoystickEvent.Axis[SEvent::SJoystickEvent::AXIS_X] = (s16)((65535 * (info.dwXpos - caps.wXmin)) / (caps.wXmax - caps.wXmin) - 32768); } - + event.JoystickEvent.ButtonStates = info.dwButtons; (void)postEventFromUser(event); } } #endif // _IRR_COMPILE_WITH_JOYSTICK_EVENTS_ -} +} IRRLICHT_API IrrlichtDevice* IRRCALLCONV createDeviceEx( const SIrrlichtCreationParameters& parameters) diff --git a/source/Irrlicht/CIrrDeviceWin32.h b/source/Irrlicht/CIrrDeviceWin32.h index 0eb60524..f12766d6 100644 --- a/source/Irrlicht/CIrrDeviceWin32.h +++ b/source/Irrlicht/CIrrDeviceWin32.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -76,7 +76,7 @@ namespace irr { public: - CCursorControl(const core::dimension2d& wsize, HWND hwnd, bool fullscreen) + CCursorControl(const core::dimension2d& wsize, HWND hwnd, bool fullscreen) : WindowSize(wsize), InvWindowSize(0.0f, 0.0f), IsVisible(true), HWnd(hwnd), BorderX(0), BorderY(0), UseReferenceRect(false) { @@ -96,9 +96,12 @@ namespace irr //! Changes the visible state of the mouse cursor. virtual void setVisible(bool visible) { - IsVisible = visible; - updateInternalCursorPosition(); - setPosition(CursorPos.X, CursorPos.Y); + if(visible != IsVisible) + { + IsVisible = visible; + updateInternalCursorPosition(); + setPosition(CursorPos.X, CursorPos.Y); + } } //! Returns if the cursor is currently visible. @@ -132,15 +135,14 @@ namespace irr //! Sets the new position of the cursor. virtual void setPosition(s32 x, s32 y) { - RECT rect; - if (UseReferenceRect) { - SetCursorPos(ReferenceRect.UpperLeftCorner.X + x, + SetCursorPos(ReferenceRect.UpperLeftCorner.X + x, ReferenceRect.UpperLeftCorner.Y + y); } else { + RECT rect; if (GetWindowRect(HWnd, &rect)) SetCursorPos(x + rect.left + BorderX, y + rect.top + BorderY); } @@ -198,7 +200,6 @@ namespace irr { POINT p; GetCursorPos(&p); - RECT rect; if (UseReferenceRect) { @@ -207,6 +208,7 @@ namespace irr } else { + RECT rect; if (GetWindowRect(HWnd, &rect)) { CursorPos.X = p.x-rect.left-BorderX; @@ -223,7 +225,7 @@ namespace irr } core::position2d CursorPos; - core::dimension2d WindowSize; + core::dimension2d WindowSize; core::dimension2d InvWindowSize; bool IsVisible; HWND HWnd; @@ -248,7 +250,7 @@ namespace irr void resizeIfNecessary(); - void pollJoysticks(); + void pollJoysticks(); HWND HWnd; diff --git a/source/Irrlicht/CIrrDeviceWinCE.cpp b/source/Irrlicht/CIrrDeviceWinCE.cpp index 6085ba53..7d8831bf 100644 --- a/source/Irrlicht/CIrrDeviceWinCE.cpp +++ b/source/Irrlicht/CIrrDeviceWinCE.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CIrrDeviceWinCE.h b/source/Irrlicht/CIrrDeviceWinCE.h index a96272eb..1f4ca919 100644 --- a/source/Irrlicht/CIrrDeviceWinCE.h +++ b/source/Irrlicht/CIrrDeviceWinCE.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CIrrMeshFileLoader.cpp b/source/Irrlicht/CIrrMeshFileLoader.cpp index eeafa6d9..0bba98a3 100644 --- a/source/Irrlicht/CIrrMeshFileLoader.cpp +++ b/source/Irrlicht/CIrrMeshFileLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CIrrMeshFileLoader.h b/source/Irrlicht/CIrrMeshFileLoader.h index 099a6b45..abcff377 100644 --- a/source/Irrlicht/CIrrMeshFileLoader.h +++ b/source/Irrlicht/CIrrMeshFileLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CIrrMeshWriter.cpp b/source/Irrlicht/CIrrMeshWriter.cpp index 87b813c3..451a9594 100644 --- a/source/Irrlicht/CIrrMeshWriter.cpp +++ b/source/Irrlicht/CIrrMeshWriter.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CIrrMeshWriter.h b/source/Irrlicht/CIrrMeshWriter.h index d3b8f41a..94cf6f36 100644 --- a/source/Irrlicht/CIrrMeshWriter.h +++ b/source/Irrlicht/CIrrMeshWriter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CLMTSMeshFileLoader.cpp b/source/Irrlicht/CLMTSMeshFileLoader.cpp index 310dea1e..dff5d0b0 100644 --- a/source/Irrlicht/CLMTSMeshFileLoader.cpp +++ b/source/Irrlicht/CLMTSMeshFileLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // This file was written by Jonas Petersen and modified by Nikolaus Gebhardt. diff --git a/source/Irrlicht/CLMTSMeshFileLoader.h b/source/Irrlicht/CLMTSMeshFileLoader.h index b1868f9a..8d17e533 100644 --- a/source/Irrlicht/CLMTSMeshFileLoader.h +++ b/source/Irrlicht/CLMTSMeshFileLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // diff --git a/source/Irrlicht/CLWOMeshFileLoader.cpp b/source/Irrlicht/CLWOMeshFileLoader.cpp index 4bd9ab15..988c8dc7 100644 --- a/source/Irrlicht/CLWOMeshFileLoader.cpp +++ b/source/Irrlicht/CLWOMeshFileLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CLWOMeshFileLoader.h b/source/Irrlicht/CLWOMeshFileLoader.h index 674690b9..8751183d 100644 --- a/source/Irrlicht/CLWOMeshFileLoader.h +++ b/source/Irrlicht/CLWOMeshFileLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CLightSceneNode.cpp b/source/Irrlicht/CLightSceneNode.cpp index ec6cf755..c069f36a 100644 --- a/source/Irrlicht/CLightSceneNode.cpp +++ b/source/Irrlicht/CLightSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -17,7 +17,7 @@ namespace scene //! constructor CLightSceneNode::CLightSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, const core::vector3df& position, video::SColorf color, f32 radius) -: ILightSceneNode(parent, mgr, id, position) +: ILightSceneNode(parent, mgr, id, position), DriverLightIndex(-1), LightIsOn(true) { #ifdef _DEBUG setDebugName("CLightSceneNode"); @@ -72,7 +72,9 @@ void CLightSceneNode::render() break; } } - driver->addDynamicLight(LightData); + + DriverLightIndex = driver->addDynamicLight(LightData); + setVisible(LightIsOn); } @@ -96,6 +98,19 @@ video::SLight& CLightSceneNode::getLightData() return LightData; } +void CLightSceneNode::setVisible(bool isVisible) +{ + ISceneNode::setVisible(isVisible); + + if(DriverLightIndex < 0) + return; + video::IVideoDriver* driver = SceneManager->getVideoDriver(); + if (!driver) + return; + + LightIsOn = isVisible; + driver->turnLightOn((u32)DriverLightIndex, LightIsOn); +} //! returns the axis aligned bounding box of this node const core::aabbox3d& CLightSceneNode::getBoundingBox() const diff --git a/source/Irrlicht/CLightSceneNode.h b/source/Irrlicht/CLightSceneNode.h index 689e3f64..1db890a1 100644 --- a/source/Irrlicht/CLightSceneNode.h +++ b/source/Irrlicht/CLightSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -39,6 +39,12 @@ public: //! \return Returns the light data. virtual video::SLight& getLightData(); + //! Sets if the node should be visible or not. + /** All children of this node won't be visible either, when set + to true. + \param isVisible If the node shall be visible. */ + virtual void setVisible(bool isVisible); + //! returns the axis aligned bounding box of this node virtual const core::aabbox3d& getBoundingBox() const; @@ -89,6 +95,8 @@ private: video::SLight LightData; core::aabbox3d BBox; + s32 DriverLightIndex; + bool LightIsOn; void doLightRecalc(); }; diff --git a/source/Irrlicht/CLimitReadFile.cpp b/source/Irrlicht/CLimitReadFile.cpp index f192141d..2127f826 100644 --- a/source/Irrlicht/CLimitReadFile.cpp +++ b/source/Irrlicht/CLimitReadFile.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CLimitReadFile.h b/source/Irrlicht/CLimitReadFile.h index 0f3c5434..b5436052 100644 --- a/source/Irrlicht/CLimitReadFile.h +++ b/source/Irrlicht/CLimitReadFile.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CLogger.cpp b/source/Irrlicht/CLogger.cpp index 84eaa9a9..dafcd3b6 100644 --- a/source/Irrlicht/CLogger.cpp +++ b/source/Irrlicht/CLogger.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CLogger.h b/source/Irrlicht/CLogger.h index d9be3033..a311ba83 100644 --- a/source/Irrlicht/CLogger.h +++ b/source/Irrlicht/CLogger.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CMD2MeshFileLoader.cpp b/source/Irrlicht/CMD2MeshFileLoader.cpp index 5652d571..583ff151 100644 --- a/source/Irrlicht/CMD2MeshFileLoader.cpp +++ b/source/Irrlicht/CMD2MeshFileLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -7,20 +7,96 @@ #include "CMD2MeshFileLoader.h" #include "CAnimatedMeshMD2.h" +#include "os.h" namespace irr { namespace scene { + +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) +# pragma pack( push, packing ) +# pragma pack( 1 ) +# define PACK_STRUCT +#elif defined( __GNUC__ ) +# define PACK_STRUCT __attribute__((packed)) +#else +# error compiler not supported +#endif + + // structs needed to load the md2-format + + const s32 MD2_MAGIC_NUMBER = 844121161; + const s32 MD2_VERSION = 8; + const s32 MD2_MAX_VERTS = 2048; + + struct SMD2Header + { + s32 magic; // four character code "IDP2" + s32 version; // must be 8 + s32 skinWidth; // width of the texture + s32 skinHeight; // height of the texture + s32 frameSize; // size in bytes of an animation frame + s32 numSkins; // number of textures + s32 numVertices; // total number of vertices + s32 numTexcoords; // number of vertices with texture coords + s32 numTriangles; // number of triangles + s32 numGlCommands; // number of opengl commands (triangle strip or triangle fan) + s32 numFrames; // animation keyframe count + s32 offsetSkins; // offset in bytes to 64 character skin names + s32 offsetTexcoords; // offset in bytes to texture coordinate list + s32 offsetTriangles; // offset in bytes to triangle list + s32 offsetFrames; // offset in bytes to frame list + s32 offsetGlCommands;// offset in bytes to opengl commands + s32 offsetEnd; // offset in bytes to end of file + } PACK_STRUCT; + + struct SMD2Vertex + { + u8 vertex[3]; // [0] = X, [1] = Z, [2] = Y + u8 lightNormalIndex; // index in the normal table + } PACK_STRUCT; + + struct SMD2Frame + { + f32 scale[3]; // first scale the vertex position + f32 translate[3]; // then translate the position + c8 name[16]; // the name of the animation that this key belongs to + SMD2Vertex vertices[1]; // vertex 1 of SMD2Header.numVertices + } PACK_STRUCT; + + struct SMD2Triangle + { + u16 vertexIndices[3]; + u16 textureIndices[3]; + } PACK_STRUCT; + + struct SMD2TextureCoordinate + { + s16 s; + s16 t; + } PACK_STRUCT; + + struct SMD2GLCommand + { + f32 s, t; + s32 vertexIndex; + } PACK_STRUCT; + +// Default alignment +#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__) +# pragma pack( pop, packing ) +#endif + +#undef PACK_STRUCT + //! Constructor CMD2MeshFileLoader::CMD2MeshFileLoader() { - #ifdef _DEBUG setDebugName("CMD2MeshFileLoader"); #endif - } @@ -41,7 +117,7 @@ IAnimatedMesh* CMD2MeshFileLoader::createMesh(io::IReadFile* file) IAnimatedMesh* msh = new CAnimatedMeshMD2(); if (msh) { - if (((CAnimatedMeshMD2*)msh)->loadFile(file)) + if (loadFile(file, (CAnimatedMeshMD2*)msh) ) return msh; msh->drop(); @@ -50,6 +126,246 @@ IAnimatedMesh* CMD2MeshFileLoader::createMesh(io::IReadFile* file) return 0; } +//! loads an md2 file +bool CMD2MeshFileLoader::loadFile(io::IReadFile* file, CAnimatedMeshMD2* mesh) +{ + if (!file) + return false; + + SMD2Header header; + + file->read(&header, sizeof(SMD2Header)); + +#ifdef __BIG_ENDIAN__ + header.magic = os::Byteswap::byteswap(header.magic); + header.version = os::Byteswap::byteswap(header.version); + header.skinWidth = os::Byteswap::byteswap(header.skinWidth); + header.skinHeight = os::Byteswap::byteswap(header.skinHeight); + header.frameSize = os::Byteswap::byteswap(header.frameSize); + header.numSkins = os::Byteswap::byteswap(header.numSkins); + header.numVertices = os::Byteswap::byteswap(header.numVertices); + header.numTexcoords = os::Byteswap::byteswap(header.numTexcoords); + header.numTriangles = os::Byteswap::byteswap(header.numTriangles); + header.numGlCommands = os::Byteswap::byteswap(header.numGlCommands); + header.numFrames = os::Byteswap::byteswap(header.numFrames); + header.offsetSkins = os::Byteswap::byteswap(header.offsetSkins); + header.offsetTexcoords = os::Byteswap::byteswap(header.offsetTexcoords); + header.offsetTriangles = os::Byteswap::byteswap(header.offsetTriangles); + header.offsetFrames = os::Byteswap::byteswap(header.offsetFrames); + header.offsetGlCommands = os::Byteswap::byteswap(header.offsetGlCommands); + header.offsetEnd = os::Byteswap::byteswap(header.offsetEnd); +#endif + + if (header.magic != MD2_MAGIC_NUMBER || header.version != MD2_VERSION) + { + os::Printer::log("MD2 Loader: Wrong file header", file->getFileName(), ELL_WARNING); + return false; + } + + // + // prepare mesh and allocate memory + // + + mesh->FrameCount = header.numFrames; + + // create keyframes + mesh->FrameTransforms.set_used(header.numFrames); + + // create vertex arrays for each keyframe + if (mesh->FrameList) + delete [] mesh->FrameList; + mesh->FrameList = new core::array[header.numFrames]; + + // allocate space in vertex arrays + s32 i; + for (i=0; iFrameList[i].reallocate(header.numVertices); + + // allocate interpolation buffer vertices + mesh->InterpolationBuffer->Vertices.set_used(header.numTriangles*3); + + // populate triangles + mesh->InterpolationBuffer->Indices.reallocate(header.numTriangles*3); + const s32 count = header.numTriangles*3; + for (i=0; iInterpolationBuffer->Indices.push_back(i); + mesh->InterpolationBuffer->Indices.push_back(i+1); + mesh->InterpolationBuffer->Indices.push_back(i+2); + } + + // + // read texture coordinates + // + + file->seek(header.offsetTexcoords); + SMD2TextureCoordinate* textureCoords = new SMD2TextureCoordinate[header.numTexcoords]; + + if (!file->read(textureCoords, sizeof(SMD2TextureCoordinate)*header.numTexcoords)) + { + os::Printer::log("MD2 Loader: Error reading TextureCoords.", file->getFileName(), ELL_ERROR); + return false; + } + +#ifdef __BIG_ENDIAN__ + for (i=0; iseek(header.offsetTriangles); + + SMD2Triangle *triangles = new SMD2Triangle[header.numTriangles]; + if (!file->read(triangles, header.numTriangles *sizeof(SMD2Triangle))) + { + os::Printer::log("MD2 Loader: Error reading triangles.", file->getFileName(), ELL_ERROR); + return false; + } + +#ifdef __BIG_ENDIAN__ + for (i=0; iseek(header.offsetFrames); + + for (i = 0; iread(frame, header.frameSize); + +#ifdef __BIG_ENDIAN__ + frame->scale[0] = os::Byteswap::byteswap(frame->scale[0]); + frame->scale[1] = os::Byteswap::byteswap(frame->scale[1]); + frame->scale[2] = os::Byteswap::byteswap(frame->scale[2]); + frame->translate[0] = os::Byteswap::byteswap(frame->translate[0]); + frame->translate[1] = os::Byteswap::byteswap(frame->translate[1]); + frame->translate[2] = os::Byteswap::byteswap(frame->translate[2]); +#endif + // + // store frame data + // + + CAnimatedMeshMD2::SAnimationData adata; + adata.begin = i; + adata.end = i; + adata.fps = 7; + + // Add new named animation if necessary + if (frame->name[0]) + { + // get animation name + for (s32 s = 0; s < 16 && frame->name[s]!=0 && (frame->name[s] < '0' || frame->name[s] > '9'); ++s) + { + adata.name += frame->name[s]; + } + + // Does this keyframe have the same animation name as the current animation? + if (!mesh->AnimationData.empty() && mesh->AnimationData[mesh->AnimationData.size()-1].name == adata.name) + { + // Increase the length of the animation + ++mesh->AnimationData[mesh->AnimationData.size() - 1].end; + } + else + { + // Add the new animation + mesh->AnimationData.push_back(adata); + } + } + + // save keyframe scale and translation + + mesh->FrameTransforms[i].scale.X = frame->scale[0]; + mesh->FrameTransforms[i].scale.Z = frame->scale[1]; + mesh->FrameTransforms[i].scale.Y = frame->scale[2]; + mesh->FrameTransforms[i].translate.X = frame->translate[0]; + mesh->FrameTransforms[i].translate.Z = frame->translate[1]; + mesh->FrameTransforms[i].translate.Y = frame->translate[2]; + + // add vertices + for (s32 j=0; jvertices[num].vertex[0]; + v.Pos.Z = frame->vertices[num].vertex[1]; + v.Pos.Y = frame->vertices[num].vertex[2]; + v.NormalIdx = frame->vertices[num].lightNormalIndex; + + mesh->FrameList[i].push_back(v); + } + } + + // calculate bounding boxes + if (header.numVertices) + { + core::aabbox3d box; + core::vector3df pos; + pos.X = f32(mesh->FrameList[i] [0].Pos.X) * mesh->FrameTransforms[i].scale.X + mesh->FrameTransforms[i].translate.X; + pos.Y = f32(mesh->FrameList[i] [0].Pos.Y) * mesh->FrameTransforms[i].scale.Y + mesh->FrameTransforms[i].translate.Y; + pos.Z = f32(mesh->FrameList[i] [0].Pos.Z) * mesh->FrameTransforms[i].scale.Z + mesh->FrameTransforms[i].translate.Z; + + box.reset(pos); + + for (s32 j=1; jFrameList[i] [j].Pos.X) * mesh->FrameTransforms[i].scale.X + mesh->FrameTransforms[i].translate.X; + pos.Y = f32(mesh->FrameList[i] [j].Pos.Y) * mesh->FrameTransforms[i].scale.Y + mesh->FrameTransforms[i].translate.Y; + pos.Z = f32(mesh->FrameList[i] [j].Pos.Z) * mesh->FrameTransforms[i].scale.Z + mesh->FrameTransforms[i].translate.Z; + + box.addInternalPoint(pos); + } + mesh->BoxList.push_back(box); + } + } + + // populate interpolation buffer with texture coordinates and colours + if (header.numFrames) + { + f32 dmaxs = 1.0f/(header.skinWidth); + f32 dmaxt = 1.0f/(header.skinHeight); + + for (s32 t=0; tInterpolationBuffer->Vertices[t*3 + n].TCoords.X = (textureCoords[triangles[t].textureIndices[n]].s + 0.5f) * dmaxs; + mesh->InterpolationBuffer->Vertices[t*3 + n].TCoords.Y = (textureCoords[triangles[t].textureIndices[n]].t + 0.5f) * dmaxt; + mesh->InterpolationBuffer->Vertices[t*3 + n].Color = video::SColor(255,255,255,255); + } + } + } + + // clean up + delete [] triangles; + delete [] textureCoords; + + // return + + mesh->calculateBoundingBox(); + + return true; +} + } // end namespace scene } // end namespace irr diff --git a/source/Irrlicht/CMD2MeshFileLoader.h b/source/Irrlicht/CMD2MeshFileLoader.h index 24ec8d56..b6b828a2 100644 --- a/source/Irrlicht/CMD2MeshFileLoader.h +++ b/source/Irrlicht/CMD2MeshFileLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -11,6 +11,8 @@ namespace irr { namespace scene { + +class CAnimatedMeshMD2; //! Meshloader capable of loading MD2 files class CMD2MeshFileLoader : public IMeshLoader @@ -30,6 +32,10 @@ public: //! See IReferenceCounted::drop() for more information. virtual IAnimatedMesh* createMesh(io::IReadFile* file); +private: + //! Loads the file data into the mesh + bool loadFile(io::IReadFile* file, CAnimatedMeshMD2* mesh); + }; } // end namespace scene diff --git a/source/Irrlicht/CMD3MeshFileLoader.cpp b/source/Irrlicht/CMD3MeshFileLoader.cpp index 7405e3aa..dc622ac2 100644 --- a/source/Irrlicht/CMD3MeshFileLoader.cpp +++ b/source/Irrlicht/CMD3MeshFileLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CMD3MeshFileLoader.h b/source/Irrlicht/CMD3MeshFileLoader.h index 845992c7..25dcec27 100644 --- a/source/Irrlicht/CMD3MeshFileLoader.h +++ b/source/Irrlicht/CMD3MeshFileLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CMS3DMeshFileLoader.cpp b/source/Irrlicht/CMS3DMeshFileLoader.cpp index 768767cf..22ba58c3 100644 --- a/source/Irrlicht/CMS3DMeshFileLoader.cpp +++ b/source/Irrlicht/CMS3DMeshFileLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CMS3DMeshFileLoader.h b/source/Irrlicht/CMS3DMeshFileLoader.h index 84ff7a3b..a4483f81 100644 --- a/source/Irrlicht/CMS3DMeshFileLoader.h +++ b/source/Irrlicht/CMS3DMeshFileLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CMY3DHelper.h b/source/Irrlicht/CMY3DHelper.h index dc54df3d..dcbb8c63 100644 --- a/source/Irrlicht/CMY3DHelper.h +++ b/source/Irrlicht/CMY3DHelper.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // diff --git a/source/Irrlicht/CMY3DMeshFileLoader.cpp b/source/Irrlicht/CMY3DMeshFileLoader.cpp index 909696bb..e3c4445d 100644 --- a/source/Irrlicht/CMY3DMeshFileLoader.cpp +++ b/source/Irrlicht/CMY3DMeshFileLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // @@ -8,7 +8,7 @@ // This tool created by ZDimitor everyone can use it as wants //----------------------------------------------------------------------------- -#include "IrrCompileConfig.h" +#include "IrrCompileConfig.h" #ifdef _IRR_COMPILE_WITH_MY3D_LOADER_ #include "CMY3DMeshFileLoader.h" @@ -59,7 +59,7 @@ CMY3DMeshFileLoader::CMY3DMeshFileLoader(ISceneManager* scmgr, io::IFileSystem* #ifdef _DEBUG setDebugName("CMY3DMeshFileLoader"); #endif - + if (FileSystem) FileSystem->grab(); } @@ -827,8 +827,8 @@ video::ITexture* CMY3DMeshFileLoader::readEmbeddedLightmap(io::IReadFile* file, { // 24 bit lightmap format light_img = SceneManager->getVideoDriver()->createImageFromData( - video::ECF_R8G8B8, - core::dimension2d(texDataHeader.Width, texDataHeader.Height), + video::ECF_R8G8B8, + core::dimension2d(texDataHeader.Width, texDataHeader.Height), data, true); } else @@ -836,7 +836,7 @@ video::ITexture* CMY3DMeshFileLoader::readEmbeddedLightmap(io::IReadFile* file, // 16 bit lightmap format light_img = SceneManager->getVideoDriver()->createImageFromData( video::ECF_A1R5G5B5, - core::dimension2d(texDataHeader.Width, texDataHeader.Height), + core::dimension2d(texDataHeader.Width, texDataHeader.Height), data, true); } diff --git a/source/Irrlicht/CMY3DMeshFileLoader.h b/source/Irrlicht/CMY3DMeshFileLoader.h index 0cb7849e..ab94d538 100644 --- a/source/Irrlicht/CMY3DMeshFileLoader.h +++ b/source/Irrlicht/CMY3DMeshFileLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // diff --git a/source/Irrlicht/CMemoryReadFile.cpp b/source/Irrlicht/CMemoryFile.cpp similarity index 59% rename from source/Irrlicht/CMemoryReadFile.cpp rename to source/Irrlicht/CMemoryFile.cpp index 05e6d9f1..cf8daa7a 100644 --- a/source/Irrlicht/CMemoryReadFile.cpp +++ b/source/Irrlicht/CMemoryFile.cpp @@ -2,7 +2,7 @@ // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h -#include "CMemoryReadFile.h" +#include "CMemoryFile.h" #include "irrString.h" namespace irr @@ -11,16 +11,16 @@ namespace io { -CMemoryReadFile::CMemoryReadFile(void* memory, long len, const c8* fileName, bool d) +CMemoryFile::CMemoryFile(void* memory, long len, const c8* fileName, bool d) : Buffer(memory), Len(len), Pos(0), Filename(fileName), deleteMemoryWhenDropped(d) { #ifdef _DEBUG - setDebugName("CMemoryReadFile"); + setDebugName("CMemoryFile"); #endif } -CMemoryReadFile::~CMemoryReadFile() +CMemoryFile::~CMemoryFile() { if (deleteMemoryWhenDropped) delete [] (c8*)Buffer; @@ -28,7 +28,7 @@ CMemoryReadFile::~CMemoryReadFile() //! returns how much was read -s32 CMemoryReadFile::read(void* buffer, u32 sizeToRead) +s32 CMemoryFile::read(void* buffer, u32 sizeToRead) { s32 amount = static_cast(sizeToRead); if (Pos + amount > Len) @@ -45,11 +45,30 @@ s32 CMemoryReadFile::read(void* buffer, u32 sizeToRead) return amount; } +//! returns how much was written +s32 CMemoryFile::write(const void* buffer, u32 sizeToWrite) +{ + s32 amount = static_cast(sizeToWrite); + if (Pos + amount > Len) + amount -= Pos + amount - Len; + + if (amount <= 0) + return 0; + + c8* p = (c8*)Buffer; + memcpy(p + Pos, buffer, amount); + + Pos += amount; + + return amount; +} + + //! changes position in file, returns true if successful //! if relativeMovement==true, the pos is changed relative to current pos, //! otherwise from begin of file -bool CMemoryReadFile::seek(long finalPos, bool relativeMovement) +bool CMemoryFile::seek(long finalPos, bool relativeMovement) { if (relativeMovement) { @@ -71,21 +90,21 @@ bool CMemoryReadFile::seek(long finalPos, bool relativeMovement) //! returns size of file -long CMemoryReadFile::getSize() const +long CMemoryFile::getSize() const { return Len; } //! returns where in the file we are. -long CMemoryReadFile::getPos() const +long CMemoryFile::getPos() const { return Pos; } //! returns name of file -const c8* CMemoryReadFile::getFileName() const +const c8* CMemoryFile::getFileName() const { return Filename.c_str(); } @@ -93,7 +112,7 @@ const c8* CMemoryReadFile::getFileName() const IReadFile* createMemoryReadFile(void* memory, long size, const c8* fileName, bool deleteMemoryWhenDropped) { - CMemoryReadFile* file = new CMemoryReadFile(memory, size, fileName, deleteMemoryWhenDropped); + CMemoryFile* file = new CMemoryFile(memory, size, fileName, deleteMemoryWhenDropped); return file; } diff --git a/source/Irrlicht/CMemoryReadFile.h b/source/Irrlicht/CMemoryFile.h similarity index 71% rename from source/Irrlicht/CMemoryReadFile.h rename to source/Irrlicht/CMemoryFile.h index 32124b80..7495a4b0 100644 --- a/source/Irrlicht/CMemoryReadFile.h +++ b/source/Irrlicht/CMemoryFile.h @@ -6,6 +6,7 @@ #define __C_MEMORY_READ_FILE_H_INCLUDED__ #include "IReadFile.h" +#include "IWriteFile.h" #include "irrString.h" namespace irr @@ -15,21 +16,24 @@ namespace io { /*! - Class for reading from memory. + Class for reading and writing from memory. */ - class CMemoryReadFile : public IReadFile + class CMemoryFile : public IReadFile, public IWriteFile { public: //! Constructor - CMemoryReadFile(void* memory, long len, const c8* fileName, bool deleteMemoryWhenDropped); + CMemoryFile(void* memory, long len, const c8* fileName, bool deleteMemoryWhenDropped); //! Destructor - virtual ~CMemoryReadFile(); + virtual ~CMemoryFile(); //! returns how much was read virtual s32 read(void* buffer, u32 sizeToRead); + //! returns how much was written + virtual s32 write(const void* buffer, u32 sizeToWrite); + //! changes position in file, returns true if successful virtual bool seek(long finalPos, bool relativeMovement = false); diff --git a/source/Irrlicht/CMeshCache.cpp b/source/Irrlicht/CMeshCache.cpp index bb3fbf99..46513987 100644 --- a/source/Irrlicht/CMeshCache.cpp +++ b/source/Irrlicht/CMeshCache.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CMeshCache.h b/source/Irrlicht/CMeshCache.h index dea2ba5f..ff85ca39 100644 --- a/source/Irrlicht/CMeshCache.h +++ b/source/Irrlicht/CMeshCache.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CMeshManipulator.cpp b/source/Irrlicht/CMeshManipulator.cpp index 1b22d156..d4d18342 100644 --- a/source/Irrlicht/CMeshManipulator.cpp +++ b/source/Irrlicht/CMeshManipulator.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CMeshManipulator.h b/source/Irrlicht/CMeshManipulator.h index 59a6bdcd..606ecc1e 100644 --- a/source/Irrlicht/CMeshManipulator.h +++ b/source/Irrlicht/CMeshManipulator.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CMeshSceneNode.cpp b/source/Irrlicht/CMeshSceneNode.cpp index bb57b640..d99f9f9d 100644 --- a/source/Irrlicht/CMeshSceneNode.cpp +++ b/source/Irrlicht/CMeshSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CMeshSceneNode.h b/source/Irrlicht/CMeshSceneNode.h index cc76ff3f..f96ecb1a 100644 --- a/source/Irrlicht/CMeshSceneNode.h +++ b/source/Irrlicht/CMeshSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CMetaTriangleSelector.cpp b/source/Irrlicht/CMetaTriangleSelector.cpp index 6641360a..a74a8563 100644 --- a/source/Irrlicht/CMetaTriangleSelector.cpp +++ b/source/Irrlicht/CMetaTriangleSelector.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -41,11 +41,12 @@ void CMetaTriangleSelector::getTriangles(core::triangle3df* triangles, s32 array s32& outTriangleCount, const core::matrix4* transform) const { s32 outWritten = 0; - for (u32 i=0; igetTriangles(triangles + outWritten, arraySize - outWritten, t, transform); + TriangleSelectors[i]->getTriangles(triangles + outWritten, + arraySize - outWritten, t, + transform); outWritten += t; } @@ -59,12 +60,12 @@ void CMetaTriangleSelector::getTriangles(core::triangle3df* triangles, s32 array const core::matrix4* transform) const { s32 outWritten = 0; - for (u32 i=0; igetTriangles(triangles + outWritten, arraySize - outWritten, t, - box, transform); + TriangleSelectors[i]->getTriangles(triangles + outWritten, + arraySize - outWritten, t, + box, transform); outWritten += t; } @@ -78,12 +79,12 @@ void CMetaTriangleSelector::getTriangles(core::triangle3df* triangles, s32 array const core::matrix4* transform) const { s32 outWritten = 0; - for (u32 i=0; igetTriangles(triangles + outWritten, arraySize - outWritten, t, - line, transform); + TriangleSelectors[i]->getTriangles(triangles + outWritten, + arraySize - outWritten, t, + line, transform); outWritten += t; } @@ -129,6 +130,24 @@ void CMetaTriangleSelector::removeAllTriangleSelectors() TriangleSelectors.clear(); } +//! Return the scene node associated with a given triangle. +const ISceneNode* CMetaTriangleSelector::getSceneNodeForTriangle(u32 triangleIndex) const +{ + u32 totalTriangles = 0; + + for (u32 i=0; igetTriangleCount(); + + if(totalTriangles > triangleIndex) + return TriangleSelectors[i]->getSceneNodeForTriangle(0); + } + + // For lack of anything more sensible, return the first selector. + return TriangleSelectors[0]->getSceneNodeForTriangle(0); +} + + } // end namespace scene } // end namespace irr diff --git a/source/Irrlicht/CMetaTriangleSelector.h b/source/Irrlicht/CMetaTriangleSelector.h index e995aecd..04cb8558 100644 --- a/source/Irrlicht/CMetaTriangleSelector.h +++ b/source/Irrlicht/CMetaTriangleSelector.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -51,6 +51,9 @@ public: //! Removes all triangle selectors from the collection. virtual void removeAllTriangleSelectors(); + //! Return the scene node associated with a given triangle. + virtual const ISceneNode* getSceneNodeForTriangle(u32 triangleIndex) const; + private: core::array TriangleSelectors; diff --git a/source/Irrlicht/CNullDriver.cpp b/source/Irrlicht/CNullDriver.cpp index 645d0d6a..b87d9173 100644 --- a/source/Irrlicht/CNullDriver.cpp +++ b/source/Irrlicht/CNullDriver.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -68,9 +68,10 @@ IImageWriter* createImageWriterPPM(); //! constructor -CNullDriver::CNullDriver(io::IFileSystem* io, const core::dimension2d& screenSize) +CNullDriver::CNullDriver(io::IFileSystem* io, const core::dimension2d& screenSize) : FileSystem(io), MeshManipulator(0), ViewPort(0,0,0,0), ScreenSize(screenSize), - PrimitivesDrawn(0), TextureCreationFlags(0), AllowZWriteOnTransparent(false) + PrimitivesDrawn(0), MinVertexCountForVBO(500), TextureCreationFlags(0), + AllowZWriteOnTransparent(false) { #ifdef _DEBUG setDebugName("CNullDriver"); @@ -81,7 +82,7 @@ CNullDriver::CNullDriver(io::IFileSystem* io, const core::dimension2d& scre setTextureCreationFlag(ETCF_ALWAYS_32_BIT, true); setTextureCreationFlag(ETCF_CREATE_MIP_MAPS, true); - ViewPort = core::rect(core::position2d(0,0), screenSize); + ViewPort = core::rect(core::position2d(0,0), core::dimension2di(screenSize)); // create manipulator MeshManipulator = new scene::CMeshManipulator(); @@ -227,7 +228,7 @@ void CNullDriver::disableFeature(E_VIDEO_DRIVER_FEATURE feature, bool flag) { FeatureEnabled[feature]=!flag; } - + //! queries the features of the driver, returns true if feature is available bool CNullDriver::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const @@ -467,7 +468,7 @@ ITexture* CNullDriver::addTexture(const c8* name, IImage* image) //! creates a Texture -ITexture* CNullDriver::addTexture(const core::dimension2d& size, +ITexture* CNullDriver::addTexture(const core::dimension2d& size, const c8* name, ECOLOR_FORMAT format) { if (!name) @@ -498,6 +499,16 @@ ITexture* CNullDriver::createDeviceDependentTexture(IImage* surface, const char* } +//! set or reset special render targets +bool CNullDriver::setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget, + bool clearZBuffer, SColor color) +{ + if (ERT_FRAME_BUFFER==target) + return setRenderTarget(0,clearTarget, clearZBuffer, color); + else + return false; +} + //! sets a render target bool CNullDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer, @@ -507,14 +518,12 @@ bool CNullDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer } - //! sets a viewport void CNullDriver::setViewPort(const core::rect& area) { } - //! gets the area of the current viewport const core::rect& CNullDriver::getViewPort() const { @@ -522,7 +531,6 @@ const core::rect& CNullDriver::getViewPort() const } - //! draws a vertex primitive list void CNullDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount, const void* indexList, u32 primitiveCount, E_VERTEX_TYPE vType, scene::E_PRIMITIVE_TYPE pType, E_INDEX_TYPE iType) { @@ -530,7 +538,6 @@ void CNullDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCount, } - //! draws an indexed triangle list inline void CNullDriver::drawIndexedTriangleList(const S3DVertex* vertices, u32 vertexCount, const u16* indexList, u32 triangleCount) { @@ -538,7 +545,6 @@ inline void CNullDriver::drawIndexedTriangleList(const S3DVertex* vertices, u32 } - //! draws an indexed triangle list inline void CNullDriver::drawIndexedTriangleList(const S3DVertex2TCoords* vertices, u32 vertexCount, const u16* indexList, u32 triangleCount) { @@ -630,7 +636,8 @@ void CNullDriver::draw2DImage(const video::ITexture* texture, const core::positi if (!texture) return; - draw2DImage(texture,destPos, core::rect(core::position2d(0,0), texture->getOriginalSize())); + draw2DImage(texture,destPos, core::rect(core::position2d(0,0), + core::dimension2di(texture->getOriginalSize()))); } @@ -669,7 +676,7 @@ void CNullDriver::draw2DImage(const video::ITexture* texture, const core::rect& destPos, const core::rect& sourceRect, const core::rect* clipRect, SColor color, @@ -678,8 +685,17 @@ void CNullDriver::draw2DImage(const video::ITexture* texture, const core::positi } +//! Draws the outline of a 2d rectangle +void CNullDriver::draw2DRectangleOutline(const core::recti& pos, SColor color) +{ + draw2DLine(pos.UpperLeftCorner, core::position2di(pos.LowerRightCorner.X, pos.UpperLeftCorner.Y), color); + draw2DLine(core::position2di(pos.LowerRightCorner.X, pos.UpperLeftCorner.Y), pos.LowerRightCorner, color); + draw2DLine(pos.LowerRightCorner, core::position2di(pos.UpperLeftCorner.X, pos.LowerRightCorner.Y), color); + draw2DLine(core::position2di(pos.UpperLeftCorner.X, pos.LowerRightCorner.Y), pos.UpperLeftCorner, color); +} -//! draw an 2d rectangle + +//! Draw a 2d rectangle void CNullDriver::draw2DRectangle(SColor color, const core::rect& pos, const core::rect* clip) { draw2DRectangle(pos, color, color, color, color, clip); @@ -687,7 +703,7 @@ void CNullDriver::draw2DRectangle(SColor color, const core::rect& pos, cons -//!Draws an 2d rectangle with a gradient. +//! Draws a 2d rectangle with a gradient. void CNullDriver::draw2DRectangle(const core::rect& pos, SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, const core::rect* clip) @@ -743,7 +759,7 @@ ECOLOR_FORMAT CNullDriver::getColorFormat() const //! returns screen size -const core::dimension2d& CNullDriver::getScreenSize() const +const core::dimension2d& CNullDriver::getScreenSize() const { return ScreenSize; } @@ -751,7 +767,7 @@ const core::dimension2d& CNullDriver::getScreenSize() const //! returns the current render target size, //! or the screen size if render targets are not implemented -const core::dimension2d& CNullDriver::getCurrentRenderTargetSize() const +const core::dimension2d& CNullDriver::getCurrentRenderTargetSize() const { return ScreenSize; } @@ -818,11 +834,19 @@ void CNullDriver::deleteAllDynamicLights() //! adds a dynamic light -void CNullDriver::addDynamicLight(const SLight& light) +s32 CNullDriver::addDynamicLight(const SLight& light) { Lights.push_back(light); + return Lights.size() - 1; } +//! Turns a dynamic light on or off +//! \param lightIndex: the index returned by addDynamicLight +//! \param turnOn: true to turn the light on, false to turn it off +void CNullDriver::turnLightOn(s32 lightIndex, bool turnOn) +{ + // Do nothing +} //! returns the maximal amount of dynamic lights the device can handle @@ -853,8 +877,10 @@ const SLight& CNullDriver::getDynamicLight(u32 idx) const } -//! Creates an 1bit alpha channel of the texture based of an color key. -void CNullDriver::makeColorKeyTexture(video::ITexture* texture, video::SColor color) const +//! Creates a boolean alpha channel of the texture based of an color key. +void CNullDriver::makeColorKeyTexture(video::ITexture* texture, + video::SColor color, + bool zeroTexels) const { if (!texture) return; @@ -876,19 +902,27 @@ void CNullDriver::makeColorKeyTexture(video::ITexture* texture, video::SColor co return; } - core::dimension2d dim = texture->getSize(); - s32 pitch = texture->getPitch() / 2; + const core::dimension2d dim = texture->getSize(); + const s32 pitch = texture->getPitch() / 2; - // color with alpha enabled (color opaque) - s16 ref = (0x1<<15) | (0x7fff & color.toA1R5G5B5()); + // color with alpha disabled (i.e. fully transparent) + const s16 refZeroAlpha = (0x7fff & color.toA1R5G5B5()); - for (s32 y=0; yunlock(); @@ -903,19 +937,26 @@ void CNullDriver::makeColorKeyTexture(video::ITexture* texture, video::SColor co return; } - core::dimension2d dim = texture->getSize(); + core::dimension2d dim = texture->getSize(); s32 pitch = texture->getPitch() / 4; - // color with alpha enabled (color opaque) - s32 ref = 0xff000000 | (0x00ffffff & color.color); + // color with alpha disabled (fully transparent) + const s32 refZeroAlpha = 0x00ffffff & color.color; - for (s32 y=0; yunlock(); @@ -924,9 +965,10 @@ void CNullDriver::makeColorKeyTexture(video::ITexture* texture, video::SColor co -//! Creates an 1bit alpha channel of the texture based of an color key position. +//! Creates an boolean alpha channel of the texture based of an color key position. void CNullDriver::makeColorKeyTexture(video::ITexture* texture, - core::position2d colorKeyPixelPos) const + core::position2d colorKeyPixelPos, + bool zeroTexels) const { if (!texture) return; @@ -938,6 +980,8 @@ void CNullDriver::makeColorKeyTexture(video::ITexture* texture, return; } + SColor colorKey; + if (texture->getColorFormat() == ECF_A1R5G5B5) { s16 *p = (s16*)texture->lock(); @@ -948,21 +992,11 @@ void CNullDriver::makeColorKeyTexture(video::ITexture* texture, return; } - core::dimension2d dim = texture->getSize(); s32 pitch = texture->getPitch() / 2; - s16 ref = (0x1<<15) | (0x7fff & p[colorKeyPixelPos.Y*dim.Width + colorKeyPixelPos.X]); + const s16 key16Bit = 0x7fff & p[colorKeyPixelPos.Y*pitch + colorKeyPixelPos.X]; - for (s32 y=0; yunlock(); + colorKey = video::A1R5G5B5toA8R8G8B8(key16Bit); } else { @@ -974,22 +1008,12 @@ void CNullDriver::makeColorKeyTexture(video::ITexture* texture, return; } - core::dimension2d dim = texture->getSize(); s32 pitch = texture->getPitch() / 4; - - s32 ref = (0xff<<24) | (0x00ffffff & p[colorKeyPixelPos.Y*dim.Width + colorKeyPixelPos.X]); - - for (s32 y=0; yunlock(); + colorKey = 0x00ffffff & p[colorKeyPixelPos.Y*pitch + colorKeyPixelPos.X]; } + + texture->unlock(); + makeColorKeyTexture(texture, colorKey, zeroTexels); } @@ -1008,7 +1032,7 @@ void CNullDriver::makeNormalMapTexture(video::ITexture* texture, f32 amplitude) return; } - core::dimension2d dim = texture->getSize(); + core::dimension2d dim = texture->getSize(); amplitude = amplitude / 255.0f; f32 vh = dim.Height / (f32)dim.Width; f32 hh = dim.Width / (f32)dim.Height; @@ -1027,13 +1051,13 @@ void CNullDriver::makeNormalMapTexture(video::ITexture* texture, f32 amplitude) // copy texture - s32 pitch = texture->getPitch() / 4; + u32 pitch = texture->getPitch() / 4; s32* in = new s32[dim.Height * pitch]; memcpy(in, p, dim.Height * pitch * 4); - for (s32 x=0; xgetPitch() / 2; + u32 pitch = texture->getPitch() / 2; // copy texture s16* in = new s16[dim.Height * pitch]; memcpy(in, p, dim.Height * pitch * 2); - for (s32 x=0; xcreateAndWriteFile(filename); + if(!file) + return false; + + bool result = writeImageToFile(image, file, param); + file->drop(); + + return result; +} + +//! Writes the provided image to a file. +bool CNullDriver::writeImageToFile(IImage* image, io::IWriteFile * file, u32 param) +{ + if(!file) + return false; + for (u32 i=0; iisAWriteableFileExtension(filename)) + if (SurfaceWriter[i]->isAWriteableFileExtension(file->getFileName())) { - io::IWriteFile* file = FileSystem->createAndWriteFile(filename); - if (file) - { - bool written = SurfaceWriter[i]->writeImage(file, image, param); - file->drop(); - if (written) - return true; - } + bool written = SurfaceWriter[i]->writeImage(file, image, param); + if (written) + return true; } } return false; // failed to write } - //! Creates a software image from a byte array. IImage* CNullDriver::createImageFromData(ECOLOR_FORMAT format, - const core::dimension2d& size, + const core::dimension2d& size, void *data, bool ownForeignMemory, bool deleteMemory) { @@ -1258,7 +1291,7 @@ IImage* CNullDriver::createImageFromData(ECOLOR_FORMAT format, //! Creates an empty software image. -IImage* CNullDriver::createImage(ECOLOR_FORMAT format, const core::dimension2d& size) +IImage* CNullDriver::createImage(ECOLOR_FORMAT format, const core::dimension2d& size) { return new CImage(format, size); } @@ -1272,7 +1305,7 @@ IImage* CNullDriver::createImage(ECOLOR_FORMAT format, IImage *imageToCopy) //! Creates a software image from part of another image. -IImage* CNullDriver::createImage(IImage* imageToCopy, const core::position2d& pos, const core::dimension2d& size) +IImage* CNullDriver::createImage(IImage* imageToCopy, const core::position2d& pos, const core::dimension2d& size) { return new CImage(imageToCopy, pos, size); } @@ -1307,6 +1340,7 @@ void CNullDriver::drawMeshBuffer(const scene::IMeshBuffer* mb) drawVertexPrimitiveList(mb->getVertices(), mb->getVertexCount(), mb->getIndices(), mb->getIndexCount()/3, mb->getVertexType(), scene::EPT_TRIANGLES, mb->getIndexType()); } + CNullDriver::SHWBufferLink *CNullDriver::getBufferLink(const scene::IMeshBuffer* mb) { if (!mb || !isHardwareBufferRecommend(mb)) @@ -1314,11 +1348,13 @@ CNullDriver::SHWBufferLink *CNullDriver::getBufferLink(const scene::IMeshBuffer* //search for hardware links core::map< const scene::IMeshBuffer*,SHWBufferLink* >::Node* node = HWBufferMap.find(mb); - if (node) return node->getValue(); + if (node) + return node->getValue(); return createHardwareBuffer(mb); //no hardware links, and mesh wants one, create it } + //! Update all hardware buffers, remove unused ones void CNullDriver::updateAllHardwareBuffers() { @@ -1342,18 +1378,22 @@ void CNullDriver::updateAllHardwareBuffers() void CNullDriver::deleteHardwareBuffer(SHWBufferLink *HWBuffer) { - if (!HWBuffer) return; - HWBufferMap.remove( HWBuffer->MeshBuffer ); + if (!HWBuffer) + return; + HWBufferMap.remove(HWBuffer->MeshBuffer); delete HWBuffer; } + //! Remove hardware buffer void CNullDriver::removeHardwareBuffer(const scene::IMeshBuffer* mb) { core::map::Node* node = HWBufferMap.find(mb); - if (node) deleteHardwareBuffer( node->getValue() ); + if (node) + deleteHardwareBuffer(node->getValue()); } + //! Remove all hardware buffers void CNullDriver::removeAllHardwareBuffers() { @@ -1361,28 +1401,32 @@ void CNullDriver::removeAllHardwareBuffers() deleteHardwareBuffer(HWBufferMap.getRoot()->getValue()); } + bool CNullDriver::isHardwareBufferRecommend(const scene::IMeshBuffer* mb) { if (!mb || (mb->getHardwareMappingHint_Index()==scene::EHM_NEVER && mb->getHardwareMappingHint_Vertex()==scene::EHM_NEVER)) return false; - if (mb->getVertexCount()<500) //todo: tweak and make user definable + if (mb->getVertexCount()& size) +void CNullDriver::OnResize(const core::dimension2d& size) { - if (ViewPort.getWidth() == ScreenSize.Width && - ViewPort.getHeight() == ScreenSize.Height) - ViewPort = core::rect(core::position2d(0,0), size); + if (ViewPort.getWidth() == (s32)ScreenSize.Width && + ViewPort.getHeight() == (s32)ScreenSize.Height) + ViewPort = core::rect(core::position2d(0,0), + core::dimension2di(size)); ScreenSize = size; } + // adds a material renderer and drops it afterwards. To be used for internal creation s32 CNullDriver::addAndDropMaterialRenderer(IMaterialRenderer* m) { @@ -1469,7 +1513,7 @@ io::IAttributes* CNullDriver::createAttributesFromMaterial(const video::SMateria attr->addBool((prefix+core::stringc(i+1)).c_str(), material.TextureLayer[i].TrilinearFilter); prefix = "AnisotropicFilter"; for (i=0; iaddBool((prefix+core::stringc(i+1)).c_str(), material.TextureLayer[i].AnisotropicFilter); + attr->addInt((prefix+core::stringc(i+1)).c_str(), material.TextureLayer[i].AnisotropicFilter); prefix="TextureWrap"; for (i=0; iaddEnum((prefix+core::stringc(i+1)).c_str(), material.TextureLayer[i].TextureWrap, aTextureClampNames); @@ -1511,7 +1555,7 @@ void CNullDriver::fillMaterialStructureFromAttributes(video::SMaterial& outMater outMaterial.GouraudShading = attr->getAttributeAsBool("GouraudShading"); outMaterial.Lighting = attr->getAttributeAsBool("Lighting"); outMaterial.ZWriteEnable = attr->getAttributeAsBool("ZWriteEnable"); - outMaterial.ZBuffer = (char)attr->getAttributeAsInt("ZBuffer"); + outMaterial.ZBuffer = (u8)attr->getAttributeAsInt("ZBuffer"); outMaterial.BackfaceCulling = attr->getAttributeAsBool("BackfaceCulling"); outMaterial.FrontfaceCulling = attr->getAttributeAsBool("FrontfaceCulling"); outMaterial.FogEnable = attr->getAttributeAsBool("FogEnable"); @@ -1535,7 +1579,7 @@ void CNullDriver::fillMaterialStructureFromAttributes(video::SMaterial& outMater outMaterial.setFlag(EMF_ANISOTROPIC_FILTER, attr->getAttributeAsBool(prefix.c_str())); else for (i=0; igetAttributeAsBool((prefix+core::stringc(i+1)).c_str()); + outMaterial.TextureLayer[i].AnisotropicFilter = attr->getAttributeAsInt((prefix+core::stringc(i+1)).c_str()); prefix = "TextureWrap"; for (i=0; i& size, +ITexture* CNullDriver::addRenderTargetTexture(const core::dimension2d& size, const c8* name) { return 0; @@ -1865,7 +1914,7 @@ void CNullDriver::printVersion() //! creates a video driver -IVideoDriver* createNullDriver(io::IFileSystem* io, const core::dimension2d& screenSize) +IVideoDriver* createNullDriver(io::IFileSystem* io, const core::dimension2d& screenSize) { CNullDriver* nullDriver = new CNullDriver(io, screenSize); @@ -1891,17 +1940,15 @@ bool CNullDriver::setClipPlane(u32 index, const core::plane3df& plane, bool enab return false; } + //! Enable/disable a clipping plane. -//! There are at least 6 clipping planes available for the user to set at will. -//! \param index: The plane index. Must be between 0 and MaxUserClipPlanes. -//! \param enable: If true, enable the clipping plane else disable it. void CNullDriver::enableClipPlane(u32 index, bool enable) { // not necessary } -ITexture* CNullDriver::createRenderTargetTexture(const core::dimension2d& size, +ITexture* CNullDriver::createRenderTargetTexture(const core::dimension2d& size, const c8* name) { os::Printer::log("createRenderTargetTexture is deprecated, use addRenderTargetTexture instead"); @@ -1910,7 +1957,11 @@ ITexture* CNullDriver::createRenderTargetTexture(const core::dimension2d& s return tex; } + +void CNullDriver::setMinHardwareBufferVertexCount(u32 count) +{ + MinVertexCountForVBO = count; +} + } // end namespace } // end namespace - - diff --git a/source/Irrlicht/CNullDriver.h b/source/Irrlicht/CNullDriver.h index 8a40f8b1..8845db01 100644 --- a/source/Irrlicht/CNullDriver.h +++ b/source/Irrlicht/CNullDriver.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -39,7 +39,7 @@ namespace video public: //! constructor - CNullDriver(io::IFileSystem* io, const core::dimension2d& screenSize); + CNullDriver(io::IFileSystem* io, const core::dimension2d& screenSize); //! destructor virtual ~CNullDriver(); @@ -83,12 +83,16 @@ namespace video virtual void renameTexture(ITexture* texture, const c8* newName); //! creates a Texture - virtual ITexture* addTexture(const core::dimension2d& size, const c8* name, ECOLOR_FORMAT format = ECF_A8R8G8B8); + virtual ITexture* addTexture(const core::dimension2d& size, const c8* name, ECOLOR_FORMAT format = ECF_A8R8G8B8); //! sets a render target virtual bool setRenderTarget(video::ITexture* texture, bool clearBackBuffer, bool clearZBuffer, SColor color); + //! set or reset special render targets + virtual bool setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget, + bool clearZBuffer, SColor color); + //! sets a viewport virtual void setViewPort(const core::rect& area); @@ -163,7 +167,7 @@ namespace video SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false); - //! draws an 2d image, using a color (if color is other then Color(255,255,255,255)) and the alpha channel of the texture if wanted. + //! Draws a 2d image, using a color (if color is other then Color(255,255,255,255)) and the alpha channel of the texture if wanted. virtual void draw2DImage(const video::ITexture* texture, const core::position2d& destPos, const core::rect& sourceRect, const core::rect* clipRect = 0, SColor color=SColor(255,255,255,255), bool useAlphaChannelOfTexture=false); @@ -173,21 +177,24 @@ namespace video const core::rect& sourceRect, const core::rect* clipRect = 0, const video::SColor* const colors=0, bool useAlphaChannelOfTexture=false); - //! draw an 2d rectangle + //! Draws a 2d rectangle virtual void draw2DRectangle(SColor color, const core::rect& pos, const core::rect* clip = 0); - //!Draws an 2d rectangle with a gradient. + //! Draws a 2d rectangle with a gradient. virtual void draw2DRectangle(const core::rect& pos, SColor colorLeftUp, SColor colorRightUp, SColor colorLeftDown, SColor colorRightDown, const core::rect* clip = 0); + //! Draws the outline of a 2d rectangle + virtual void draw2DRectangleOutline(const core::recti& pos, SColor color=SColor(255,255,255,255)); + //! Draws a 2d line. virtual void draw2DLine(const core::position2d& start, const core::position2d& end, SColor color=SColor(255,255,255,255)); //! Draws a pixel - virtual void drawPixel(u32 x, u32 y, const SColor & color); + virtual void drawPixel(u32 x, u32 y, const SColor & color); //! Draws a non filled concyclic reqular 2d polyon. virtual void draw2DPolygon(core::position2d center, @@ -201,10 +208,10 @@ namespace video virtual ECOLOR_FORMAT getColorFormat() const; //! get screen size - virtual const core::dimension2d& getScreenSize() const; + virtual const core::dimension2d& getScreenSize() const; //! get render target size - virtual const core::dimension2d& getCurrentRenderTargetSize() const; + virtual const core::dimension2d& getCurrentRenderTargetSize() const; // get current frames per second value virtual s32 getFPS() const; @@ -216,8 +223,15 @@ namespace video //! deletes all dynamic lights there are virtual void deleteAllDynamicLights(); - //! adds a dynamic light - virtual void addDynamicLight(const SLight& light); + //! adds a dynamic light, returning an index to the light + //! \param light: the light data to use to create the light + //! \return An index to the light, or -1 if an error occurs + virtual s32 addDynamicLight(const SLight& light); + + //! Turns a dynamic light on or off + //! \param lightIndex: the index returned by addDynamicLight + //! \param turnOn: true to turn the light on, false to turn it off + virtual void turnLightOn(s32 lightIndex, bool turnOn); //! returns the maximal amount of dynamic lights the device can handle virtual u32 getMaximalDynamicLightAmount() const; @@ -270,14 +284,14 @@ namespace video virtual void removeAllTextures(); //! Creates a render target texture. - virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, const c8* name); //! Creates an 1bit alpha channel of the texture based of an color key. - virtual void makeColorKeyTexture(video::ITexture* texture, video::SColor color) const; + virtual void makeColorKeyTexture(video::ITexture* texture, video::SColor color, bool zeroTexels) const; //! Creates an 1bit alpha channel of the texture based of an color key position. - virtual void makeColorKeyTexture(video::ITexture* texture, core::position2d colorKeyPixelPos) const; + virtual void makeColorKeyTexture(video::ITexture* texture, core::position2d colorKeyPixelPos, bool zeroTexels) const; //! Creates a normal map from a height map texture. //! \param amplitude: Constant value by which the height information is multiplied. @@ -305,11 +319,11 @@ namespace video directly and own it from now on, which means it will also try to delete [] the data when the image will be destructed. If false, the memory will by copied. */ virtual IImage* createImageFromData(ECOLOR_FORMAT format, - const core::dimension2d& size, void *data, + const core::dimension2d& size, void *data, bool ownForeignMemory=true, bool deleteForeignMemory = true); //! Creates an empty software image. - virtual IImage* createImage(ECOLOR_FORMAT format, const core::dimension2d& size); + virtual IImage* createImage(ECOLOR_FORMAT format, const core::dimension2d& size); //! Creates a software image from another image. @@ -318,7 +332,7 @@ namespace video //! Creates a software image from part of another image. virtual IImage* createImage(IImage* imageToCopy, const core::position2d& pos, - const core::dimension2d& size); + const core::dimension2d& size); //! Draws a mesh buffer virtual void drawMeshBuffer(const scene::IMeshBuffer* mb); @@ -338,7 +352,6 @@ namespace video MeshBuffer->drop(); } - scene::E_BUFFER_TYPE Contains; const scene::IMeshBuffer *MeshBuffer; u32 ChangedID_Vertex; u32 ChangedID_Index; @@ -377,7 +390,7 @@ namespace video public: //! Only used by the engine internally. /** Used to notify the driver that the window was resized. */ - virtual void OnResize(const core::dimension2d& size); + virtual void OnResize(const core::dimension2d& size); //! Adds a new material renderer to the video device. virtual s32 addMaterialRenderer(IMaterialRenderer* renderer, @@ -479,6 +492,9 @@ namespace video //! Writes the provided image to disk file virtual bool writeImageToFile(IImage* image, const char* filename, u32 param = 0); + //! Writes the provided image to a file. + virtual bool writeImageToFile(IImage* image, io::IWriteFile * file, u32 param = 0); + //! Sets the name of a material renderer. virtual void setMaterialRendererName(s32 idx, const char* name); @@ -507,12 +523,16 @@ namespace video //! Returns the graphics card vendor name. virtual core::stringc getVendorInfo() {return "Not available on this driver.";} + //! Set the minimum number of vertices for which a hw buffer will be created + /** \param count Number of vertices to set as minimum. */ + virtual void setMinHardwareBufferVertexCount(u32 count); + //! Only used by the engine internally. virtual void setAllowZWriteOnTransparent(bool flag) { AllowZWriteOnTransparent=flag; } //! deprecated method - virtual ITexture* createRenderTargetTexture(const core::dimension2d& size, + virtual ITexture* createRenderTargetTexture(const core::dimension2d& size, const c8* name=0); virtual bool checkDriverReset() {return false;} @@ -585,13 +605,13 @@ namespace video virtual void* lock(bool readOnly = false) { return 0; }; virtual void unlock(){} - virtual const core::dimension2d& getOriginalSize() const { return size; } - virtual const core::dimension2d& getSize() const { return size; } + virtual const core::dimension2d& getOriginalSize() const { return size; } + virtual const core::dimension2d& getSize() const { return size; } virtual E_DRIVER_TYPE getDriverType() const { return video::EDT_NULL; } virtual ECOLOR_FORMAT getColorFormat() const { return video::ECF_A1R5G5B5; }; virtual u32 getPitch() const { return 0; } virtual void regenerateMipMapLevels() {}; - core::dimension2d size; + core::dimension2d size; }; @@ -611,12 +631,13 @@ namespace video scene::IMeshManipulator* MeshManipulator; core::rect ViewPort; - core::dimension2d ScreenSize; + core::dimension2d ScreenSize; core::matrix4 TransformationMatrix; CFPSCounter FPSCounter; u32 PrimitivesDrawn; + u32 MinVertexCountForVBO; u32 TextureCreationFlags; @@ -624,14 +645,13 @@ namespace video f32 FogEnd; f32 FogDensity; SColor FogColor; + SExposedVideoData ExposedData; + bool LinearFog; bool PixelFog; bool RangeFog; - bool AllowZWriteOnTransparent; - SExposedVideoData ExposedData; - bool FeatureEnabled[video::EVDF_COUNT]; }; diff --git a/source/Irrlicht/COBJMeshFileLoader.cpp b/source/Irrlicht/COBJMeshFileLoader.cpp index 2c363479..75fb9a2c 100644 --- a/source/Irrlicht/COBJMeshFileLoader.cpp +++ b/source/Irrlicht/COBJMeshFileLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COBJMeshFileLoader.h b/source/Irrlicht/COBJMeshFileLoader.h index 6d3a5bd8..2e10594b 100644 --- a/source/Irrlicht/COBJMeshFileLoader.h +++ b/source/Irrlicht/COBJMeshFileLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COBJMeshWriter.cpp b/source/Irrlicht/COBJMeshWriter.cpp index 5062555e..a1ed075f 100644 --- a/source/Irrlicht/COBJMeshWriter.cpp +++ b/source/Irrlicht/COBJMeshWriter.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Christian Stehno +// Copyright (C) 2008-2009 Christian Stehno // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COBJMeshWriter.h b/source/Irrlicht/COBJMeshWriter.h index cc04fa5e..e4bf5870 100644 --- a/source/Irrlicht/COBJMeshWriter.h +++ b/source/Irrlicht/COBJMeshWriter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Christian Stehno +// Copyright (C) 2008-2009 Christian Stehno // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COCTLoader.cpp b/source/Irrlicht/COCTLoader.cpp index 0fc9b616..1cb3ddbd 100644 --- a/source/Irrlicht/COCTLoader.cpp +++ b/source/Irrlicht/COCTLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // @@ -219,7 +219,7 @@ IAnimatedMesh* COCTLoader::createMesh(io::IReadFile* file) const u32 lightmapWidth = 128; const u32 lightmapHeight = 128; - const core::dimension2d lmapsize(lightmapWidth, lightmapHeight); + const core::dimension2d lmapsize(lightmapWidth, lightmapHeight); bool oldMipMapState = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); diff --git a/source/Irrlicht/COCTLoader.h b/source/Irrlicht/COCTLoader.h index ba13074d..6e08c78c 100644 --- a/source/Irrlicht/COCTLoader.h +++ b/source/Irrlicht/COCTLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // diff --git a/source/Irrlicht/COSOperator.cpp b/source/Irrlicht/COSOperator.cpp index 6ad21399..3e0a7f74 100644 --- a/source/Irrlicht/COSOperator.cpp +++ b/source/Irrlicht/COSOperator.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COSOperator.h b/source/Irrlicht/COSOperator.h index a9f794f1..9f5a4640 100644 --- a/source/Irrlicht/COSOperator.h +++ b/source/Irrlicht/COSOperator.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COctTreeSceneNode.cpp b/source/Irrlicht/COctTreeSceneNode.cpp index 7200945e..2e9ffacd 100644 --- a/source/Irrlicht/COctTreeSceneNode.cpp +++ b/source/Irrlicht/COctTreeSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COctTreeSceneNode.h b/source/Irrlicht/COctTreeSceneNode.h index 16feeb00..d5d71511 100644 --- a/source/Irrlicht/COctTreeSceneNode.h +++ b/source/Irrlicht/COctTreeSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COctTreeTriangleSelector.cpp b/source/Irrlicht/COctTreeTriangleSelector.cpp index 3f95563f..316ef7f3 100644 --- a/source/Irrlicht/COctTreeTriangleSelector.cpp +++ b/source/Irrlicht/COctTreeTriangleSelector.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COctTreeTriangleSelector.h b/source/Irrlicht/COctTreeTriangleSelector.h index 1a52e4ca..1e11efb8 100644 --- a/source/Irrlicht/COctTreeTriangleSelector.h +++ b/source/Irrlicht/COctTreeTriangleSelector.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COgreMeshFileLoader.cpp b/source/Irrlicht/COgreMeshFileLoader.cpp index d7eeea3a..b4009ca8 100644 --- a/source/Irrlicht/COgreMeshFileLoader.cpp +++ b/source/Irrlicht/COgreMeshFileLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // orginally written by Christian Stehno, modified by Nikolaus Gebhardt @@ -761,7 +761,7 @@ void COgreMeshFileLoader::readPass(io::IReadFile* file, OgreTechnique& technique else if (token=="depth_check") { getMaterialToken(file, token); - pass.Material.ZBuffer=(token=="on"); + pass.Material.ZBuffer=((token=="on")?video::ECFN_LESSEQUAL:video::ECFN_NEVER); } else if (token=="depth_write") { diff --git a/source/Irrlicht/COgreMeshFileLoader.h b/source/Irrlicht/COgreMeshFileLoader.h index 2d61a653..29adf0fb 100644 --- a/source/Irrlicht/COgreMeshFileLoader.h +++ b/source/Irrlicht/COgreMeshFileLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // orginally written by Christian Stehno, modified by Nikolaus Gebhardt diff --git a/source/Irrlicht/COpenGLDriver.cpp b/source/Irrlicht/COpenGLDriver.cpp index 791c6248..6b7e04c4 100644 --- a/source/Irrlicht/COpenGLDriver.cpp +++ b/source/Irrlicht/COpenGLDriver.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -36,7 +36,9 @@ COpenGLDriver::COpenGLDriver(const irr::SIrrlichtCreationParameters& params, : CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), CurrentRenderMode(ERM_NONE), ResetRenderStates(true), Transformation3DChanged(true), AntiAlias(params.AntiAlias), RenderTargetTexture(0), LastSetLight(-1), - CurrentRendertargetSize(0,0), + CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8), + CurrentTarget(ERT_FRAME_BUFFER), + Doublebuffer(params.Doublebuffer), Stereo(params.Stereobuffer), HDc(0), Window(static_cast(params.WindowId)), HRc(0) { #ifdef _DEBUG @@ -47,13 +49,14 @@ COpenGLDriver::COpenGLDriver(const irr::SIrrlichtCreationParameters& params, //! inits the open gl driver bool COpenGLDriver::initDriver(irr::SIrrlichtCreationParameters params) { - // Set up ixel format descriptor with desired parameters + // Set up pixel format descriptor with desired parameters PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor 1, // Version Number PFD_DRAW_TO_WINDOW | // Format Must Support Window PFD_SUPPORT_OPENGL | // Format Must Support OpenGL - PFD_DOUBLEBUFFER, // Must Support Double Buffering + (params.Doublebuffer?PFD_DOUBLEBUFFER:0) | // Must Support Double Buffering + (params.Stereobuffer?PFD_STEREO:0) | // Must Support Stereo Buffer PFD_TYPE_RGBA, // Request An RGBA Format params.Bits, // Select Our Color Depth 0, 0, 0, 0, 0, 0, // Color Bits Ignored @@ -71,7 +74,7 @@ bool COpenGLDriver::initDriver(irr::SIrrlichtCreationParameters params) GLuint PixelFormat; - if (AntiAlias) + if (AntiAlias > 1) { // Create a window to test antialiasing support const c8* ClassName = "GLCIrrDeviceWin32"; @@ -79,19 +82,19 @@ bool COpenGLDriver::initDriver(irr::SIrrlichtCreationParameters params) // Register Class WNDCLASSEX wcex; - wcex.cbSize = sizeof(WNDCLASSEX); - wcex.style = CS_HREDRAW | CS_VREDRAW; + wcex.cbSize = sizeof(WNDCLASSEX); + wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = (WNDPROC)DefWindowProc; - wcex.cbClsExtra = 0; - wcex.cbWndExtra = 0; - wcex.hInstance = lhInstance; - wcex.hIcon = NULL; - wcex.hCursor = LoadCursor(NULL, IDC_ARROW); - wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); - wcex.lpszMenuName = 0; - wcex.lpszClassName = ClassName; - wcex.hIconSm = 0; - wcex.hIcon = 0; + wcex.cbClsExtra = 0; + wcex.cbWndExtra = 0; + wcex.hInstance = lhInstance; + wcex.hIcon = NULL; + wcex.hCursor = LoadCursor(NULL, IDC_ARROW); + wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + wcex.lpszMenuName = 0; + wcex.lpszClassName = ClassName; + wcex.hIconSm = 0; + wcex.hIcon = 0; RegisterClassEx(&wcex); RECT clientSize; @@ -114,9 +117,9 @@ bool COpenGLDriver::initDriver(irr::SIrrlichtCreationParameters params) const s32 windowTop = (GetSystemMetrics(SM_CYSCREEN) - realHeight) / 2; HWND temporary_wnd=CreateWindow(ClassName, "", style, windowLeft, windowTop, - realWidth, realHeight, NULL, NULL, lhInstance, NULL); + realWidth, realHeight, NULL, NULL, lhInstance, NULL); - if(!temporary_wnd) + if (!temporary_wnd) { os::Printer::log("Cannot create a temporary window.", ELL_ERROR); return false; @@ -150,6 +153,15 @@ bool COpenGLDriver::initDriver(irr::SIrrlichtCreationParameters params) } else if (i == 4) + { + // try single buffer + if (params.Doublebuffer) + pfd.dwFlags &= ~PFD_DOUBLEBUFFER; + else + continue; + } + else + if (i == 5) { os::Printer::log("Cannot create a GL device context", "No suitable format for temporary window.", ELL_ERROR); ReleaseDC(temporary_wnd, HDc); @@ -165,7 +177,7 @@ bool COpenGLDriver::initDriver(irr::SIrrlichtCreationParameters params) SetPixelFormat(HDc, PixelFormat, &pfd); HRc=wglCreateContext(HDc); - if(!HRc) + if (!HRc) { os::Printer::log("Cannot create a temporary GL rendering context.", ELL_ERROR); ReleaseDC(temporary_wnd, HDc); @@ -173,7 +185,7 @@ bool COpenGLDriver::initDriver(irr::SIrrlichtCreationParameters params) return false; } - if(!wglMakeCurrent(HDc, HRc)) + if (!wglMakeCurrent(HDc, HRc)) { os::Printer::log("Cannot activate a temporary GL rendering context.", ELL_ERROR); wglDeleteContext(HRc); @@ -183,18 +195,17 @@ bool COpenGLDriver::initDriver(irr::SIrrlichtCreationParameters params) } PFNWGLCHOOSEPIXELFORMATARBPROC wglChoosePixelFormat_ARB = (PFNWGLCHOOSEPIXELFORMATARBPROC)wglGetProcAddress("wglChoosePixelFormatARB"); - if(wglChoosePixelFormat_ARB) + if (wglChoosePixelFormat_ARB) { // This value determines the number of samples used for antialiasing - // valid numbers are 2, 4, 8. My experience is that 8 does not - // show a big improvement over 4, but 4 shows a big improvement over - // 2. - const s32 numSamples = 4; - f32 fAttributes[] = - { - 0.0, 0.0 - }; + // My experience is that 8 does not show a big + // improvement over 4, but 4 shows a big improvement + // over 2. + if(AntiAlias > 32) + AntiAlias = 32; + + f32 fAttributes[] = {0.0, 0.0}; s32 iAttributes[] = { WGL_DRAW_TO_WINDOW_ARB,GL_TRUE, @@ -204,28 +215,34 @@ bool COpenGLDriver::initDriver(irr::SIrrlichtCreationParameters params) WGL_ALPHA_BITS_ARB,(params.Bits==32) ? 8 : 1, WGL_DEPTH_BITS_ARB,params.ZBufferBits, WGL_STENCIL_BITS_ARB,(params.Stencilbuffer) ? 1 : 0, - WGL_DOUBLE_BUFFER_ARB,GL_TRUE, - WGL_SAMPLE_BUFFERS_ARB,GL_TRUE, - WGL_SAMPLES_ARB,numSamples, + WGL_DOUBLE_BUFFER_ARB,(params.Doublebuffer) ? GL_TRUE : GL_FALSE, + WGL_STEREO_ARB,(params.Stereobuffer) ? GL_TRUE : GL_FALSE, + WGL_SAMPLE_BUFFERS_ARB, 1, + WGL_SAMPLES_ARB,AntiAlias, 0,0 }; - s32 rv=0; + s32 rv=0; // Try to get an acceptable pixel format - while(rv==0 && iAttributes[19]>1) + while(rv==0 && iAttributes[21]>1) { s32 pixelFormat=0; u32 numFormats=0; const s32 valid = wglChoosePixelFormat_ARB(HDc,iAttributes,fAttributes,1,&pixelFormat,&numFormats); - if(valid && numFormats>0) + if (valid && numFormats>0) rv = pixelFormat; else - iAttributes[19] >>= 1; + iAttributes[21] -= 1; } - if(rv) + if (rv) + { PixelFormat=rv; + AntiAlias=iAttributes[21]; + } } + else + AntiAlias=0; wglMakeCurrent(HDc, NULL); wglDeleteContext(HRc); @@ -242,7 +259,7 @@ bool COpenGLDriver::initDriver(irr::SIrrlichtCreationParameters params) } // search for pixel format the simple way - if (!AntiAlias) + if (AntiAlias < 2) { for (u32 i=0; i<5; ++i) { @@ -284,7 +301,7 @@ bool COpenGLDriver::initDriver(irr::SIrrlichtCreationParameters params) } // set pixel format - if(!SetPixelFormat(HDc, PixelFormat, &pfd)) + if (!SetPixelFormat(HDc, PixelFormat, &pfd)) { os::Printer::log("Cannot set the pixel format.", ELL_ERROR); return false; @@ -299,7 +316,7 @@ bool COpenGLDriver::initDriver(irr::SIrrlichtCreationParameters params) } // activate rendering context - if(!wglMakeCurrent(HDc, HRc)) + if (!wglMakeCurrent(HDc, HRc)) { os::Printer::log("Cannot activate GL rendering context", ELL_ERROR); wglDeleteContext(HRc); @@ -348,8 +365,11 @@ COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, io::IFileSystem* io, CIrrDeviceMacOSX *device) : CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), CurrentRenderMode(ERM_NONE), ResetRenderStates(true), Transformation3DChanged(true), - AntiAlias(params.AntiAlias), RenderTargetTexture(0), LastSetLight(-1), - CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8), _device(device) + AntiAlias(params.AntiAlias), RenderTargetTexture(0), + CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8), + CurrentTarget(ERT_FRAME_BUFFER), + Doublebuffer(params.Doublebuffer), Stereo(params.Stereobuffer), + _device(device) { #ifdef _DEBUG setDebugName("COpenGLDriver"); @@ -369,7 +389,9 @@ COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, : CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), CurrentRenderMode(ERM_NONE), ResetRenderStates(true), Transformation3DChanged(true), AntiAlias(params.AntiAlias), - RenderTargetTexture(0), LastSetLight(-1), CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8) + RenderTargetTexture(0), CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8), + CurrentTarget(ERT_FRAME_BUFFER), + Doublebuffer(params.Doublebuffer), Stereo(params.Stereobuffer) { #ifdef _DEBUG setDebugName("COpenGLDriver"); @@ -406,7 +428,9 @@ COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, : CNullDriver(io, params.WindowSize), COpenGLExtensionHandler(), CurrentRenderMode(ERM_NONE), ResetRenderStates(true), Transformation3DChanged(true), AntiAlias(params.AntiAlias), - RenderTargetTexture(0), LastSetLight(-1), CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8) + RenderTargetTexture(0), CurrentRendertargetSize(0,0), ColorFormat(ECF_R8G8B8), + CurrentTarget(ERT_FRAME_BUFFER), + Doublebuffer(params.Doublebuffer), Stereo(params.Stereobuffer) { #ifdef _DEBUG setDebugName("COpenGLDriver"); @@ -421,6 +445,8 @@ COpenGLDriver::COpenGLDriver(const SIrrlichtCreationParameters& params, //! destructor COpenGLDriver::~COpenGLDriver() { + RequestedLights.clear(); + deleteMaterialRenders(); // I get a blue screen on my laptop, when I do not delete the @@ -447,7 +473,7 @@ COpenGLDriver::~COpenGLDriver() // METHODS // ----------------------------------------------------------------------- -bool COpenGLDriver::genericDriverInit(const core::dimension2d& screenSize, bool stencilBuffer) +bool COpenGLDriver::genericDriverInit(const core::dimension2d& screenSize, bool stencilBuffer) { Name=L"OpenGL "; Name.append(glGetString(GL_VERSION)); @@ -502,20 +528,10 @@ bool COpenGLDriver::genericDriverInit(const core::dimension2d& screenSize, glClearDepth(1.0); glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); + glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); + glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST); glDepthFunc(GL_LEQUAL); - glFrontFace( GL_CW ); - - if (AntiAlias) - { - if (MultiSamplingExtension) - glEnable(GL_MULTISAMPLE_ARB); - - glHint(GL_LINE_SMOOTH_HINT, GL_NICEST); - glEnable(GL_LINE_SMOOTH); - } -// currently disabled, because often in software, and thus very slow -// glHint(GL_POINT_SMOOTH_HINT, GL_FASTEST); -// glEnable(GL_POINT_SMOOTH); + glFrontFace(GL_CW); UserClipPlane.reallocate(MaxUserClipPlanes); UserClipPlaneEnabled.reallocate(MaxUserClipPlanes); @@ -618,14 +634,10 @@ bool COpenGLDriver::endScene() } -//! clears the zbuffer -bool COpenGLDriver::beginScene(bool backBuffer, bool zBuffer, SColor color, - void* windowId, core::rect* sourceRect) +//! clears the zbuffer and color buffer +void COpenGLDriver::clearBuffers(bool backBuffer, bool zBuffer, bool stencilBuffer, SColor color) { - CNullDriver::beginScene(backBuffer, zBuffer, color, windowId, sourceRect); - GLbitfield mask = 0; - if (backBuffer) { const f32 inv = 1.0f / 255.0f; @@ -642,7 +654,20 @@ bool COpenGLDriver::beginScene(bool backBuffer, bool zBuffer, SColor color, mask |= GL_DEPTH_BUFFER_BIT; } + if (stencilBuffer) + mask |= GL_STENCIL_BUFFER_BIT; + glClear(mask); +} + + +//! init call for rendering start +bool COpenGLDriver::beginScene(bool backBuffer, bool zBuffer, SColor color, + void* windowId, core::rect* sourceRect) +{ + CNullDriver::beginScene(backBuffer, zBuffer, color, windowId, sourceRect); + + clearBuffers(backBuffer, zBuffer, false, color); return true; } @@ -660,7 +685,7 @@ void COpenGLDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matri Matrices[state] = mat; Transformation3DChanged = true; - switch(state) + switch (state) { case ETS_VIEW: case ETS_WORLD: @@ -715,6 +740,7 @@ void COpenGLDriver::setTransform(E_TRANSFORMATION_STATE state, const core::matri } } + bool COpenGLDriver::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) { if (!HWBuffer) @@ -778,7 +804,8 @@ bool COpenGLDriver::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) if (!HWBuffer->vbo_verticesID) { extGlGenBuffers(1, &HWBuffer->vbo_verticesID); - if (!HWBuffer->vbo_verticesID) return false; + if (!HWBuffer->vbo_verticesID) + return false; newBuffer=true; } else if (HWBuffer->vbo_verticesSize < vertexCount*vertexSize) @@ -786,7 +813,7 @@ bool COpenGLDriver::updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) newBuffer=true; } - extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID ); + extGlBindBuffer(GL_ARRAY_BUFFER, HWBuffer->vbo_verticesID); //copy data to graphics card glGetError(); // clear error storage @@ -818,7 +845,7 @@ bool COpenGLDriver::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) if (!HWBuffer) return false; - if(!FeatureAvailable[IRR_ARB_vertex_buffer_object]) + if (!FeatureAvailable[IRR_ARB_vertex_buffer_object]) return false; #if defined(GL_ARB_vertex_buffer_object) @@ -830,12 +857,12 @@ bool COpenGLDriver::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) GLenum indexSize; switch (mb->getIndexType()) { - case (EIT_16BIT): + case EIT_16BIT: { indexSize=sizeof(u16); break; } - case (EIT_32BIT): + case EIT_32BIT: { indexSize=sizeof(u32); break; @@ -852,7 +879,8 @@ bool COpenGLDriver::updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer) if (!HWBuffer->vbo_indicesID) { extGlGenBuffers(1, &HWBuffer->vbo_indicesID); - if (!HWBuffer->vbo_indicesID) return false; + if (!HWBuffer->vbo_indicesID) + return false; newBuffer=true; } else if (HWBuffer->vbo_indicesSize < indexCount*indexSize) @@ -960,8 +988,8 @@ COpenGLDriver::SHWBufferLink *COpenGLDriver::createHardwareBuffer(const scene::I void COpenGLDriver::deleteHardwareBuffer(SHWBufferLink *_HWBuffer) { - if (!_HWBuffer) return; - + if (!_HWBuffer) + return; #if defined(GL_ARB_vertex_buffer_object) SHWBufferLink_opengl *HWBuffer=(SHWBufferLink_opengl*)_HWBuffer; @@ -978,7 +1006,6 @@ void COpenGLDriver::deleteHardwareBuffer(SHWBufferLink *_HWBuffer) #endif CNullDriver::deleteHardwareBuffer(_HWBuffer); - } @@ -988,16 +1015,13 @@ void COpenGLDriver::drawHardwareBuffer(SHWBufferLink *_HWBuffer) if (!_HWBuffer) return; - SHWBufferLink_opengl *HWBuffer=(SHWBufferLink_opengl*)_HWBuffer; - - updateHardwareBuffer(HWBuffer); //check if update is needed - - HWBuffer->LastUsed=0;//reset count + updateHardwareBuffer(_HWBuffer); //check if update is needed + _HWBuffer->LastUsed=0; //reset count #if defined(GL_ARB_vertex_buffer_object) + SHWBufferLink_opengl *HWBuffer=(SHWBufferLink_opengl*)_HWBuffer; + const scene::IMeshBuffer* mb = HWBuffer->MeshBuffer; - - const void *vertices=mb->getVertices(); const void *indexList=mb->getIndices(); @@ -1013,17 +1037,12 @@ void COpenGLDriver::drawHardwareBuffer(SHWBufferLink *_HWBuffer) indexList=0; } - drawVertexPrimitiveList(vertices, mb->getVertexCount(), indexList, mb->getIndexCount()/3, mb->getVertexType(), scene::EPT_TRIANGLES, mb->getIndexType()); if (HWBuffer->Mapped_Vertex!=scene::EHM_NEVER) extGlBindBuffer(GL_ARRAY_BUFFER, 0); - if (HWBuffer->Mapped_Index!=scene::EHM_NEVER) extGlBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - - - #endif } @@ -1060,7 +1079,7 @@ void COpenGLDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCoun case EVT_STANDARD: { const S3DVertex* p = static_cast(vertices); - for ( i=0; iColor.toOpenGLColor(&ColorBuffer[i]); ++p; @@ -1070,7 +1089,7 @@ void COpenGLDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCoun case EVT_2TCOORDS: { const S3DVertex2TCoords* p = static_cast(vertices); - for ( i=0; iColor.toOpenGLColor(&ColorBuffer[i]); ++p; @@ -1080,7 +1099,7 @@ void COpenGLDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCoun case EVT_TANGENTS: { const S3DVertexTangents* p = static_cast(vertices); - for ( i=0; iColor.toOpenGLColor(&ColorBuffer[i]); ++p; @@ -1184,7 +1203,7 @@ void COpenGLDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCoun glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), buffer_offset(36)); extGlClientActiveTexture(GL_TEXTURE2_ARB); - glEnableClientState ( GL_TEXTURE_COORD_ARRAY ); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); if (vertices) glTexCoordPointer(3, GL_FLOAT, sizeof(S3DVertexTangents), &(static_cast(vertices))[0].Binormal); else @@ -1197,12 +1216,12 @@ void COpenGLDriver::drawVertexPrimitiveList(const void* vertices, u32 vertexCoun switch (iType) { - case (EIT_16BIT): + case EIT_16BIT: { indexSize=GL_UNSIGNED_SHORT; break; } - case (EIT_32BIT): + case EIT_32BIT: { indexSize=GL_UNSIGNED_INT; break; @@ -1308,6 +1327,7 @@ void COpenGLDriver::draw2DImage(const video::ITexture* texture, core::position2d targetPos(pos); core::position2d sourcePos(sourceRect.UpperLeftCorner); + // This needs to be signed as it may go negative. core::dimension2d sourceSize(sourceRect.getSize()); if (clipRect) { @@ -1358,9 +1378,9 @@ void COpenGLDriver::draw2DImage(const video::ITexture* texture, targetPos.X = 0; } - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); - if (targetPos.X + sourceSize.Width > renderTargetSize.Width) + if (targetPos.X + sourceSize.Width > (s32)renderTargetSize.Width) { sourceSize.Width -= (targetPos.X + sourceSize.Width) - renderTargetSize.Width; if (sourceSize.Width <= 0) @@ -1377,7 +1397,7 @@ void COpenGLDriver::draw2DImage(const video::ITexture* texture, targetPos.Y = 0; } - if (targetPos.Y + sourceSize.Height > renderTargetSize.Height) + if (targetPos.Y + sourceSize.Height > (s32)renderTargetSize.Height) { sourceSize.Height -= (targetPos.Y + sourceSize.Height) - renderTargetSize.Height; if (sourceSize.Height <= 0) @@ -1389,7 +1409,7 @@ void COpenGLDriver::draw2DImage(const video::ITexture* texture, // texcoords need to be flipped horizontally for RTTs const bool isRTT = texture->isRenderTarget(); - const core::dimension2d& ss = texture->getOriginalSize(); + const core::dimension2d& ss = texture->getOriginalSize(); const f32 invW = 1.f / static_cast(ss.Width); const f32 invH = 1.f / static_cast(ss.Height); const core::rect tcoords( @@ -1398,7 +1418,7 @@ void COpenGLDriver::draw2DImage(const video::ITexture* texture, (sourcePos.X + sourceSize.Width) * invW, (isRTT?sourcePos.Y:(sourcePos.Y + sourceSize.Height)) * invH); - const core::rect poss(targetPos, sourceSize); + const core::rect poss(targetPos, core::dimension2di(sourceSize)); disableTextures(1); if (!setTexture(0, texture)) @@ -1434,7 +1454,7 @@ void COpenGLDriver::draw2DImage(const video::ITexture* texture, const core::rect // texcoords need to be flipped horizontally for RTTs const bool isRTT = texture->isRenderTarget(); - const core::dimension2d& ss = texture->getOriginalSize(); + const core::dimension2d& ss = texture->getOriginalSize(); const f32 invW = 1.f / static_cast(ss.Width); const f32 invH = 1.f / static_cast(ss.Height); const core::rect tcoords( @@ -1465,7 +1485,7 @@ void COpenGLDriver::draw2DImage(const video::ITexture* texture, const core::rect return; glEnable(GL_SCISSOR_TEST); - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y, clipRect->getWidth(), clipRect->getHeight()); } @@ -1522,12 +1542,12 @@ void COpenGLDriver::draw2DImage(const video::ITexture* texture, return; glEnable(GL_SCISSOR_TEST); - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); glScissor(clipRect->UpperLeftCorner.X, renderTargetSize.Height-clipRect->LowerRightCorner.Y, clipRect->getWidth(),clipRect->getHeight()); } - const core::dimension2d& ss = texture->getOriginalSize(); + const core::dimension2d& ss = texture->getOriginalSize(); core::position2d targetPos(pos); // texcoords need to be flipped horizontally for RTTs const bool isRTT = texture->isRenderTarget(); @@ -1650,8 +1670,8 @@ void COpenGLDriver::draw2DLine(const core::position2d& start, //! Draws a pixel void COpenGLDriver::drawPixel(u32 x, u32 y, const SColor &color) { - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); - if(x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height) + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + if (x > (u32)renderTargetSize.Width || y > (u32)renderTargetSize.Height) return; disableTextures(); @@ -1661,7 +1681,7 @@ void COpenGLDriver::drawPixel(u32 x, u32 y, const SColor &color) glColor4ub(color.getRed(), color.getGreen(), color.getBlue(), color.getAlpha()); glVertex2i(x, y); glEnd(); -} +} bool COpenGLDriver::setTexture(u32 stage, const video::ITexture* texture) { @@ -1757,7 +1777,7 @@ void COpenGLDriver::setMaterial(const SMaterial& material) for (s32 i = MaxTextureUnits-1; i>= 0; --i) { - setTransform ((E_TRANSFORMATION_STATE) ( ETS_TEXTURE_0 + i ), + setTransform ((E_TRANSFORMATION_STATE) (ETS_TEXTURE_0 + i), material.getTextureMatrix(i)); } } @@ -1768,7 +1788,7 @@ bool COpenGLDriver::testGLError() { #ifdef _DEBUG GLenum g = glGetError(); - switch(g) + switch (g) { case GL_NO_ERROR: return false; @@ -1821,7 +1841,7 @@ void COpenGLDriver::setRenderStates3DMode() ResetRenderStates = true; } - if ( ResetRenderStates || LastMaterial != Material) + if (ResetRenderStates || LastMaterial != Material) { // unset old material @@ -1993,22 +2013,35 @@ void COpenGLDriver::setBasicRenderStates(const SMaterial& material, const SMater else if (i>0) break; - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, +#ifdef EXT_texture_lod_bias + 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); + } +#endif + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); if (material.getTexture(i) && material.getTexture(i)->hasMipMaps()) - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, material.TextureLayer[i].TrilinearFilter ? GL_LINEAR_MIPMAP_LINEAR : material.TextureLayer[i].BilinearFilter ? GL_LINEAR_MIPMAP_NEAREST : - GL_NEAREST_MIPMAP_NEAREST ); + GL_NEAREST_MIPMAP_NEAREST); else - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (material.TextureLayer[i].BilinearFilter || material.TextureLayer[i].TrilinearFilter) ? GL_LINEAR : GL_NEAREST); #ifdef GL_EXT_texture_filter_anisotropic - if (AnisotropyExtension) - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, - material.TextureLayer[i].AnisotropicFilter ? MaxAnisotropy : 1.0f ); + if (FeatureAvailable[IRR_EXT_texture_filter_anisotropic]) + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, + material.TextureLayer[i].AnisotropicFilter>1 ? core::min_(MaxAnisotropy, material.TextureLayer[i].AnisotropicFilter) : 1); #endif } @@ -2039,16 +2072,36 @@ void COpenGLDriver::setBasicRenderStates(const SMaterial& material, const SMater { switch (material.ZBuffer) { - case 0: + case ECFN_NEVER: glDisable(GL_DEPTH_TEST); break; - case 1: + case ECFN_LESSEQUAL: glEnable(GL_DEPTH_TEST); - glDepthFunc ( GL_LEQUAL ); + glDepthFunc(GL_LEQUAL); break; - case 2: + case ECFN_EQUAL: glEnable(GL_DEPTH_TEST); - glDepthFunc ( GL_EQUAL ); + glDepthFunc(GL_EQUAL); + break; + case ECFN_LESS: + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + break; + case ECFN_NOTEQUAL: + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_NOTEQUAL); + break; + case ECFN_GREATEREQUAL: + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_GEQUAL); + break; + case ECFN_GREATER: + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_GREATER); + break; + case ECFN_ALWAYS: + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_ALWAYS); break; } } @@ -2106,6 +2159,16 @@ void COpenGLDriver::setBasicRenderStates(const SMaterial& material, const SMater glDisable(GL_NORMALIZE); } + // Color Mask + if (resetAllRenderStates || lastmaterial.ColorMask != material.ColorMask) + { + glColorMask( + (material.ColorMask & ECP_RED)?GL_TRUE:GL_FALSE, + (material.ColorMask & ECP_GREEN)?GL_TRUE:GL_FALSE, + (material.ColorMask & ECP_BLUE)?GL_TRUE:GL_FALSE, + (material.ColorMask & ECP_ALPHA)?GL_TRUE:GL_FALSE); + } + // thickness if (resetAllRenderStates || lastmaterial.Thickness != material.Thickness) { @@ -2113,6 +2176,41 @@ void COpenGLDriver::setBasicRenderStates(const SMaterial& material, const SMater glLineWidth(material.Thickness); } + // Anti aliasing + if (resetAllRenderStates || lastmaterial.AntiAliasing != material.AntiAliasing) + { + if (FeatureAvailable[IRR_ARB_multisample]) + { + if (material.AntiAliasing & EAAM_ALPHA_TO_COVERAGE) + glEnable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); + else if (lastmaterial.AntiAliasing & EAAM_ALPHA_TO_COVERAGE) + glDisable(GL_SAMPLE_ALPHA_TO_COVERAGE_ARB); + + if ((AntiAlias >= 2) && (material.AntiAliasing & (EAAM_SIMPLE|EAAM_QUALITY))) + { + glEnable(GL_MULTISAMPLE_ARB); +#ifdef GL_NV_multisample_filter_hint + if (FeatureAvailable[IRR_NV_multisample_filter_hint]) + glHint(GL_MULTISAMPLE_FILTER_HINT_NV, (material.AntiAliasing & EAAM_QUALITY)?GL_NICEST:GL_FASTEST); +#endif + } + else + glDisable(GL_MULTISAMPLE_ARB); + } + if (AntiAlias >= 2) + { + if (material.AntiAliasing & EAAM_LINE_SMOOTH) + glEnable(GL_LINE_SMOOTH); + else if (lastmaterial.AntiAliasing & EAAM_LINE_SMOOTH) + glDisable(GL_LINE_SMOOTH); + if (material.AntiAliasing & EAAM_POINT_SMOOTH) + // often in software, and thus very slow + glEnable(GL_POINT_SMOOTH); + else if (lastmaterial.AntiAliasing & EAAM_POINT_SMOOTH) + glDisable(GL_POINT_SMOOTH); + } + } + setWrapMode(material); // be sure to leave in texture stage 0 @@ -2132,7 +2230,7 @@ void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaCh if (static_cast(LastMaterial.MaterialType) < MaterialRenderers.size()) MaterialRenderers[LastMaterial.MaterialType].Renderer->OnUnsetMaterial(); SMaterial mat; - mat.ZBuffer=0; + mat.ZBuffer=ECFN_NEVER; mat.Lighting=false; mat.TextureLayer[0].BilinearFilter=false; setBasicRenderStates(mat, mat, true); @@ -2142,9 +2240,9 @@ void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaCh glMatrixMode(GL_PROJECTION); - const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); + const core::dimension2d& renderTargetSize = getCurrentRenderTargetSize(); core::matrix4 m; - m.buildProjectionMatrixOrthoLH(f32(renderTargetSize.Width), f32(-renderTargetSize.Height), -1.0, 1.0); + m.buildProjectionMatrixOrthoLH(f32(renderTargetSize.Width), f32(-(s32)(renderTargetSize.Height)), -1.0, 1.0); m.setTranslation(core::vector3df(-1,1,0)); glLoadMatrixf(m.pointer()); @@ -2172,8 +2270,8 @@ void COpenGLDriver::setRenderStates2DMode(bool alpha, bool texture, bool alphaCh if (texture) { - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); @@ -2229,28 +2327,50 @@ const wchar_t* COpenGLDriver::getName() const //! deletes all dynamic lights there are void COpenGLDriver::deleteAllDynamicLights() { - for (s32 i=0; i= (s32)RequestedLights.size()) + return; + + RequestedLight & requestedLight = RequestedLights[lightIndex]; + + requestedLight.DesireToBeOn = turnOn; + + if(turnOn) + { + if(-1 == requestedLight.HardwareLightIndex) + assignHardwareLight(lightIndex); + } + else + { + if(-1 != requestedLight.HardwareLightIndex) + { + // It's currently assigned, so free up the hardware light + glDisable(requestedLight.HardwareLightIndex); + requestedLight.HardwareLightIndex = -1; + + // Now let the first light that's waiting on a free hardware light grab it + for(u32 requested = 0; requested < RequestedLights.size(); ++requested) + if(RequestedLights[requested].DesireToBeOn + && + -1 == RequestedLights[requested].HardwareLightIndex) + { + assignHardwareLight(requested); + break; + } + } + } +} + + //! returns the maximal amount of dynamic lights the device can handle u32 COpenGLDriver::getMaximalDynamicLightAmount() const { @@ -2385,7 +2544,7 @@ void COpenGLDriver::drawStencilShadowVolume(const core::vector3df* triangles, s3 glDisable(GL_FOG); glDepthFunc(GL_LEQUAL); glDepthMask(GL_FALSE); // no depth buffer writing - glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE ); // no color buffer drawing + glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); // no color buffer drawing glEnable(GL_STENCIL_TEST); glEnable(GL_POLYGON_OFFSET_FILL); glPolygonOffset(0.0f, 1.0f); @@ -2523,19 +2682,19 @@ void COpenGLDriver::drawStencilShadow(bool clearStencilBuffer, video::SColor lef disableTextures(); // store attributes - glPushAttrib( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT ); + glPushAttrib(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_ENABLE_BIT | GL_POLYGON_BIT | GL_STENCIL_BUFFER_BIT); - glDisable( GL_LIGHTING ); + glDisable(GL_LIGHTING); glDisable(GL_FOG); glDepthMask(GL_FALSE); - glShadeModel( GL_FLAT ); - glColorMask( GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE ); + glShadeModel(GL_FLAT); + glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable( GL_STENCIL_TEST ); + glEnable(GL_STENCIL_TEST); glStencilFunc(GL_NOTEQUAL, 0, ~0); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); @@ -2546,22 +2705,21 @@ void COpenGLDriver::drawStencilShadow(bool clearStencilBuffer, video::SColor lef glBegin(GL_QUADS); - glColor4ub (leftDownEdge.getRed(), leftDownEdge.getGreen(), leftDownEdge.getBlue(), leftDownEdge.getAlpha() ); + glColor4ub(leftDownEdge.getRed(), leftDownEdge.getGreen(), leftDownEdge.getBlue(), leftDownEdge.getAlpha()); glVertex3f(-1.1f,-1.1f,0.9f); - glColor4ub (leftUpEdge.getRed(), leftUpEdge.getGreen(), leftUpEdge.getBlue(), leftUpEdge.getAlpha() ); + glColor4ub(leftUpEdge.getRed(), leftUpEdge.getGreen(), leftUpEdge.getBlue(), leftUpEdge.getAlpha()); glVertex3f(-1.1f, 1.1f,0.9f); - glColor4ub (rightUpEdge.getRed(), rightUpEdge.getGreen(), rightUpEdge.getBlue(), rightUpEdge.getAlpha() ); - glVertex3f( 1.1f, 1.1f,0.9f); + glColor4ub(rightUpEdge.getRed(), rightUpEdge.getGreen(), rightUpEdge.getBlue(), rightUpEdge.getAlpha()); + glVertex3f(1.1f, 1.1f,0.9f); - glColor4ub (rightDownEdge.getRed(), rightDownEdge.getGreen(), rightDownEdge.getBlue(), rightDownEdge.getAlpha() ); - glVertex3f( 1.1f,-1.1f,0.9f); + glColor4ub(rightDownEdge.getRed(), rightDownEdge.getGreen(), rightDownEdge.getBlue(), rightDownEdge.getAlpha()); + glVertex3f(1.1f,-1.1f,0.9f); glEnd(); - if (clearStencilBuffer) - glClear(GL_STENCIL_BUFFER_BIT); + clearBuffers(false, false, clearStencilBuffer, 0x0); // restore settings glPopMatrix(); @@ -2581,7 +2739,7 @@ void COpenGLDriver::setFog(SColor c, bool linearFog, f32 start, glFogi(GL_FOG_COORDINATE_SOURCE, GL_FRAGMENT_DEPTH); #endif - if(linearFog) + if (linearFog) { glFogf(GL_FOG_START, start); glFogf(GL_FOG_END, end); @@ -2619,7 +2777,7 @@ void COpenGLDriver::draw3DLine(const core::vector3df& start, //! Only used by the internal engine. Used to notify the driver that //! the window was resized. -void COpenGLDriver::OnResize(const core::dimension2d& size) +void COpenGLDriver::OnResize(const core::dimension2d& size) { CNullDriver::OnResize(size); glViewport(0, 0, size.Width, size.Height); @@ -2729,7 +2887,7 @@ IGPUProgrammingServices* COpenGLDriver::getGPUProgrammingServices() } -ITexture* COpenGLDriver::addRenderTargetTexture(const core::dimension2d& size, const c8* name) +ITexture* COpenGLDriver::addRenderTargetTexture(const core::dimension2d& size, const c8* name) { //disable mip-mapping bool generateMipLevels = getTextureCreationFlag(ETCF_CREATE_MIP_MAPS); @@ -2745,14 +2903,20 @@ ITexture* COpenGLDriver::addRenderTargetTexture(const core::dimension2d& si rtt = new COpenGLFBOTexture(size, name, this); if (rtt) { + bool success = false; addTexture(rtt); ITexture* tex = createDepthTexture(rtt); if (tex) { - static_cast(tex)->attach(rtt); + success = static_cast(tex)->attach(rtt); tex->drop(); } rtt->drop(); + if (!success) + { + removeTexture(rtt); + rtt=0; + } } } else @@ -2760,7 +2924,7 @@ ITexture* COpenGLDriver::addRenderTargetTexture(const core::dimension2d& si { // the simple texture is only possible for size <= screensize // we try to find an optimal size with the original constraints - core::dimension2di destSize(core::min_(size.Width,ScreenSize.Width), core::min_(size.Height,ScreenSize.Height)); + core::dimension2du destSize(core::min_(size.Width,ScreenSize.Width), core::min_(size.Height,ScreenSize.Height)); destSize = destSize.getOptimalSize((size==size.getOptimalSize()), false, false); rtt = addTexture(destSize, name, ECF_A8R8G8B8); if (rtt) @@ -2785,6 +2949,53 @@ u32 COpenGLDriver::getMaximalPrimitiveCount() const } +//! set or reset render target +bool COpenGLDriver::setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget, + bool clearZBuffer, SColor color) +{ + if (target != CurrentTarget) + setRenderTarget(0, false, false, 0x0); + + if (ERT_RENDER_TEXTURE == target) + { + os::Printer::log("Fatal Error: For render textures call setRenderTarget with the actual texture as first parameter.", ELL_ERROR); + return false; + } + + if (Stereo && (ERT_STEREO_RIGHT_BUFFER == target)) + { + if (Doublebuffer) + glDrawBuffer(GL_BACK_RIGHT); + else + glDrawBuffer(GL_FRONT_RIGHT); + } + else if (Stereo && ERT_STEREO_BOTH_BUFFERS == target) + { + if (Doublebuffer) + glDrawBuffer(GL_BACK); + else + glDrawBuffer(GL_FRONT); + } + else if ((target >= ERT_AUX_BUFFER0) && (target-ERT_AUX_BUFFER0 < MaxAuxBuffers)) + { + glDrawBuffer(GL_AUX0+target-ERT_AUX_BUFFER0); + } + else + { + if (Doublebuffer) + glDrawBuffer(GL_BACK_LEFT); + else + glDrawBuffer(GL_FRONT_LEFT); + // exit with false, but also with working color buffer + if (target != ERT_FRAME_BUFFER) + return false; + } + CurrentTarget=target; + clearBuffers(clearTarget, clearZBuffer, false, color); + return true; +} + + //! set or reset render target bool COpenGLDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuffer, bool clearZBuffer, SColor color) @@ -2813,40 +3024,25 @@ bool COpenGLDriver::setRenderTarget(video::ITexture* texture, bool clearBackBuff RenderTargetTexture = static_cast(texture); RenderTargetTexture->bindRTT(); CurrentRendertargetSize = texture->getSize(); + CurrentTarget=ERT_RENDER_TEXTURE; } else { glViewport(0,0,ScreenSize.Width,ScreenSize.Height); RenderTargetTexture = 0; - CurrentRendertargetSize = core::dimension2d(0,0); + CurrentRendertargetSize = core::dimension2d(0,0); + CurrentTarget=ERT_FRAME_BUFFER; } - GLbitfield mask = 0; - if (clearBackBuffer) - { - const f32 inv = 1.0f / 255.0f; - glClearColor(color.getRed() * inv, color.getGreen() * inv, - color.getBlue() * inv, color.getAlpha() * inv); - - mask |= GL_COLOR_BUFFER_BIT; - } - if (clearZBuffer) - { - glDepthMask(GL_TRUE); - LastMaterial.ZWriteEnable=true; - mask |= GL_DEPTH_BUFFER_BIT; - } - - glClear(mask); - + clearBuffers(clearBackBuffer, clearZBuffer, false, color); return true; } // returns the current size of the screen or rendertarget -const core::dimension2d& COpenGLDriver::getCurrentRenderTargetSize() const +const core::dimension2d& COpenGLDriver::getCurrentRenderTargetSize() const { - if ( CurrentRendertargetSize.Width == 0 ) + if (CurrentRendertargetSize.Width == 0) return ScreenSize; else return CurrentRendertargetSize; @@ -2856,13 +3052,7 @@ const core::dimension2d& COpenGLDriver::getCurrentRenderTargetSize() const //! Clears the ZBuffer. void COpenGLDriver::clearZBuffer() { - GLboolean enabled = GL_TRUE; - glGetBooleanv(GL_DEPTH_WRITEMASK, &enabled); - - glDepthMask(GL_TRUE); - glClear(GL_DEPTH_BUFFER_BIT); - - glDepthMask(enabled); + clearBuffers(false, true, false, 0x0); } @@ -2899,7 +3089,7 @@ IImage* COpenGLDriver::createScreenShot() const s32 pitch=newImage->getPitch(); u8* p2 = pixels + (ScreenSize.Height - 1) * pitch; u8* tmpBuffer = new u8[pitch]; - for (s32 i=0; i < ScreenSize.Height; i += 2) + for (u32 i=0; i < ScreenSize.Height; i += 2) { memcpy(tmpBuffer, pixels, pitch); memcpy(pixels, p2, pitch); diff --git a/source/Irrlicht/COpenGLDriver.h b/source/Irrlicht/COpenGLDriver.h index 3682a300..8358a644 100644 --- a/source/Irrlicht/COpenGLDriver.h +++ b/source/Irrlicht/COpenGLDriver.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in Irrlicht.h @@ -116,12 +116,8 @@ namespace video GLuint vbo_verticesSize; //tmp GLuint vbo_indicesSize; //tmp - }; - bool updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer); - bool updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer); - //! updates hardware buffer if needed virtual bool updateHardwareBuffer(SHWBufferLink *HWBuffer); @@ -213,8 +209,15 @@ namespace video //! deletes all dynamic lights there are virtual void deleteAllDynamicLights(); - //! adds a dynamic light - virtual void addDynamicLight(const SLight& light); + //! adds a dynamic light, returning an index to the light + //! \param light: the light data to use to create the light + //! \return An index to the light, or -1 if an error occurs + virtual s32 addDynamicLight(const SLight& light); + + //! Turns a dynamic light on or off + //! \param lightIndex: the index returned by addDynamicLight + //! \param turnOn: true to turn the light on, false to turn it off + virtual void turnLightOn(s32 lightIndex, bool turnOn); //! returns the maximal amount of dynamic lights the device can handle virtual u32 getMaximalDynamicLightAmount() const; @@ -247,7 +250,7 @@ namespace video //! Only used by the internal engine. Used to notify the driver that //! the window was resized. - virtual void OnResize(const core::dimension2d& size); + virtual void OnResize(const core::dimension2d& size); //! Returns type of video driver virtual E_DRIVER_TYPE getDriverType() const; @@ -306,9 +309,14 @@ namespace video //! call. virtual u32 getMaximalPrimitiveCount() const; - virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, const c8* name); + //! set or reset render target + virtual bool setRenderTarget(video::E_RENDER_TARGET target, bool clearTarget, + bool clearZBuffer, SColor color); + + //! set or reset render target texture virtual bool setRenderTarget(video::ITexture* texture, bool clearBackBuffer, bool clearZBuffer, SColor color); @@ -343,10 +351,16 @@ namespace video private: + //! clears the zbuffer and color buffer + void clearBuffers(bool backBuffer, bool zBuffer, bool stencilBuffer, SColor color); + + bool updateVertexHardwareBuffer(SHWBufferLink_opengl *HWBuffer); + bool updateIndexHardwareBuffer(SHWBufferLink_opengl *HWBuffer); + void uploadClipPlane(u32 index); //! inits the parts of the open gl driver used on all platforms - bool genericDriverInit(const core::dimension2d& screenSize, bool stencilBuffer); + bool genericDriverInit(const core::dimension2d& screenSize, bool stencilBuffer); //! returns a device dependent texture from a software surface (IImage) virtual video::ITexture* createDeviceDependentTexture(IImage* surface, const char* name); @@ -364,10 +378,14 @@ namespace video void setRenderStates2DMode(bool alpha, bool texture, bool alphaChannel); // returns the current size of the screen or rendertarget - virtual const core::dimension2d& getCurrentRenderTargetSize() const; + virtual const core::dimension2d& getCurrentRenderTargetSize() const; void createMaterialRenderers(); + //! Assign a hardware light to the specified requested light, if any + //! free hardware lights exist. + //! \param[in] lightIndex: the index of the requesting light + void assignHardwareLight(u32 lightIndex); core::stringw Name; core::matrix4 Matrices[ETS_COUNT]; @@ -385,7 +403,7 @@ namespace video //! bool to make all renderstates reset if set to true. bool ResetRenderStates; bool Transformation3DChanged; - bool AntiAlias; + u8 AntiAlias; SMaterial Material, LastMaterial; COpenGLTexture* RenderTargetTexture; @@ -395,7 +413,7 @@ namespace video core::array UserClipPlane; core::array UserClipPlaneEnabled; - core::dimension2d CurrentRendertargetSize; + core::dimension2d CurrentRendertargetSize; core::stringc vendorName; @@ -404,6 +422,25 @@ namespace video //! Color buffer format ECOLOR_FORMAT ColorFormat; + //! Render target type for render operations + E_RENDER_TARGET CurrentTarget; + + bool Doublebuffer; + bool Stereo; + + //! All the lights that have been requested; a hardware limited + //! number of them will be used at once. + struct RequestedLight + { + RequestedLight(SLight const & lightData) + : LightData(lightData), HardwareLightIndex(-1), DesireToBeOn(true) { } + + SLight LightData; + s32 HardwareLightIndex; // GL_LIGHT0 - GL_LIGHT7 + bool DesireToBeOn; + }; + core::array RequestedLights; + #ifdef _IRR_WINDOWS_API_ HDC HDc; // Private GDI Device Context HWND Window; diff --git a/source/Irrlicht/COpenGLExtensionHandler.cpp b/source/Irrlicht/COpenGLExtensionHandler.cpp index 82afe254..5df9a045 100644 --- a/source/Irrlicht/COpenGLExtensionHandler.cpp +++ b/source/Irrlicht/COpenGLExtensionHandler.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -17,12 +17,11 @@ namespace video { COpenGLExtensionHandler::COpenGLExtensionHandler() : - StencilBuffer(false), - MultiTextureExtension(false), MultiSamplingExtension(false), AnisotropyExtension(false), + StencilBuffer(false), MultiTextureExtension(false), TextureCompressionExtension(false), - MaxTextureUnits(1), MaxLights(1), MaxIndices(65535), - MaxAnisotropy(1.0f), MaxUserClipPlanes(0), - Version(0), ShaderLanguageVersion(0) + MaxTextureUnits(1), MaxLights(1), MaxAnisotropy(1), MaxUserClipPlanes(0), + MaxAuxBuffers(0), MaxIndices(65535), MaxTextureSize(1), + MaxTextureLODBias(0.f), Version(0), ShaderLanguageVersion(0) #ifdef _IRR_OPENGL_USE_EXTPOINTER_ ,pGlActiveTextureARB(0), pGlClientActiveTextureARB(0), pGlGenProgramsARB(0), pGlBindProgramARB(0), pGlProgramStringARB(0), @@ -66,7 +65,7 @@ void COpenGLExtensionHandler::dump() const void COpenGLExtensionHandler::initExtensions(bool stencilBuffer) { const f32 ogl_ver = core::fast_atof(reinterpret_cast(glGetString(GL_VERSION))); - Version = core::floor32(ogl_ver)*100+core::ceil32(core::fract(ogl_ver)*10.0f); + Version = static_cast(core::floor32(ogl_ver)*100+core::round32(core::fract(ogl_ver)*10.0f)); if ( Version >= 102) os::Printer::log("OpenGL driver version is 1.2 or better.", ELL_INFORMATION); else @@ -102,8 +101,6 @@ void COpenGLExtensionHandler::initExtensions(bool stencilBuffer) } MultiTextureExtension = FeatureAvailable[IRR_ARB_multitexture]; - MultiSamplingExtension = FeatureAvailable[IRR_ARB_multisample]; - AnisotropyExtension = FeatureAvailable[IRR_EXT_texture_filter_anisotropic]; TextureCompressionExtension = FeatureAvailable[IRR_ARB_texture_compression]; StencilBuffer=stencilBuffer; @@ -389,25 +386,39 @@ void COpenGLExtensionHandler::initExtensions(bool stencilBuffer) #endif // _IRR_OPENGL_USE_EXTPOINTER_ #endif // _IRR_WINDOWS_API_ + GLint num; // set some properties #if defined(GL_ARB_multitexture) || defined(GL_VERSION_1_3) if (Version>102 || FeatureAvailable[IRR_ARB_multitexture]) { - GLint num; glGetIntegerv(GL_MAX_TEXTURE_UNITS, &num); - MaxTextureUnits=num; + MaxTextureUnits=static_cast(num); } #endif - glGetIntegerv(GL_MAX_LIGHTS, &MaxLights); + glGetIntegerv(GL_MAX_LIGHTS, &num); + MaxLights=static_cast(num); #ifdef GL_EXT_texture_filter_anisotropic if (FeatureAvailable[IRR_EXT_texture_filter_anisotropic]) - glGetFloatv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &MaxAnisotropy); + glGetIntegerv(GL_MAX_TEXTURE_MAX_ANISOTROPY_EXT, &num); + MaxAnisotropy=static_cast(num); #endif #ifdef GL_VERSION_1_2 if (Version>101) - glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &MaxIndices); + { + glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &num); + MaxIndices=num; + } #endif - glGetIntegerv(GL_MAX_CLIP_PLANES, reinterpret_cast(&MaxUserClipPlanes)); + glGetIntegerv(GL_MAX_TEXTURE_SIZE, &num); + MaxTextureSize=static_cast(num); +#ifdef EXT_texture_lod_bias + if (FeatureAvailable[IRR_EXT_texture_lod_bias]) + glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS_EXT, &MaxTextureLODBias); +#endif + glGetIntegerv(GL_MAX_CLIP_PLANES, &num); + MaxUserClipPlanes=static_cast(num); + glGetIntegerv(GL_AUX_BUFFERS, &num); + MaxAuxBuffers=static_cast(num); #if defined(GL_ARB_shading_language_100) || defined (GL_VERSION_2_0) if (FeatureAvailable[IRR_ARB_shading_language_100] || Version>=200) { @@ -422,7 +433,7 @@ void COpenGLExtensionHandler::initExtensions(bool stencilBuffer) else { const f32 sl_ver = core::fast_atof(reinterpret_cast(shaderVersion)); - ShaderLanguageVersion = core::floor32(sl_ver)*100+core::ceil32(core::fract(sl_ver)*10.0f); + ShaderLanguageVersion = static_cast(core::floor32(sl_ver)*100+core::round32(core::fract(sl_ver)*10.0f)); } } #endif @@ -440,7 +451,7 @@ void COpenGLExtensionHandler::initExtensions(bool stencilBuffer) MultiTextureExtension = false; os::Printer::log("Warning: OpenGL device only has one texture unit. Disabling multitexturing.", ELL_WARNING); } - MaxTextureUnits = core::min_(MaxTextureUnits,MATERIAL_MAX_TEXTURES); + MaxTextureUnits = core::min_(MaxTextureUnits,static_cast(MATERIAL_MAX_TEXTURES)); } @@ -478,6 +489,10 @@ bool COpenGLExtensionHandler::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const return FeatureAvailable[IRR_EXT_framebuffer_object]; case EVDF_VERTEX_BUFFER_OBJECT: return FeatureAvailable[IRR_ARB_vertex_buffer_object]; + case EVDF_COLOR_MASK: + return true; + case EVDF_ALPHA_TO_COVERAGE: + return FeatureAvailable[IRR_ARB_multisample]; default: return false; }; @@ -488,5 +503,3 @@ bool COpenGLExtensionHandler::queryFeature(E_VIDEO_DRIVER_FEATURE feature) const } #endif - - diff --git a/source/Irrlicht/COpenGLExtensionHandler.h b/source/Irrlicht/COpenGLExtensionHandler.h index ade7b3ab..28ae5467 100644 --- a/source/Irrlicht/COpenGLExtensionHandler.h +++ b/source/Irrlicht/COpenGLExtensionHandler.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in Irrlicht.h @@ -218,6 +218,7 @@ static const char* const OpenGLFeatureStrings[] = { "GL_EXT_texture_perturb_normal", "GL_EXT_texture_shared_exponent", "GL_EXT_texture_sRGB", + "GL_EXT_texture_swizzle", "GL_EXT_timer_query", "GL_EXT_transform_feedback", "GL_EXT_vertex_array", @@ -253,6 +254,7 @@ static const char* const OpenGLFeatureStrings[] = { "GL_NV_depth_buffer_float", "GL_NV_depth_clamp", "GL_NV_evaluators", + "GL_NV_explicit_multisample", "GL_NV_fence", "GL_NV_float_buffer", "GL_NV_fog_distance", @@ -286,6 +288,7 @@ static const char* const OpenGLFeatureStrings[] = { "GL_NV_texture_shader2", "GL_NV_texture_shader3", "GL_NV_transform_feedback", + "GL_NV_transform_feedback2", "GL_NV_vertex_array_range", "GL_NV_vertex_array_range2", "GL_NV_vertex_program", @@ -530,6 +533,7 @@ class COpenGLExtensionHandler IRR_EXT_texture_perturb_normal, IRR_EXT_texture_shared_exponent, IRR_EXT_texture_sRGB, + IRR_EXT_texture_swizzle, IRR_EXT_timer_query, IRR_EXT_transform_feedback, IRR_EXT_vertex_array, @@ -565,6 +569,7 @@ class COpenGLExtensionHandler IRR_NV_depth_buffer_float, IRR_NV_depth_clamp, IRR_NV_evaluators, + IRR_NV_explicit_multisample, IRR_NV_fence, IRR_NV_float_buffer, IRR_NV_fog_distance, @@ -598,6 +603,7 @@ class COpenGLExtensionHandler IRR_NV_texture_shader2, IRR_NV_texture_shader3, IRR_NV_transform_feedback, + IRR_NV_transform_feedback2, IRR_NV_vertex_array_range, IRR_NV_vertex_array_range2, IRR_NV_vertex_program, @@ -708,26 +714,30 @@ class COpenGLExtensionHandler // Some variables for properties bool StencilBuffer; bool MultiTextureExtension; - bool MultiSamplingExtension; - bool AnisotropyExtension; bool TextureCompressionExtension; // Some non-boolean properties //! Maxmimum texture layers supported by the fixed pipeline - u32 MaxTextureUnits; + u8 MaxTextureUnits; //! Maximum hardware lights supported - GLint MaxLights; - //! Optimal number of indices per meshbuffer - GLint MaxIndices; + u8 MaxLights; //! Maximal Anisotropy - f32 MaxAnisotropy; + u8 MaxAnisotropy; //! Number of user clipplanes - u32 MaxUserClipPlanes; + u8 MaxUserClipPlanes; + //! Number of auxiliary buffers + u8 MaxAuxBuffers; + //! Optimal number of indices per meshbuffer + u32 MaxIndices; + //! Maximal texture dimension + u32 MaxTextureSize; + //! Maximal LOD Bias + f32 MaxTextureLODBias; //! OpenGL version as Integer: 100*Major+Minor, i.e. 2.1 becomes 201 - u32 Version; + u16 Version; //! GLSL version as Integer: 100*Major+Minor - u32 ShaderLanguageVersion; + u16 ShaderLanguageVersion; // public access to the (loaded) extensions. // general functions diff --git a/source/Irrlicht/COpenGLMaterialRenderer.h b/source/Irrlicht/COpenGLMaterialRenderer.h index 83dde8a8..788f7f38 100644 --- a/source/Irrlicht/COpenGLMaterialRenderer.h +++ b/source/Irrlicht/COpenGLMaterialRenderer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COpenGLNormalMapRenderer.cpp b/source/Irrlicht/COpenGLNormalMapRenderer.cpp index d9017121..2f7606bf 100644 --- a/source/Irrlicht/COpenGLNormalMapRenderer.cpp +++ b/source/Irrlicht/COpenGLNormalMapRenderer.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COpenGLNormalMapRenderer.h b/source/Irrlicht/COpenGLNormalMapRenderer.h index 9f7d7559..4b50954b 100644 --- a/source/Irrlicht/COpenGLNormalMapRenderer.h +++ b/source/Irrlicht/COpenGLNormalMapRenderer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COpenGLParallaxMapRenderer.cpp b/source/Irrlicht/COpenGLParallaxMapRenderer.cpp index dde494e6..04243a02 100644 --- a/source/Irrlicht/COpenGLParallaxMapRenderer.cpp +++ b/source/Irrlicht/COpenGLParallaxMapRenderer.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COpenGLParallaxMapRenderer.h b/source/Irrlicht/COpenGLParallaxMapRenderer.h index 0fc0f1da..a97c3ab8 100644 --- a/source/Irrlicht/COpenGLParallaxMapRenderer.h +++ b/source/Irrlicht/COpenGLParallaxMapRenderer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COpenGLSLMaterialRenderer.cpp b/source/Irrlicht/COpenGLSLMaterialRenderer.cpp index e4b5bad0..0a7825bb 100644 --- a/source/Irrlicht/COpenGLSLMaterialRenderer.cpp +++ b/source/Irrlicht/COpenGLSLMaterialRenderer.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COpenGLSLMaterialRenderer.h b/source/Irrlicht/COpenGLSLMaterialRenderer.h index ef7f58ac..af1709e6 100644 --- a/source/Irrlicht/COpenGLSLMaterialRenderer.h +++ b/source/Irrlicht/COpenGLSLMaterialRenderer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COpenGLShaderMaterialRenderer.cpp b/source/Irrlicht/COpenGLShaderMaterialRenderer.cpp index 4dac60ee..2583312b 100644 --- a/source/Irrlicht/COpenGLShaderMaterialRenderer.cpp +++ b/source/Irrlicht/COpenGLShaderMaterialRenderer.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COpenGLShaderMaterialRenderer.h b/source/Irrlicht/COpenGLShaderMaterialRenderer.h index c433de92..2fd2a46a 100644 --- a/source/Irrlicht/COpenGLShaderMaterialRenderer.h +++ b/source/Irrlicht/COpenGLShaderMaterialRenderer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/COpenGLTexture.cpp b/source/Irrlicht/COpenGLTexture.cpp index 6130d8a1..01bc1860 100644 --- a/source/Irrlicht/COpenGLTexture.cpp +++ b/source/Irrlicht/COpenGLTexture.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -135,6 +135,17 @@ void COpenGLTexture::getImageData(IImage* image) return; } + const f32 ratio = (f32)ImageSize.Width/(f32)ImageSize.Height; + if ((ImageSize.Width>Driver->MaxTextureSize) && (ratio >= 1.0f)) + { + ImageSize.Width = Driver->MaxTextureSize; + ImageSize.Height = (u32)(Driver->MaxTextureSize/ratio); + } + else if (ImageSize.Height>Driver->MaxTextureSize) + { + ImageSize.Height = Driver->MaxTextureSize; + ImageSize.Width = (u32)(Driver->MaxTextureSize*ratio); + } TextureSize=ImageSize.getOptimalSize(!Driver->queryFeature(EVDF_TEXTURE_NPOT)); ColorFormat = getBestColorFormat(image->getColorFormat()); @@ -178,20 +189,28 @@ void COpenGLTexture::copyTexture(bool newTexture) break; } - glBindTexture(GL_TEXTURE_2D, TextureName); + Driver->setTexture(0, this); if (Driver->testGLError()) os::Printer::log("Could not bind Texture", ELL_ERROR); if (newTexture) { - #ifndef DISABLE_MIPMAPPING +#ifndef DISABLE_MIPMAPPING +#ifdef GL_SGIS_generate_mipmap if (HasMipMaps && Driver->queryFeature(EVDF_MIP_MAP_AUTO_UPDATE)) { + if (Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_SPEED)) + glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_FASTEST); + else if (Driver->getTextureCreationFlag(ETCF_OPTIMIZED_FOR_QUALITY)) + glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_NICEST); + else + glHint(GL_GENERATE_MIPMAP_HINT_SGIS, GL_DONT_CARE); // automatically generate and update mipmaps glTexParameteri( GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE ); AutomaticMipmapUpdate=true; } else +#endif { AutomaticMipmapUpdate=false; regenerateMipMapLevels(); @@ -269,7 +288,7 @@ void* COpenGLTexture::lock(bool readOnly) const s32 pitch=Image->getPitch(); u8* p2 = pPixels + (ImageSize.Height - 1) * pitch; u8* tmpBuffer = new u8[pitch]; - for (s32 i=0; i < ImageSize.Height; i += 2) + for (u32 i=0; i < ImageSize.Height; i += 2) { memcpy(tmpBuffer, pPixels, pitch); memcpy(pPixels, p2, pitch); @@ -306,14 +325,14 @@ void COpenGLTexture::unlock() //! Returns size of the original image. -const core::dimension2d& COpenGLTexture::getOriginalSize() const +const core::dimension2d& COpenGLTexture::getOriginalSize() const { return ImageSize; } //! Returns size of the texture. -const core::dimension2d& COpenGLTexture::getSize() const +const core::dimension2d& COpenGLTexture::getSize() const { return TextureSize; } @@ -416,7 +435,7 @@ void COpenGLTexture::bindRTT() //! Unbind Render Target Texture void COpenGLTexture::unbindRTT() { - glBindTexture(GL_TEXTURE_2D, getOpenGLTextureName()); + Driver->setTexture(0, this); // Copy Our ViewPort To The Texture glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, getSize().Width, getSize().Height); @@ -425,14 +444,11 @@ void COpenGLTexture::unbindRTT() /* FBO Textures */ -#ifdef GL_EXT_framebuffer_object // helper function for render to texture static bool checkFBOStatus(COpenGLDriver* Driver); -#endif - //! RTT ColorFrameBuffer constructor -COpenGLFBOTexture::COpenGLFBOTexture(const core::dimension2d& size, +COpenGLFBOTexture::COpenGLFBOTexture(const core::dimension2d& size, const char* name, COpenGLDriver* driver) : COpenGLTexture(name, driver), DepthTexture(0), ColorFrameBuffer(0) @@ -456,7 +472,7 @@ COpenGLFBOTexture::COpenGLFBOTexture(const core::dimension2d& size, // generate color texture glGenTextures(1, &TextureName); - glBindTexture(GL_TEXTURE_2D, TextureName); + Driver->setTexture(0, this); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -515,7 +531,7 @@ void COpenGLFBOTexture::unbindRTT() //! RTT DepthBuffer constructor COpenGLFBODepthTexture::COpenGLFBODepthTexture( - const core::dimension2d& size, + const core::dimension2d& size, const char* name, COpenGLDriver* driver, bool useStencil) @@ -597,10 +613,10 @@ COpenGLFBODepthTexture::~COpenGLFBODepthTexture() //combine depth texture and rtt -void COpenGLFBODepthTexture::attach(ITexture* renderTex) +bool COpenGLFBODepthTexture::attach(ITexture* renderTex) { if (!renderTex) - return; + return false; video::COpenGLFBOTexture* rtt = static_cast(renderTex); rtt->bindRTT(); #ifdef GL_EXT_framebuffer_object @@ -628,13 +644,17 @@ void COpenGLFBODepthTexture::attach(ITexture* renderTex) GL_RENDERBUFFER_EXT, DepthRenderBuffer); } +#endif // check the status if (!checkFBOStatus(Driver)) + { os::Printer::log("FBO incomplete"); -#endif + return false; + } rtt->DepthTexture=this; grab(); // grab the depth buffer, not the RTT rtt->unbindRTT(); + return true; } @@ -650,9 +670,9 @@ void COpenGLFBODepthTexture::unbindRTT() } -#ifdef GL_EXT_framebuffer_object bool checkFBOStatus(COpenGLDriver* Driver) { +#ifdef GL_EXT_framebuffer_object GLenum status = Driver->extGlCheckFramebufferStatus(GL_FRAMEBUFFER_EXT); switch (status) @@ -699,13 +719,14 @@ bool checkFBOStatus(COpenGLDriver* Driver) default: break; } +#endif os::Printer::log("FBO error", ELL_ERROR); return false; } -#endif } // end namespace video } // end namespace irr #endif // _IRR_COMPILE_WITH_OPENGL_ + diff --git a/source/Irrlicht/COpenGLTexture.h b/source/Irrlicht/COpenGLTexture.h index 6989395f..73dc0bee 100644 --- a/source/Irrlicht/COpenGLTexture.h +++ b/source/Irrlicht/COpenGLTexture.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -60,10 +60,10 @@ public: virtual void unlock(); //! Returns original size of the texture (image). - virtual const core::dimension2d& getOriginalSize() const; + virtual const core::dimension2d& getOriginalSize() const; //! Returns size of the texture. - virtual const core::dimension2d& getSize() const; + virtual const core::dimension2d& getSize() const; //! returns driver type of texture (=the driver, that created it) virtual E_DRIVER_TYPE getDriverType() const; @@ -114,8 +114,8 @@ protected: //! \param: newTexture is true if method is called from a newly created texture for the first time. Otherwise call with false to improve memory handling. void copyTexture(bool newTexture=true); - core::dimension2d ImageSize; - core::dimension2d TextureSize; + core::dimension2d ImageSize; + core::dimension2d TextureSize; ECOLOR_FORMAT ColorFormat; s32 Pitch; COpenGLDriver* Driver; @@ -139,7 +139,7 @@ class COpenGLFBOTexture : public COpenGLTexture public: //! FrameBufferObject constructor - COpenGLFBOTexture(const core::dimension2d& size, const char* name, COpenGLDriver* driver=0); + COpenGLFBOTexture(const core::dimension2d& size, const char* name, COpenGLDriver* driver=0); //! destructor virtual ~COpenGLFBOTexture(); @@ -164,7 +164,7 @@ class COpenGLFBODepthTexture : public COpenGLFBOTexture { public: //! FrameBufferObject depth constructor - COpenGLFBODepthTexture(const core::dimension2d& size, const char* name, COpenGLDriver* driver=0, bool useStencil=false); + COpenGLFBODepthTexture(const core::dimension2d& size, const char* name, COpenGLDriver* driver=0, bool useStencil=false); //! destructor virtual ~COpenGLFBODepthTexture(); @@ -175,7 +175,7 @@ public: //! Unbind RenderTargetTexture virtual void unbindRTT(); - void attach(ITexture*); + bool attach(ITexture*); protected: GLuint DepthRenderBuffer; diff --git a/source/Irrlicht/CPakReader.cpp b/source/Irrlicht/CPakReader.cpp index 0315f69b..9daca52c 100644 --- a/source/Irrlicht/CPakReader.cpp +++ b/source/Irrlicht/CPakReader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // Code contributed by skreamz diff --git a/source/Irrlicht/CPakReader.h b/source/Irrlicht/CPakReader.h index 5ed6b24c..82d75e0d 100644 --- a/source/Irrlicht/CPakReader.h +++ b/source/Irrlicht/CPakReader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.cpp b/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.cpp index c8a56f5f..6ecead67 100644 --- a/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.cpp +++ b/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.h b/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.h index ccf60494..d6bf9233 100644 --- a/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.h +++ b/source/Irrlicht/CParticleAnimatedMeshSceneNodeEmitter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleAttractionAffector.cpp b/source/Irrlicht/CParticleAttractionAffector.cpp index 15c376e5..872c9457 100644 --- a/source/Irrlicht/CParticleAttractionAffector.cpp +++ b/source/Irrlicht/CParticleAttractionAffector.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleAttractionAffector.h b/source/Irrlicht/CParticleAttractionAffector.h index 4cc3e22c..0c5eddac 100644 --- a/source/Irrlicht/CParticleAttractionAffector.h +++ b/source/Irrlicht/CParticleAttractionAffector.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleBoxEmitter.cpp b/source/Irrlicht/CParticleBoxEmitter.cpp index fd72b8f0..86b8f17f 100644 --- a/source/Irrlicht/CParticleBoxEmitter.cpp +++ b/source/Irrlicht/CParticleBoxEmitter.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleBoxEmitter.h b/source/Irrlicht/CParticleBoxEmitter.h index 4ea1ee25..052ee49c 100644 --- a/source/Irrlicht/CParticleBoxEmitter.h +++ b/source/Irrlicht/CParticleBoxEmitter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleCylinderEmitter.cpp b/source/Irrlicht/CParticleCylinderEmitter.cpp index c0287e62..095f447e 100644 --- a/source/Irrlicht/CParticleCylinderEmitter.cpp +++ b/source/Irrlicht/CParticleCylinderEmitter.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleCylinderEmitter.h b/source/Irrlicht/CParticleCylinderEmitter.h index 1907066f..709aa567 100644 --- a/source/Irrlicht/CParticleCylinderEmitter.h +++ b/source/Irrlicht/CParticleCylinderEmitter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleFadeOutAffector.cpp b/source/Irrlicht/CParticleFadeOutAffector.cpp index 0df27baf..87c3897e 100644 --- a/source/Irrlicht/CParticleFadeOutAffector.cpp +++ b/source/Irrlicht/CParticleFadeOutAffector.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleFadeOutAffector.h b/source/Irrlicht/CParticleFadeOutAffector.h index 71cfc7aa..9db8af46 100644 --- a/source/Irrlicht/CParticleFadeOutAffector.h +++ b/source/Irrlicht/CParticleFadeOutAffector.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleGravityAffector.cpp b/source/Irrlicht/CParticleGravityAffector.cpp index f6ce52c8..295677c8 100644 --- a/source/Irrlicht/CParticleGravityAffector.cpp +++ b/source/Irrlicht/CParticleGravityAffector.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleGravityAffector.h b/source/Irrlicht/CParticleGravityAffector.h index df082b69..1ab67a00 100644 --- a/source/Irrlicht/CParticleGravityAffector.h +++ b/source/Irrlicht/CParticleGravityAffector.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleMeshEmitter.cpp b/source/Irrlicht/CParticleMeshEmitter.cpp index d18288c1..2f673550 100644 --- a/source/Irrlicht/CParticleMeshEmitter.cpp +++ b/source/Irrlicht/CParticleMeshEmitter.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleMeshEmitter.h b/source/Irrlicht/CParticleMeshEmitter.h index 9a8d7b89..3cbb4f35 100644 --- a/source/Irrlicht/CParticleMeshEmitter.h +++ b/source/Irrlicht/CParticleMeshEmitter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticlePointEmitter.cpp b/source/Irrlicht/CParticlePointEmitter.cpp index 8ea92360..889076b7 100644 --- a/source/Irrlicht/CParticlePointEmitter.cpp +++ b/source/Irrlicht/CParticlePointEmitter.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticlePointEmitter.h b/source/Irrlicht/CParticlePointEmitter.h index bc3ebc45..ae436ae2 100644 --- a/source/Irrlicht/CParticlePointEmitter.h +++ b/source/Irrlicht/CParticlePointEmitter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleRingEmitter.cpp b/source/Irrlicht/CParticleRingEmitter.cpp index 91ea47b3..e424f94a 100644 --- a/source/Irrlicht/CParticleRingEmitter.cpp +++ b/source/Irrlicht/CParticleRingEmitter.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleRingEmitter.h b/source/Irrlicht/CParticleRingEmitter.h index 5b40e257..21451e94 100644 --- a/source/Irrlicht/CParticleRingEmitter.h +++ b/source/Irrlicht/CParticleRingEmitter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleRotationAffector.cpp b/source/Irrlicht/CParticleRotationAffector.cpp index 4f9210b7..90a15949 100644 --- a/source/Irrlicht/CParticleRotationAffector.cpp +++ b/source/Irrlicht/CParticleRotationAffector.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleRotationAffector.h b/source/Irrlicht/CParticleRotationAffector.h index 3ced8369..68fc81ad 100644 --- a/source/Irrlicht/CParticleRotationAffector.h +++ b/source/Irrlicht/CParticleRotationAffector.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleSphereEmitter.cpp b/source/Irrlicht/CParticleSphereEmitter.cpp index fc4cee2f..5fefe7df 100644 --- a/source/Irrlicht/CParticleSphereEmitter.cpp +++ b/source/Irrlicht/CParticleSphereEmitter.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleSphereEmitter.h b/source/Irrlicht/CParticleSphereEmitter.h index 3858bcc0..7618d0bf 100644 --- a/source/Irrlicht/CParticleSphereEmitter.h +++ b/source/Irrlicht/CParticleSphereEmitter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleSystemSceneNode.cpp b/source/Irrlicht/CParticleSystemSceneNode.cpp index dc27d214..984c8a3c 100644 --- a/source/Irrlicht/CParticleSystemSceneNode.cpp +++ b/source/Irrlicht/CParticleSystemSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CParticleSystemSceneNode.h b/source/Irrlicht/CParticleSystemSceneNode.h index 85f8c115..915cf95e 100644 --- a/source/Irrlicht/CParticleSystemSceneNode.h +++ b/source/Irrlicht/CParticleSystemSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CQ3LevelMesh.cpp b/source/Irrlicht/CQ3LevelMesh.cpp index cf28c766..85ce38f1 100644 --- a/source/Irrlicht/CQ3LevelMesh.cpp +++ b/source/Irrlicht/CQ3LevelMesh.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -615,7 +615,7 @@ s32 CQ3LevelMesh::setShaderMaterial( video::SMaterial &material, const tBSPFace material.setTexture(1, 0); material.setTexture(2, 0); material.setTexture(3, 0); - material.ZBuffer = true; + material.ZBuffer = video::ECFN_LESSEQUAL; material.ZWriteEnable = true; material.MaterialTypeParam = 0.f; @@ -1650,7 +1650,7 @@ void CQ3LevelMesh::loadTextures() lig[0] = 0; c8 lightmapname[255]; - core::dimension2d lmapsize(128,128); + core::dimension2d lmapsize(128,128); //bool oldMipMapState = Driver->getTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS); //Driver->setTextureCreationFlag(video::ETCF_CREATE_MIP_MAPS, false); @@ -1775,7 +1775,7 @@ void CQ3LevelMesh::loadTextures2() Lightmap.set_used(NumLightMaps+1); c8 lightmapname[255]; - core::dimension2d lmapsize(128,128); + core::dimension2d lmapsize(128,128); video::IImage* lmapImg; for ( t = 0; t < NumLightMaps ; ++t) diff --git a/source/Irrlicht/CQ3LevelMesh.h b/source/Irrlicht/CQ3LevelMesh.h index 864ce723..ca08ba37 100644 --- a/source/Irrlicht/CQ3LevelMesh.h +++ b/source/Irrlicht/CQ3LevelMesh.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CQuake3ShaderSceneNode.cpp b/source/Irrlicht/CQuake3ShaderSceneNode.cpp index 4527c855..9f8e3538 100644 --- a/source/Irrlicht/CQuake3ShaderSceneNode.cpp +++ b/source/Irrlicht/CQuake3ShaderSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CQuake3ShaderSceneNode.h b/source/Irrlicht/CQuake3ShaderSceneNode.h index 34082c4a..7ffc7b6d 100644 --- a/source/Irrlicht/CQuake3ShaderSceneNode.h +++ b/source/Irrlicht/CQuake3ShaderSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CReadFile.cpp b/source/Irrlicht/CReadFile.cpp index 7fe733f9..a8550f3e 100644 --- a/source/Irrlicht/CReadFile.cpp +++ b/source/Irrlicht/CReadFile.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CReadFile.h b/source/Irrlicht/CReadFile.h index b09da7b5..497c58c1 100644 --- a/source/Irrlicht/CReadFile.h +++ b/source/Irrlicht/CReadFile.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CSTLMeshFileLoader.cpp b/source/Irrlicht/CSTLMeshFileLoader.cpp index 3f4a496b..8779dbb5 100644 --- a/source/Irrlicht/CSTLMeshFileLoader.cpp +++ b/source/Irrlicht/CSTLMeshFileLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2008 Christian Stehno +// Copyright (C) 2007-2009 Christian Stehno // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CSTLMeshFileLoader.h b/source/Irrlicht/CSTLMeshFileLoader.h index 41e86d31..3210f294 100644 --- a/source/Irrlicht/CSTLMeshFileLoader.h +++ b/source/Irrlicht/CSTLMeshFileLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2007-2008 Christian Stehno +// Copyright (C) 2007-2009 Christian Stehno // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CSTLMeshWriter.cpp b/source/Irrlicht/CSTLMeshWriter.cpp index ca87c6a9..647aa6aa 100644 --- a/source/Irrlicht/CSTLMeshWriter.cpp +++ b/source/Irrlicht/CSTLMeshWriter.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CSTLMeshWriter.h b/source/Irrlicht/CSTLMeshWriter.h index 13802456..017d0eb3 100644 --- a/source/Irrlicht/CSTLMeshWriter.h +++ b/source/Irrlicht/CSTLMeshWriter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CSceneCollisionManager.cpp b/source/Irrlicht/CSceneCollisionManager.cpp index b4636ef7..063c2d2d 100644 --- a/source/Irrlicht/CSceneCollisionManager.cpp +++ b/source/Irrlicht/CSceneCollisionManager.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -43,7 +43,7 @@ CSceneCollisionManager::~CSceneCollisionManager() //! Returns the scene node, which is currently visible under the overgiven //! screencoordinates, viewed from the currently active camera. ISceneNode* CSceneCollisionManager::getSceneNodeFromScreenCoordinatesBB( - core::position2d pos, s32 idBitMask, bool bNoDebugObjects) + const core::position2d & pos, s32 idBitMask, bool bNoDebugObjects) { core::line3d ln = getRayFromScreenCoordinates(pos, 0); @@ -57,14 +57,16 @@ ISceneNode* CSceneCollisionManager::getSceneNodeFromScreenCoordinatesBB( //! Returns the nearest scene node which collides with a 3d ray and //! which id matches a bitmask. -ISceneNode* CSceneCollisionManager::getSceneNodeFromRayBB(core::line3d ray, +ISceneNode* CSceneCollisionManager::getSceneNodeFromRayBB(const core::line3d & ray, s32 idBitMask, bool bNoDebugObjects) { ISceneNode* best = 0; f32 dist = FLT_MAX; - getPickedNodeBB(SceneManager->getRootSceneNode(), ray, + core::line3d truncatableRay(ray); + + getPickedNodeBB(SceneManager->getRootSceneNode(), truncatableRay, idBitMask, bNoDebugObjects, dist, best); return best; @@ -73,61 +75,143 @@ ISceneNode* CSceneCollisionManager::getSceneNodeFromRayBB(core::line3d ray, //! recursive method for going through all scene nodes void CSceneCollisionManager::getPickedNodeBB(ISceneNode* root, - const core::line3df& ray, + core::line3df& ray, s32 bits, bool bNoDebugObjects, f32& outbestdistance, ISceneNode*& outbestnode) { - core::vector3df edges[8]; - const core::list& children = root->getChildren(); + const core::vector3df rayVector = ray.getVector().normalize(); core::list::ConstIterator it = children.begin(); for (; it != children.end(); ++it) { ISceneNode* current = *it; - if (current->isVisible() && - (bNoDebugObjects ? !current->isDebugObject() : true) && - (bits==0 || (bits != 0 && (current->getID() & bits)))) - { - // get world to object space transform - core::matrix4 mat; - if (!current->getAbsoluteTransformation().getInverse(mat)) - continue; + if (current->isVisible()) + { + if((bNoDebugObjects ? !current->isDebugObject() : true) && + (bits==0 || (bits != 0 && (current->getID() & bits)))) + { + // get world to object space transform + core::matrix4 worldToObject; + if (!current->getAbsoluteTransformation().getInverse(worldToObject)) + continue; - // transform vector from world space to object space - core::line3df line(ray); - mat.transformVect(line.start); - mat.transformVect(line.end); + // transform vector from world space to object space + core::line3df objectRay(ray); + worldToObject.transformVect(objectRay.start); + worldToObject.transformVect(objectRay.end); - const core::aabbox3df& box = current->getBoundingBox(); + const core::aabbox3df & objectBox = current->getBoundingBox(); - // do intersection test in object space - if (box.intersectsWithLine(line)) - { - box.getEdges(edges); - f32 distance = 0.0f; + // Do the initial intersection test in object space, since the + // object space box test is more accurate. + if(objectBox.isPointInside(objectRay.start)) + { + // If the line starts inside the box, then consider the distance as being + // to the centre of the box. + const f32 toIntersectionSq = objectRay.start.getDistanceFromSQ(objectBox.getCenter()); + if(toIntersectionSq < outbestdistance) + { + outbestdistance = toIntersectionSq; + outbestnode = current; - for (s32 e=0; e<8; ++e) - { - f32 t = edges[e].getDistanceFromSQ(line.start); - if (t > distance) - distance = t; - } + // And we can truncate the ray to stop us hitting further nodes. + ray.end = ray.start + (rayVector * sqrtf(toIntersectionSq)); + } + } + else if (objectBox.intersectsWithLine(objectRay)) + { + // Now transform into world space, since we need to use world space + // scales and distances. + core::aabbox3df worldBox(objectBox); + current->getAbsoluteTransformation().transformBox(worldBox); - if (distance < outbestdistance) - { - outbestnode = current; - outbestdistance = distance; - } - } - } + core::vector3df edges[8]; + worldBox.getEdges(edges); - getPickedNodeBB(current, ray, bits, bNoDebugObjects, outbestdistance, outbestnode); + /* We need to check against each of 6 faces, composed of these corners: + /3--------/7 + / | / | + / | / | + 1---------5 | + | 2- - -| -6 + | / | / + |/ | / + 0---------4/ + + Note that we define them as opposite pairs of faces. + */ + static const s32 faceEdges[6][3] = + { + { 0, 1, 5 }, // Front + { 6, 7, 3 }, // Back + { 2, 3, 1 }, // Left + { 4, 5, 7 }, // Right + { 1, 3, 7 }, // Top + { 2, 0, 4 } // Bottom + }; + + core::vector3df intersection; + core::plane3df facePlane; + + bool gotHit = false; + for(s32 face = 0; face < 6 && !gotHit; ++face) + { + facePlane.setPlane(edges[faceEdges[face][0]], + edges[faceEdges[face][1]], + edges[faceEdges[face][2]]); + + // Only consider lines that might be entering through this face, since we + // already know that the start point is outside the box. + if(facePlane.classifyPointRelation(ray.start) != core::ISREL3D_FRONT) + continue; + + // Don't bother using a limited ray, since we already know that it should be long + // enough to intersect with the box. + if(facePlane.getIntersectionWithLine(ray.start, rayVector, intersection)) + { + const f32 toIntersectionSq = ray.start.getDistanceFromSQ(intersection); + if(toIntersectionSq < outbestdistance) + { + // We have to check that the intersection with this plane is actually + // on the box, so need to go back to object space again. We also + // need to move the intersection very slightly closer to the centre of + // the box to take into account fp precision losses, since the intersection + // will axiomatically be on the very edge of the box. + worldToObject.transformVect(intersection); + intersection *= 0.99f; + + if(objectBox.isPointInside(intersection)) + { + outbestdistance = toIntersectionSq; + outbestnode = current; + + // We can only hit one face, so stop checking now. + gotHit = true; + } + } + } + + // If the ray could be entering through the first face of a pair, then it can't + // also be entering through the opposite face, and so we can skip that face. + if(0 == (face % 2)) + ++face; + } + + // If we got a hit, we can now truncate the ray to stop us hitting further nodes. + if(gotHit) + ray.end = ray.start + (rayVector * sqrtf(outbestdistance)); + } + } + + // Only check the children if this node is visible. + getPickedNodeBB(current, ray, bits, bNoDebugObjects, outbestdistance, outbestnode); + } } -} +} @@ -153,7 +237,8 @@ ISceneNode* CSceneCollisionManager::getSceneNodeFromCameraBB( //! 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) + core::triangle3df& outTriangle, + const ISceneNode*& outNode) { if (!selector) { @@ -197,11 +282,6 @@ bool CSceneCollisionManager::getCollisionPoint(const core::line3d& ray, if(maxZ < triangle.pointA.Z && maxZ < triangle.pointB.Z && maxZ < triangle.pointC.Z) continue; - if(ray.start.getDistanceFromSQ(triangle.pointA) >= nearest && - ray.start.getDistanceFromSQ(triangle.pointB) >= nearest && - ray.start.getDistanceFromSQ(triangle.pointC) >= nearest) - continue; - if (triangle.getIntersectionWithLine(ray.start, linevect, intersection)) { const f32 tmp = intersection.getDistanceFromSQ(ray.start); @@ -212,6 +292,7 @@ bool CSceneCollisionManager::getCollisionPoint(const core::line3d& ray, nearest = tmp; outTriangle = triangle; outIntersection = intersection; + outNode = selector->getSceneNodeForTriangle(i); found = true; } } @@ -232,6 +313,7 @@ core::vector3df CSceneCollisionManager::getCollisionResultPosition( core::triangle3df& triout, core::vector3df& hitPosition, bool& outFalling, + const ISceneNode*& outNode, f32 slidingSpeed, const core::vector3df& gravity) { @@ -239,18 +321,18 @@ core::vector3df CSceneCollisionManager::getCollisionResultPosition( return position; return collideEllipsoidWithWorld(selector, position, - radius, direction, slidingSpeed, gravity, triout, hitPosition, outFalling); + radius, direction, slidingSpeed, gravity, triout, hitPosition, outFalling, outNode); } -void CSceneCollisionManager::testTriangleIntersection(SCollisionData* colData, +bool CSceneCollisionManager::testTriangleIntersection(SCollisionData* colData, const core::triangle3df& triangle) { const core::plane3d trianglePlane = triangle.getPlane(); // only check front facing polygons if ( !trianglePlane.isFrontFacing(colData->normalizedVelocity) ) - return; + return false; // get interval of plane intersection @@ -269,7 +351,7 @@ void CSceneCollisionManager::testTriangleIntersection(SCollisionData* colData, // sphere is traveling parallel to plane if (fabs(signedDistToTrianglePlane) >= 1.0f) - return; // no collision possible + return false; // no collision possible else { // sphere is embedded in plane @@ -291,7 +373,7 @@ void CSceneCollisionManager::testTriangleIntersection(SCollisionData* colData, // check if at least one value is within the range if (t0 > 1.0f || t1 < 0.0f) - return; // both t values are outside 1 and 0, no collision possible + return false; // both t values are outside 1 and 0, no collision possible // clamp to 0 and 1 t0 = core::clamp ( t0, 0.f, 1.f ); @@ -484,9 +566,11 @@ void CSceneCollisionManager::testTriangleIntersection(SCollisionData* colData, colData->foundCollision = true; colData->intersectionTriangle = triangle; ++colData->triangleHits; + return true; } - }// end found collision + + return false; } @@ -498,9 +582,10 @@ core::vector3df CSceneCollisionManager::collideEllipsoidWithWorld( const core::vector3df& radius, const core::vector3df& velocity, f32 slidingSpeed, const core::vector3df& gravity, - core::triangle3df& triout, + core::triangle3df& triout, core::vector3df& hitPosition, - bool& outFalling) + bool& outFalling, + const ISceneNode*& outNode) { if (!selector || radius.X == 0.0f || radius.Y == 0.0f || radius.Z == 0.0f) return position; @@ -516,6 +601,7 @@ core::vector3df CSceneCollisionManager::collideEllipsoidWithWorld( colData.selector = selector; colData.slidingSpeed = slidingSpeed; colData.triangleHits = 0; + colData.triangleIndex = -1; core::vector3df eSpacePosition = colData.R3Position / colData.eRadius; core::vector3df eSpaceVelocity = colData.R3Velocity / colData.eRadius; @@ -549,6 +635,7 @@ core::vector3df CSceneCollisionManager::collideEllipsoidWithWorld( triout.pointA *= colData.eRadius; triout.pointB *= colData.eRadius; triout.pointC *= colData.eRadius; + outNode = selector->getSceneNodeForTriangle(colData.triangleIndex); } finalPos *= colData.eRadius; @@ -584,17 +671,17 @@ core::vector3df CSceneCollisionManager::collideWithWorld(s32 recursionDepth, core::matrix4 scaleMatrix; scaleMatrix.setScale( - core::vector3df(1.0f / colData.eRadius.X, + core::vector3df(1.0f / colData.eRadius.X, 1.0f / colData.eRadius.Y, 1.0f / colData.eRadius.Z) ); s32 triangleCnt = 0; colData.selector->getTriangles(Triangles.pointer(), totalTriangleCnt, triangleCnt, box, &scaleMatrix); - //colData.selector->getTriangles(Triangles.pointer(), totalTriangleCnt, triangleCnt, &scaleMatrix); for (s32 i=0; i CSceneCollisionManager::getRayFromScreenCoordinates( - core::position2d pos, ICameraSceneNode* camera) + const core::position2d & pos, ICameraSceneNode* camera) { core::line3d ln(0,0,0,0,0,0); @@ -664,7 +751,7 @@ core::line3d CSceneCollisionManager::getRayFromScreenCoordinates( core::vector3df uptodown = f->getFarLeftDown() - farLeftUp; const core::rect& viewPort = Driver->getViewPort(); - core::dimension2d screenSize(viewPort.getWidth(), viewPort.getHeight()); + core::dimension2d screenSize(viewPort.getWidth(), viewPort.getHeight()); f32 dx = pos.X / (f32)screenSize.Width; f32 dy = pos.Y / (f32)screenSize.Height; @@ -682,7 +769,7 @@ core::line3d CSceneCollisionManager::getRayFromScreenCoordinates( //! Calculates 2d screen position from a 3d position. core::position2d CSceneCollisionManager::getScreenCoordinatesFrom3DPosition( - core::vector3df pos3d, ICameraSceneNode* camera) + const core::vector3df & pos3d, ICameraSceneNode* camera) { if (!SceneManager || !Driver) return core::position2d(-1000,-1000); @@ -694,7 +781,7 @@ core::position2d CSceneCollisionManager::getScreenCoordinatesFrom3DPosition return core::position2d(-1000,-1000); const core::rect& viewPort = Driver->getViewPort(); - core::dimension2d dim(viewPort.getWidth(), viewPort.getHeight()); + core::dimension2d dim(viewPort.getWidth(), viewPort.getHeight()); dim.Width /= 2; dim.Height /= 2; diff --git a/source/Irrlicht/CSceneCollisionManager.h b/source/Irrlicht/CSceneCollisionManager.h index b4dc9c59..6c3f8d6b 100644 --- a/source/Irrlicht/CSceneCollisionManager.h +++ b/source/Irrlicht/CSceneCollisionManager.h @@ -1,7 +1,7 @@ #ifndef __C_SCENE_COLLISION_MANAGER_H_INCLUDED__ #define __C_SCENE_COLLISION_MANAGER_H_INCLUDED__ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -27,12 +27,13 @@ namespace scene //! Returns the scene node, which is currently visible under the overgiven //! screencoordinates, viewed from the currently active camera. - virtual ISceneNode* getSceneNodeFromScreenCoordinatesBB(core::position2d pos, + virtual ISceneNode* getSceneNodeFromScreenCoordinatesBB(const core::position2d & pos, s32 idBitMask=0, bool bNoDebugObjects = false); //! Returns the nearest scene node which collides with a 3d ray and //! which id matches a bitmask. - virtual ISceneNode* getSceneNodeFromRayBB(core::line3d ray, s32 idBitMask=0, + virtual ISceneNode* getSceneNodeFromRayBB(const core::line3d & ray, + s32 idBitMask=0, bool bNoDebugObjects = false); //! Returns the scene node, at which the overgiven camera is looking at and @@ -43,33 +44,36 @@ namespace scene //! Finds the collision point of a line and lots of triangles, if there is one. virtual bool getCollisionPoint(const core::line3d& ray, ITriangleSelector* selector, core::vector3df& outCollisionPoint, - core::triangle3df& outTriangle); + core::triangle3df& outTriangle, + const ISceneNode* & outNode); //! Collides a moving ellipsoid with a 3d world with gravity and returns //! the resulting new position of the ellipsoid. virtual core::vector3df getCollisionResultPosition( ITriangleSelector* selector, - const core::vector3df &ellipsoidPosition, const core::vector3df& ellipsoidRadius, + const core::vector3df &ellipsoidPosition, + const core::vector3df& ellipsoidRadius, const core::vector3df& ellipsoidDirectionAndSpeed, core::triangle3df& triout, core::vector3df& hitPosition, bool& outFalling, + const ISceneNode*& outNode, f32 slidingSpeed, const core::vector3df& gravityDirectionAndSpeed); //! Returns a 3d ray which would go through the 2d screen coodinates. virtual core::line3d getRayFromScreenCoordinates( - core::position2d pos, ICameraSceneNode* camera = 0); + const core::position2d & pos, ICameraSceneNode* camera = 0); //! Calculates 2d screen position from a 3d position. virtual core::position2d getScreenCoordinatesFrom3DPosition( - core::vector3df pos, ICameraSceneNode* camera=0); + const core::vector3df & pos, ICameraSceneNode* camera=0); private: //! recursive method for going through all scene nodes void getPickedNodeBB(ISceneNode* root, - const core::line3df& ray, + core::line3df& ray, s32 bits, bool bNoDebugObjects, f32& outbestdistance, @@ -91,6 +95,7 @@ namespace scene core::vector3df intersectionPoint; core::triangle3df intersectionTriangle; + s32 triangleIndex; s32 triangleHits; f32 slidingSpeed; @@ -98,7 +103,12 @@ namespace scene ITriangleSelector* selector; }; - void testTriangleIntersection(SCollisionData* colData, + //! Tests the current collision data against an individual triangle. + /** + \param colData: the collision data. + \param triangle: the triangle to test against. + \return true if the triangle is hit (and is the closest hit), false otherwise */ + bool testTriangleIntersection(SCollisionData* colData, const core::triangle3df& triangle); //! recursive method for doing collision response @@ -108,7 +118,8 @@ namespace scene f32 slidingSpeed, const core::vector3df& gravity, core::triangle3df& triout, core::vector3df& hitPosition, - bool& outFalling); + bool& outFalling, + const ISceneNode*& outNode); core::vector3df collideWithWorld(s32 recursionDepth, SCollisionData &colData, core::vector3df pos, core::vector3df vel); diff --git a/source/Irrlicht/CSceneManager.cpp b/source/Irrlicht/CSceneManager.cpp index 596ed8c1..50483e75 100644 --- a/source/Irrlicht/CSceneManager.cpp +++ b/source/Irrlicht/CSceneManager.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -14,6 +14,7 @@ #include "IGUIEnvironment.h" #include "IMaterialRenderer.h" #include "IReadFile.h" +#include "ILightManager.h" #include "os.h" @@ -162,7 +163,7 @@ CSceneManager::CSceneManager(video::IVideoDriver* driver, io::IFileSystem* fs, : ISceneNode(0, 0), Driver(driver), FileSystem(fs), GUIEnvironment(gui), CursorControl(cursorControl), CollisionManager(0), ActiveCamera(0), ShadowColor(150,0,0,0), AmbientLight(0,0,0,0), - MeshCache(cache), CurrentRendertime(ESNRP_COUNT), + MeshCache(cache), CurrentRendertime(ESNRP_COUNT), LightManager(0), IRR_XML_FORMAT_SCENE(L"irr_scene"), IRR_XML_FORMAT_NODE(L"node"), IRR_XML_FORMAT_NODE_ATTR_TYPE(L"type") { #ifdef _DEBUG @@ -298,6 +299,9 @@ CSceneManager::~CSceneManager() for (i=0; idrop(); + if(LightManager) + LightManager->drop(); + // remove all nodes and animators before dropping the driver // as render targets may be destroyed twice removeAll(); @@ -644,7 +648,7 @@ ICameraSceneNode* CSceneManager::addCameraSceneNodeMaya(ISceneNode* parent, parent = this; ICameraSceneNode* node = new CCameraSceneNode(parent, this, id); - ISceneNodeAnimator* anm = new CSceneNodeAnimatorCameraMaya(CursorControl, + ISceneNodeAnimator* anm = new CSceneNodeAnimatorCameraMaya(CursorControl, rotateSpeed, zoomSpeed, translationSpeed); node->addAnimator(anm); @@ -661,7 +665,7 @@ ICameraSceneNode* CSceneManager::addCameraSceneNodeMaya(ISceneNode* parent, //! like in most first person shooters (FPS): ICameraSceneNode* CSceneManager::addCameraSceneNodeFPS(ISceneNode* parent, f32 rotateSpeed, f32 moveSpeed, s32 id, - SKeyMap* keyMapArray, s32 keyMapSize, bool noVerticalMovement,f32 jumpSpeed) + SKeyMap* keyMapArray, s32 keyMapSize, bool noVerticalMovement, f32 jumpSpeed, bool invertMouseY) { if (!parent) parent = this; @@ -669,7 +673,7 @@ ICameraSceneNode* CSceneManager::addCameraSceneNodeFPS(ISceneNode* parent, ICameraSceneNode* node = new CCameraSceneNode(parent, this, id); ISceneNodeAnimator* anm = new CSceneNodeAnimatorCameraFPS(CursorControl, rotateSpeed, moveSpeed, jumpSpeed, - keyMapArray, keyMapSize, noVerticalMovement); + keyMapArray, keyMapSize, noVerticalMovement, invertMouseY); // Bind the node's rotation to its target. This is consistent with 1.4.2 and below. node->bindTargetAndRotation(true); @@ -915,7 +919,7 @@ IAnimatedMesh* CSceneManager::addTerrainMesh(const c8* name, video::IImage* texture, video::IImage* heightmap, const core::dimension2d& stretchSize, f32 maxHeight, - const core::dimension2d& defaultVertexBlockSize) + const core::dimension2d& defaultVertexBlockSize) { if (!name) return 0; @@ -1163,7 +1167,7 @@ u32 CSceneManager::registerNodeForRendering(ISceneNode* node, E_SCENE_NODE_RENDE // Lighting modell in irrlicht has to be redone.. //if (!isCulled(node)) { - LightList.push_back(DistanceNodeEntry(node, camWorldPos)); + LightList.push_back(static_cast(node)); taken = 1; } break; @@ -1284,69 +1288,158 @@ void CSceneManager::drawAll() // let all nodes register themselves OnRegisterSceneNode(); + if(LightManager) + LightManager->OnPreRender(LightList); + u32 i; // new ISO for scoping problem in some compilers //render camera scenes { CurrentRendertime = ESNRP_CAMERA; + + if(LightManager) + LightManager->OnRenderPassPreRender(CurrentRendertime); + for (i=0; irender(); CameraList.set_used(0); + + if(LightManager) + LightManager->OnRenderPassPostRender(CurrentRendertime); } //render lights scenes { CurrentRendertime = ESNRP_LIGHT; + if(LightManager) + { + LightManager->OnRenderPassPreRender(CurrentRendertime); + } + else + { + // Sort the lights by distance from the camera + core::vector3df camWorldPos(0, 0, 0); + if(ActiveCamera) + camWorldPos = ActiveCamera->getAbsolutePosition(); + + core::array SortedLights; + SortedLights.set_used(LightList.size()); + for(s32 light = (s32)LightList.size() - 1; light >= 0; --light) + SortedLights[light].setNodeAndDistanceFromPosition(LightList[light], camWorldPos); + + SortedLights.set_sorted(false); + SortedLights.sort(); + + for(s32 light = (s32)LightList.size() - 1; light >= 0; --light) + LightList[light] = static_cast(SortedLights[light].Node); + } + + Driver->deleteAllDynamicLights(); Driver->setAmbientLight(AmbientLight); - LightList.sort(); // on distance to camera + u32 maxLights = LightList.size(); + + if(!LightManager) + maxLights = core::min_ ( Driver->getMaximalDynamicLightAmount(), maxLights); - u32 maxLights = core::min_ ( Driver->getMaximalDynamicLightAmount(), LightList.size() ); for (i=0; i< maxLights; ++i) - LightList[i].Node->render(); + LightList[i]->render(); - LightList.set_used(0); + if(LightManager) + LightManager->OnRenderPassPostRender(CurrentRendertime); } // render skyboxes { CurrentRendertime = ESNRP_SKY_BOX; - - for (i=0; irender(); + if(LightManager) + { + LightManager->OnRenderPassPreRender(CurrentRendertime); + for (i=0; iOnNodePreRender(node); + node->render(); + LightManager->OnNodePostRender(node); + } + } + else + { + for (i=0; irender(); + } SkyBoxList.set_used(0); + + if(LightManager) + LightManager->OnRenderPassPostRender(CurrentRendertime); } // render default objects { CurrentRendertime = ESNRP_SOLID; + SolidNodeList.sort(); // sort by textures - for (i=0; irender(); + if(LightManager) + { + LightManager->OnRenderPassPreRender(CurrentRendertime); + for (i=0; iOnNodePreRender(node); + node->render(); + LightManager->OnNodePostRender(node); + } + } + else + { + for (i=0; irender(); + } Parameters.setAttribute ( "drawn", (s32) SolidNodeList.size() ); SolidNodeList.set_used(0); + + if(LightManager) + LightManager->OnRenderPassPostRender(CurrentRendertime); } // render shadows { CurrentRendertime = ESNRP_SHADOW; - for (i=0; irender(); + + if(LightManager) + { + LightManager->OnRenderPassPreRender(CurrentRendertime); + for (i=0; iOnNodePreRender(node); + node->render(); + LightManager->OnNodePostRender(node); + } + } + else + { + for (i=0; irender(); + } if (!ShadowNodeList.empty()) Driver->drawStencilShadow(true,ShadowColor, ShadowColor, ShadowColor, ShadowColor); ShadowNodeList.set_used(0); + + if(LightManager) + LightManager->OnRenderPassPostRender(CurrentRendertime); } // render transparent objects. @@ -1354,17 +1447,50 @@ void CSceneManager::drawAll() CurrentRendertime = ESNRP_TRANSPARENT; TransparentNodeList.sort(); // sort by distance from camera - for (i=0; irender(); + if(LightManager) + { + LightManager->OnRenderPassPreRender(CurrentRendertime); + + for (i=0; iOnNodePreRender(node); + node->render(); + LightManager->OnNodePostRender(node); + } + } + else + { + for (i=0; irender(); + } TransparentNodeList.set_used(0); + + if(LightManager) + LightManager->OnRenderPassPostRender(CurrentRendertime); } + if(LightManager) + LightManager->OnPostRender(); + + LightList.set_used(0); clearDeletionList(); CurrentRendertime = ESNRP_COUNT; } +void CSceneManager::setLightManager(ILightManager* lightManager) +{ + if(LightManager) + LightManager->drop(); + + LightManager = lightManager; + + if(LightManager) + LightManager->grab(); +} + //! Sets the color of stencil buffers shadows drawn by the scene manager. void CSceneManager::setShadowColor(video::SColor color) @@ -1395,10 +1521,14 @@ ISceneNodeAnimator* CSceneManager::createRotationAnimator(const core::vector3df& //! creates a fly circle animator, which lets the attached scene node fly around a center. ISceneNodeAnimator* CSceneManager::createFlyCircleAnimator( const core::vector3df& center, f32 radius, f32 speed, - const core::vector3df& direction) + const core::vector3df& direction, + f32 startPosition) { + const f32 orbitDurationMs = (core::DEGTORAD * 360.f) / speed; + u32 effectiveTime = os::Timer::getTime() + (u32)(orbitDurationMs * startPosition); + ISceneNodeAnimator* anim = new CSceneNodeAnimatorFlyCircle( - os::Timer::getTime(), center, + effectiveTime, center, radius, speed, direction); return anim; } diff --git a/source/Irrlicht/CSceneManager.h b/source/Irrlicht/CSceneManager.h index d6b90d3b..04256e54 100644 --- a/source/Irrlicht/CSceneManager.h +++ b/source/Irrlicht/CSceneManager.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -140,7 +140,7 @@ namespace scene virtual ICameraSceneNode* addCameraSceneNodeFPS(ISceneNode* parent = 0, f32 rotateSpeed = 100.0f, f32 moveSpeed = .5f, s32 id=-1, SKeyMap* keyMapArray=0, s32 keyMapSize=0, bool noVerticalMovement=false, - f32 jumpSpeed = 0.f); + f32 jumpSpeed = 0.f, bool invertMouseY=false); //! Adds a dynamic light scene node. The light will cast dynamic light on all //! other scene nodes in the scene, which have the material flag video::MTF_LIGHTING @@ -207,7 +207,7 @@ namespace scene //! Adds a terrain mesh to the mesh pool. virtual IAnimatedMesh* addTerrainMesh(const c8* meshname, video::IImage* texture, video::IImage* heightmap, const core::dimension2d& stretchSize, - f32 maxHeight, const core::dimension2d& defaultVertexBlockSize); + f32 maxHeight, const core::dimension2d& defaultVertexBlockSize); //! Add a arrow mesh to the mesh pool virtual IAnimatedMesh* addArrowMesh(const c8* name, @@ -281,13 +281,17 @@ namespace scene //! creates a fly circle animator /** Lets the attached scene node fly around a center. \param center Center relative to node origin - \param speed rotation speed - \return Animator. Attach it to a scene node with ISceneNode::addAnimator() - and the animator will animate it. */ + \param speed: The orbital speed, in radians per millisecond. + \param direction: Specifies the upvector used for alignment of the mesh. + \param startPosition: The position on the circle where the animator will + begin. Value is in multiples of a circle, i.e. 0.5 is half way around. + \return The animator. Attach it to a scene node with ISceneNode::addAnimator() + */ virtual ISceneNodeAnimator* createFlyCircleAnimator( const core::vector3df& center=core::vector3df(0.f, 0.f, 0.f), f32 radius=100.f, f32 speed=0.001f, - const core::vector3df& direction=core::vector3df(0.f, 1.f, 0.f)); + const core::vector3df& direction=core::vector3df(0.f, 1.f, 0.f), + f32 startPosition = 0.f); //! Creates a fly straight animator, which lets the attached scene node //! fly or move along a line between two points. @@ -452,6 +456,9 @@ namespace scene //! Returns ambient color of the scene virtual const video::SColorf& getAmbientLight() const; + //! Register a custom callbacks manager which gets callbacks during scene rendering. + virtual void setLightManager(ILightManager* lightManager); + private: //! Returns a typename from a scene node animator type or null if not found @@ -525,8 +532,7 @@ namespace scene DistanceNodeEntry(ISceneNode* n, const core::vector3df& cameraPos) : Node(n) { - Distance = Node->getAbsoluteTransformation().getTranslation().getDistanceFromSQ(cameraPos); - Distance -= Node->getBoundingBox().getExtent().getLengthSQ() * 0.5; + setNodeAndDistanceFromPosition(n, cameraPos); } bool operator < (const DistanceNodeEntry& other) const @@ -534,6 +540,13 @@ namespace scene return Distance < other.Distance; } + void setNodeAndDistanceFromPosition(ISceneNode* n, const core::vector3df & fromPosition) + { + Node = n; + Distance = Node->getAbsoluteTransformation().getTranslation().getDistanceFromSQ(fromPosition); + Distance -= Node->getBoundingBox().getExtent().getLengthSQ() * 0.5; + } + ISceneNode* Node; private: f64 Distance; @@ -556,7 +569,7 @@ namespace scene //! render pass lists core::array CameraList; - core::array LightList; + core::array LightList; core::array ShadowNodeList; core::array SkyBoxList; core::array SolidNodeList; @@ -582,6 +595,10 @@ namespace scene E_SCENE_NODE_RENDER_PASS CurrentRendertime; + //! An optional callbacks manager to allow the user app finer control + //! over the scene lighting and rendering. + ILightManager* LightManager; + //! constants for reading and writing XML. //! Not made static due to portability problems. const core::stringw IRR_XML_FORMAT_SCENE; diff --git a/source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp b/source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp index 2e665f31..7f30cab5 100644 --- a/source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp +++ b/source/Irrlicht/CSceneNodeAnimatorCameraFPS.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -18,9 +18,10 @@ namespace scene //! constructor CSceneNodeAnimatorCameraFPS::CSceneNodeAnimatorCameraFPS(gui::ICursorControl* cursorControl, f32 rotateSpeed, f32 moveSpeed, f32 jumpSpeed, - SKeyMap* keyMapArray, u32 keyMapSize, bool noVerticalMovement) + SKeyMap* keyMapArray, u32 keyMapSize, bool noVerticalMovement, bool invertY) : CursorControl(cursorControl), MaxVerticalAngle(88.0f), - MoveSpeed(moveSpeed), RotateSpeed(rotateSpeed), JumpSpeed(jumpSpeed), + MoveSpeed(moveSpeed), RotateSpeed(rotateSpeed), JumpSpeed(jumpSpeed), + MouseYDirection(invertY ? -1.0f : 1.0f), LastAnimationTime(0), firstUpdate(true), NoVerticalMovement(noVerticalMovement) { #ifdef _DEBUG @@ -139,7 +140,7 @@ void CSceneNodeAnimatorCameraFPS::animateNode(ISceneNode* node, u32 timeMs) if (CursorPos != CenterCursor) { relativeRotation.Y -= (0.5f - CursorPos.X) * RotateSpeed; - relativeRotation.X -= (0.5f - CursorPos.Y) * RotateSpeed; + relativeRotation.X -= (0.5f - CursorPos.Y) * RotateSpeed * MouseYDirection; // X < MaxVerticalAngle or X > 360-MaxVerticalAngle @@ -233,8 +234,6 @@ void CSceneNodeAnimatorCameraFPS::animateNode(ISceneNode* node, u32 timeMs) camera->setPosition(pos); // write right target - - TargetVector = target; target += pos; camera->setTarget(target); } @@ -310,6 +309,16 @@ void CSceneNodeAnimatorCameraFPS::setVerticalMovement(bool allow) } +//! Sets whether the Y axis of the mouse should be inverted. +void CSceneNodeAnimatorCameraFPS::setInvertMouse(bool invert) +{ + if (invert) + MouseYDirection = -1.0f; + else + MouseYDirection = 1.0f; +} + + ISceneNodeAnimator* CSceneNodeAnimatorCameraFPS::createClone(ISceneNode* node, ISceneManager* newManager) { CSceneNodeAnimatorCameraFPS * newAnimator = diff --git a/source/Irrlicht/CSceneNodeAnimatorCameraFPS.h b/source/Irrlicht/CSceneNodeAnimatorCameraFPS.h index c4bc8e7c..6ac3ca76 100644 --- a/source/Irrlicht/CSceneNodeAnimatorCameraFPS.h +++ b/source/Irrlicht/CSceneNodeAnimatorCameraFPS.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -28,7 +28,8 @@ namespace scene //! Constructor CSceneNodeAnimatorCameraFPS(gui::ICursorControl* cursorControl, f32 rotateSpeed = 100.0f, f32 moveSpeed = .5f, f32 jumpSpeed=0.f, - SKeyMap* keyMapArray=0, u32 keyMapSize=0, bool noVerticalMovement=false); + SKeyMap* keyMapArray=0, u32 keyMapSize=0, bool noVerticalMovement=false, + bool invertY=false); //! Destructor virtual ~CSceneNodeAnimatorCameraFPS(); @@ -58,6 +59,11 @@ namespace scene //! Sets whether vertical movement should be allowed. virtual void setVerticalMovement(bool allow); + + //! Sets whether the Y axis of the mouse should be inverted. + /** If enabled then moving the mouse down will cause + the camera to look up. It is disabled by default. */ + virtual void setInvertMouse(bool invert); //! This animator will receive events when attached to the active camera virtual bool isEventReceiverEnabled() const @@ -73,8 +79,8 @@ namespace scene //! Creates a clone of this animator. /** Please note that you will have to drop - (IReferenceCounted::drop()) the returned pointer after calling - this. */ + (IReferenceCounted::drop()) the returned pointer once you're + done with it. */ virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0); struct SCamKeyMap @@ -101,10 +107,11 @@ namespace scene f32 MoveSpeed; f32 RotateSpeed; f32 JumpSpeed; + // -1.0f for inverted mouse, defaults to 1.0f + f32 MouseYDirection; s32 LastAnimationTime; - core::vector3df TargetVector; core::array KeyMap; core::position2d CenterCursor, CursorPos; diff --git a/source/Irrlicht/CSceneNodeAnimatorCameraMaya.cpp b/source/Irrlicht/CSceneNodeAnimatorCameraMaya.cpp index 89b16f53..3edfdb03 100644 --- a/source/Irrlicht/CSceneNodeAnimatorCameraMaya.cpp +++ b/source/Irrlicht/CSceneNodeAnimatorCameraMaya.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CSceneNodeAnimatorCameraMaya.h b/source/Irrlicht/CSceneNodeAnimatorCameraMaya.h index 39010f32..4350770f 100644 --- a/source/Irrlicht/CSceneNodeAnimatorCameraMaya.h +++ b/source/Irrlicht/CSceneNodeAnimatorCameraMaya.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.cpp b/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.cpp index 8fe6fc6a..b1fab102 100644 --- a/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.cpp +++ b/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.cpp @@ -1,244 +1,272 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt -// This file is part of the "Irrlicht Engine". -// For conditions of distribution and use, see copyright notice in irrlicht.h - -#include "CSceneNodeAnimatorCollisionResponse.h" -#include "ISceneCollisionManager.h" -#include "ISceneManager.h" -#include "ICameraSceneNode.h" -#include "os.h" - -namespace irr -{ -namespace scene -{ - -//! constructor -CSceneNodeAnimatorCollisionResponse::CSceneNodeAnimatorCollisionResponse( - ISceneManager* scenemanager, - ITriangleSelector* world, ISceneNode* object, - const core::vector3df& ellipsoidRadius, - const core::vector3df& gravityPerSecond, - const core::vector3df& ellipsoidTranslation, - f32 slidingSpeed) -: Radius(ellipsoidRadius), Gravity(gravityPerSecond), Translation(ellipsoidTranslation), - World(world), Object(object), SceneManager(scenemanager), LastTime(0), - SlidingSpeed(slidingSpeed), Falling(false), IsCamera(false), - AnimateCameraTarget(true) -{ - #ifdef _DEBUG - setDebugName("CSceneNodeAnimatorCollisionResponse"); - #endif - - if (World) - World->grab(); - - setNode(Object); -} - - -//! destructor -CSceneNodeAnimatorCollisionResponse::~CSceneNodeAnimatorCollisionResponse() -{ - if (World) - World->drop(); -} - - -//! Returns if the attached scene node is falling, which means that -//! there is no blocking wall from the scene node in the direction of -//! the gravity. -bool CSceneNodeAnimatorCollisionResponse::isFalling() const -{ - _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; - return Falling; -} - - -//! Sets the radius of the ellipsoid with which collision detection and -//! response is done. -void CSceneNodeAnimatorCollisionResponse::setEllipsoidRadius( - const core::vector3df& radius) -{ - Radius = radius; -} - - -//! Returns the radius of the ellipsoid with wich the collision detection and -//! response is done. -core::vector3df CSceneNodeAnimatorCollisionResponse::getEllipsoidRadius() const -{ - return Radius; -} - - -//! Sets the gravity of the environment. -void CSceneNodeAnimatorCollisionResponse::setGravity(const core::vector3df& gravity) -{ - Gravity = gravity; -} - - -//! Returns current vector of gravity. -core::vector3df CSceneNodeAnimatorCollisionResponse::getGravity() const -{ - return Gravity; -} - - +// Copyright (C) 2002-2009 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#include "CSceneNodeAnimatorCollisionResponse.h" +#include "ISceneCollisionManager.h" +#include "ISceneManager.h" +#include "ICameraSceneNode.h" +#include "os.h" + +namespace irr +{ +namespace scene +{ + +//! constructor +CSceneNodeAnimatorCollisionResponse::CSceneNodeAnimatorCollisionResponse( + ISceneManager* scenemanager, + ITriangleSelector* world, ISceneNode* object, + const core::vector3df& ellipsoidRadius, + const core::vector3df& gravityPerSecond, + const core::vector3df& ellipsoidTranslation, + f32 slidingSpeed) +: Radius(ellipsoidRadius), Gravity(gravityPerSecond), Translation(ellipsoidTranslation), + World(world), Object(object), SceneManager(scenemanager), LastTime(0), + SlidingSpeed(slidingSpeed), Falling(false), IsCamera(false), + AnimateCameraTarget(true), CollisionOccurred(false), + CollisionCallback(0) +{ + #ifdef _DEBUG + setDebugName("CSceneNodeAnimatorCollisionResponse"); + #endif + + if (World) + World->grab(); + + setNode(Object); +} + + +//! destructor +CSceneNodeAnimatorCollisionResponse::~CSceneNodeAnimatorCollisionResponse() +{ + if (World) + World->drop(); + + if (CollisionCallback) + CollisionCallback->drop(); +} + + +//! Returns if the attached scene node is falling, which means that +//! there is no blocking wall from the scene node in the direction of +//! the gravity. +bool CSceneNodeAnimatorCollisionResponse::isFalling() const +{ + _IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX; + return Falling; +} + + +//! Sets the radius of the ellipsoid with which collision detection and +//! response is done. +void CSceneNodeAnimatorCollisionResponse::setEllipsoidRadius( + const core::vector3df& radius) +{ + Radius = radius; +} + + +//! Returns the radius of the ellipsoid with wich the collision detection and +//! response is done. +core::vector3df CSceneNodeAnimatorCollisionResponse::getEllipsoidRadius() const +{ + return Radius; +} + + +//! Sets the gravity of the environment. +void CSceneNodeAnimatorCollisionResponse::setGravity(const core::vector3df& gravity) +{ + Gravity = gravity; +} + + +//! Returns current vector of gravity. +core::vector3df CSceneNodeAnimatorCollisionResponse::getGravity() const +{ + return Gravity; +} + + //! 'Jump' the animator, by adding a jump speed opposite to its gravity void CSceneNodeAnimatorCollisionResponse::jump(f32 jumpSpeed) { FallingVelocity -= (core::vector3df(Gravity).normalize()) * jumpSpeed; Falling = true; -} - - -//! Sets the translation of the ellipsoid for collision detection. -void CSceneNodeAnimatorCollisionResponse::setEllipsoidTranslation(const core::vector3df &translation) -{ - Translation = translation; -} - - -//! Returns the translation of the ellipsoid for collision detection. -core::vector3df CSceneNodeAnimatorCollisionResponse::getEllipsoidTranslation() const -{ - return Translation; -} - - -//! Sets a triangle selector holding all triangles of the world with which -//! the scene node may collide. -void CSceneNodeAnimatorCollisionResponse::setWorld(ITriangleSelector* newWorld) -{ - Falling = false; - - LastTime = os::Timer::getTime(); - - if (World) - World->drop(); - - World = newWorld; - if (World) - World->grab(); - -} - - -//! Returns the current triangle selector containing all triangles for -//! collision detection. -ITriangleSelector* CSceneNodeAnimatorCollisionResponse::getWorld() const -{ - return World; -} - - -void CSceneNodeAnimatorCollisionResponse::animateNode(ISceneNode* node, u32 timeMs) -{ - if (node != Object) - setNode(node); - - if(!Object || !World) - return; - - u32 diff = timeMs - LastTime; - LastTime = timeMs; - - core::vector3df pos = Object->getPosition(); - core::vector3df vel = pos - LastPosition; - - FallingVelocity += Gravity * (f32)diff * 0.001f; - - core::triangle3df triangle = RefTriangle; - - core::vector3df force = vel + FallingVelocity; - - const core::vector3df nullVector ( 0.f, 0.f, 0.f ); - - if ( force != nullVector ) - { - // TODO: divide SlidingSpeed by frame time - - bool f = false; - core::vector3df collisionPosition; // Not used. - pos = SceneManager->getSceneCollisionManager()->getCollisionResultPosition( - World, LastPosition-Translation, - Radius, vel, triangle, collisionPosition, f, SlidingSpeed, FallingVelocity); - - pos += Translation; - - if (f)//triangle == RefTriangle) - { - Falling = true; - } - else - { - Falling = false; - FallingVelocity.set(0, 0, 0); - } - - Object->setPosition(pos); - } - - // move camera target - if (AnimateCameraTarget && IsCamera) - { - const core::vector3df pdiff = Object->getPosition() - LastPosition - vel; - ICameraSceneNode* cam = (ICameraSceneNode*)Object; - cam->setTarget(cam->getTarget() + pdiff); - } - - LastPosition = Object->getPosition(); -} - - -void CSceneNodeAnimatorCollisionResponse::setNode(ISceneNode* node) -{ - Object = node; - - if (Object) - { - LastPosition = Object->getPosition(); - IsCamera = (Object->getType() == ESNT_CAMERA); - } - - LastTime = os::Timer::getTime(); -} - - -//! Writes attributes of the scene node animator. -void CSceneNodeAnimatorCollisionResponse::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const -{ - out->addVector3d("Radius", Radius); - out->addVector3d("Gravity", Gravity); - out->addVector3d("Translation", Translation); - out->addBool("AnimateCameraTarget", AnimateCameraTarget); -} - - -//! Reads attributes of the scene node animator. -void CSceneNodeAnimatorCollisionResponse::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) -{ - Radius = in->getAttributeAsVector3d("Radius"); - Gravity = in->getAttributeAsVector3d("Gravity"); - Translation = in->getAttributeAsVector3d("Translation"); - AnimateCameraTarget = in->getAttributeAsBool("AnimateCameraTarget"); -} - - -ISceneNodeAnimator* CSceneNodeAnimatorCollisionResponse::createClone(ISceneNode* node, ISceneManager* newManager) -{ - if (!newManager) newManager = SceneManager; - - CSceneNodeAnimatorCollisionResponse * newAnimator = - new CSceneNodeAnimatorCollisionResponse(newManager, World, Object, Radius, (Gravity * 1000.0f), Translation, - SlidingSpeed); - - return newAnimator; -} - - -} // end namespace scene -} // end namespace irr - +} + + +//! Sets the translation of the ellipsoid for collision detection. +void CSceneNodeAnimatorCollisionResponse::setEllipsoidTranslation(const core::vector3df &translation) +{ + Translation = translation; +} + + +//! Returns the translation of the ellipsoid for collision detection. +core::vector3df CSceneNodeAnimatorCollisionResponse::getEllipsoidTranslation() const +{ + return Translation; +} + + +//! Sets a triangle selector holding all triangles of the world with which +//! the scene node may collide. +void CSceneNodeAnimatorCollisionResponse::setWorld(ITriangleSelector* newWorld) +{ + Falling = false; + + LastTime = os::Timer::getTime(); + + if (World) + World->drop(); + + World = newWorld; + if (World) + World->grab(); + +} + + +//! Returns the current triangle selector containing all triangles for +//! collision detection. +ITriangleSelector* CSceneNodeAnimatorCollisionResponse::getWorld() const +{ + return World; +} + + +void CSceneNodeAnimatorCollisionResponse::animateNode(ISceneNode* node, u32 timeMs) +{ + CollisionOccurred = false; + + if (node != Object) + setNode(node); + + if(!Object || !World) + return; + + u32 diff = timeMs - LastTime; + LastTime = timeMs; + + CollisionResultPosition = Object->getPosition(); + core::vector3df vel = CollisionResultPosition - LastPosition; + + FallingVelocity += Gravity * (f32)diff * 0.001f; + + CollisionTriangle = RefTriangle; + CollisionPoint = core::vector3df(); + CollisionResultPosition = core::vector3df(); + CollisionNode = 0; + + core::vector3df force = vel + FallingVelocity; + + const core::vector3df nullVector ( 0.f, 0.f, 0.f ); + + if ( force != nullVector ) + { + // TODO: divide SlidingSpeed by frame time + + bool f = false; + CollisionResultPosition + = SceneManager->getSceneCollisionManager()->getCollisionResultPosition( + World, LastPosition-Translation, + Radius, vel, CollisionTriangle, CollisionPoint, f, + CollisionNode, SlidingSpeed, FallingVelocity); + + CollisionOccurred = (CollisionTriangle != RefTriangle); + + CollisionResultPosition += Translation; + + if (f)//CollisionTriangle == RefTriangle) + { + Falling = true; + } + else + { + Falling = false; + FallingVelocity.set(0, 0, 0); + } + + bool collisionConsumed = false; + + if (CollisionOccurred && CollisionCallback) + collisionConsumed = CollisionCallback->onCollision(*this); + + if(!collisionConsumed) + Object->setPosition(CollisionResultPosition); + } + + // move camera target + if (AnimateCameraTarget && IsCamera) + { + const core::vector3df pdiff = Object->getPosition() - LastPosition - vel; + ICameraSceneNode* cam = (ICameraSceneNode*)Object; + cam->setTarget(cam->getTarget() + pdiff); + } + + LastPosition = Object->getPosition(); +} + + +void CSceneNodeAnimatorCollisionResponse::setNode(ISceneNode* node) +{ + Object = node; + + if (Object) + { + LastPosition = Object->getPosition(); + IsCamera = (Object->getType() == ESNT_CAMERA); + } + + LastTime = os::Timer::getTime(); +} + + +//! Writes attributes of the scene node animator. +void CSceneNodeAnimatorCollisionResponse::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const +{ + out->addVector3d("Radius", Radius); + out->addVector3d("Gravity", Gravity); + out->addVector3d("Translation", Translation); + out->addBool("AnimateCameraTarget", AnimateCameraTarget); +} + + +//! Reads attributes of the scene node animator. +void CSceneNodeAnimatorCollisionResponse::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options) +{ + Radius = in->getAttributeAsVector3d("Radius"); + Gravity = in->getAttributeAsVector3d("Gravity"); + Translation = in->getAttributeAsVector3d("Translation"); + AnimateCameraTarget = in->getAttributeAsBool("AnimateCameraTarget"); +} + + +ISceneNodeAnimator* CSceneNodeAnimatorCollisionResponse::createClone(ISceneNode* node, ISceneManager* newManager) +{ + if (!newManager) newManager = SceneManager; + + CSceneNodeAnimatorCollisionResponse * newAnimator = + new CSceneNodeAnimatorCollisionResponse(newManager, World, Object, Radius, (Gravity * 1000.0f), Translation, + SlidingSpeed); + + return newAnimator; +} + +void CSceneNodeAnimatorCollisionResponse::setCollisionCallback(ICollisionCallback* callback) +{ + if (CollisionCallback) + CollisionCallback->drop(); + + CollisionCallback = callback; + + if (CollisionCallback) + CollisionCallback->grab(); +} + +} // end namespace scene +} // end namespace irr + diff --git a/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.h b/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.h index 13eb1972..d425d226 100644 --- a/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.h +++ b/source/Irrlicht/CSceneNodeAnimatorCollisionResponse.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -95,6 +95,26 @@ namespace scene //! Gets the single node that this animator is acting on. virtual ISceneNode* getTargetNode(void) const { return Object; } + //! Returns true if a collision occurred during the last animateNode() + virtual bool collisionOccurred() const { return CollisionOccurred; } + + //! Returns the last point of collision. + virtual const core::vector3df & getCollisionPoint() const { return CollisionPoint; } + + //! Returns the last triangle that caused a collision. + virtual const core::triangle3df & getCollisionTriangle() const { return CollisionTriangle; } + + virtual const core::vector3df & getCollisionResultPosition(void) const { return CollisionResultPosition; } + + virtual const ISceneNode* getCollisionNode(void) const { return CollisionNode; } + + + //! Sets a callback interface which will be called if a collision occurs. + /** \param callback: collision callback handler that will be called when a collision + occurs. Set this to 0 to disable the callback. + */ + virtual void setCollisionCallback(ICollisionCallback* callback); + private: void setNode(ISceneNode* node); @@ -115,6 +135,14 @@ namespace scene bool Falling; bool IsCamera; bool AnimateCameraTarget; + + bool CollisionOccurred; + core::vector3df CollisionPoint; + core::triangle3df CollisionTriangle; + core::vector3df CollisionResultPosition; + const ISceneNode * CollisionNode; + + ICollisionCallback* CollisionCallback; }; } // end namespace scene diff --git a/source/Irrlicht/CSceneNodeAnimatorDelete.cpp b/source/Irrlicht/CSceneNodeAnimatorDelete.cpp index 68f09a2c..bbb11f1d 100644 --- a/source/Irrlicht/CSceneNodeAnimatorDelete.cpp +++ b/source/Irrlicht/CSceneNodeAnimatorDelete.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -13,7 +13,7 @@ namespace scene //! constructor CSceneNodeAnimatorDelete::CSceneNodeAnimatorDelete(ISceneManager* manager, u32 time) -: DeleteTime(time), SceneManager(manager) +: ISceneNodeAnimatorFinishing(time), SceneManager(manager) { #ifdef _DEBUG setDebugName("CSceneNodeAnimatorDelete"); @@ -32,18 +32,22 @@ CSceneNodeAnimatorDelete::~CSceneNodeAnimatorDelete() //! animates a scene node void CSceneNodeAnimatorDelete::animateNode(ISceneNode* node, u32 timeMs) { - if (timeMs > DeleteTime && node && SceneManager) + if (timeMs > FinishTime) { - // don't delete if scene manager is attached to an editor - if (!SceneManager->getParameters()->getAttributeAsBool(IRR_SCENE_MANAGER_IS_EDITOR)) - SceneManager->addToDeletionQueue(node); + HasFinished = true; + if(node && SceneManager) + { + // don't delete if scene manager is attached to an editor + if (!SceneManager->getParameters()->getAttributeAsBool(IRR_SCENE_MANAGER_IS_EDITOR)) + SceneManager->addToDeletionQueue(node); + } } } ISceneNodeAnimator* CSceneNodeAnimatorDelete::createClone(ISceneNode* node, ISceneManager* newManager) { CSceneNodeAnimatorDelete * newAnimator = - new CSceneNodeAnimatorDelete(SceneManager, DeleteTime); + new CSceneNodeAnimatorDelete(SceneManager, FinishTime); return newAnimator; } diff --git a/source/Irrlicht/CSceneNodeAnimatorDelete.h b/source/Irrlicht/CSceneNodeAnimatorDelete.h index 36a933c7..e74bd143 100644 --- a/source/Irrlicht/CSceneNodeAnimatorDelete.h +++ b/source/Irrlicht/CSceneNodeAnimatorDelete.h @@ -1,17 +1,17 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h #ifndef __C_SCENE_NODE_ANIMATOR_DELETE_H_INCLUDED__ #define __C_SCENE_NODE_ANIMATOR_DELETE_H_INCLUDED__ -#include "ISceneNode.h" +#include "ISceneNodeAnimatorFinishing.h" namespace irr { namespace scene { - class CSceneNodeAnimatorDelete : public ISceneNodeAnimator + class CSceneNodeAnimatorDelete : public ISceneNodeAnimatorFinishing { public: @@ -38,7 +38,6 @@ namespace scene private: - u32 DeleteTime; ISceneManager* SceneManager; }; diff --git a/source/Irrlicht/CSceneNodeAnimatorFlyCircle.cpp b/source/Irrlicht/CSceneNodeAnimatorFlyCircle.cpp index 79d877ca..8c7d397d 100644 --- a/source/Irrlicht/CSceneNodeAnimatorFlyCircle.cpp +++ b/source/Irrlicht/CSceneNodeAnimatorFlyCircle.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -38,9 +38,15 @@ void CSceneNodeAnimatorFlyCircle::animateNode(ISceneNode* node, u32 timeMs) if ( 0 == node ) return; - const f32 t = (timeMs-StartTime) * Speed; + f32 time; - node->setPosition(Center + Radius * ((VecU*cosf(t)) + (VecV*sinf(t)))); + // Check for the condition where the StartTime is in the future. + if(StartTime > timeMs) + time = ((s32)timeMs - (s32)StartTime) * Speed; + else + time = (timeMs-StartTime) * Speed; + + node->setPosition(Center + Radius * ((VecU*cosf(time)) + (VecV*sinf(time)))); } diff --git a/source/Irrlicht/CSceneNodeAnimatorFlyCircle.h b/source/Irrlicht/CSceneNodeAnimatorFlyCircle.h index 3c1fe380..675c7992 100644 --- a/source/Irrlicht/CSceneNodeAnimatorFlyCircle.h +++ b/source/Irrlicht/CSceneNodeAnimatorFlyCircle.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CSceneNodeAnimatorFlyStraight.cpp b/source/Irrlicht/CSceneNodeAnimatorFlyStraight.cpp index cb419e28..0eafb03e 100644 --- a/source/Irrlicht/CSceneNodeAnimatorFlyStraight.cpp +++ b/source/Irrlicht/CSceneNodeAnimatorFlyStraight.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -14,17 +14,19 @@ namespace scene CSceneNodeAnimatorFlyStraight::CSceneNodeAnimatorFlyStraight(const core::vector3df& startPoint, const core::vector3df& endPoint, u32 timeForWay, bool loop, u32 now) -: Start(startPoint), End(endPoint), WayLength(0.0f), TimeFactor(0.0f), StartTime(now), TimeForWay(timeForWay), Loop(loop) +: ISceneNodeAnimatorFinishing(now + timeForWay), + Start(startPoint), End(endPoint), WayLength(0.0f), + TimeFactor(0.0f), StartTime(now), TimeForWay(timeForWay), Loop(loop) { #ifdef _DEBUG setDebugName("CSceneNodeAnimatorFlyStraight"); #endif - recalculateImidiateValues(); + recalculateIntermediateValues(); } -void CSceneNodeAnimatorFlyStraight::recalculateImidiateValues() +void CSceneNodeAnimatorFlyStraight::recalculateIntermediateValues() { Vector = End - Start; WayLength = (f32)Vector.getLength(); @@ -53,9 +55,15 @@ void CSceneNodeAnimatorFlyStraight::animateNode(ISceneNode* node, u32 timeMs) core::vector3df pos = Start; if (!Loop && t >= TimeForWay) + { pos = End; + HasFinished = true; + } else + { pos += Vector * (f32)fmod((f32)t, (f32)TimeForWay) * TimeFactor; + } + node->setPosition(pos); } @@ -78,7 +86,7 @@ void CSceneNodeAnimatorFlyStraight::deserializeAttributes(io::IAttributes* in, i TimeForWay = in->getAttributeAsInt("TimeForWay"); Loop = in->getAttributeAsBool("Loop"); - recalculateImidiateValues(); + recalculateIntermediateValues(); } ISceneNodeAnimator* CSceneNodeAnimatorFlyStraight::createClone(ISceneNode* node, ISceneManager* newManager) diff --git a/source/Irrlicht/CSceneNodeAnimatorFlyStraight.h b/source/Irrlicht/CSceneNodeAnimatorFlyStraight.h index b4129780..b6342bc9 100644 --- a/source/Irrlicht/CSceneNodeAnimatorFlyStraight.h +++ b/source/Irrlicht/CSceneNodeAnimatorFlyStraight.h @@ -1,17 +1,17 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h #ifndef __C_SCENE_NODE_ANIMATOR_FLY_STRAIGHT_H_INCLUDED__ #define __C_SCENE_NODE_ANIMATOR_FLY_STRAIGHT_H_INCLUDED__ -#include "ISceneNode.h" +#include "ISceneNodeAnimatorFinishing.h" namespace irr { namespace scene { - class CSceneNodeAnimatorFlyStraight : public ISceneNodeAnimator + class CSceneNodeAnimatorFlyStraight : public ISceneNodeAnimatorFinishing { public: @@ -44,7 +44,7 @@ namespace scene private: - void recalculateImidiateValues(); + void recalculateIntermediateValues(); core::vector3df Start; core::vector3df End; diff --git a/source/Irrlicht/CSceneNodeAnimatorFollowSpline.cpp b/source/Irrlicht/CSceneNodeAnimatorFollowSpline.cpp index dab93f38..a25d37c4 100644 --- a/source/Irrlicht/CSceneNodeAnimatorFollowSpline.cpp +++ b/source/Irrlicht/CSceneNodeAnimatorFollowSpline.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CSceneNodeAnimatorFollowSpline.h b/source/Irrlicht/CSceneNodeAnimatorFollowSpline.h index 6c9d80c4..ce108738 100644 --- a/source/Irrlicht/CSceneNodeAnimatorFollowSpline.h +++ b/source/Irrlicht/CSceneNodeAnimatorFollowSpline.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CSceneNodeAnimatorRotation.cpp b/source/Irrlicht/CSceneNodeAnimatorRotation.cpp index 8aab8ab5..e48d051f 100644 --- a/source/Irrlicht/CSceneNodeAnimatorRotation.cpp +++ b/source/Irrlicht/CSceneNodeAnimatorRotation.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CSceneNodeAnimatorRotation.h b/source/Irrlicht/CSceneNodeAnimatorRotation.h index 78dfdbd0..cbaa7695 100644 --- a/source/Irrlicht/CSceneNodeAnimatorRotation.h +++ b/source/Irrlicht/CSceneNodeAnimatorRotation.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CSceneNodeAnimatorTexture.cpp b/source/Irrlicht/CSceneNodeAnimatorTexture.cpp index 44d32497..79323e0a 100644 --- a/source/Irrlicht/CSceneNodeAnimatorTexture.cpp +++ b/source/Irrlicht/CSceneNodeAnimatorTexture.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -14,7 +14,8 @@ namespace scene //! constructor CSceneNodeAnimatorTexture::CSceneNodeAnimatorTexture(const core::array& textures, s32 timePerFrame, bool loop, u32 now) -: TimePerFrame(timePerFrame), StartTime(now), Loop(loop) +: ISceneNodeAnimatorFinishing(0), + TimePerFrame(timePerFrame), StartTime(now), Loop(loop) { #ifdef _DEBUG setDebugName("CSceneNodeAnimatorTexture"); @@ -28,7 +29,7 @@ CSceneNodeAnimatorTexture::CSceneNodeAnimatorTexture(const core::array= EndTime) + if (!Loop && timeMs >= FinishTime) + { idx = Textures.size() - 1; + HasFinished = true; + } else + { idx = (t/TimePerFrame) % Textures.size(); + } if (idx < Textures.size()) node->setMaterialTexture(0, Textures[idx]); diff --git a/source/Irrlicht/CSceneNodeAnimatorTexture.h b/source/Irrlicht/CSceneNodeAnimatorTexture.h index 96178915..04e9fec5 100644 --- a/source/Irrlicht/CSceneNodeAnimatorTexture.h +++ b/source/Irrlicht/CSceneNodeAnimatorTexture.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -6,13 +6,13 @@ #define __C_SCENE_NODE_ANIMATOR_TEXTURE_H_INCLUDED__ #include "irrArray.h" -#include "ISceneNode.h" +#include "ISceneNodeAnimatorFinishing.h" namespace irr { namespace scene { - class CSceneNodeAnimatorTexture : public ISceneNodeAnimator + class CSceneNodeAnimatorTexture : public ISceneNodeAnimatorFinishing { public: @@ -48,7 +48,6 @@ namespace scene core::array Textures; u32 TimePerFrame; u32 StartTime; - u32 EndTime; bool Loop; }; diff --git a/source/Irrlicht/CShadowVolumeSceneNode.cpp b/source/Irrlicht/CShadowVolumeSceneNode.cpp index 397b3ee8..8ca6c4d8 100644 --- a/source/Irrlicht/CShadowVolumeSceneNode.cpp +++ b/source/Irrlicht/CShadowVolumeSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CShadowVolumeSceneNode.h b/source/Irrlicht/CShadowVolumeSceneNode.h index 4c924f06..40ae8283 100644 --- a/source/Irrlicht/CShadowVolumeSceneNode.h +++ b/source/Irrlicht/CShadowVolumeSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CSkinnedMesh.cpp b/source/Irrlicht/CSkinnedMesh.cpp index 971244ba..3fbd8462 100644 --- a/source/Irrlicht/CSkinnedMesh.cpp +++ b/source/Irrlicht/CSkinnedMesh.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CSkinnedMesh.h b/source/Irrlicht/CSkinnedMesh.h index 9ce64abb..901b30df 100644 --- a/source/Irrlicht/CSkinnedMesh.h +++ b/source/Irrlicht/CSkinnedMesh.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CSkyBoxSceneNode.cpp b/source/Irrlicht/CSkyBoxSceneNode.cpp index eda6beed..9a6f8ad8 100644 --- a/source/Irrlicht/CSkyBoxSceneNode.cpp +++ b/source/Irrlicht/CSkyBoxSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -38,7 +38,7 @@ CSkyBoxSceneNode::CSkyBoxSceneNode(video::ITexture* top, video::ITexture* bottom video::SMaterial mat; mat.Lighting = false; - mat.ZBuffer = false; + mat.ZBuffer = video::ECFN_NEVER; mat.ZWriteEnable = false; mat.TextureLayer[0].TextureWrap = video::ETC_CLAMP; @@ -140,7 +140,7 @@ void CSkyBoxSceneNode::render() core::matrix4 translate(AbsoluteTransformation); translate.setTranslation(camera->getAbsolutePosition()); - + // Draw the sky box between the near and far clip plane const f32 viewDistance = (camera->getNearValue() + camera->getFarValue()) * 0.5f; core::matrix4 scale; @@ -190,8 +190,10 @@ void CSkyBoxSceneNode::render() if ( tex ) { - core::rect rctDest(core::position2d(-1,0), driver->getCurrentRenderTargetSize()); - core::rect rctSrc(core::position2d(0,0), tex->getSize()); + core::rect rctDest(core::position2d(-1,0), + core::dimension2di(driver->getCurrentRenderTargetSize())); + core::rect rctSrc(core::position2d(0,0), + core::dimension2di(tex->getSize())); driver->draw2DImage(tex, rctDest, rctSrc); } @@ -240,7 +242,7 @@ ISceneNode* CSkyBoxSceneNode::clone(ISceneNode* newParent, ISceneManager* newMan if (!newParent) newParent = Parent; if (!newManager) newManager = SceneManager; - CSkyBoxSceneNode* nb = new CSkyBoxSceneNode(0,0,0,0,0,0, newParent, + CSkyBoxSceneNode* nb = new CSkyBoxSceneNode(0,0,0,0,0,0, newParent, newManager, ID); nb->cloneMembers(this, newManager); diff --git a/source/Irrlicht/CSkyBoxSceneNode.h b/source/Irrlicht/CSkyBoxSceneNode.h index 7d9fa12f..e229cd11 100644 --- a/source/Irrlicht/CSkyBoxSceneNode.h +++ b/source/Irrlicht/CSkyBoxSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CSkyDomeSceneNode.cpp b/source/Irrlicht/CSkyDomeSceneNode.cpp index 0d6837b2..570169cf 100644 --- a/source/Irrlicht/CSkyDomeSceneNode.cpp +++ b/source/Irrlicht/CSkyDomeSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // Code for this scene node has been contributed by Anders la Cour-Harbo (alc) @@ -48,7 +48,7 @@ CSkyDomeSceneNode::CSkyDomeSceneNode(video::ITexture* sky, u32 horiRes, u32 vert Buffer = new SMeshBuffer(); Buffer->Material.Lighting = false; - Buffer->Material.ZBuffer = false; + Buffer->Material.ZBuffer = video::ECFN_NEVER; Buffer->Material.ZWriteEnable = false; Buffer->Material.setTexture(0, sky); Buffer->BoundingBox.MaxEdge.set(0,0,0); diff --git a/source/Irrlicht/CSkyDomeSceneNode.h b/source/Irrlicht/CSkyDomeSceneNode.h index 11090d15..77dc0ac7 100644 --- a/source/Irrlicht/CSkyDomeSceneNode.h +++ b/source/Irrlicht/CSkyDomeSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // Code for this scene node has been contributed by Anders la Cour-Harbo (alc) diff --git a/source/Irrlicht/CSoftware2MaterialRenderer.h b/source/Irrlicht/CSoftware2MaterialRenderer.h index 7057230a..f9618461 100644 --- a/source/Irrlicht/CSoftware2MaterialRenderer.h +++ b/source/Irrlicht/CSoftware2MaterialRenderer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CSoftwareDriver.cpp b/source/Irrlicht/CSoftwareDriver.cpp index 9893927c..d6b986b9 100644 --- a/source/Irrlicht/CSoftwareDriver.cpp +++ b/source/Irrlicht/CSoftwareDriver.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -18,7 +18,7 @@ namespace video //! constructor -CSoftwareDriver::CSoftwareDriver(const core::dimension2d& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter) +CSoftwareDriver::CSoftwareDriver(const core::dimension2d& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter) : CNullDriver(io, windowSize), BackBuffer(0), Presenter(presenter), WindowId(0), SceneSourceRect(0), RenderTargetTexture(0), RenderTargetSurface(0), CurrentTriangleRenderer(0), ZBuffer(0), Texture(0) @@ -133,7 +133,7 @@ void CSoftwareDriver::selectRightTriangleRenderer() renderer = ETR_TEXTURE_GOURAUD_ADD; } else - if (!Material.ZBuffer && !Material.ZWriteEnable) + if ((Material.ZBuffer==ECFN_NEVER) && !Material.ZWriteEnable) renderer = ETR_TEXTURE_GOURAUD_NOZ; else { @@ -316,7 +316,7 @@ void CSoftwareDriver::setViewPort(const core::rect& area) core::rect rendert(0,0,RenderTargetSize.Width,RenderTargetSize.Height); ViewPort.clipAgainst(rendert); - ViewPortSize = ViewPort.getSize(); + ViewPortSize = core::dimension2du(ViewPort.getSize()); Render2DTranslation.X = (ViewPortSize.Width / 2) + ViewPort.UpperLeftCorner.X; Render2DTranslation.Y = ViewPort.UpperLeftCorner.Y + ViewPortSize.Height - (ViewPortSize.Height / 2);// + ViewPort.UpperLeftCorner.Y; @@ -453,6 +453,8 @@ void CSoftwareDriver::drawVertexPrimitiveList16(const void* vertices, u32 vertex case scene::EPT_TRIANGLES: indexPointer=indexList; break; + default: + return; } switch (vType) { @@ -660,7 +662,7 @@ void CSoftwareDriver::drawClippedIndexedTriangleListT(const VERTEXTYPE* vertices const VERTEXTYPE* currentVertex = clippedVertices.pointer(); S2DVertex* tp = &TransformedPoints[0]; - core::dimension2d textureSize(0,0); + core::dimension2d textureSize(0,0); f32 zDiv; if (Texture) @@ -740,10 +742,10 @@ void CSoftwareDriver::clipTriangle(f32* transformedPos) //! Only used by the internal engine. Used to notify the driver that //! the window was resized. -void CSoftwareDriver::OnResize(const core::dimension2d& size) +void CSoftwareDriver::OnResize(const core::dimension2d& size) { // make sure width and height are multiples of 2 - core::dimension2d realSize(size); + core::dimension2d realSize(size); if (realSize.Width % 2) realSize.Width += 1; @@ -753,10 +755,11 @@ void CSoftwareDriver::OnResize(const core::dimension2d& size) if (ScreenSize != realSize) { - if (ViewPort.getWidth() == ScreenSize.Width && - ViewPort.getHeight() == ScreenSize.Height) + if (ViewPort.getWidth() == (s32)ScreenSize.Width && + ViewPort.getHeight() == (s32)ScreenSize.Height) { - ViewPort = core::rect(core::position2d(0,0), realSize); + ViewPort = core::rect(core::position2d(0,0), + core::dimension2di(realSize)); } ScreenSize = realSize; @@ -773,7 +776,7 @@ void CSoftwareDriver::OnResize(const core::dimension2d& size) } //! returns the current render target size -const core::dimension2d& CSoftwareDriver::getCurrentRenderTargetSize() const +const core::dimension2d& CSoftwareDriver::getCurrentRenderTargetSize() const { return RenderTargetSize; } @@ -817,7 +820,7 @@ void CSoftwareDriver::drawPixel(u32 x, u32 y, const SColor & color) { ((CImage*)BackBuffer)->setPixel(x, y, color); } - + //! draw a 2d rectangle void CSoftwareDriver::draw2DRectangle(SColor color, const core::rect& pos, @@ -887,7 +890,7 @@ const core::matrix4& CSoftwareDriver::getTransform(E_TRANSFORMATION_STATE state) //! Creates a render target texture. -ITexture* CSoftwareDriver::addRenderTargetTexture(const core::dimension2d& size, const c8* name) +ITexture* CSoftwareDriver::addRenderTargetTexture(const core::dimension2d& size, const c8* name) { CImage* img = new CImage(video::ECF_A1R5G5B5, size); if (!name) @@ -938,7 +941,7 @@ namespace video //! creates a video driver -IVideoDriver* createSoftwareDriver(const core::dimension2d& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter) +IVideoDriver* createSoftwareDriver(const core::dimension2d& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter) { #ifdef _IRR_COMPILE_WITH_SOFTWARE_ return new CSoftwareDriver(windowSize, fullscreen, io, presenter); diff --git a/source/Irrlicht/CSoftwareDriver.h b/source/Irrlicht/CSoftwareDriver.h index 7494ea2c..c9e4c562 100644 --- a/source/Irrlicht/CSoftwareDriver.h +++ b/source/Irrlicht/CSoftwareDriver.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -19,7 +19,7 @@ namespace video public: //! constructor - CSoftwareDriver(const core::dimension2d& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter); + CSoftwareDriver(const core::dimension2d& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter); //! destructor virtual ~CSoftwareDriver(); @@ -50,10 +50,10 @@ namespace video //! Only used by the internal engine. Used to notify the driver that //! the window was resized. - virtual void OnResize(const core::dimension2d& size); + virtual void OnResize(const core::dimension2d& size); //! returns size of the current render target - virtual const core::dimension2d& getCurrentRenderTargetSize() const; + virtual const core::dimension2d& getCurrentRenderTargetSize() const; //! draws a vertex primitive list void drawVertexPrimitiveList(const void* vertices, u32 vertexCount, @@ -84,7 +84,7 @@ namespace video SColor color=SColor(255,255,255,255)); //! Draws a single pixel - virtual void drawPixel(u32 x, u32 y, const SColor & color); + virtual void drawPixel(u32 x, u32 y, const SColor & color); //! \return Returns the name of the video driver. Example: In case of the Direct3D8 //! driver, it would return "Direct3D8.1". @@ -100,7 +100,7 @@ namespace video virtual const core::matrix4& getTransform(E_TRANSFORMATION_STATE state) const; //! Creates a render target texture. - virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, const c8* name); //! Clears the ZBuffer. @@ -152,8 +152,8 @@ namespace video video::ITexture* RenderTargetTexture; video::IImage* RenderTargetSurface; core::position2d Render2DTranslation; - core::dimension2d RenderTargetSize; - core::dimension2d ViewPortSize; + core::dimension2d RenderTargetSize; + core::dimension2d ViewPortSize; core::matrix4 TransformationMatrix[ETS_COUNT]; diff --git a/source/Irrlicht/CSoftwareDriver2.cpp b/source/Irrlicht/CSoftwareDriver2.cpp index 8b966466..e336a910 100644 --- a/source/Irrlicht/CSoftwareDriver2.cpp +++ b/source/Irrlicht/CSoftwareDriver2.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -25,7 +25,7 @@ namespace video //! constructor -CBurningVideoDriver::CBurningVideoDriver(const core::dimension2d& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter) +CBurningVideoDriver::CBurningVideoDriver(const core::dimension2d& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter) : CNullDriver(io, windowSize), BackBuffer(0), Presenter(presenter), WindowId(0), SceneSourceRect(0), RenderTargetTexture(0), RenderTargetSurface(0), CurrentShader(0), @@ -166,7 +166,7 @@ void CBurningVideoDriver::setCurrentShader() case EMT_TRANSPARENT_ALPHA_CHANNEL_REF: case EMT_TRANSPARENT_ALPHA_CHANNEL: - if ( Material.org.ZBuffer ) + if ( Material.org.ZBuffer != ECFN_NEVER ) { shader = ETR_TEXTURE_GOURAUD_ALPHA; } @@ -178,7 +178,7 @@ void CBurningVideoDriver::setCurrentShader() break; case EMT_TRANSPARENT_ADD_COLOR: - if ( Material.org.ZBuffer ) + if ( Material.org.ZBuffer != ECFN_NEVER ) { shader = ETR_TEXTURE_GOURAUD_ADD; } @@ -226,7 +226,7 @@ void CBurningVideoDriver::setCurrentShader() } - if ( zMaterialTest && !Material.org.ZBuffer && !Material.org.ZWriteEnable) + if ( zMaterialTest && (Material.org.ZBuffer==ECFN_NEVER) && !Material.org.ZWriteEnable) { shader = ETR_TEXTURE_GOURAUD_NOZ; } @@ -1262,7 +1262,7 @@ void CBurningVideoDriver::drawVertexPrimitiveList16(const void* vertices, u32 ve /* // TODO: don't stick on 32 Bit Pointer - #define PointerAsValue(x) ( (u32) (u32*) (x) ) + #define PointerAsValue(x) ( (u32) (u32*) (x) ) // if not complete inside clipping necessary if ( ( test & VERTEX4D_INSIDE ) != VERTEX4D_INSIDE ) @@ -1340,13 +1340,11 @@ void CBurningVideoDriver::setAmbientLight(const SColorf& color) //! adds a dynamic light -void CBurningVideoDriver::addDynamicLight(const SLight& dl) +s32 CBurningVideoDriver::addDynamicLight(const SLight& dl) { - if ( LightSpace.Light.size () >= getMaximalDynamicLightAmount () ) - return; - SBurningShaderLight l; l.org = dl; + l.LightIsOn = true; // light in eye space Transformation[ETS_VIEW].m.transformVect ( &l.posEyeSpace.x, l.org.Position ); @@ -1365,12 +1363,26 @@ void CBurningVideoDriver::addDynamicLight(const SLight& dl) { l.posEyeSpace.normalize_xyz (); } break; + + default: + break; } LightSpace.Light.push_back ( l ); - CNullDriver::addDynamicLight( l.org ); + (void)CNullDriver::addDynamicLight( l.org ); + + return LightSpace.Light.size() - 1; } +//! Turns a dynamic light on or off +void CBurningVideoDriver::turnLightOn(s32 lightIndex, bool turnOn) +{ + if(lightIndex > -1 && lightIndex < (s32)LightSpace.Light.size()) + LightSpace.Light[lightIndex].LightIsOn = turnOn; +} + + + //! deletes all dynamic lights there are void CBurningVideoDriver::deleteAllDynamicLights() { @@ -1401,12 +1413,6 @@ void CBurningVideoDriver::lightVertex ( s4DVertex *dest, const S3DVertex *source return; } - if ( Lights.size () == 0 ) - { - dest->Color[0] = Material.EmissiveColor; - return; - } - // eyespace /* core::matrix4 modelview = Transformation[ETS_WORLD].m * Transformation[ETS_VIEW].m; @@ -1453,6 +1459,9 @@ void CBurningVideoDriver::lightVertex ( s4DVertex *dest, const S3DVertex *source { const SBurningShaderLight &light = LightSpace.Light[i]; + if(!light.LightIsOn) + continue; + sVec4 vp; // unit vector vertex to light sVec4 lightHalf; // blinn-phong reflection @@ -1504,6 +1513,9 @@ void CBurningVideoDriver::lightVertex ( s4DVertex *dest, const S3DVertex *source lightHalf.z = vp.z - 1.f; lightHalf.normalize_xyz(); } break; + + default: + break; } // build diffuse reflection @@ -1581,7 +1593,7 @@ void CBurningVideoDriver::draw2DLine(const core::position2d& start, void CBurningVideoDriver::drawPixel(u32 x, u32 y, const SColor & color) { ((CImage*)BackBuffer)->setPixel(x, y, color); -} +} //! draw an 2d rectangle void CBurningVideoDriver::draw2DRectangle(SColor color, const core::rect& pos, @@ -1610,10 +1622,10 @@ void CBurningVideoDriver::draw2DRectangle(SColor color, const core::rect& p //! Only used by the internal engine. Used to notify the driver that //! the window was resized. -void CBurningVideoDriver::OnResize(const core::dimension2d& size) +void CBurningVideoDriver::OnResize(const core::dimension2d& size) { // make sure width and height are multiples of 2 - core::dimension2d realSize(size); + core::dimension2d realSize(size); if (realSize.Width % 2) realSize.Width += 1; @@ -1623,10 +1635,11 @@ void CBurningVideoDriver::OnResize(const core::dimension2d& size) if (ScreenSize != realSize) { - if (ViewPort.getWidth() == ScreenSize.Width && - ViewPort.getHeight() == ScreenSize.Height) + if (ViewPort.getWidth() == (s32)ScreenSize.Width && + ViewPort.getHeight() == (s32)ScreenSize.Height) { - ViewPort = core::rect(core::position2d(0,0), realSize); + ViewPort = core::rect(core::position2d(0,0), + core::dimension2di(realSize)); } ScreenSize = realSize; @@ -1644,7 +1657,7 @@ void CBurningVideoDriver::OnResize(const core::dimension2d& size) //! returns the current render target size -const core::dimension2d& CBurningVideoDriver::getCurrentRenderTargetSize() const +const core::dimension2d& CBurningVideoDriver::getCurrentRenderTargetSize() const { return RenderTargetSize; } @@ -1665,9 +1678,9 @@ void CBurningVideoDriver::draw2DRectangle(const core::rect& position, if (!pos.isValid()) return; - const core::dimension2d renderTargetSize ( ViewPort.getSize() ); + const core::dimension2d renderTargetSize ( ViewPort.getSize() ); - const s32 xPlus = -(renderTargetSize.Width>>1); + const s32 xPlus = -(s32)(renderTargetSize.Width>>1); const f32 xFact = 1.0f / (renderTargetSize.Width>>1); const s32 yPlus = renderTargetSize.Height-(renderTargetSize.Height>>1); @@ -1849,7 +1862,7 @@ const core::matrix4& CBurningVideoDriver::getTransform(E_TRANSFORMATION_STATE st //! Creates a render target texture. -ITexture* CBurningVideoDriver::addRenderTargetTexture(const core::dimension2d& size, +ITexture* CBurningVideoDriver::addRenderTargetTexture(const core::dimension2d& size, const c8* name) { CImage* img = new CImage(BURNINGSHADER_COLOR_FORMAT, size); @@ -1991,7 +2004,7 @@ namespace video { //! creates a video driver -IVideoDriver* createSoftwareDriver2(const core::dimension2d& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter) +IVideoDriver* createSoftwareDriver2(const core::dimension2d& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter) { #ifdef _IRR_COMPILE_WITH_BURNINGSVIDEO_ return new CBurningVideoDriver(windowSize, fullscreen, io, presenter); diff --git a/source/Irrlicht/CSoftwareDriver2.h b/source/Irrlicht/CSoftwareDriver2.h index 3647111c..fd0d1b12 100644 --- a/source/Irrlicht/CSoftwareDriver2.h +++ b/source/Irrlicht/CSoftwareDriver2.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -21,7 +21,7 @@ namespace video public: //! constructor - CBurningVideoDriver(const core::dimension2d& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter); + CBurningVideoDriver(const core::dimension2d& windowSize, bool fullscreen, io::IFileSystem* io, video::IImagePresenter* presenter); //! destructor virtual ~CBurningVideoDriver(); @@ -52,16 +52,23 @@ namespace video //! Only used by the internal engine. Used to notify the driver that //! the window was resized. - virtual void OnResize(const core::dimension2d& size); + virtual void OnResize(const core::dimension2d& size); //! returns size of the current render target - virtual const core::dimension2d& getCurrentRenderTargetSize() const; + virtual const core::dimension2d& getCurrentRenderTargetSize() const; //! deletes all dynamic lights there are virtual void deleteAllDynamicLights(); - //! adds a dynamic light - virtual void addDynamicLight(const SLight& light); + //! adds a dynamic light, returning an index to the light + //! \param light: the light data to use to create the light + //! \return An index to the light, or -1 if an error occurs + virtual s32 addDynamicLight(const SLight& light); + + //! Turns a dynamic light on or off + //! \param lightIndex: the index returned by addDynamicLight + //! \param turnOn: true to turn the light on, false to turn it off + virtual void turnLightOn(s32 lightIndex, bool turnOn); //! returns the maximal amount of dynamic lights the device can handle virtual u32 getMaximalDynamicLightAmount() const; @@ -116,7 +123,7 @@ namespace video virtual const core::matrix4& getTransform(E_TRANSFORMATION_STATE state) const; //! Creates a render target texture. - virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, const c8* name); + virtual ITexture* addRenderTargetTexture(const core::dimension2d& size, const c8* name); //! Clears the DepthBuffer. virtual void clearZBuffer(); @@ -169,7 +176,7 @@ namespace video video::ITexture* RenderTargetTexture; video::IImage* RenderTargetSurface; - core::dimension2d RenderTargetSize; + core::dimension2d RenderTargetSize; //! selects the right triangle renderer based on the render states. void setCurrentShader(); diff --git a/source/Irrlicht/CSoftwareTexture.cpp b/source/Irrlicht/CSoftwareTexture.cpp index 5418100a..23ecfec7 100644 --- a/source/Irrlicht/CSoftwareTexture.cpp +++ b/source/Irrlicht/CSoftwareTexture.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -23,7 +23,7 @@ CSoftwareTexture::CSoftwareTexture(IImage* image, const char* name, bool renderT if (image) { - core::dimension2d optSize; + core::dimension2d optSize; OrigSize = image->getDimension(); optSize.Width = getTextureSizeFromSurfaceSize(OrigSize.Width); @@ -80,14 +80,14 @@ void CSoftwareTexture::unlock() //! Returns original size of the texture. -const core::dimension2d& CSoftwareTexture::getOriginalSize() const +const core::dimension2d& CSoftwareTexture::getOriginalSize() const { return OrigSize; } //! Returns (=size) of the texture. -const core::dimension2d& CSoftwareTexture::getSize() const +const core::dimension2d& CSoftwareTexture::getSize() const { return Image->getDimension(); } diff --git a/source/Irrlicht/CSoftwareTexture.h b/source/Irrlicht/CSoftwareTexture.h index acd13c61..c8854ddd 100644 --- a/source/Irrlicht/CSoftwareTexture.h +++ b/source/Irrlicht/CSoftwareTexture.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -33,10 +33,10 @@ public: virtual void unlock(); //! Returns original size of the texture. - virtual const core::dimension2d& getOriginalSize() const; + virtual const core::dimension2d& getOriginalSize() const; //! Returns (=size) of the texture. - virtual const core::dimension2d& getSize() const; + virtual const core::dimension2d& getSize() const; //! returns unoptimized surface virtual CImage* getImage(); @@ -53,7 +53,7 @@ public: //! returns pitch of texture (in bytes) virtual u32 getPitch() const; - //! Regenerates the mip map levels of the texture. Useful after locking and + //! Regenerates the mip map levels of the texture. Useful after locking and //! modifying the texture virtual void regenerateMipMapLevels(); @@ -67,7 +67,7 @@ private: CImage* Image; CImage* Texture; - core::dimension2d OrigSize; + core::dimension2d OrigSize; bool IsRenderTarget; }; diff --git a/source/Irrlicht/CSoftwareTexture2.cpp b/source/Irrlicht/CSoftwareTexture2.cpp index 67895e19..93fbbe15 100644 --- a/source/Irrlicht/CSoftwareTexture2.cpp +++ b/source/Irrlicht/CSoftwareTexture2.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -12,7 +12,7 @@ namespace irr { -namespace video +namespace video { //! constructor @@ -33,9 +33,9 @@ CSoftwareTexture2::CSoftwareTexture2(IImage* image, const char* name, bool gener { OrigSize = image->getDimension(); - core::dimension2d optSize( + core::dimension2d optSize( OrigSize.getOptimalSize(true, false, false)); - + if ( OrigSize == optSize ) { MipMap[0] = new CImage(BURNINGSHADER_COLOR_FORMAT, image); @@ -69,7 +69,7 @@ CSoftwareTexture2::~CSoftwareTexture2() } -//! Regenerates the mip map levels of the texture. Useful after locking and +//! Regenerates the mip map levels of the texture. Useful after locking and //! modifying the texture void CSoftwareTexture2::regenerateMipMapLevels() { @@ -85,8 +85,8 @@ void CSoftwareTexture2::regenerateMipMapLevels() MipMap[i]->drop(); } - core::dimension2d newSize; - core::dimension2d currentSize; + core::dimension2d newSize; + core::dimension2d currentSize; i = 1; CImage * c = MipMap[0]; diff --git a/source/Irrlicht/CSoftwareTexture2.h b/source/Irrlicht/CSoftwareTexture2.h index 3ef61aa9..679e71ac 100644 --- a/source/Irrlicht/CSoftwareTexture2.h +++ b/source/Irrlicht/CSoftwareTexture2.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -41,7 +41,7 @@ public: } //! Returns original size of the texture. - virtual const core::dimension2d& getOriginalSize() const + virtual const core::dimension2d& getOriginalSize() const { //return MipMap[0]->getDimension(); return OrigSize; @@ -54,7 +54,7 @@ public: } //! Returns (=size) of the texture. - virtual const core::dimension2d& getSize() const + virtual const core::dimension2d& getSize() const { return MipMap[MipMapLOD]->getDimension(); } @@ -90,7 +90,7 @@ public: return MipMap[MipMapLOD]->getPitch(); } - //! Regenerates the mip map levels of the texture. Useful after locking and + //! Regenerates the mip map levels of the texture. Useful after locking and //! modifying the texture virtual void regenerateMipMapLevels(); @@ -100,7 +100,7 @@ public: if ( HasMipMaps ) MipMapLOD = lod; } - + //! support mipmaps virtual bool hasMipMaps() const { @@ -114,7 +114,7 @@ public: } private: - core::dimension2d OrigSize; + core::dimension2d OrigSize; CImage * MipMap[SOFTWARE_DRIVER_2_MIPMAPPING_MAX]; diff --git a/source/Irrlicht/CSphereSceneNode.cpp b/source/Irrlicht/CSphereSceneNode.cpp index a37083b9..a596e52a 100644 --- a/source/Irrlicht/CSphereSceneNode.cpp +++ b/source/Irrlicht/CSphereSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CSphereSceneNode.h b/source/Irrlicht/CSphereSceneNode.h index 5b8e9dae..1583ac31 100644 --- a/source/Irrlicht/CSphereSceneNode.h +++ b/source/Irrlicht/CSphereSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRFlat.cpp b/source/Irrlicht/CTRFlat.cpp index 800d966c..f9ac119d 100644 --- a/source/Irrlicht/CTRFlat.cpp +++ b/source/Irrlicht/CTRFlat.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRFlatWire.cpp b/source/Irrlicht/CTRFlatWire.cpp index 4ea0b254..71133601 100644 --- a/source/Irrlicht/CTRFlatWire.cpp +++ b/source/Irrlicht/CTRFlatWire.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRGouraud.cpp b/source/Irrlicht/CTRGouraud.cpp index 508b4212..5ffb7233 100644 --- a/source/Irrlicht/CTRGouraud.cpp +++ b/source/Irrlicht/CTRGouraud.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRGouraud2.cpp b/source/Irrlicht/CTRGouraud2.cpp index 93e1b59f..ecd086ef 100644 --- a/source/Irrlicht/CTRGouraud2.cpp +++ b/source/Irrlicht/CTRGouraud2.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRGouraudAlpha2.cpp b/source/Irrlicht/CTRGouraudAlpha2.cpp index 9c42eff7..465f77f9 100644 --- a/source/Irrlicht/CTRGouraudAlpha2.cpp +++ b/source/Irrlicht/CTRGouraudAlpha2.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRGouraudAlphaNoZ2.cpp b/source/Irrlicht/CTRGouraudAlphaNoZ2.cpp index 7ab18fd1..cfa31a32 100644 --- a/source/Irrlicht/CTRGouraudAlphaNoZ2.cpp +++ b/source/Irrlicht/CTRGouraudAlphaNoZ2.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRGouraudWire.cpp b/source/Irrlicht/CTRGouraudWire.cpp index a6822d01..c301a4cb 100644 --- a/source/Irrlicht/CTRGouraudWire.cpp +++ b/source/Irrlicht/CTRGouraudWire.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureBlend.cpp b/source/Irrlicht/CTRTextureBlend.cpp index 53b48ce3..a09a671f 100644 --- a/source/Irrlicht/CTRTextureBlend.cpp +++ b/source/Irrlicht/CTRTextureBlend.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureDetailMap2.cpp b/source/Irrlicht/CTRTextureDetailMap2.cpp index 97f7dac6..122a139a 100644 --- a/source/Irrlicht/CTRTextureDetailMap2.cpp +++ b/source/Irrlicht/CTRTextureDetailMap2.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureFlat.cpp b/source/Irrlicht/CTRTextureFlat.cpp index f93216af..67c3b7a7 100644 --- a/source/Irrlicht/CTRTextureFlat.cpp +++ b/source/Irrlicht/CTRTextureFlat.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureFlatWire.cpp b/source/Irrlicht/CTRTextureFlatWire.cpp index d7b20ec2..d1d4694c 100644 --- a/source/Irrlicht/CTRTextureFlatWire.cpp +++ b/source/Irrlicht/CTRTextureFlatWire.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureGouraud.cpp b/source/Irrlicht/CTRTextureGouraud.cpp index 24e76361..bd8225d0 100644 --- a/source/Irrlicht/CTRTextureGouraud.cpp +++ b/source/Irrlicht/CTRTextureGouraud.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureGouraud.h b/source/Irrlicht/CTRTextureGouraud.h index 715dc6aa..443f16c6 100644 --- a/source/Irrlicht/CTRTextureGouraud.h +++ b/source/Irrlicht/CTRTextureGouraud.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureGouraud2.cpp b/source/Irrlicht/CTRTextureGouraud2.cpp index e9d67659..f4288673 100644 --- a/source/Irrlicht/CTRTextureGouraud2.cpp +++ b/source/Irrlicht/CTRTextureGouraud2.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureGouraudAdd.cpp b/source/Irrlicht/CTRTextureGouraudAdd.cpp index 2e845c51..6b373afa 100644 --- a/source/Irrlicht/CTRTextureGouraudAdd.cpp +++ b/source/Irrlicht/CTRTextureGouraudAdd.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureGouraudAdd2.cpp b/source/Irrlicht/CTRTextureGouraudAdd2.cpp index 78b72b05..46363de5 100644 --- a/source/Irrlicht/CTRTextureGouraudAdd2.cpp +++ b/source/Irrlicht/CTRTextureGouraudAdd2.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureGouraudAddNoZ2.cpp b/source/Irrlicht/CTRTextureGouraudAddNoZ2.cpp index 3bd15167..0798f440 100644 --- a/source/Irrlicht/CTRTextureGouraudAddNoZ2.cpp +++ b/source/Irrlicht/CTRTextureGouraudAddNoZ2.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureGouraudAlpha.cpp b/source/Irrlicht/CTRTextureGouraudAlpha.cpp index 240be1e1..617f4d68 100644 --- a/source/Irrlicht/CTRTextureGouraudAlpha.cpp +++ b/source/Irrlicht/CTRTextureGouraudAlpha.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureGouraudAlphaNoZ.cpp b/source/Irrlicht/CTRTextureGouraudAlphaNoZ.cpp index de71bf62..590aeb70 100644 --- a/source/Irrlicht/CTRTextureGouraudAlphaNoZ.cpp +++ b/source/Irrlicht/CTRTextureGouraudAlphaNoZ.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureGouraudNoZ.cpp b/source/Irrlicht/CTRTextureGouraudNoZ.cpp index fa052f91..9f105ce2 100644 --- a/source/Irrlicht/CTRTextureGouraudNoZ.cpp +++ b/source/Irrlicht/CTRTextureGouraudNoZ.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureGouraudNoZ2.cpp b/source/Irrlicht/CTRTextureGouraudNoZ2.cpp index 622e83ca..18a7db06 100644 --- a/source/Irrlicht/CTRTextureGouraudNoZ2.cpp +++ b/source/Irrlicht/CTRTextureGouraudNoZ2.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureGouraudVertexAlpha2.cpp b/source/Irrlicht/CTRTextureGouraudVertexAlpha2.cpp index 85ea2eec..e03c4e05 100644 --- a/source/Irrlicht/CTRTextureGouraudVertexAlpha2.cpp +++ b/source/Irrlicht/CTRTextureGouraudVertexAlpha2.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureGouraudWire.cpp b/source/Irrlicht/CTRTextureGouraudWire.cpp index 75cdbd31..0cbf20ed 100644 --- a/source/Irrlicht/CTRTextureGouraudWire.cpp +++ b/source/Irrlicht/CTRTextureGouraudWire.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureLightMap2_Add.cpp b/source/Irrlicht/CTRTextureLightMap2_Add.cpp index 88dea23b..9441092c 100644 --- a/source/Irrlicht/CTRTextureLightMap2_Add.cpp +++ b/source/Irrlicht/CTRTextureLightMap2_Add.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureLightMap2_M1.cpp b/source/Irrlicht/CTRTextureLightMap2_M1.cpp index d1cf9ed5..dd197ca0 100644 --- a/source/Irrlicht/CTRTextureLightMap2_M1.cpp +++ b/source/Irrlicht/CTRTextureLightMap2_M1.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureLightMap2_M2.cpp b/source/Irrlicht/CTRTextureLightMap2_M2.cpp index b32ea314..644565e2 100644 --- a/source/Irrlicht/CTRTextureLightMap2_M2.cpp +++ b/source/Irrlicht/CTRTextureLightMap2_M2.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureLightMap2_M4.cpp b/source/Irrlicht/CTRTextureLightMap2_M4.cpp index e096ec1f..ebc864d5 100644 --- a/source/Irrlicht/CTRTextureLightMap2_M4.cpp +++ b/source/Irrlicht/CTRTextureLightMap2_M4.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureLightMapGouraud2_M4.cpp b/source/Irrlicht/CTRTextureLightMapGouraud2_M4.cpp index 421e31b9..6d818920 100644 --- a/source/Irrlicht/CTRTextureLightMapGouraud2_M4.cpp +++ b/source/Irrlicht/CTRTextureLightMapGouraud2_M4.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTRTextureWire2.cpp b/source/Irrlicht/CTRTextureWire2.cpp index 2309143e..843c94b9 100644 --- a/source/Irrlicht/CTRTextureWire2.cpp +++ b/source/Irrlicht/CTRTextureWire2.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTerrainSceneNode.cpp b/source/Irrlicht/CTerrainSceneNode.cpp index 301b195f..cb8997bf 100644 --- a/source/Irrlicht/CTerrainSceneNode.cpp +++ b/source/Irrlicht/CTerrainSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -39,6 +39,7 @@ namespace scene OverrideDistanceThreshold(false), UseDefaultRotationPivot(true), ForceRecalculation(false), OldCameraPosition(core::vector3df(-99999.9f, -99999.9f, -99999.9f)), OldCameraRotation(core::vector3df(-99999.9f, -99999.9f, -99999.9f)), + OldCameraUp(core::vector3df(-99999.9f, -99999.9f, -99999.9f)), CameraMovementDelta(10.0f), CameraRotationDelta(1.0f),CameraFOVDelta(0.1f), TCoordScale1(1.0f), TCoordScale2(1.0f), FileSystem(fs) { @@ -47,11 +48,13 @@ namespace scene #endif RenderBuffer = new CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT); + RenderBuffer->setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_VERTEX); + RenderBuffer->setHardwareMappingHint(scene::EHM_DYNAMIC, scene::EBT_INDEX); if (FileSystem) FileSystem->grab(); - setAutomaticCulling( scene::EAC_OFF ); + setAutomaticCulling(scene::EAC_OFF); } @@ -72,7 +75,7 @@ namespace scene bool CTerrainSceneNode::loadHeightMap(io::IReadFile* file, video::SColor vertexColor, s32 smoothFactor) { - if( !file ) + if (!file) return false; Mesh.MeshBuffers.clear(); @@ -90,34 +93,34 @@ namespace scene // Get the dimension of the heightmap data TerrainData.Size = heightMap->getDimension().Width; - switch( TerrainData.PatchSize ) + switch (TerrainData.PatchSize) { case ETPS_9: - if( TerrainData.MaxLOD > 3 ) + if (TerrainData.MaxLOD > 3) { TerrainData.MaxLOD = 3; } break; case ETPS_17: - if( TerrainData.MaxLOD > 4 ) + if (TerrainData.MaxLOD > 4) { TerrainData.MaxLOD = 4; } break; case ETPS_33: - if( TerrainData.MaxLOD > 5 ) + if (TerrainData.MaxLOD > 5) { TerrainData.MaxLOD = 5; } break; case ETPS_65: - if( TerrainData.MaxLOD > 6 ) + if (TerrainData.MaxLOD > 6) { TerrainData.MaxLOD = 6; } break; case ETPS_129: - if( TerrainData.MaxLOD > 7 ) + if (TerrainData.MaxLOD > 7) { TerrainData.MaxLOD = 7; } @@ -152,17 +155,17 @@ namespace scene s32 index = 0; float fx=0.f; float fx2=0.f; - for( s32 x = 0; x < TerrainData.Size; ++x ) + for (s32 x = 0; x < TerrainData.Size; ++x) { float fz=0.f; float fz2=0.f; - for( s32 z = 0; z < TerrainData.Size; ++z ) + for (s32 z = 0; z < TerrainData.Size; ++z) { video::S3DVertex2TCoords& vertex= static_cast(mb->getVertexBuffer().pointer())[index++]; vertex.Normal.set(0.0f, 1.0f, 0.0f); vertex.Color = vertexColor; vertex.Pos.X = fx; - vertex.Pos.Y = (f32) heightMap->getPixel(TerrainData.Size-x,z).getLuminance(); + vertex.Pos.Y = (f32) heightMap->getPixel(TerrainData.Size-x-1,z).getLuminance(); vertex.Pos.Z = fz; vertex.TCoords.X = vertex.TCoords2.X = 1.f-fx2; @@ -189,7 +192,7 @@ namespace scene // We copy the data to the renderBuffer, after the normals have been calculated. RenderBuffer->getVertexBuffer().set_used(numVertices); - for( u32 i = 0; i < numVertices; ++i ) + for (u32 i = 0; i < numVertices; ++i) { RenderBuffer->getVertexBuffer()[i] = mb->getVertexBuffer()[i]; RenderBuffer->getVertexBuffer()[i].Pos *= TerrainData.Scale; @@ -232,7 +235,9 @@ namespace scene //! Initializes the terrain data. Loads the vertices from the heightMapFile - bool CTerrainSceneNode::loadHeightMapRAW( io::IReadFile* file, s32 bitsPerPixel, bool signedData, bool floatVals, s32 width, video::SColor vertexColor, s32 smoothFactor ) + bool CTerrainSceneNode::loadHeightMapRAW(io::IReadFile* file, + s32 bitsPerPixel, bool signedData, bool floatVals, + s32 width, video::SColor vertexColor, s32 smoothFactor) { if (!file) return false; @@ -249,7 +254,7 @@ namespace scene // Get the dimension of the heightmap data const s32 filesize = file->getSize(); if (!width) - TerrainData.Size = core::floor32(sqrtf( (f32)( filesize / bytesPerPixel ) )); + TerrainData.Size = core::floor32(sqrtf((f32)(filesize / bytesPerPixel))); else { if ((filesize-file->getPos())/bytesPerPixel>width*width) @@ -260,34 +265,34 @@ namespace scene TerrainData.Size = width; } - switch( TerrainData.PatchSize ) + switch (TerrainData.PatchSize) { case ETPS_9: - if( TerrainData.MaxLOD > 3 ) + if (TerrainData.MaxLOD > 3) { TerrainData.MaxLOD = 3; } break; case ETPS_17: - if( TerrainData.MaxLOD > 4 ) + if (TerrainData.MaxLOD > 4) { TerrainData.MaxLOD = 4; } break; case ETPS_33: - if( TerrainData.MaxLOD > 5 ) + if (TerrainData.MaxLOD > 5) { TerrainData.MaxLOD = 5; } break; case ETPS_65: - if( TerrainData.MaxLOD > 6 ) + if (TerrainData.MaxLOD > 6) { TerrainData.MaxLOD = 6; } break; case ETPS_129: - if( TerrainData.MaxLOD > 7 ) + if (TerrainData.MaxLOD > 7) { TerrainData.MaxLOD = 7; } @@ -322,17 +327,17 @@ namespace scene const f32 tdSize = 1.0f/(f32)(TerrainData.Size-1); float fx=0.f; float fx2=0.f; - for( s32 x = 0; x < TerrainData.Size; ++x ) + for (s32 x = 0; x < TerrainData.Size; ++x) { float fz=0.f; float fz2=0.f; - for( s32 z = 0; z < TerrainData.Size; ++z ) + for (s32 z = 0; z < TerrainData.Size; ++z) { bool failure=false; vertex.Pos.X = fx; if (floatVals) { - if( file->read( &vertex.Pos.Y, bytesPerPixel ) != bytesPerPixel ) + if (file->read(&vertex.Pos.Y, bytesPerPixel) != bytesPerPixel) failure=true; } else if (signedData) @@ -342,7 +347,7 @@ namespace scene case 1: { s8 val; - if( file->read( &val, bytesPerPixel ) != bytesPerPixel ) + if (file->read(&val, bytesPerPixel) != bytesPerPixel) failure=true; vertex.Pos.Y=val; } @@ -350,7 +355,7 @@ namespace scene case 2: { s16 val; - if( file->read( &val, bytesPerPixel ) != bytesPerPixel ) + if (file->read(&val, bytesPerPixel) != bytesPerPixel) failure=true; vertex.Pos.Y=val/256.f; } @@ -358,7 +363,7 @@ namespace scene case 4: { s32 val; - if( file->read( &val, bytesPerPixel ) != bytesPerPixel ) + if (file->read(&val, bytesPerPixel) != bytesPerPixel) failure=true; vertex.Pos.Y=val/16777216.f; } @@ -372,7 +377,7 @@ namespace scene case 1: { u8 val; - if( file->read( &val, bytesPerPixel ) != bytesPerPixel ) + if (file->read(&val, bytesPerPixel) != bytesPerPixel) failure=true; vertex.Pos.Y=val; } @@ -380,7 +385,7 @@ namespace scene case 2: { u16 val; - if( file->read( &val, bytesPerPixel ) != bytesPerPixel ) + if (file->read(&val, bytesPerPixel) != bytesPerPixel) failure=true; vertex.Pos.Y=val/256.f; } @@ -388,7 +393,7 @@ namespace scene case 4: { u32 val; - if( file->read( &val, bytesPerPixel ) != bytesPerPixel ) + if (file->read(&val, bytesPerPixel) != bytesPerPixel) failure=true; vertex.Pos.Y=val/16777216.f; } @@ -406,7 +411,7 @@ namespace scene vertex.TCoords.X = vertex.TCoords2.X = 1.f-fx2; vertex.TCoords.Y = vertex.TCoords2.Y = fz2; - mb->getVertexBuffer().push_back( vertex ); + mb->getVertexBuffer().push_back(vertex); ++fz; fz2 += tdSize; } @@ -417,16 +422,16 @@ namespace scene smoothTerrain(mb, smoothFactor); // calculate smooth normals for the vertices - calculateNormals( mb ); + calculateNormals(mb); // add the MeshBuffer to the mesh - Mesh.addMeshBuffer( mb ); + Mesh.addMeshBuffer(mb); const u32 vertexCount = mb->getVertexCount(); // We copy the data to the renderBuffer, after the normals have been calculated. - RenderBuffer->getVertexBuffer().set_used( vertexCount ); + RenderBuffer->getVertexBuffer().set_used(vertexCount); - for( u32 i = 0; i < vertexCount; i++ ) + for (u32 i = 0; i < vertexCount; i++) { RenderBuffer->getVertexBuffer()[i] = mb->getVertexBuffer()[i]; RenderBuffer->getVertexBuffer()[i].Pos *= TerrainData.Scale; @@ -447,11 +452,12 @@ namespace scene // Rotate the vertices of the terrain by the rotation specified. Must be done // after calculating the terrain data, so we know what the current center of the // terrain is. - setRotation( TerrainData.Rotation ); + setRotation(TerrainData.Rotation); // Pre-allocate memory for indices - RenderBuffer->getIndexBuffer().set_used( TerrainData.PatchCount * TerrainData.PatchCount * - TerrainData.CalcPatchSize * TerrainData.CalcPatchSize * 6 ); + RenderBuffer->getIndexBuffer().set_used( + TerrainData.PatchCount*TerrainData.PatchCount* + TerrainData.CalcPatchSize*TerrainData.CalcPatchSize*6); const u32 endTime = os::Timer::getTime(); @@ -488,7 +494,7 @@ namespace scene //! Sets the pivot point for rotation of this node. This is useful for the TiledTerrainManager to //! rotate all terrain tiles around a global world point. //! NOTE: The default for the RotationPivot will be the center of the individual tile. - void CTerrainSceneNode::setRotationPivot( const core::vector3df& pivot ) + void CTerrainSceneNode::setRotationPivot(const core::vector3df& pivot) { UseDefaultRotationPivot = false; TerrainData.RotationPivot = pivot; @@ -505,28 +511,27 @@ namespace scene } - //! Apply transformation changes( scale, position, rotation ) + //! Apply transformation changes(scale, position, rotation) void CTerrainSceneNode::applyTransformation() { - if( !Mesh.getMeshBufferCount() ) + if (!Mesh.getMeshBufferCount()) return; TerrainData.Position = TerrainData.Position; - video::S3DVertex2TCoords* meshVertices = (video::S3DVertex2TCoords*)Mesh.getMeshBuffer(0)->getVertices(); - s32 vtxCount = Mesh.getMeshBuffer( 0 )->getVertexCount(); + s32 vtxCount = Mesh.getMeshBuffer(0)->getVertexCount(); core::matrix4 rotMatrix; - rotMatrix.setRotationDegrees( TerrainData.Rotation ); + rotMatrix.setRotationDegrees(TerrainData.Rotation); - for( s32 i = 0; i < vtxCount; ++i ) + for (s32 i = 0; i < vtxCount; ++i) { - RenderBuffer->getVertexBuffer()[i].Pos = meshVertices[i].Pos * TerrainData.Scale + TerrainData.Position; + RenderBuffer->getVertexBuffer()[i].Pos = Mesh.getMeshBuffer(0)->getPosition(i) * TerrainData.Scale + TerrainData.Position; RenderBuffer->getVertexBuffer()[i].Pos -= TerrainData.RotationPivot; - rotMatrix.inverseRotateVect( RenderBuffer->getVertexBuffer()[i].Pos ); + rotMatrix.inverseRotateVect(RenderBuffer->getVertexBuffer()[i].Pos); RenderBuffer->getVertexBuffer()[i].Pos += TerrainData.RotationPivot; } - calculateDistanceThresholds( true ); + calculateDistanceThresholds(true); calculatePatchData(); RenderBuffer->setDirty(EBT_VERTEX); @@ -552,25 +557,32 @@ namespace scene void CTerrainSceneNode::preRenderLODCalculations() { + scene::ICameraSceneNode * camera = SceneManager->getActiveCamera(); + if(!camera) + return; + SceneManager->registerNodeForRendering(this); // Do Not call ISceneNode::OnRegisterSceneNode(), this node should have no children // Determine the camera rotation, based on the camera direction. - const core::vector3df cameraPosition = SceneManager->getActiveCamera()->getAbsolutePosition(); - const core::vector3df cameraRotation = core::line3d(cameraPosition, SceneManager->getActiveCamera()->getTarget()).getVector().getHorizontalAngle(); + const core::vector3df cameraPosition = camera->getAbsolutePosition(); + const core::vector3df cameraRotation = core::line3d(cameraPosition, camera->getTarget()).getVector().getHorizontalAngle(); + core::vector3df cameraUp = camera->getUpVector(); + cameraUp.normalize(); const f32 CameraFOV = SceneManager->getActiveCamera()->getFOV(); // Only check on the Camera's Y Rotation if (!ForceRecalculation) { - if (( fabs(cameraRotation.X - OldCameraRotation.X) < CameraRotationDelta) && - ( fabs(cameraRotation.Y - OldCameraRotation.Y) < CameraRotationDelta)) + if ((fabsf(cameraRotation.X - OldCameraRotation.X) < CameraRotationDelta) && + (fabsf(cameraRotation.Y - OldCameraRotation.Y) < CameraRotationDelta)) { if ((fabs(cameraPosition.X - OldCameraPosition.X) < CameraMovementDelta) && (fabs(cameraPosition.Y - OldCameraPosition.Y) < CameraMovementDelta) && (fabs(cameraPosition.Z - OldCameraPosition.Z) < CameraMovementDelta)) { - if (fabs(CameraFOV-OldCameraFOV) < CameraFOVDelta) + if (fabs(CameraFOV-OldCameraFOV) < CameraFOVDelta && + cameraUp.dotProduct(OldCameraUp) > (1.f - (cos(core::DEGTORAD * CameraRotationDelta)))) { return; } @@ -580,6 +592,7 @@ namespace scene OldCameraPosition = cameraPosition; OldCameraRotation = cameraRotation; + OldCameraUp = cameraUp; OldCameraFOV = CameraFOV; const SViewFrustum* frustum = SceneManager->getActiveCamera()->getViewFrustum(); @@ -587,22 +600,22 @@ namespace scene // Determine each patches LOD based on distance from camera (and whether or not they are in // the view frustum). const s32 count = TerrainData.PatchCount * TerrainData.PatchCount; - for( s32 j = 0; j < count; ++j ) + for (s32 j = 0; j < count; ++j) { - if( frustum->getBoundingBox().intersectsWithBox( TerrainData.Patches[j].BoundingBox ) ) + if (frustum->getBoundingBox().intersectsWithBox(TerrainData.Patches[j].BoundingBox)) { const f32 distance = (cameraPosition.X - TerrainData.Patches[j].Center.X) * (cameraPosition.X - TerrainData.Patches[j].Center.X) + (cameraPosition.Y - TerrainData.Patches[j].Center.Y) * (cameraPosition.Y - TerrainData.Patches[j].Center.Y) + (cameraPosition.Z - TerrainData.Patches[j].Center.Z) * (cameraPosition.Z - TerrainData.Patches[j].Center.Z); - for( s32 i = TerrainData.MaxLOD - 1; i >= 0; --i ) + for (s32 i = TerrainData.MaxLOD - 1; i >= 0; --i) { - if( distance >= TerrainData.LODDistanceThreshold[i] ) + if (distance >= TerrainData.LODDistanceThreshold[i]) { TerrainData.Patches[j].CurrentLOD = i; break; } - //else if( i == 0 ) + //else if (i == 0) { // If we've turned off a patch from viewing, because of the frustum, and now we turn around and it's // too close, we need to turn it back on, at the highest LOD. The if above doesn't catch this. @@ -620,30 +633,17 @@ namespace scene void CTerrainSceneNode::preRenderIndicesCalculations() { - switch (RenderBuffer->getIndexBuffer().getType()) - { - case video::EIT_16BIT: - preRenderIndicesCalculationsDirect((u16*)RenderBuffer->getIndexBuffer().pointer()); - break; - case video::EIT_32BIT: - preRenderIndicesCalculationsDirect((u32*)RenderBuffer->getIndexBuffer().pointer()); - break; - } - } - - - template - void CTerrainSceneNode::preRenderIndicesCalculationsDirect(INDEX_TYPE* IndexBuffer) - { + scene::IIndexBuffer& indexBuffer = RenderBuffer->getIndexBuffer(); IndicesToRender = 0; + indexBuffer.set_used(0); + s32 index = 0; // Then generate the indices for all patches that are visible. - for( s32 i = 0; i < TerrainData.PatchCount; ++i ) + for (s32 i = 0; i < TerrainData.PatchCount; ++i) { - for( s32 j = 0; j < TerrainData.PatchCount; ++j ) + for (s32 j = 0; j < TerrainData.PatchCount; ++j) { - const s32 index = i * TerrainData.PatchCount + j; - if( TerrainData.Patches[index].CurrentLOD >= 0 ) + if (TerrainData.Patches[index].CurrentLOD >= 0) { s32 x = 0; s32 z = 0; @@ -652,19 +652,20 @@ namespace scene const s32 step = 1 << TerrainData.Patches[index].CurrentLOD; // Loop through patch and generate indices - while( z < TerrainData.CalcPatchSize ) + while (z < TerrainData.CalcPatchSize) { - const s32 index11 = getIndex( j, i, index, x, z ); - const s32 index21 = getIndex( j, i, index, x + step, z ); - const s32 index12 = getIndex( j, i, index, x, z + step ); - const s32 index22 = getIndex( j, i, index, x + step, z + step ); + const s32 index11 = getIndex(j, i, index, x, z); + const s32 index21 = getIndex(j, i, index, x + step, z); + const s32 index12 = getIndex(j, i, index, x, z + step); + const s32 index22 = getIndex(j, i, index, x + step, z + step); - IndexBuffer[IndicesToRender++]= static_cast(index12); - IndexBuffer[IndicesToRender++]= static_cast(index11); - IndexBuffer[IndicesToRender++]= static_cast(index22); - IndexBuffer[IndicesToRender++]= static_cast(index22); - IndexBuffer[IndicesToRender++]= static_cast(index11); - IndexBuffer[IndicesToRender++]= static_cast(index21); + indexBuffer.push_back(index12); + indexBuffer.push_back(index11); + indexBuffer.push_back(index22); + indexBuffer.push_back(index22); + indexBuffer.push_back(index11); + indexBuffer.push_back(index21); + IndicesToRender+=6; // increment index position horizontally x += step; @@ -677,12 +678,13 @@ namespace scene } } } + ++index; } } RenderBuffer->setDirty(EBT_INDEX); - if ( DynamicSelectorUpdate && TriangleSelector ) + if (DynamicSelectorUpdate && TriangleSelector) { CTerrainTriangleSelector* selector = (CTerrainTriangleSelector*)TriangleSelector; selector->setTriangleData(this, -1); @@ -709,7 +711,7 @@ namespace scene // For use with geomorphing driver->drawMeshBuffer(RenderBuffer); - RenderBuffer->getIndexBuffer().set_used( RenderBuffer->getIndexBuffer().allocated_size() ); + RenderBuffer->getIndexBuffer().set_used(RenderBuffer->getIndexBuffer().allocated_size()); // for debug purposes only: if (DebugDataVisible) @@ -718,15 +720,15 @@ namespace scene m.Lighting = false; driver->setMaterial(m); if (DebugDataVisible & scene::EDS_BBOX) - driver->draw3DBox( TerrainData.BoundingBox, video::SColor(255,255,255,255)); + driver->draw3DBox(TerrainData.BoundingBox, video::SColor(255,255,255,255)); const s32 count = TerrainData.PatchCount * TerrainData.PatchCount; s32 visible = 0; if (DebugDataVisible & scene::EDS_BBOX_BUFFERS) { - for( s32 j = 0; j < count; ++j ) + for (s32 j = 0; j < count; ++j) { - driver->draw3DBox( TerrainData.Patches[j].BoundingBox, video::SColor(255,255,0,0)); + driver->draw3DBox(TerrainData.Patches[j].BoundingBox, video::SColor(255,255,0,0)); visible += (TerrainData.Patches[j].CurrentLOD >= 0); } } @@ -737,9 +739,9 @@ namespace scene "__debugnormal", 0xFFECEC00, 0xFF999900, 4, 8, 1.f, 0.6f, 0.05f, 0.3f); - if ( 0 == arrow ) + if (0 == arrow) { - arrow = SceneManager->getMesh( "__debugnormal" ); + arrow = SceneManager->getMesh("__debugnormal"); } IMesh *mesh = arrow->getMesh(0); @@ -749,7 +751,7 @@ namespace scene // draw normals driver->setTransform(video::ETS_WORLD, core::IdentityMatrix); - for ( u32 i=0; i != RenderBuffer->getVertexCount(); ++i ) + for (u32 i=0; i != RenderBuffer->getVertexCount(); ++i) { const core::vector3df& v = RenderBuffer->getNormal(i); // align to v->Normal @@ -768,7 +770,7 @@ namespace scene m2=AbsoluteTransformation*m2; driver->setTransform(video::ETS_WORLD, m2 ); - for ( u32 a = 0; a != mesh->getMeshBufferCount(); ++a ) + for (u32 a = 0; a != mesh->getMeshBufferCount(); ++a) driver->drawMeshBuffer(mesh->getMeshBuffer(a)); } driver->setTransform(video::ETS_WORLD, AbsoluteTransformation); @@ -797,7 +799,7 @@ namespace scene //! Return the bounding box of a patch - const core::aabbox3d& CTerrainSceneNode::getBoundingBox( s32 patchX, s32 patchZ ) const + const core::aabbox3d& CTerrainSceneNode::getBoundingBox(s32 patchX, s32 patchZ) const { return TerrainData.Patches[patchX * TerrainData.PatchCount + patchZ].BoundingBox; } @@ -820,7 +822,7 @@ namespace scene for (u32 n=0; ngetIndexBuffer().getType() ); + mb.getIndexBuffer().setType(RenderBuffer->getIndexBuffer().getType()); // calculate the step we take for all patches, since LOD is the same const s32 step = 1 << LOD; @@ -837,17 +839,17 @@ namespace scene // Loop through patch and generate indices while (z < TerrainData.CalcPatchSize) { - const s32 index11 = getIndex( j, i, index, x, z ); - const s32 index21 = getIndex( j, i, index, x + step, z ); - const s32 index12 = getIndex( j, i, index, x, z + step ); - const s32 index22 = getIndex( j, i, index, x + step, z + step ); + const s32 index11 = getIndex(j, i, index, x, z); + const s32 index21 = getIndex(j, i, index, x + step, z); + const s32 index12 = getIndex(j, i, index, x, z + step); + const s32 index22 = getIndex(j, i, index, x + step, z + step); - mb.getIndexBuffer().push_back( index12 ); - mb.getIndexBuffer().push_back( index11 ); - mb.getIndexBuffer().push_back( index22 ); - mb.getIndexBuffer().push_back( index22 ); - mb.getIndexBuffer().push_back( index11 ); - mb.getIndexBuffer().push_back( index21 ); + mb.getIndexBuffer().push_back(index12); + mb.getIndexBuffer().push_back(index11); + mb.getIndexBuffer().push_back(index22); + mb.getIndexBuffer().push_back(index22); + mb.getIndexBuffer().push_back(index11); + mb.getIndexBuffer().push_back(index21); // increment index position horizontally x += step; @@ -874,17 +876,18 @@ namespace scene //! \return: Number if indices put into the buffer. s32 CTerrainSceneNode::getIndicesForPatch(core::array& indices, s32 patchX, s32 patchZ, s32 LOD) { - if ( patchX < 0 || patchX > TerrainData.PatchCount - 1 || patchZ < 0 || patchZ > TerrainData.PatchCount - 1 ) + if (patchX < 0 || patchX > TerrainData.PatchCount-1 || + patchZ < 0 || patchZ > TerrainData.PatchCount-1) return -1; - if ( LOD < -1 || LOD > TerrainData.MaxLOD - 1 ) + if (LOD < -1 || LOD > TerrainData.MaxLOD - 1) return -1; core::array cLODs; bool setLODs = false; // If LOD of -1 was passed in, use the CurrentLOD of the patch specified - if ( LOD == -1 ) + if (LOD == -1) { LOD = TerrainData.Patches[patchX * TerrainData.PatchCount + patchZ].CurrentLOD; } @@ -895,7 +898,7 @@ namespace scene setLODs = true; } - if ( LOD < 0 ) + if (LOD < 0) return -2; // Patch not visible, don't generate indices. // calculate the step we take for this LOD @@ -913,10 +916,10 @@ namespace scene s32 rv=0; while (z TerrainData.MaxLOD - 1 ) + if (LOD < 0 || LOD > TerrainData.MaxLOD - 1) return false; TerrainData.LODDistanceThreshold[LOD] = newDistance * newDistance; @@ -1007,7 +1010,7 @@ namespace scene if (RenderBuffer->getVertexType()==video::EVT_2TCOORDS) { - if ( resolution2 == 0 ) + if (resolution2 == 0) { ((video::S3DVertex2TCoords&)RenderBuffer->getVertexBuffer()[index]).TCoords2 = RenderBuffer->getVertexBuffer()[index].TCoords; } @@ -1039,47 +1042,47 @@ namespace scene { if (TerrainData.Patches[PatchIndex].Top && TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Top->CurrentLOD && - (vX % ( 1 << TerrainData.Patches[PatchIndex].Top->CurrentLOD)) != 0 ) + (vX % (1 << TerrainData.Patches[PatchIndex].Top->CurrentLOD)) != 0 ) { - vX -= vX % ( 1 << TerrainData.Patches[PatchIndex].Top->CurrentLOD ); + vX -= vX % (1 << TerrainData.Patches[PatchIndex].Top->CurrentLOD); } } else - if ( vZ == (u32)TerrainData.CalcPatchSize ) // bottom border + if (vZ == (u32)TerrainData.CalcPatchSize) // bottom border { if (TerrainData.Patches[PatchIndex].Bottom && TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Bottom->CurrentLOD && - (vX % ( 1 << TerrainData.Patches[PatchIndex].Bottom->CurrentLOD)) != 0) + (vX % (1 << TerrainData.Patches[PatchIndex].Bottom->CurrentLOD)) != 0) { - vX -= vX % ( 1 << TerrainData.Patches[PatchIndex].Bottom->CurrentLOD ); + vX -= vX % (1 << TerrainData.Patches[PatchIndex].Bottom->CurrentLOD); } } // left border - if ( vX == 0 ) + if (vX == 0) { if (TerrainData.Patches[PatchIndex].Left && TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Left->CurrentLOD && - ( vZ % ( 1 << TerrainData.Patches[PatchIndex].Left->CurrentLOD ) ) != 0) + (vZ % (1 << TerrainData.Patches[PatchIndex].Left->CurrentLOD)) != 0) { - vZ -= vZ % ( 1 << TerrainData.Patches[PatchIndex].Left->CurrentLOD ); + vZ -= vZ % (1 << TerrainData.Patches[PatchIndex].Left->CurrentLOD); } } else - if ( vX == (u32)TerrainData.CalcPatchSize ) // right border + if (vX == (u32)TerrainData.CalcPatchSize) // right border { if (TerrainData.Patches[PatchIndex].Right && TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Right->CurrentLOD && - ( vZ % ( 1 << TerrainData.Patches[PatchIndex].Right->CurrentLOD ) ) != 0) + (vZ % (1 << TerrainData.Patches[PatchIndex].Right->CurrentLOD)) != 0) { - vZ -= vZ % ( 1 << TerrainData.Patches[PatchIndex].Right->CurrentLOD ); + vZ -= vZ % (1 << TerrainData.Patches[PatchIndex].Right->CurrentLOD); } } - if ( vZ >= (u32)TerrainData.PatchSize ) + if (vZ >= (u32)TerrainData.PatchSize) vZ = TerrainData.CalcPatchSize; - if ( vX >= (u32)TerrainData.PatchSize ) + if (vX >= (u32)TerrainData.PatchSize) vX = TerrainData.CalcPatchSize; return (vZ + ((TerrainData.CalcPatchSize) * PatchZ)) * TerrainData.Size + @@ -1110,7 +1113,7 @@ namespace scene //! calculate smooth normals - void CTerrainSceneNode::calculateNormals( CDynamicMeshBuffer* mb ) + void CTerrainSceneNode::calculateNormals(CDynamicMeshBuffer* mb) { s32 count; core::vector3df a, b, c, t; @@ -1224,7 +1227,7 @@ namespace scene } else { - normal.set( 0.0f, 1.0f, 0.0f ); + normal.set(0.0f, 1.0f, 0.0f); } mb->getVertexBuffer()[x * TerrainData.Size + z].Normal = normal; @@ -1236,7 +1239,7 @@ namespace scene //! create patches, stuff that needs to be done only once for patches goes here. void CTerrainSceneNode::createPatches() { - TerrainData.PatchCount = (TerrainData.Size - 1) / ( TerrainData.CalcPatchSize ); + TerrainData.PatchCount = (TerrainData.Size - 1) / (TerrainData.CalcPatchSize); if (TerrainData.Patches) delete [] TerrainData.Patches; @@ -1251,9 +1254,9 @@ namespace scene // Reset the Terrains Bounding Box for re-calculation TerrainData.BoundingBox = core::aabbox3df(999999.9f, 999999.9f, 999999.9f, -999999.9f, -999999.9f, -999999.9f); - for( s32 x = 0; x < TerrainData.PatchCount; ++x ) + for (s32 x = 0; x < TerrainData.PatchCount; ++x) { - for( s32 z = 0; z < TerrainData.PatchCount; ++z ) + for (s32 z = 0; z < TerrainData.PatchCount; ++z) { const s32 index = x * TerrainData.PatchCount + z; TerrainData.Patches[index].CurrentLOD = 0; @@ -1262,38 +1265,38 @@ namespace scene TerrainData.Patches[index].BoundingBox = core::aabbox3df(999999.9f, 999999.9f, 999999.9f, -999999.9f, -999999.9f, -999999.9f); - for( s32 xx = x*(TerrainData.CalcPatchSize); xx <= ( x + 1 ) * TerrainData.CalcPatchSize; ++xx ) - for( s32 zz = z*(TerrainData.CalcPatchSize); zz <= ( z + 1 ) * TerrainData.CalcPatchSize; ++zz ) - TerrainData.Patches[index].BoundingBox.addInternalPoint( RenderBuffer->getVertexBuffer()[xx * TerrainData.Size + zz].Pos ); + for (s32 xx = x*(TerrainData.CalcPatchSize); xx <= (x + 1) * TerrainData.CalcPatchSize; ++xx) + for (s32 zz = z*(TerrainData.CalcPatchSize); zz <= (z + 1) * TerrainData.CalcPatchSize; ++zz) + TerrainData.Patches[index].BoundingBox.addInternalPoint(RenderBuffer->getVertexBuffer()[xx * TerrainData.Size + zz].Pos); // Reconfigure the bounding box of the terrain as a whole - TerrainData.BoundingBox.addInternalBox( TerrainData.Patches[index].BoundingBox ); + TerrainData.BoundingBox.addInternalBox(TerrainData.Patches[index].BoundingBox); // get center of Patch TerrainData.Patches[index].Center = TerrainData.Patches[index].BoundingBox.getCenter(); // Assign Neighbours // Top - if( x > 0 ) + if (x > 0) TerrainData.Patches[index].Top = &TerrainData.Patches[(x-1) * TerrainData.PatchCount + z]; else TerrainData.Patches[index].Top = 0; // Bottom - if( x < TerrainData.PatchCount - 1 ) + if (x < TerrainData.PatchCount - 1) TerrainData.Patches[index].Bottom = &TerrainData.Patches[(x+1) * TerrainData.PatchCount + z]; else TerrainData.Patches[index].Bottom = 0; // Left - if( z > 0 ) + if (z > 0) TerrainData.Patches[index].Left = &TerrainData.Patches[x * TerrainData.PatchCount + z - 1]; else TerrainData.Patches[index].Left = 0; // Right - if( z < TerrainData.PatchCount - 1 ) + if (z < TerrainData.PatchCount - 1) TerrainData.Patches[index].Right = &TerrainData.Patches[x * TerrainData.PatchCount + z + 1]; else TerrainData.Patches[index].Right = 0; @@ -1304,7 +1307,7 @@ namespace scene TerrainData.Center = TerrainData.BoundingBox.getCenter(); // if the default rotation pivot is still being used, update it. - if( UseDefaultRotationPivot ) + if (UseDefaultRotationPivot) { TerrainData.RotationPivot = TerrainData.Center; } @@ -1356,28 +1359,29 @@ namespace scene f32 height = -999999.9f; core::matrix4 rotMatrix; - rotMatrix.setRotationDegrees( TerrainData.Rotation ); - core::vector3df pos( x, 0.0f, z ); - rotMatrix.rotateVect( pos ); + rotMatrix.setRotationDegrees(TerrainData.Rotation); + core::vector3df pos(x, 0.0f, z); + rotMatrix.rotateVect(pos); pos -= TerrainData.Position; pos /= TerrainData.Scale; - s32 X(core::floor32( pos.X )); - s32 Z(core::floor32( pos.Z )); + s32 X(core::floor32(pos.X)); + s32 Z(core::floor32(pos.Z)); - if( X >= 0 && X < TerrainData.Size && Z >= 0 && Z < TerrainData.Size ) + if (X >= 0 && X < TerrainData.Size-1 && + Z >= 0 && Z < TerrainData.Size-1) { const video::S3DVertex2TCoords* Vertices = (const video::S3DVertex2TCoords*)Mesh.getMeshBuffer(0)->getVertices(); const core::vector3df& a = Vertices[X * TerrainData.Size + Z].Pos; const core::vector3df& b = Vertices[(X + 1) * TerrainData.Size + Z].Pos; - const core::vector3df& c = Vertices[X * TerrainData.Size + ( Z + 1 )].Pos; - const core::vector3df& d = Vertices[(X + 1) * TerrainData.Size + ( Z + 1 )].Pos; + const core::vector3df& c = Vertices[X * TerrainData.Size + (Z + 1)].Pos; + const core::vector3df& d = Vertices[(X + 1) * TerrainData.Size + (Z + 1)].Pos; // offset from integer position const f32 dx = pos.X - X; const f32 dz = pos.Z - Z; - if( dx > dz ) + if (dx > dz) height = a.Y + (d.Y - b.Y)*dz + (b.Y - a.Y)*dx; else height = a.Y + (d.Y - c.Y)*dx + (c.Y - a.Y)*dz; diff --git a/source/Irrlicht/CTerrainSceneNode.h b/source/Irrlicht/CTerrainSceneNode.h index 0c262cea..6d7ce011 100644 --- a/source/Irrlicht/CTerrainSceneNode.h +++ b/source/Irrlicht/CTerrainSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -278,9 +278,6 @@ namespace scene virtual void preRenderLODCalculations(); virtual void preRenderIndicesCalculations(); - template - void preRenderIndicesCalculationsDirect(INDEX_TYPE* IndexBuffer); - //! get indices when generating index data for patches at varying levels of detail. u32 getIndex(const s32 PatchX, const s32 PatchZ, const s32 PatchIndex, u32 vX, u32 vZ) const; @@ -323,6 +320,7 @@ namespace scene core::vector3df OldCameraPosition; core::vector3df OldCameraRotation; + core::vector3df OldCameraUp; f32 OldCameraFOV; f32 CameraMovementDelta; f32 CameraRotationDelta; diff --git a/source/Irrlicht/CTerrainTriangleSelector.cpp b/source/Irrlicht/CTerrainTriangleSelector.cpp index fedeee1d..54a83b63 100644 --- a/source/Irrlicht/CTerrainTriangleSelector.cpp +++ b/source/Irrlicht/CTerrainTriangleSelector.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -76,7 +76,7 @@ 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 + s32& outTriangleCount, const core::matrix4* transform) const { s32 count = TrianglePatches.TotalTriangles; diff --git a/source/Irrlicht/CTerrainTriangleSelector.h b/source/Irrlicht/CTerrainTriangleSelector.h index 013818b3..5840f3f4 100644 --- a/source/Irrlicht/CTerrainTriangleSelector.h +++ b/source/Irrlicht/CTerrainTriangleSelector.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -52,6 +52,11 @@ public: //! Returns amount of all available triangles in this selector virtual s32 getTriangleCount() const; + //! Return the scene node associated with a given triangle. + /** ITerrainSceneNode is an ISceneNode, we just don't know it yet. */ + virtual const ISceneNode* getSceneNodeForTriangle(u32 triangleIndex) const + { return (ISceneNode*)SceneNode; } + private: friend class CTerrainSceneNode; diff --git a/source/Irrlicht/CTextSceneNode.cpp b/source/Irrlicht/CTextSceneNode.cpp index a7eb0fbe..242541ef 100644 --- a/source/Irrlicht/CTextSceneNode.cpp +++ b/source/Irrlicht/CTextSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -24,7 +24,7 @@ CTextSceneNode::CTextSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, video::SColor color) : ITextSceneNode(parent, mgr, id, position), Text(text), Color(color), Font(font), Coll(coll) - + { #ifdef _DEBUG setDebugName("CTextSceneNode"); @@ -57,7 +57,7 @@ void CTextSceneNode::render() if (!Font || !Coll) return; - core::position2d pos = Coll->getScreenCoordinatesFrom3DPosition(getAbsolutePosition(), + core::position2d pos = Coll->getScreenCoordinatesFrom3DPosition(getAbsolutePosition(), SceneManager->getActiveCamera()); core::rect r(pos, core::dimension2d(1,1)); @@ -89,7 +89,7 @@ void CTextSceneNode::setTextColor(video::SColor color) //! constructor -CBillboardTextSceneNode::CBillboardTextSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, +CBillboardTextSceneNode::CBillboardTextSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 id, gui::IGUIFont* font,const wchar_t* text, const core::vector3df& position, const core::dimension2d& size, video::SColor colorTop,video::SColor shade_bottom ) @@ -104,7 +104,7 @@ CBillboardTextSceneNode::CBillboardTextSceneNode(ISceneNode* parent, ISceneManag Material.MaterialTypeParam = 1.f / 255.f; Material.BackfaceCulling = false; Material.Lighting = false; - Material.ZBuffer = true; + Material.ZBuffer = video::ECFN_LESSEQUAL; Material.ZWriteEnable = false; if (font) @@ -199,7 +199,7 @@ void CBillboardTextSceneNode::setText(const wchar_t* text) tex[1] = (s.LowerRightCorner.Y * dim[1]) + 0.5f*dim[1]; tex[2] = (s.UpperLeftCorner.Y * dim[1]) - 0.5f*dim[1]; tex[3] = (s.UpperLeftCorner.X * dim[0]) - 0.5f*dim[0]; - + buf->Vertices[firstVert+0].TCoords.set(tex[0], tex[1]); buf->Vertices[firstVert+1].TCoords.set(tex[0], tex[2]); buf->Vertices[firstVert+2].TCoords.set(tex[3], tex[2]); @@ -218,7 +218,7 @@ void CBillboardTextSceneNode::setText(const wchar_t* text) buf->Indices[firstInd+5] = (u16)firstVert+2; wchar_t *tp = 0; - if (i>0) + if (i>0) tp = &Text[i-1]; info.Width = (f32)s.getWidth(); diff --git a/source/Irrlicht/CTextSceneNode.h b/source/Irrlicht/CTextSceneNode.h index 8700a9c9..8588dc78 100644 --- a/source/Irrlicht/CTextSceneNode.h +++ b/source/Irrlicht/CTextSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTimer.h b/source/Irrlicht/CTimer.h index a106c508..3e4d4e74 100644 --- a/source/Irrlicht/CTimer.h +++ b/source/Irrlicht/CTimer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTriangleBBSelector.cpp b/source/Irrlicht/CTriangleBBSelector.cpp index 954472e3..034e19d0 100644 --- a/source/Irrlicht/CTriangleBBSelector.cpp +++ b/source/Irrlicht/CTriangleBBSelector.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTriangleBBSelector.h b/source/Irrlicht/CTriangleBBSelector.h index f30b5eb7..db85286e 100644 --- a/source/Irrlicht/CTriangleBBSelector.h +++ b/source/Irrlicht/CTriangleBBSelector.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CTriangleSelector.cpp b/source/Irrlicht/CTriangleSelector.cpp index 635bc32e..9a4d8083 100644 --- a/source/Irrlicht/CTriangleSelector.cpp +++ b/source/Irrlicht/CTriangleSelector.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -103,7 +103,7 @@ void CTriangleSelector::getTriangles(core::triangle3df* triangles, const core::matrix4* transform) const { // return all triangles - getTriangles(triangles, arraySize, outTriangleCount, transform); + return getTriangles(triangles, arraySize, outTriangleCount, transform); } @@ -114,7 +114,7 @@ void CTriangleSelector::getTriangles(core::triangle3df* triangles, const core::matrix4* transform) const { // return all triangles - getTriangles(triangles, arraySize, outTriangleCount, transform); + return getTriangles(triangles, arraySize, outTriangleCount, transform); } diff --git a/source/Irrlicht/CTriangleSelector.h b/source/Irrlicht/CTriangleSelector.h index ed8ebc7b..6f5d8a84 100644 --- a/source/Irrlicht/CTriangleSelector.h +++ b/source/Irrlicht/CTriangleSelector.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -46,6 +46,9 @@ public: //! Returns amount of all available triangles in this selector virtual s32 getTriangleCount() const; + //! Return the scene node associated with a given triangle. + virtual const ISceneNode* getSceneNodeForTriangle(u32 triangleIndex) const { return SceneNode; } + protected: const ISceneNode* SceneNode; diff --git a/source/Irrlicht/CVideoModeList.cpp b/source/Irrlicht/CVideoModeList.cpp index 4784eb59..c4ea7785 100644 --- a/source/Irrlicht/CVideoModeList.cpp +++ b/source/Irrlicht/CVideoModeList.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -18,11 +18,11 @@ CVideoModeList::CVideoModeList() #endif Desktop.depth = 0; - Desktop.size = core::dimension2d(0,0); + Desktop.size = core::dimension2d(0,0); } -void CVideoModeList::setDesktop(s32 desktopDepth, const core::dimension2d& desktopSize) +void CVideoModeList::setDesktop(s32 desktopDepth, const core::dimension2d& desktopSize) { Desktop.depth = desktopDepth; Desktop.size = desktopSize; @@ -37,18 +37,18 @@ s32 CVideoModeList::getVideoModeCount() const //! Returns the screen size of a video mode in pixels. -core::dimension2d CVideoModeList::getVideoModeResolution(s32 modeNumber) const +core::dimension2d CVideoModeList::getVideoModeResolution(s32 modeNumber) const { if (modeNumber < 0 || modeNumber > (s32)VideoModes.size()) - return core::dimension2d(0,0); + return core::dimension2d(0,0); return VideoModes[modeNumber].size; } -core::dimension2d CVideoModeList::getVideoModeResolution( - const core::dimension2d& minSize, - const core::dimension2d& maxSize) const +core::dimension2d CVideoModeList::getVideoModeResolution( + const core::dimension2d& minSize, + const core::dimension2d& maxSize) const { u32 best=VideoModes.size(); // if only one or no mode @@ -96,7 +96,7 @@ s32 CVideoModeList::getVideoModeDepth(s32 modeNumber) const //! Returns current desktop screen resolution. -const core::dimension2d& CVideoModeList::getDesktopResolution() const +const core::dimension2d& CVideoModeList::getDesktopResolution() const { return Desktop.size; } @@ -110,7 +110,7 @@ s32 CVideoModeList::getDesktopDepth() const //! adds a new mode to the list -void CVideoModeList::addMode(const core::dimension2d& size, s32 depth) +void CVideoModeList::addMode(const core::dimension2d& size, s32 depth) { SVideoMode m; m.depth = depth; diff --git a/source/Irrlicht/CVideoModeList.h b/source/Irrlicht/CVideoModeList.h index e670e697..1b462d74 100644 --- a/source/Irrlicht/CVideoModeList.h +++ b/source/Irrlicht/CVideoModeList.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -25,30 +25,30 @@ namespace video virtual s32 getVideoModeCount() const; //! Returns the screen size of a video mode in pixels. - virtual core::dimension2d getVideoModeResolution(s32 modeNumber) const; + virtual core::dimension2d getVideoModeResolution(s32 modeNumber) const; //! Returns the screen size of an optimal video mode in pixels. - virtual core::dimension2d getVideoModeResolution(const core::dimension2d& minSize, const core::dimension2d& maxSize) const; + virtual core::dimension2d getVideoModeResolution(const core::dimension2d& minSize, const core::dimension2d& maxSize) const; //! Returns the pixel depth of a video mode in bits. virtual s32 getVideoModeDepth(s32 modeNumber) const; //! Returns current desktop screen resolution. - virtual const core::dimension2d& getDesktopResolution() const; + virtual const core::dimension2d& getDesktopResolution() const; //! Returns the pixel depth of a video mode in bits. virtual s32 getDesktopDepth() const; //! adds a new mode to the list - void addMode(const core::dimension2d& size, s32 depth); + void addMode(const core::dimension2d& size, s32 depth); - void setDesktop(s32 desktopDepth, const core::dimension2d& desktopSize); + void setDesktop(s32 desktopDepth, const core::dimension2d& desktopSize); private: struct SVideoMode { - core::dimension2d size; + core::dimension2d size; s32 depth; bool operator==(const SVideoMode& other) const @@ -59,9 +59,9 @@ namespace video bool operator <(const SVideoMode& other) const { return (size.Width < other.size.Width || - (size.Width == other.size.Width && + (size.Width == other.size.Width && size.Height < other.size.Height) || - (size.Width == other.size.Width && + (size.Width == other.size.Width && size.Height == other.size.Height && depth < other.depth)); } diff --git a/source/Irrlicht/CVolumeLightSceneNode.cpp b/source/Irrlicht/CVolumeLightSceneNode.cpp index 10396f52..866c3c69 100644 --- a/source/Irrlicht/CVolumeLightSceneNode.cpp +++ b/source/Irrlicht/CVolumeLightSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // diff --git a/source/Irrlicht/CVolumeLightSceneNode.h b/source/Irrlicht/CVolumeLightSceneNode.h index 68ade2b9..4f759e79 100644 --- a/source/Irrlicht/CVolumeLightSceneNode.h +++ b/source/Irrlicht/CVolumeLightSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // diff --git a/source/Irrlicht/CWaterSurfaceSceneNode.cpp b/source/Irrlicht/CWaterSurfaceSceneNode.cpp index c83a2e34..e03cc9bd 100644 --- a/source/Irrlicht/CWaterSurfaceSceneNode.cpp +++ b/source/Irrlicht/CWaterSurfaceSceneNode.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CWaterSurfaceSceneNode.h b/source/Irrlicht/CWaterSurfaceSceneNode.h index 6ccb053c..05c4714e 100644 --- a/source/Irrlicht/CWaterSurfaceSceneNode.h +++ b/source/Irrlicht/CWaterSurfaceSceneNode.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CWriteFile.cpp b/source/Irrlicht/CWriteFile.cpp index 1dd1f612..dc29e162 100644 --- a/source/Irrlicht/CWriteFile.cpp +++ b/source/Irrlicht/CWriteFile.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CWriteFile.h b/source/Irrlicht/CWriteFile.h index e8dae3a4..f1add8ed 100644 --- a/source/Irrlicht/CWriteFile.h +++ b/source/Irrlicht/CWriteFile.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CXMLReader.cpp b/source/Irrlicht/CXMLReader.cpp index 6de37ab3..dac2c7ac 100644 --- a/source/Irrlicht/CXMLReader.cpp +++ b/source/Irrlicht/CXMLReader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CXMLReader.h b/source/Irrlicht/CXMLReader.h index 67005ff9..62c1b908 100644 --- a/source/Irrlicht/CXMLReader.h +++ b/source/Irrlicht/CXMLReader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CXMLReaderImpl.h b/source/Irrlicht/CXMLReaderImpl.h index 11594ae8..781b45cd 100644 --- a/source/Irrlicht/CXMLReaderImpl.h +++ b/source/Irrlicht/CXMLReaderImpl.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine" and the "irrXML" project. // For conditions of distribution and use, see copyright notice in irrlicht.h and/or irrXML.h diff --git a/source/Irrlicht/CXMLWriter.cpp b/source/Irrlicht/CXMLWriter.cpp index ffc7c4e2..43dea14a 100644 --- a/source/Irrlicht/CXMLWriter.cpp +++ b/source/Irrlicht/CXMLWriter.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CXMLWriter.h b/source/Irrlicht/CXMLWriter.h index f3667e05..0921d366 100644 --- a/source/Irrlicht/CXMLWriter.h +++ b/source/Irrlicht/CXMLWriter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CXMeshFileLoader.cpp b/source/Irrlicht/CXMeshFileLoader.cpp index 55087d56..dff65509 100644 --- a/source/Irrlicht/CXMeshFileLoader.cpp +++ b/source/Irrlicht/CXMeshFileLoader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -28,9 +28,9 @@ namespace scene //! Constructor CXMeshFileLoader::CXMeshFileLoader(scene::ISceneManager* smgr, io::IFileSystem* fs) -: SceneManager(smgr), FileSystem(fs), AnimatedMesh(0), MajorVersion(0), - MinorVersion(0), BinaryFormat(false), BinaryNumCount(0), Buffer(0), - P(0), End(0), FloatSize(0), CurFrame(0) +: SceneManager(smgr), FileSystem(fs), AllJoints(0), AnimatedMesh(0), + Buffer(0), P(0), End(0), BinaryNumCount(0), Line(0), + CurFrame(0), MajorVersion(0), MinorVersion(0), BinaryFormat(false), FloatSize(0) { #ifdef _DEBUG setDebugName("CXMeshFileLoader"); @@ -116,7 +116,13 @@ bool CXMeshFileLoader::load(io::IReadFile* file) // default material if nothing loaded if (!mesh->Materials.size()) + { mesh->Materials.push_back(video::SMaterial()); + mesh->Materials[0].DiffuseColor.set(0xff777777); + mesh->Materials[0].Shininess=0.f; + mesh->Materials[0].SpecularColor.set(0xff777777); + mesh->Materials[0].EmissiveColor.set(0xff000000); + } u32 i; @@ -139,6 +145,13 @@ bool CXMeshFileLoader::load(io::IReadFile* file) } } + if (!mesh->FaceMaterialIndices.size()) + { + mesh->FaceMaterialIndices.set_used(mesh->Indices.size() / 3); + for (i=0; iFaceMaterialIndices.size(); ++i) + mesh->FaceMaterialIndices[i]=0; + } + if (!mesh->HasVertexColors) { for (u32 j=0;jFaceMaterialIndices.size();++j) @@ -435,7 +448,8 @@ bool CXMeshFileLoader::readFileIntoMemory(io::IReadFile* file) P = &Buffer[16]; readUntilEndOfLine(); - FilePath = stripPathFromString(file->getFileName(),true); + FilePath = FileSystem->getFileDir(file->getFileName()); + FilePath += '/'; return true; } @@ -479,9 +493,6 @@ bool CXMeshFileLoader::parseDataObject() // some meshes have no frames at all //CurFrame = AnimatedMesh->createJoint(0); - //CurFrame->Meshes.push_back(SXMesh()); - //return parseDataObjectMesh(CurFrame->Meshes.getLast()); - SXMesh *mesh=new SXMesh; //mesh->Buffer=AnimatedMesh->createBuffer(); @@ -770,7 +781,7 @@ bool CXMeshFileLoader::parseDataObjectMesh(SXMesh &mesh) polygonfaces.set_used(fcnt); u32 triangles = (fcnt-2); mesh.Indices.set_used(mesh.Indices.size() + ((triangles-1)*3)); - mesh.IndexCountPerFace[k] = triangles * 3; + mesh.IndexCountPerFace[k] = (u16)(triangles * 3); for (u32 f=0; fexistFile(TextureFileName.c_str())) - material.setTexture(textureLayer, SceneManager->getVideoDriver()->getTexture (TextureFileName.c_str())); + if (FileSystem->existFile(TextureFileName)) + material.setTexture(textureLayer, SceneManager->getVideoDriver()->getTexture(TextureFileName)); // mesh path else { - TextureFileName=FilePath + stripPathFromString(TextureFileName,false); - if (FileSystem->existFile(TextureFileName.c_str())) - material.setTexture(textureLayer, SceneManager->getVideoDriver()->getTexture(TextureFileName.c_str())); + TextureFileName=FilePath + FileSystem->getFileBasename(TextureFileName); + if (FileSystem->existFile(TextureFileName)) + material.setTexture(textureLayer, SceneManager->getVideoDriver()->getTexture(TextureFileName)); // working directory else - material.setTexture(textureLayer, SceneManager->getVideoDriver()->getTexture(stripPathFromString(TextureFileName,false).c_str())); + material.setTexture(textureLayer, SceneManager->getVideoDriver()->getTexture(FileSystem->getFileBasename(TextureFileName))); } ++textureLayer; if (textureLayer==2) @@ -1538,17 +1552,17 @@ bool CXMeshFileLoader::parseDataObjectMaterial(video::SMaterial& material) return false; // original name - if (FileSystem->existFile(TextureFileName.c_str())) - material.setTexture(1, SceneManager->getVideoDriver()->getTexture (TextureFileName.c_str())); + if (FileSystem->existFile(TextureFileName)) + material.setTexture(1, SceneManager->getVideoDriver()->getTexture(TextureFileName)); // mesh path else { - TextureFileName=FilePath + stripPathFromString(TextureFileName,false); - if (FileSystem->existFile(TextureFileName.c_str())) - material.setTexture(1, SceneManager->getVideoDriver()->getTexture(TextureFileName.c_str())); + TextureFileName=FilePath + FileSystem->getFileBasename(TextureFileName); + if (FileSystem->existFile(TextureFileName)) + material.setTexture(1, SceneManager->getVideoDriver()->getTexture(TextureFileName)); // working directory else - material.setTexture(1, SceneManager->getVideoDriver()->getTexture(stripPathFromString(TextureFileName,false).c_str())); + material.setTexture(1, SceneManager->getVideoDriver()->getTexture(FileSystem->getFileBasename(TextureFileName))); } if (textureLayer==1) ++textureLayer; @@ -2377,29 +2391,6 @@ bool CXMeshFileLoader::readMatrix(core::matrix4& mat) } -core::stringc CXMeshFileLoader::stripPathFromString(core::stringc string, bool returnPath) -{ - s32 slashIndex=string.findLast('/'); // forward slash - s32 backSlash=string.findLast('\\'); // back slash - - if (backSlash>slashIndex) - slashIndex=backSlash; - - if (slashIndex==-1)//no slashes found - { - if (returnPath) - return core::stringc(); //no path to return - else - return string; - } - - if (returnPath) - return string.subString(0, slashIndex + 1); - else - return string.subString(slashIndex+1, string.size() - (slashIndex+1)); -} - - } // end namespace scene } // end namespace irr diff --git a/source/Irrlicht/CXMeshFileLoader.h b/source/Irrlicht/CXMeshFileLoader.h index 77af6177..b0c2d608 100644 --- a/source/Irrlicht/CXMeshFileLoader.h +++ b/source/Irrlicht/CXMeshFileLoader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -62,7 +62,7 @@ public: u32 MaxSkinWeightsPerFace; u32 BoneCount; - core::array< u32 > IndexCountPerFace; // default 3, but could be more + core::array IndexCountPerFace; // default 3, but could be more core::array Buffers; @@ -75,13 +75,13 @@ public: core::array Materials; // material array + core::array WeightJoint; + core::array WeightNum; + s32 AttachedJointID; bool HasSkinning; bool HasVertexColors; - - core::array WeightJoint; - core::array WeightNum; }; private: @@ -92,7 +92,6 @@ private: bool parseFile(); - bool parseDataObject(); bool parseDataObjectTemplate(); @@ -156,8 +155,6 @@ private: void readUntilEndOfLine(); - core::stringc stripPathFromString(core::stringc string, bool returnPath); - u16 readBinWord(); u32 readBinDWord(); u32 readInt(); @@ -168,23 +165,18 @@ private: bool readRGB(video::SColor& color); bool readRGBA(video::SColor& color); - ISceneManager* SceneManager; - io::IFileSystem* FileSystem; + ISceneManager* SceneManager; + io::IFileSystem* FileSystem; core::array *AllJoints; CSkinnedMesh* AnimatedMesh; - u32 MajorVersion; - u32 MinorVersion; - bool BinaryFormat; - // counter for number arrays in binary format - u32 BinaryNumCount; - c8* Buffer; const c8* P; c8* End; - c8 FloatSize; + // counter for number arrays in binary format + u32 BinaryNumCount; u32 Line; core::stringc FilePath; @@ -193,10 +185,14 @@ private: core::array Meshes; core::array TemplateMaterials; + + u32 MajorVersion; + u32 MinorVersion; + bool BinaryFormat; + c8 FloatSize; }; } // end namespace scene } // end namespace irr #endif - diff --git a/source/Irrlicht/CZBuffer.cpp b/source/Irrlicht/CZBuffer.cpp index 1300bb8a..53bf79bf 100644 --- a/source/Irrlicht/CZBuffer.cpp +++ b/source/Irrlicht/CZBuffer.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -15,7 +15,7 @@ namespace video //! constructor -CZBuffer::CZBuffer(const core::dimension2d& size) +CZBuffer::CZBuffer(const core::dimension2d& size) : Buffer(0), BufferEnd(0), Size(0,0), TotalSize(0) { #ifdef _DEBUG @@ -44,7 +44,7 @@ void CZBuffer::clear() //! sets the new size of the zbuffer -void CZBuffer::setSize(const core::dimension2d& size) +void CZBuffer::setSize(const core::dimension2d& size) { if (size == Size) return; @@ -61,7 +61,7 @@ void CZBuffer::setSize(const core::dimension2d& size) //! returns the size of the zbuffer -const core::dimension2d& CZBuffer::getSize() const +const core::dimension2d& CZBuffer::getSize() const { return Size; } @@ -92,7 +92,7 @@ namespace video { //! creates a ZBuffer -IZBuffer* createZBuffer(const core::dimension2d& size) +IZBuffer* createZBuffer(const core::dimension2d& size) { #ifdef _IRR_COMPILE_WITH_SOFTWARE_ return new CZBuffer(size); @@ -101,7 +101,7 @@ IZBuffer* createZBuffer(const core::dimension2d& size) #endif // _IRR_COMPILE_WITH_SOFTWARE_ } - + } // end namespace video } // end namespace irr diff --git a/source/Irrlicht/CZBuffer.h b/source/Irrlicht/CZBuffer.h index a1fb11f2..72a7971a 100644 --- a/source/Irrlicht/CZBuffer.h +++ b/source/Irrlicht/CZBuffer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -17,7 +17,7 @@ namespace video public: //! constructor - CZBuffer(const core::dimension2d& size); + CZBuffer(const core::dimension2d& size); //! destructor virtual ~CZBuffer(); @@ -26,10 +26,10 @@ namespace video virtual void clear(); //! sets the new size of the zbuffer - virtual void setSize(const core::dimension2d& size); + virtual void setSize(const core::dimension2d& size); //! returns the size of the zbuffer - virtual const core::dimension2d& getSize() const; + virtual const core::dimension2d& getSize() const; //! locks the zbuffer virtual TZBufferType* lock(); @@ -41,10 +41,10 @@ namespace video TZBufferType* Buffer; TZBufferType* BufferEnd; - core::dimension2d Size; + core::dimension2d Size; s32 TotalSize; }; - + } // end namespace video } // end namespace irr diff --git a/source/Irrlicht/CZipReader.cpp b/source/Irrlicht/CZipReader.cpp index d8f43a30..2bb8f1f9 100644 --- a/source/Irrlicht/CZipReader.cpp +++ b/source/Irrlicht/CZipReader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/CZipReader.h b/source/Irrlicht/CZipReader.h index c206e79d..a6317b42 100644 --- a/source/Irrlicht/CZipReader.h +++ b/source/Irrlicht/CZipReader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/IBurningShader.cpp b/source/Irrlicht/IBurningShader.cpp index 26d9b85a..d4f00dc8 100644 --- a/source/Irrlicht/IBurningShader.cpp +++ b/source/Irrlicht/IBurningShader.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -98,7 +98,7 @@ namespace video // prepare for optimal fixpoint it->pitchlog2 = s32_log2_s32 ( it->Texture->getPitch() ); - const core::dimension2d &dim = it->Texture->getSize(); + const core::dimension2d &dim = it->Texture->getSize(); it->textureXMask = s32_to_fixPoint ( dim.Width - 1 ) & FIX_POINT_UNSIGNED_MASK; it->textureYMask = s32_to_fixPoint ( dim.Height - 1 ) & FIX_POINT_UNSIGNED_MASK; it->data = (tVideoSample*) it->Texture->lock(); diff --git a/source/Irrlicht/IBurningShader.h b/source/Irrlicht/IBurningShader.h index a9b79764..bc824561 100644 --- a/source/Irrlicht/IBurningShader.h +++ b/source/Irrlicht/IBurningShader.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -27,6 +27,7 @@ namespace video struct SBurningShaderLight { SLight org; + bool LightIsOn; sVec4 posEyeSpace; diff --git a/source/Irrlicht/IDepthBuffer.h b/source/Irrlicht/IDepthBuffer.h index 8110cad3..b9c33151 100644 --- a/source/Irrlicht/IDepthBuffer.h +++ b/source/Irrlicht/IDepthBuffer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -24,10 +24,10 @@ namespace video virtual void clear() = 0; //! sets the new size of the zbuffer - virtual void setSize(const core::dimension2d& size) = 0; + virtual void setSize(const core::dimension2d& size) = 0; //! returns the size of the zbuffer - virtual const core::dimension2d& getSize() const = 0; + virtual const core::dimension2d& getSize() const = 0; //! locks the zbuffer virtual void* lock() = 0; @@ -42,7 +42,7 @@ namespace video //! creates a ZBuffer - IDepthBuffer* createDepthBuffer(const core::dimension2d& size); + IDepthBuffer* createDepthBuffer(const core::dimension2d& size); } // end namespace video } // end namespace irr diff --git a/source/Irrlicht/IImagePresenter.h b/source/Irrlicht/IImagePresenter.h index ef01f692..75077137 100644 --- a/source/Irrlicht/IImagePresenter.h +++ b/source/Irrlicht/IImagePresenter.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/ISceneNodeAnimatorFinishing.h b/source/Irrlicht/ISceneNodeAnimatorFinishing.h new file mode 100644 index 00000000..d7023ba2 --- /dev/null +++ b/source/Irrlicht/ISceneNodeAnimatorFinishing.h @@ -0,0 +1,42 @@ +// Copyright (C) 2002-2008 Nikolaus Gebhardt +// This file is part of the "Irrlicht Engine". +// For conditions of distribution and use, see copyright notice in irrlicht.h + +#ifndef __I_SCENE_NODE_ANIMATOR_FINISHING_H_INCLUDED__ +#define __I_SCENE_NODE_ANIMATOR_FINISHING_H_INCLUDED__ + +#include "ISceneNode.h" + +namespace irr +{ +namespace scene +{ + //! This is an abstract base class for animators that have a discrete end time. + class ISceneNodeAnimatorFinishing : public ISceneNodeAnimator + { + public: + + //! constructor + ISceneNodeAnimatorFinishing(u32 finishTime) + : FinishTime(finishTime), HasFinished(false) { } + + //! destructor + virtual ~ISceneNodeAnimatorFinishing() { } + + //! This is a pure virtual class, so it can't be cloned directly. + virtual ISceneNodeAnimator* createClone(ISceneNode* node, ISceneManager* newManager=0) = 0; + + virtual bool hasFinished(void) const { return HasFinished; } + + protected: + + u32 FinishTime; + bool HasFinished; + }; + + +} // end namespace scene +} // end namespace irr + +#endif + diff --git a/source/Irrlicht/ITriangleRenderer.h b/source/Irrlicht/ITriangleRenderer.h index a42cfee6..36f975d6 100644 --- a/source/Irrlicht/ITriangleRenderer.h +++ b/source/Irrlicht/ITriangleRenderer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/IZBuffer.h b/source/Irrlicht/IZBuffer.h index 7df7678d..e9654450 100644 --- a/source/Irrlicht/IZBuffer.h +++ b/source/Irrlicht/IZBuffer.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -24,10 +24,10 @@ namespace video virtual void clear() = 0; //! sets the new size of the zbuffer - virtual void setSize(const core::dimension2d& size) = 0; + virtual void setSize(const core::dimension2d& size) = 0; //! returns the size of the zbuffer - virtual const core::dimension2d& getSize() const = 0; + virtual const core::dimension2d& getSize() const = 0; //! locks the zbuffer virtual TZBufferType* lock() = 0; @@ -38,7 +38,7 @@ namespace video //! creates a ZBuffer - IZBuffer* createZBuffer(const core::dimension2d& size); + IZBuffer* createZBuffer(const core::dimension2d& size); } // end namespace video } // end namespace irr diff --git a/source/Irrlicht/Irrlicht-gcc.cbp b/source/Irrlicht/Irrlicht-gcc.cbp index e17e69d9..4cf8b5aa 100644 --- a/source/Irrlicht/Irrlicht-gcc.cbp +++ b/source/Irrlicht/Irrlicht-gcc.cbp @@ -537,8 +537,8 @@ - - + + diff --git a/source/Irrlicht/Irrlicht.cpp b/source/Irrlicht/Irrlicht.cpp index 04d3788e..c798ec5f 100644 --- a/source/Irrlicht/Irrlicht.cpp +++ b/source/Irrlicht/Irrlicht.cpp @@ -1,10 +1,10 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h #include "IrrCompileConfig.h" -static const char* const copyright = "Irrlicht Engine (c) 2002-2008 Nikolaus Gebhardt"; +static const char* const copyright = "Irrlicht Engine (c) 2002-2009 Nikolaus Gebhardt"; #ifdef _IRR_WINDOWS_ #include @@ -23,7 +23,7 @@ namespace irr { //! stub for calling createDeviceEx IRRLICHT_API IrrlichtDevice* IRRCALLCONV createDevice(video::E_DRIVER_TYPE driverType, - const core::dimension2d& windowSize, + const core::dimension2d& windowSize, u32 bits, bool fullscreen, bool stencilbuffer, bool vsync, IEventReceiver* res) { diff --git a/source/Irrlicht/Irrlicht.dev b/source/Irrlicht/Irrlicht.dev index 03983aad..90e7dc28 100644 --- a/source/Irrlicht/Irrlicht.dev +++ b/source/Irrlicht/Irrlicht.dev @@ -2840,7 +2840,7 @@ OverrideBuildCmd=0 BuildCmd= [Unit282] -FileName=CMemoryReadFile.cpp +FileName=CMemoryFile.cpp Folder=io_impl Compile=1 CompileCpp=1 @@ -2850,7 +2850,7 @@ OverrideBuildCmd=0 BuildCmd= [Unit283] -FileName=CMemoryReadFile.h +FileName=CMemoryFile.h Folder=io_impl Compile=1 CompileCpp=1 diff --git a/source/Irrlicht/Irrlicht7.1.vcproj b/source/Irrlicht/Irrlicht7.1.vcproj index c9c74a1f..9cf048da 100644 --- a/source/Irrlicht/Irrlicht7.1.vcproj +++ b/source/Irrlicht/Irrlicht7.1.vcproj @@ -1995,10 +1995,10 @@ RelativePath=".\CLimitReadFile.h"> + RelativePath=".\CMemoryFile.cpp"> + RelativePath=".\CMemoryFile.h"> diff --git a/source/Irrlicht/Irrlicht8.0.vcproj b/source/Irrlicht/Irrlicht8.0.vcproj index f770e2a3..5b4e580d 100644 --- a/source/Irrlicht/Irrlicht8.0.vcproj +++ b/source/Irrlicht/Irrlicht8.0.vcproj @@ -862,6 +862,10 @@ RelativePath=".\..\..\include\IDummyTransformationSceneNode.h" > + + @@ -2187,11 +2191,11 @@ > + + + + + + + + @@ -2707,11 +2723,11 @@ > & joystickInfo); //! \return Returns a pointer to a list with all video modes @@ -207,6 +207,7 @@ namespace irr int _screenWidth; int _screenHeight; bool _active; + bool IsShiftDown, IsControlDown; void pollJoysticks(); }; diff --git a/source/Irrlicht/MacOSX/CIrrDeviceMacOSX.mm b/source/Irrlicht/MacOSX/CIrrDeviceMacOSX.mm index 403e9010..ce20e9e7 100644 --- a/source/Irrlicht/MacOSX/CIrrDeviceMacOSX.mm +++ b/source/Irrlicht/MacOSX/CIrrDeviceMacOSX.mm @@ -1,4 +1,4 @@ -// Copyright (C) 2005-2008 Etienne Petitjean +// Copyright (C) 2005-2009 Etienne Petitjean // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in Irrlicht.h @@ -329,7 +329,8 @@ namespace irr { //! constructor CIrrDeviceMacOSX::CIrrDeviceMacOSX(const SIrrlichtCreationParameters& param) - : CIrrDeviceStub(param), _window(NULL), _active(true), _oglcontext(NULL), _cglcontext(NULL) + : CIrrDeviceStub(param), _window(NULL), _active(true), _oglcontext(NULL), _cglcontext(NULL), + IsShiftDown(false), IsControlDown(false) { struct utsname name; NSString *path; @@ -413,15 +414,12 @@ void CIrrDeviceMacOSX::closeDevice() bool CIrrDeviceMacOSX::createWindow() { - int index; CGDisplayErr error; bool result; - NSOpenGLPixelFormat *format; CGDirectDisplayID display; CGLPixelFormatObj pixelFormat; CGRect displayRect; CGLPixelFormatAttribute fullattribs[32]; - NSOpenGLPixelFormatAttribute windowattribs[32]; CFDictionaryRef displaymode,olddisplaymode; GLint numPixelFormats,newSwapInterval; int alphaSize = CreationParams.WithAlphaChannel?4:0, depthSize = CreationParams.ZBufferBits; @@ -433,7 +431,7 @@ bool CIrrDeviceMacOSX::createWindow() display = CGMainDisplayID(); _screenWidth = (int) CGDisplayPixelsWide(display); _screenHeight = (int) CGDisplayPixelsHigh(display); - + VideoModeList.setDesktop(CreationParams.Bits,core::dimension2d(_screenWidth, _screenHeight)); if (!CreationParams.Fullscreen) @@ -441,33 +439,80 @@ bool CIrrDeviceMacOSX::createWindow() _window = [[NSWindow alloc] initWithContentRect:NSMakeRect(0,0,CreationParams.WindowSize.Width,CreationParams.WindowSize.Height) styleMask:NSTitledWindowMask+NSClosableWindowMask+NSResizableWindowMask backing:NSBackingStoreBuffered defer:FALSE]; if (_window != NULL) { - index = 0; - windowattribs[index++] = NSOpenGLPFANoRecovery; - windowattribs[index++] = NSOpenGLPFADoubleBuffer; - windowattribs[index++] = NSOpenGLPFAAccelerated; - windowattribs[index++] = NSOpenGLPFADepthSize; - windowattribs[index++] = (NSOpenGLPixelFormatAttribute)depthSize; - windowattribs[index++] = NSOpenGLPFAColorSize; - windowattribs[index++] = (NSOpenGLPixelFormatAttribute)CreationParams.Bits; - windowattribs[index++] = NSOpenGLPFAAlphaSize; - windowattribs[index++] = (NSOpenGLPixelFormatAttribute)alphaSize; + NSOpenGLPixelFormatAttribute windowattribs[] = { + NSOpenGLPFANoRecovery, + NSOpenGLPFAAccelerated, + NSOpenGLPFADepthSize, depthSize, + NSOpenGLPFAColorSize, CreationParams.Bits, + NSOpenGLPFAAlphaSize, alphaSize, + NSOpenGLPFASampleBuffers, 1, + NSOpenGLPFASamples, CreationParams.AntiAlias, + NSOpenGLPFAStencilSize, CreationParams.Stencilbuffer?1:0, + NSOpenGLPFADoubleBuffer, + (NSOpenGLPixelFormatAttribute)nil + }; - if (CreationParams.AntiAlias) { - windowattribs[index++] = NSOpenGLPFASampleBuffers; - windowattribs[index++] = (NSOpenGLPixelFormatAttribute)1; - windowattribs[index++] = NSOpenGLPFASamples; - windowattribs[index++] = (NSOpenGLPixelFormatAttribute)2; - } - - if (CreationParams.Stencilbuffer) + if (CreationParams.AntiAlias<2) { - windowattribs[index++] = NSOpenGLPFAStencilSize; - windowattribs[index++] = (NSOpenGLPixelFormatAttribute)1; + windowattribs[9] = 0; + windowattribs[11] = 0; } - windowattribs[index++] = (NSOpenGLPixelFormatAttribute)NULL; + NSOpenGLPixelFormat *format; + for (int i=0; i<3; ++i) + { + if (1==i) + { + // Second try without stencilbuffer + if (CreationParams.Stencilbuffer) + { + windowattribs[13]=0; + } + else + continue; + } + else if (2==i) + { + // Third try without Doublebuffer + os::Printer::log("No doublebuffering available.", ELL_WARNING); + windowattribs[14]=(NSOpenGLPixelFormatAttribute)nil; + } + + format = [[NSOpenGLPixelFormat alloc] initWithAttributes:windowattribs]; + if (format == NULL) + { + if (CreationParams.AntiAlias>1) + { + while (!format && windowattribs[12]>1) + { + windowattribs -= 1; + format = [[NSOpenGLPixelFormat alloc] initWithAttributes:windowattribs]; + } + if (!format) + { + windowattribs[9] = 0; + windowattribs[11] = 0; + format = [[NSOpenGLPixelFormat alloc] initWithAttributes:windowattribs]; + if (!format) + { + // reset values for next try + windowattribs[9] = 1; + windowattribs[11] = CreationParams.AntiAlias; + } + else + { + os::Printer::log("No FSAA available.", ELL_WARNING); + } + + } + } + } + else + break; + } + CreationParams.AntiAlias=windowattribs[11]; + CreationParams.Stencilbuffer=(windowattribs[13]==1); - format = [[NSOpenGLPixelFormat alloc] initWithAttributes:windowattribs]; if (format != NULL) { _oglcontext = [[NSOpenGLContext alloc] initWithFormat:format shareContext:NULL]; @@ -505,7 +550,7 @@ bool CIrrDeviceMacOSX::createWindow() pixelFormat = NULL; numPixelFormats = 0; - index = 0; + int index = 0; fullattribs[index++] = kCGLPFAFullScreen; fullattribs[index++] = kCGLPFADisplayMask; fullattribs[index++] = (CGLPixelFormatAttribute)CGDisplayIDToOpenGLDisplayMask(display); @@ -522,7 +567,7 @@ bool CIrrDeviceMacOSX::createWindow() fullattribs[index++] = kCGLPFASampleBuffers; fullattribs[index++] = (CGLPixelFormatAttribute)1; fullattribs[index++] = kCGLPFASamples; - fullattribs[index++] = (CGLPixelFormatAttribute)2; + fullattribs[index++] = (CGLPixelFormatAttribute)CreationParams.AntiAlias; } if (CreationParams.Stencilbuffer) @@ -544,8 +589,8 @@ bool CIrrDeviceMacOSX::createWindow() { CGLSetFullScreen(_cglcontext); displayRect = CGDisplayBounds(display); - _width = (int)displayRect.size.width; - _height = (int)displayRect.size.height; + _screenWidth = _width = (int)displayRect.size.width; + _screenHeight = _height = (int)displayRect.size.height; result = true; } } @@ -659,6 +704,36 @@ bool CIrrDeviceMacOSX::run() postKeyEvent(event,ievent,false); break; + case NSFlagsChanged: + ievent.EventType = irr::EET_KEY_INPUT_EVENT; + ievent.KeyInput.Shift = ([(NSEvent *)event modifierFlags] & NSShiftKeyMask) != 0; + ievent.KeyInput.Control = ([(NSEvent *)event modifierFlags] & NSControlKeyMask) != 0; + + if (IsShiftDown != ievent.KeyInput.Shift) + { + ievent.KeyInput.Char = irr::KEY_SHIFT; + ievent.KeyInput.Key = irr::KEY_SHIFT; + ievent.KeyInput.PressedDown = ievent.KeyInput.Shift; + + IsShiftDown = ievent.KeyInput.Shift; + + postEventFromUser(ievent); + } + + if (IsControlDown != ievent.KeyInput.Control) + { + ievent.KeyInput.Char = irr::KEY_CONTROL; + ievent.KeyInput.Key = irr::KEY_CONTROL; + ievent.KeyInput.PressedDown = ievent.KeyInput.Control; + + IsControlDown = ievent.KeyInput.Control; + + postEventFromUser(ievent); + } + + [NSApp sendEvent:event]; + break; + case NSLeftMouseDown: ievent.EventType = irr::EET_MOUSE_INPUT_EVENT; ievent.MouseInput.Event = irr::EMIE_LMOUSE_PRESSED_DOWN; @@ -884,6 +959,7 @@ void CIrrDeviceMacOSX::setMouseLocation(int x,int y) if (_window != NULL) { + // Irrlicht window exists p.x = (float) x; p.y = (float) (_height - y); p = [(NSWindow *)_window convertBaseToScreen:p]; diff --git a/source/Irrlicht/MacOSX/MacOSX.xcodeproj/project.pbxproj b/source/Irrlicht/MacOSX/MacOSX.xcodeproj/project.pbxproj index 89078575..18c7b045 100644 --- a/source/Irrlicht/MacOSX/MacOSX.xcodeproj/project.pbxproj +++ b/source/Irrlicht/MacOSX/MacOSX.xcodeproj/project.pbxproj @@ -907,7 +907,7 @@ 093973BD0E0458B200E0C987 /* CSceneNodeAnimatorCameraFPS.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CSceneNodeAnimatorCameraFPS.h; sourceTree = ""; }; 093973BE0E0458B200E0C987 /* CSceneNodeAnimatorCameraMaya.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CSceneNodeAnimatorCameraMaya.cpp; sourceTree = ""; }; 093973BF0E0458B200E0C987 /* CSceneNodeAnimatorCameraMaya.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CSceneNodeAnimatorCameraMaya.h; sourceTree = ""; }; - 0946CCB40EC99BBE00D945A5 /* MouseAndJoystick.app */ = {isa = PBXFileReference; includeInIndex = 0; lastKnownFileType = wrapper.application; path = MouseAndJoystick.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 0946CCB40EC99BBE00D945A5 /* MouseAndJoystick.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MouseAndJoystick.app; sourceTree = BUILT_PRODUCTS_DIR; }; 0946CCCA0EC99C6E00D945A5 /* main.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; name = main.cpp; path = 19.MouseAndJoystick/main.cpp; sourceTree = ""; }; 0968401E0D0F1A2300333EFD /* CB3DMeshFileLoader.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CB3DMeshFileLoader.cpp; sourceTree = ""; }; 0968401F0D0F1A2300333EFD /* CB3DMeshFileLoader.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CB3DMeshFileLoader.h; sourceTree = ""; }; @@ -1284,7 +1284,7 @@ 4C53E2520A4850550014E966 /* Quake3Map.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Quake3Map.app; sourceTree = BUILT_PRODUCTS_DIR; }; 4C53E26D0A4850D60014E966 /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 4C53E26E0A4850D60014E966 /* OpenGL.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = OpenGL.framework; path = /System/Library/Frameworks/OpenGL.framework; sourceTree = ""; }; - 4C53E38E0A4855BA0014E966 /* DemoApp-Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.xml; path = "DemoApp-Info.plist"; sourceTree = ""; }; + 4C53E38E0A4855BA0014E966 /* DemoApp-Info.plist */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = text.plist.xml; path = "DemoApp-Info.plist"; sourceTree = ""; }; 4C53E6F10A485CD80014E966 /* jcapimin.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = jcapimin.c; sourceTree = ""; }; 4C53E6F20A485CD80014E966 /* jcapistd.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = jcapistd.c; sourceTree = ""; }; 4C53E6F30A485CD80014E966 /* jccoefct.c */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.c; path = jccoefct.c; sourceTree = ""; }; @@ -3364,10 +3364,12 @@ 0867D690FE84028FC02AAC07 /* Project object */ = { isa = PBXProject; buildConfigurationList = 1DEB922208733DC00010E9CD /* Build configuration list for PBXProject "MacOSX" */; + compatibilityVersion = "Xcode 2.4"; hasScannedForEncodings = 1; mainGroup = 0867D691FE84028FC02AAC07 /* MacOSX */; productRefGroup = 0867D691FE84028FC02AAC07 /* MacOSX */; projectDirPath = ""; + projectRoot = ""; targets = ( D2AAC07D0554694100DB518D /* libIrrlicht.a */, B81CFF33097FE25F0057C06F /* Quake3Map */, diff --git a/source/Irrlicht/MacOSX/OSXClipboard.h b/source/Irrlicht/MacOSX/OSXClipboard.h index 0bd2618e..eeb0c962 100644 --- a/source/Irrlicht/MacOSX/OSXClipboard.h +++ b/source/Irrlicht/MacOSX/OSXClipboard.h @@ -1,4 +1,4 @@ -// Copyright (C) 2005-2008 Etienne Petitjean +// Copyright (C) 2005-2009 Etienne Petitjean // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in Irrlicht.h diff --git a/source/Irrlicht/MacOSX/OSXClipboard.mm b/source/Irrlicht/MacOSX/OSXClipboard.mm index 1308134d..7a23ef22 100644 --- a/source/Irrlicht/MacOSX/OSXClipboard.mm +++ b/source/Irrlicht/MacOSX/OSXClipboard.mm @@ -1,4 +1,4 @@ -// Copyright (C) 2005-2008 Etienne Petitjean +// Copyright (C) 2005-2009 Etienne Petitjean // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in Irrlicht.h diff --git a/source/Irrlicht/Makefile b/source/Irrlicht/Makefile index eb49ff83..88e89811 100644 --- a/source/Irrlicht/Makefile +++ b/source/Irrlicht/Makefile @@ -33,7 +33,7 @@ IRRIMAGEOBJ = CColorConverter.o CImage.o CImageLoaderBMP.o CImageLoaderJPG.o CIm CImageWriterBMP.o CImageWriterJPG.o CImageWriterPCX.o CImageWriterPNG.o CImageWriterPPM.o CImageWriterPSD.o CImageWriterTGA.o IRRVIDEOOBJ = CVideoModeList.o CFPSCounter.o $(IRRDRVROBJ) $(IRRIMAGEOBJ) IRRSWRENDEROBJ = CSoftwareDriver.o CSoftwareTexture.o CTRFlat.o CTRFlatWire.o CTRGouraud.o CTRGouraudWire.o CTRTextureFlat.o CTRTextureFlatWire.o CTRTextureGouraud.o CTRTextureGouraudAdd.o CTRTextureGouraudNoZ.o CTRTextureGouraudWire.o CZBuffer.o CTRTextureGouraudVertexAlpha2.o CTRTextureGouraudNoZ2.o CTRTextureLightMap2_M2.o CTRTextureLightMap2_M4.o CTRTextureLightMap2_M1.o CSoftwareDriver2.o CSoftwareTexture2.o CTRTextureGouraud2.o CTRGouraud2.o CTRGouraudAlpha2.o CTRGouraudAlphaNoZ2.o CTRTextureDetailMap2.o CTRTextureGouraudAdd2.o CTRTextureGouraudAddNoZ2.o CTRTextureWire2.o CTRTextureLightMap2_Add.o CTRTextureLightMapGouraud2_M4.o IBurningShader.o CTRTextureBlend.o CTRTextureGouraudAlpha.o CTRTextureGouraudAlphaNoZ.o CDepthBuffer.o CBurningShader_Raster_Reference.o -IRRIOOBJ = CFileList.o CFileSystem.o CLimitReadFile.o CMemoryReadFile.o CReadFile.o CWriteFile.o CXMLReader.o CXMLWriter.o CZipReader.o CPakReader.o irrXML.o CAttributes.o +IRRIOOBJ = CFileList.o CFileSystem.o CLimitReadFile.o CMemoryFile.o CReadFile.o CWriteFile.o CXMLReader.o CXMLWriter.o CZipReader.o CPakReader.o irrXML.o CAttributes.o IRROTHEROBJ = CIrrDeviceSDL.o CIrrDeviceLinux.o CIrrDeviceStub.o CIrrDeviceWin32.o CLogger.o COSOperator.o Irrlicht.o os.o IRRGUIOBJ = CGUIButton.o CGUICheckBox.o CGUIComboBox.o CGUIContextMenu.o CGUIEditBox.o CGUIEnvironment.o CGUIFileOpenDialog.o CGUIFont.o CGUIImage.o CGUIInOutFader.o CGUIListBox.o CGUIMenu.o CGUIMeshViewer.o CGUIMessageBox.o CGUIModalScreen.o CGUIScrollBar.o CGUISpinBox.o CGUISkin.o CGUIStaticText.o CGUITabControl.o CGUITable.o CGUIToolBar.o CGUIWindow.o CGUIColorSelectDialog.o CDefaultGUIElementFactory.o CGUISpriteBank.o ZLIBOBJ = zlib/adler32.o zlib/compress.o zlib/crc32.o zlib/deflate.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o zlib/trees.o zlib/uncompr.o zlib/zutil.o diff --git a/source/Irrlicht/OctTree.h b/source/Irrlicht/OctTree.h index 6a186937..fa46347c 100644 --- a/source/Irrlicht/OctTree.h +++ b/source/Irrlicht/OctTree.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/S2DVertex.h b/source/Irrlicht/S2DVertex.h index 40f55a12..79b2caba 100644 --- a/source/Irrlicht/S2DVertex.h +++ b/source/Irrlicht/S2DVertex.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/S4DVertex.h b/source/Irrlicht/S4DVertex.h index 12f0973f..0b5482a2 100644 --- a/source/Irrlicht/S4DVertex.h +++ b/source/Irrlicht/S4DVertex.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/SoftwareDriver2_compile_config.h b/source/Irrlicht/SoftwareDriver2_compile_config.h index f1e517ac..f15eed5a 100644 --- a/source/Irrlicht/SoftwareDriver2_compile_config.h +++ b/source/Irrlicht/SoftwareDriver2_compile_config.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/SoftwareDriver2_helper.h b/source/Irrlicht/SoftwareDriver2_helper.h index 17826fcf..1a13c60e 100644 --- a/source/Irrlicht/SoftwareDriver2_helper.h +++ b/source/Irrlicht/SoftwareDriver2_helper.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Thomas Alten +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Thomas Alten // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -169,7 +169,7 @@ REALINLINE u32 PixelBlend32 ( const u32 c2, const u32 c1, u32 alpha ) rb &= 0x00FF00FF; xg &= 0x0000FF00; - return rb | xg; + return rb | xg; } /*! @@ -220,7 +220,7 @@ inline u32 PixelLerp32 ( const u32 source, const u32 value ) srcXG &= 0xFF00FF00; srcRB &= 0x00FF00FF; - return srcRB | srcXG; + return srcRB | srcXG; } /* @@ -244,7 +244,7 @@ inline u16 PixelMul16 ( const u16 c0, const u16 c1) } /* - Pixel = c0 * (c1/31). + Pixel = c0 * (c1/31). */ inline u16 PixelMul16_2 ( u16 c0, u16 c1) { @@ -266,7 +266,7 @@ REALINLINE u32 PixelMul32 ( const u32 c0, const u32 c1) } /* - Pixel = c0 * (c1/255). + Pixel = c0 * (c1/255). */ REALINLINE u32 PixelMul32_2 ( const u32 c0, const u32 c1) { @@ -292,31 +292,31 @@ REALINLINE u32 PixelAdd32 ( const u32 c2, const u32 c1) // 1 - Bit Alpha Blending -inline u16 PixelBlend16 ( const u16 c2, const u16 c1 ) +inline u16 PixelBlend16 ( const u16 destination, const u16 source ) { - u16 c = c1 & 0x8000; - - c >>= 15; - c += 0x7fff; - - c &= c2; - c |= c1; - - return c; + if((source & 0x8000) == 0x8000) + return source; // The source is visible, so use it. + else + return destination; // The source is transparent, so use the destination. } // 1 - Bit Alpha Blending 16Bit SIMD -inline u32 PixelBlend16_simd ( const u32 c2, const u32 c1 ) +inline u32 PixelBlend16_simd ( const u32 destination, const u32 source ) { - u32 c = c1 & 0x80008000; - - c >>= 15; - c += 0x7fff7fff; - - c &= c2; - c |= c1; - - return c; + switch(source & 0x80008000) + { + case 0x80008000: // Both source pixels are visible + return source; + + case 0x80000000: // Only the first source pixel is visible + return (source & 0xFFFF0000) | (destination & 0x0000FFFF); + + case 0x00008000: // Only the second source pixel is visible. + return (destination & 0xFFFF0000) | (source & 0x0000FFFF); + + default: // Neither source pixel is visible. + return destination; + } } @@ -362,7 +362,7 @@ inline u32 PixelBlend32 ( const u32 c2, const u32 c1 ) rb &= 0x00FF00FF; xg &= 0x0000FF00; - return rb | xg; + return rb | xg; } @@ -427,7 +427,7 @@ REALINLINE f32 fix_inverse32 ( const f32 x ) convert float to fixpoint fast convert (fistp on x86) HAS to be used.. hints: compileflag /QIfist for msvc7. msvc 8.0 has smth different - others should use their favourite assembler.. + others should use their favourite assembler.. */ static inline int f_round2(f32 f) { @@ -494,7 +494,7 @@ REALINLINE tFixPoint imulFix_tex4(const tFixPoint x, const tFixPoint y) */ REALINLINE tFixPoint clampfix_maxcolor ( const tFixPoint a) { - tFixPoint c = (a - FIXPOINT_COLOR_MAX) >> 31; + tFixPoint c = (a - FIXPOINT_COLOR_MAX) >> 31; return (a & c) | ( FIXPOINT_COLOR_MAX & ~c); } @@ -561,7 +561,7 @@ typedef f32 fp24; struct fp24 { u32 v; - + fp24() {} fp24 ( const f32 f ) @@ -620,7 +620,7 @@ inline tVideoSample getTexel_plain ( const sInternalTexture * t, const tFixPoint } // get video sample to fix -inline void getTexel_fix ( tFixPoint &r, tFixPoint &g, tFixPoint &b, +inline void getTexel_fix ( tFixPoint &r, tFixPoint &g, tFixPoint &b, const sInternalTexture * t, const tFixPointu tx, const tFixPointu ty ) { @@ -640,7 +640,7 @@ inline void getTexel_fix ( tFixPoint &r, tFixPoint &g, tFixPoint &b, } -inline void getSample_texture_dither ( tFixPoint &r, tFixPoint &g, tFixPoint &b, +inline void getSample_texture_dither ( tFixPoint &r, tFixPoint &g, tFixPoint &b, const sInternalTexture * t, const tFixPointu tx, const tFixPointu ty, const u32 x, const u32 y ) @@ -678,7 +678,7 @@ inline void getSample_texture_dither ( tFixPoint &r, tFixPoint &g, tFixPoint &b, // get Sample linear == getSample_fixpoint -inline void getSample_texture ( tFixPoint &r, tFixPoint &g, tFixPoint &b, +inline void getSample_texture ( tFixPoint &r, tFixPoint &g, tFixPoint &b, const sInternalTexture * t, const tFixPointu tx, const tFixPointu ty ) { @@ -695,7 +695,7 @@ inline void getSample_texture ( tFixPoint &r, tFixPoint &g, tFixPoint &b, (tFixPointu &) b = (t00 & MASK_B) << ( FIX_POINT_PRE - SHIFT_B ); } -inline void getSample_texture ( tFixPointu &a, tFixPointu &r, tFixPointu &g, tFixPointu &b, +inline void getSample_texture ( tFixPointu &a, tFixPointu &r, tFixPointu &g, tFixPointu &b, const sInternalTexture * t, const tFixPointu tx, const tFixPointu ty ) { @@ -717,7 +717,7 @@ inline void getSample_texture ( tFixPointu &a, tFixPointu &r, tFixPointu &g, tFi #else // get sample linear -REALINLINE void getSample_linear ( tFixPointu &r, tFixPointu &g, tFixPointu &b, +REALINLINE void getSample_linear ( tFixPointu &r, tFixPointu &g, tFixPointu &b, const sInternalTexture * t, const tFixPointu tx, const tFixPointu ty ) { @@ -736,7 +736,7 @@ REALINLINE void getSample_linear ( tFixPointu &r, tFixPointu &g, tFixPointu &b, } // get Sample bilinear -REALINLINE void getSample_texture ( tFixPoint &r, tFixPoint &g, tFixPoint &b, +REALINLINE void getSample_texture ( tFixPoint &r, tFixPoint &g, tFixPoint &b, const sInternalTexture * t, const tFixPointu tx, const tFixPointu ty ) { @@ -781,7 +781,7 @@ REALINLINE void getSample_texture ( tFixPoint &r, tFixPoint &g, tFixPoint &b, // get sample linear -REALINLINE void getSample_linear ( tFixPointu &a, tFixPointu &r, tFixPointu &g, tFixPointu &b, +REALINLINE void getSample_linear ( tFixPointu &a, tFixPointu &r, tFixPointu &g, tFixPointu &b, const sInternalTexture * t, const tFixPointu tx, const tFixPointu ty ) { @@ -801,7 +801,7 @@ REALINLINE void getSample_linear ( tFixPointu &a, tFixPointu &r, tFixPointu &g, } // get Sample bilinear -REALINLINE void getSample_texture ( tFixPointu &a, tFixPointu &r, tFixPointu &g, tFixPointu &b, +REALINLINE void getSample_texture ( tFixPointu &a, tFixPointu &r, tFixPointu &g, tFixPointu &b, const sInternalTexture * t, const tFixPointu tx, const tFixPointu ty ) { @@ -890,5 +890,5 @@ inline s32 intervall_intersect_test( const sIntervall& a, const sIntervall& b) } // namespace -#endif +#endif diff --git a/source/Irrlicht/dmfsupport.h b/source/Irrlicht/dmfsupport.h index 3b3bc082..5fa146e1 100644 --- a/source/Irrlicht/dmfsupport.h +++ b/source/Irrlicht/dmfsupport.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h // @@ -95,7 +95,7 @@ struct dmfWaterPlane u32 waterID;//! tileNum;//! tileNum;//! tilenum(40,40); + core::dimension2d tilenum(40,40); f32 waveheight=3.0f; f32 wavespeed=300.0f; f32 wavelength=80.0f; diff --git a/source/Irrlicht/glext.h b/source/Irrlicht/glext.h index 4255fa86..c0941aa8 100644 --- a/source/Irrlicht/glext.h +++ b/source/Irrlicht/glext.h @@ -46,9 +46,9 @@ extern "C" { /*************************************************************/ /* Header file version number, required by OpenGL ABI for Linux */ -/* glext.h last updated 2008/10/09 */ +/* glext.h last updated 2008/11/14 */ /* Current version at http://www.opengl.org/registry/ */ -#define GL_GLEXT_VERSION 43 +#define GL_GLEXT_VERSION 44 #ifndef GL_VERSION_1_2 #define GL_UNSIGNED_BYTE_3_3_2 0x8032 @@ -3834,6 +3834,34 @@ extern "C" { /* reuse GL_BGRA */ #endif +#ifndef GL_EXT_texture_swizzle +#define GL_TEXTURE_SWIZZLE_R_EXT 0x8E42 +#define GL_TEXTURE_SWIZZLE_G_EXT 0x8E43 +#define GL_TEXTURE_SWIZZLE_B_EXT 0x8E44 +#define GL_TEXTURE_SWIZZLE_A_EXT 0x8E45 +#define GL_TEXTURE_SWIZZLE_RGBA_EXT 0x8E46 +#endif + +#ifndef GL_NV_explicit_multisample +#define GL_SAMPLE_POSITION_NV 0x8E50 +#define GL_SAMPLE_MASK_NV 0x8E51 +#define GL_SAMPLE_MASK_VALUE_NV 0x8E52 +#define GL_TEXTURE_BINDING_RENDERBUFFER_NV 0x8E53 +#define GL_TEXTURE_RENDERBUFFER_DATA_STORE_BINDING_NV 0x8E54 +#define GL_MAX_SAMPLE_MASK_WORDS_NV 0x8E59 +#define GL_TEXTURE_RENDERBUFFER_NV 0x8E55 +#define GL_SAMPLER_RENDERBUFFER_NV 0x8E56 +#define GL_INT_SAMPLER_RENDERBUFFER_NV 0x8E57 +#define GL_UNSIGNED_INT_SAMPLER_RENDERBUFFER_NV 0x8E58 +#endif + +#ifndef GL_NV_transform_feedback2 +#define GL_TRANSFORM_FEEDBACK_NV 0x8E22 +#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED_NV 0x8E23 +#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE_NV 0x8E24 +#define GL_TRANSFORM_FEEDBACK_BINDING_NV 0x8E25 +#endif + /*************************************************************/ @@ -8387,6 +8415,42 @@ typedef void (APIENTRYP PFNGLMULTITEXRENDERBUFFEREXTPROC) (GLenum texunit, GLenu #define GL_EXT_vertex_array_bgra 1 #endif +#ifndef GL_EXT_texture_swizzle +#define GL_EXT_texture_swizzle 1 +#endif + +#ifndef GL_NV_explicit_multisample +#define GL_NV_explicit_multisample 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glGetMultisamplefvNV (GLenum, GLuint, GLfloat *); +GLAPI void APIENTRY glSampleMaskIndexedNV (GLuint, GLbitfield); +GLAPI void APIENTRY glTexRenderbufferNV (GLenum, GLuint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLGETMULTISAMPLEFVNVPROC) (GLenum pname, GLuint index, GLfloat *val); +typedef void (APIENTRYP PFNGLSAMPLEMASKINDEXEDNVPROC) (GLuint index, GLbitfield mask); +typedef void (APIENTRYP PFNGLTEXRENDERBUFFERNVPROC) (GLenum target, GLuint renderbuffer); +#endif + +#ifndef GL_NV_transform_feedback2 +#define GL_NV_transform_feedback2 1 +#ifdef GL_GLEXT_PROTOTYPES +GLAPI void APIENTRY glBindTransformFeedbackNV (GLenum, GLuint); +GLAPI void APIENTRY glDeleteTransformFeedbacksNV (GLsizei, const GLuint *); +GLAPI void APIENTRY glGenTransformFeedbacksNV (GLsizei, GLuint *); +GLAPI GLboolean APIENTRY glIsTransformFeedbackNV (GLuint); +GLAPI void APIENTRY glPauseTransformFeedbackNV (void); +GLAPI void APIENTRY glResumeTransformFeedbackNV (void); +GLAPI void APIENTRY glDrawTransformFeedbackNV (GLenum, GLuint); +#endif /* GL_GLEXT_PROTOTYPES */ +typedef void (APIENTRYP PFNGLBINDTRANSFORMFEEDBACKNVPROC) (GLenum target, GLuint id); +typedef void (APIENTRYP PFNGLDELETETRANSFORMFEEDBACKSNVPROC) (GLsizei n, const GLuint *ids); +typedef void (APIENTRYP PFNGLGENTRANSFORMFEEDBACKSNVPROC) (GLsizei n, GLuint *ids); +typedef GLboolean (APIENTRYP PFNGLISTRANSFORMFEEDBACKNVPROC) (GLuint id); +typedef void (APIENTRYP PFNGLPAUSETRANSFORMFEEDBACKNVPROC) (void); +typedef void (APIENTRYP PFNGLRESUMETRANSFORMFEEDBACKNVPROC) (void); +typedef void (APIENTRYP PFNGLDRAWTRANSFORMFEEDBACKNVPROC) (GLenum mode, GLuint id); +#endif + #ifdef __cplusplus } diff --git a/source/Irrlicht/irrXML.cpp b/source/Irrlicht/irrXML.cpp index dce703f0..326593de 100644 --- a/source/Irrlicht/irrXML.cpp +++ b/source/Irrlicht/irrXML.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine" and the "irrXML" project. // For conditions of distribution and use, see copyright notice in irrlicht.h and/or irrXML.h diff --git a/source/Irrlicht/os.cpp b/source/Irrlicht/os.cpp index 5ecf59aa..ba647737 100644 --- a/source/Irrlicht/os.cpp +++ b/source/Irrlicht/os.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/source/Irrlicht/os.h b/source/Irrlicht/os.h index 84496a3c..0aa9cfa3 100644 --- a/source/Irrlicht/os.h +++ b/source/Irrlicht/os.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/tests/b3dAnimation.cpp b/tests/b3dAnimation.cpp index d11fff28..38cda941 100644 --- a/tests/b3dAnimation.cpp +++ b/tests/b3dAnimation.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Colin MacDonald +// Copyright (C) 2008-2009 Colin MacDonald // No rights reserved: this software is in the public domain. #include "irrlicht.h" @@ -17,11 +17,11 @@ using namespace gui; bool b3dAnimation(void) { // Use EDT_BURNINGSVIDEO since it is not dependent on (e.g.) OpenGL driver versions. - IrrlichtDevice *device = createDevice( EDT_BURNINGSVIDEO, dimension2d(160, 120), 32); + IrrlichtDevice *device = createDevice( EDT_BURNINGSVIDEO, dimension2d(160, 120), 32); assert(device); if (!device) return false; - + IVideoDriver* driver = device->getVideoDriver(); ISceneManager * smgr = device->getSceneManager(); diff --git a/tests/burningsVideo.cpp b/tests/burningsVideo.cpp new file mode 100644 index 00000000..4f8e5135 --- /dev/null +++ b/tests/burningsVideo.cpp @@ -0,0 +1,39 @@ +// Copyright (C) 2008-2009 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" +#include "irrlicht.h" + +using namespace irr; +using namespace scene; +using namespace video; + +/** Tests the Burning Video driver */ +bool burningsVideo(void) +{ + IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, + core::dimension2du(160,120), 32); + if (!device) + return false; + + IVideoDriver* driver = device->getVideoDriver(); + ISceneManager* smgr = device->getSceneManager(); + + smgr->addCubeSceneNode(10.f, 0, -1, core::vector3df(0.f, 0.f, 20.f)); + smgr->addCameraSceneNode(); + // Test that ambient lighting works when there are no other lights in the scene + smgr->setAmbientLight(video::SColorf(.7f, .1f, .1f, 1.f)); + + bool result = false; + device->run(); + if (driver->beginScene(true, true, video::SColor(0, 80, 80, 80))) + { + smgr->drawAll(); + driver->endScene(); + result = takeScreenshotAndCompareAgainstReference(driver, "-ambient-lighting.png", 100); + } + + device->drop(); + + return result; +} diff --git a/tests/collisionResponseAnimator.cpp b/tests/collisionResponseAnimator.cpp index a1ccaa13..c7c05684 100644 --- a/tests/collisionResponseAnimator.cpp +++ b/tests/collisionResponseAnimator.cpp @@ -10,6 +10,64 @@ using namespace core; using namespace scene; using namespace video; +static bool expectedCollisionCallbackPositions = true; + +class CMyCollisionCallback : public ICollisionCallback +{ +public: + bool onCollision(const ISceneNodeAnimatorCollisionResponse& animator) + { + const vector3df & collisionPoint = animator.getCollisionPoint(); + + logTestString("Collision callback at %f %f %f\n", + collisionPoint.X, collisionPoint.Y, collisionPoint.Z); + + if(collisionPoint != ExpectedCollisionPoint) + { + logTestString("*** Error: collision point, expected %f %f %f\n", + ExpectedCollisionPoint.X, ExpectedCollisionPoint.Y, ExpectedCollisionPoint.Z); + expectedCollisionCallbackPositions = false; + assert(false); + } + + const vector3df & nodePosition = animator.getCollisionResultPosition(); + if(nodePosition != ExpectedNodePosition) + { + logTestString("*** Error: result position, expected %f %f %f\n", + ExpectedNodePosition.X, ExpectedNodePosition.Y, ExpectedNodePosition.Z); + expectedCollisionCallbackPositions = false; + assert(false); + } + + if(animator.getTargetNode() != ExpectedTarget) + { + logTestString("*** Error: wrong node\n"); + expectedCollisionCallbackPositions = false; + assert(false); + } + + return ConsumeNextCollision; + } + + void setNextExpectedCollision(ISceneNode* target, + const vector3df& expectedPoint, + const vector3df& expectedPosition, + bool consume) + { + ExpectedTarget = target; + ExpectedCollisionPoint = expectedPoint; + ExpectedNodePosition = expectedPosition; + ConsumeNextCollision = consume; + } + +private: + + ISceneNode * ExpectedTarget; + vector3df ExpectedCollisionPoint; + vector3df ExpectedNodePosition; + bool ConsumeNextCollision; + +}; /** Test that collision response animator will reset itself when removed from a scene node, so that the scene node can then be moved without the animator @@ -39,6 +97,10 @@ bool collisionResponseAnimator(void) vector3df(10,10,10), vector3df(0, 0, 0)); testNode1->addAnimator(collisionAnimator1); + + CMyCollisionCallback collisionCallback; + collisionAnimator1->setCollisionCallback(&collisionCallback); + collisionAnimator1->drop(); collisionAnimator1 = 0; @@ -48,7 +110,8 @@ bool collisionResponseAnimator(void) vector3df(10,10,10), vector3df(0, 0, 0)); testNode2->addAnimator(collisionAnimator2); - + collisionAnimator2->setCollisionCallback(&collisionCallback); + wallSelector->drop(); // Don't drop() collisionAnimator2 since we're going to use it. @@ -59,6 +122,10 @@ bool collisionResponseAnimator(void) // Try to move both nodes to the right of the wall. // This one should be stopped by its animator. testNode1->setPosition(vector3df(50, 0,0)); + collisionCallback.setNextExpectedCollision(testNode1, + vector3df(-5.005f, 0, 0), + vector3df(-15.005f, 0, 0), + false); // Whereas this one, by forcing the animator to update its target node, should be // able to pass through the wall. (In <=1.6 it was stopped by the wall even if @@ -89,17 +156,44 @@ bool collisionResponseAnimator(void) // Now try to move the second node back through the wall again. Now it should be // stopped by the wall. testNode2->setPosition(vector3df(-50, 0, 0)); + + // We'll consume this collision, so the node will actually move all the way through. + collisionCallback.setNextExpectedCollision(testNode2, + vector3df(5.005f, 0, 0), + vector3df(15.005f, 0, 0), + true); + device->run(); smgr->drawAll(); - if(testNode2->getAbsolutePosition().X < 15.f) + if(testNode2->getAbsolutePosition().X != -50.f) { - logTestString("collisionResponseAnimator test node 2 wasn't stopped from moving.\n"); + logTestString("collisionResponseAnimator test node 2 was stopped from moving.\n"); assert(false); result = false; } + // Now we'll try to move it back to the right and allow it to be stopped. + collisionCallback.setNextExpectedCollision(testNode2, + vector3df(-5.005f, 0, 0), + vector3df(-15.005f, 0, 0), + false); + testNode2->setPosition(vector3df(50, 0, 0)); + + device->run(); + smgr->drawAll(); + + if(testNode2->getAbsolutePosition().X > -15.f) + { + logTestString("collisionResponseAnimator test node 2 moved too far.\n"); + assert(false); + result = false; + } + + device->drop(); + + result &= expectedCollisionCallbackPositions; return result; } diff --git a/tests/cursorSetVisible.cpp b/tests/cursorSetVisible.cpp new file mode 100644 index 00000000..a8f9866a --- /dev/null +++ b/tests/cursorSetVisible.cpp @@ -0,0 +1,70 @@ +// Copyright (C) 2008-2009 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "irrlicht.h" +#include "testUtils.h" +#include + +using namespace irr; +using namespace core; + +struct TrapMouseMoves : IEventReceiver +{ + int MouseMovesReceived; + + TrapMouseMoves() : MouseMovesReceived(0) { } + + virtual bool OnEvent(const SEvent & event) + { + if(event.EventType == EET_MOUSE_INPUT_EVENT + && event.MouseInput.Event == EMIE_MOUSE_MOVED) + MouseMovesReceived++; + + return false; + } +}; + +/** This test verifies that setting the cursor visibility + only generates a mouse message when it actually changes */ +bool cursorSetVisible(void) +{ + IrrlichtDevice * device = createDevice(video::EDT_SOFTWARE, dimension2d(1, 1)); + TrapMouseMoves moveTrapper; + device->setEventReceiver(&moveTrapper); + + device->run(); + + gui::ICursorControl * cursor = device->getCursorControl(); + + // Move the cursor inside the Irrlicht window so that we get messages for it. + cursor->setPosition(0, 0); + device->run(); // Receive any messages + + cursor->setVisible(false); // Should generate a mouse move + device->run(); // Receive any messages + + cursor->setVisible(false); // Should not generate a mouse move + device->run(); // Receive any messages + + cursor->setVisible(true); // Should generate a mouse move + device->run(); // Receive any messages + + cursor->setVisible(true); // Should not generate a mouse move + device->run(); // Receive any messages + + + // We should get at most 3 messages: one for the setPosition(), and one for + // each actual change of visibility. + bool result = (moveTrapper.MouseMovesReceived <= 3); + + device->drop(); + + if(!result) + { + logTestString("ERROR: cursorSetVisible received %d events.\n", moveTrapper.MouseMovesReceived); + assert(false); + } + + return result; +} + diff --git a/tests/disambiguateTextures.cpp b/tests/disambiguateTextures.cpp index cca8b9a1..b895e746 100644 --- a/tests/disambiguateTextures.cpp +++ b/tests/disambiguateTextures.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Colin MacDonald +// Copyright (C) 2008-2009 Colin MacDonald // No rights reserved: this software is in the public domain. #include "testUtils.h" @@ -17,7 +17,7 @@ using namespace gui; bool disambiguateTextures(void) { IrrlichtDevice *device = - createDevice( video::EDT_NULL, dimension2d(640, 480)); + createDevice( video::EDT_NULL, dimension2d(640, 480)); if (!device) { @@ -79,4 +79,4 @@ bool disambiguateTextures(void) device->drop(); return (changed && tex1 == tex2 && tex1 == tex3 && tex1 != tex4) ? true : false; } - + diff --git a/tests/drawPixel.cpp b/tests/drawPixel.cpp index 7565bf27..fd4631ce 100644 --- a/tests/drawPixel.cpp +++ b/tests/drawPixel.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Colin MacDonald +// Copyright (C) 2008-2009 Colin MacDonald // No rights reserved: this software is in the public domain. #include "irrlicht.h" @@ -18,7 +18,7 @@ using namespace gui; cyan 100% opaque at the top right. */ static bool runTestWithDriver(E_DRIVER_TYPE driverType) { - IrrlichtDevice *device = createDevice( driverType, dimension2d(160, 120), 32); + IrrlichtDevice *device = createDevice( driverType, dimension2d(160, 120), 32); if (!device) return true; // Treat a failure to create a driver as benign; this saves a lot of #ifdefs diff --git a/tests/drawRectOutline.cpp b/tests/drawRectOutline.cpp new file mode 100644 index 00000000..6e6a56a9 --- /dev/null +++ b/tests/drawRectOutline.cpp @@ -0,0 +1,28 @@ +#include "irrlicht.h" +#include "testUtils.h" +using namespace irr; + +bool drawRectOutline(void) +{ + IrrlichtDevice *device = + createDevice(video::EDT_BURNINGSVIDEO, core::dimension2du(160, 120)); + video::IVideoDriver* driver = device->getVideoDriver(); + + driver->beginScene(true, true, video::SColor(255,100,101,140)); + + core::recti r; + r.UpperLeftCorner = core::position2di(1,1); + r.LowerRightCorner = core::position2di(100,100); + driver->draw2DRectangleOutline( r ); + + r += core::position2di( 10 , 10 ); + driver->draw2DRectangleOutline( r , video::SColor(128, 255, 128, 128) ); + + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-drawRectOutline.png" ); + + device->drop(); + + return result ; +} diff --git a/tests/exports.cpp b/tests/exports.cpp index 09d8b390..fd2a0fd3 100644 --- a/tests/exports.cpp +++ b/tests/exports.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Colin MacDonald +// Copyright (C) 2008-2009 Colin MacDonald // No rights reserved: this software is in the public domain. #include "testUtils.h" diff --git a/tests/fast_atof.cpp b/tests/fast_atof.cpp index 20c5dd8b..9cff38b2 100644 --- a/tests/fast_atof.cpp +++ b/tests/fast_atof.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Colin MacDonald +// Copyright (C) 2008-2009 Colin MacDonald // No rights reserved: this software is in the public domain. #include "testUtils.h" @@ -146,7 +146,7 @@ bool fast_atof(void) enum { ITERATIONS = 100000 }; int i; - + f32 value; u32 then = timer->getRealTime(); for(i = 0; i < ITERATIONS; ++i) diff --git a/tests/flyCircleAnimator.cpp b/tests/flyCircleAnimator.cpp new file mode 100644 index 00000000..ebc73830 --- /dev/null +++ b/tests/flyCircleAnimator.cpp @@ -0,0 +1,59 @@ +// Copyright (C) 2008-2009 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" +#include "irrlicht.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; + +/** Tests the offset capability of the fly circle animator */ +bool flyCircleAnimator(void) +{ + IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, + core::dimension2du(160,120), 32); + if (!device) + return false; + + IVideoDriver* driver = device->getVideoDriver(); + ISceneManager* smgr = device->getSceneManager(); + + const f32 offsetDegrees[] = { 0.f, 45.f, 135.f, 270.f }; + + for(u32 i = 0; i < sizeof(offsetDegrees) / sizeof(offsetDegrees[0]); ++i) + { + IBillboardSceneNode * node = smgr->addBillboardSceneNode(); + // Have the animator rotate around the Z axis plane, rather than the default Y axis + ISceneNodeAnimator * animator = + smgr->createFlyCircleAnimator(vector3df(0, 0, 0), 30.f, + 0.001f, vector3df(0, 0, 1), + (offsetDegrees[i] / 360.f)); + if(!node || !animator) + return false; + + node->setMaterialType(video::EMT_TRANSPARENT_ADD_COLOR ); + node->setMaterialTexture(0, driver->getTexture("../media/particle.bmp")); + node->setMaterialFlag(video::EMF_LIGHTING, false); + + node->addAnimator(animator); + animator->drop(); + } + + (void)smgr->addCameraSceneNode(0, vector3df(0, 0, -50), vector3df(0, 0, 0)); + + bool result = false; + + // Don't do device->run() since I need the time to remain at 0. + if (driver->beginScene(true, true, video::SColor(0, 80, 80, 80))) + { + smgr->drawAll(); + driver->endScene(); + result = takeScreenshotAndCompareAgainstReference(driver, "-flyCircleAnimator.png", 100); + } + + device->drop(); + + return result; +} diff --git a/tests/guiDisabledMenu.cpp b/tests/guiDisabledMenu.cpp index a9dbb3d6..721811f1 100644 --- a/tests/guiDisabledMenu.cpp +++ b/tests/guiDisabledMenu.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Colin MacDonald +// Copyright (C) 2008-2009 Colin MacDonald // No rights reserved: this software is in the public domain. #include "irrlicht.h" @@ -17,7 +17,7 @@ using namespace gui; bool guiDisabledMenu(void) { IrrlichtDevice *device = createDevice( video::EDT_OPENGL, - dimension2d(160, 40), 32); + dimension2d(160, 40), 32); assert(device); if (!device) return false; diff --git a/tests/irrCoreEquals.cpp b/tests/irrCoreEquals.cpp new file mode 100644 index 00000000..8db0806d --- /dev/null +++ b/tests/irrCoreEquals.cpp @@ -0,0 +1,146 @@ +// Copyright (C) 2008-2009 Colin MacDonald and Christian Stehno +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" +#include "irrlicht.h" +#include + +bool irrCoreEquals(void) +{ + // float tests + if(!irr::core::equals(99.f, 99.f)) + { + logTestString("irr::core::equals(f32, f32 (, default)) failed.\n"); + return false; + } + + if(!irr::core::equals(99.f, 98.f, 1.f)) + { + logTestString("irr::core::equals(f32, f32, f32) failed.\n"); + return false; + } + + // double tests + if(!irr::core::equals(99.0, 99.0)) + { + logTestString("irr::core::equals(f64, f64 (,default)) failed.\n"); + return false; + } + + if(!irr::core::equals(99.0, 98.0, 1.0)) + { + logTestString("irr::core::equals(f64, f64, f64) failed.\n"); + return false; + } + + // int tests + if(!irr::core::equals(99, 99)) + { + logTestString("irr::core::equals(s32, s32 (,default)) failed.\n"); + return false; + } + + if(!irr::core::equals(99, 98, 1)) + { + logTestString("irr::core::equals(s32, s32, s32) failed.\n"); + return false; + } + + if(irr::core::equals(99, 98)) + { + logTestString("irr::core::equals(s32, s32 (,default)) failed.\n"); + return false; + } + + if(irr::core::equals(99, 98, 0)) + { + logTestString("irr::core::equals(s32, s32, 0) failed.\n"); + return false; + } + + if(!irr::core::equals(-99, -99)) + { + logTestString("irr::core::equals(s32, s32 (,default)) failed.\n"); + return false; + } + + if(!irr::core::equals(-99, -98, 1)) + { + logTestString("irr::core::equals(s32, s32, s32) failed.\n"); + return false; + } + + if(irr::core::equals(-99, -98)) + { + logTestString("irr::core::equals(s32, s32 (,default)) failed.\n"); + return false; + } + + if(irr::core::equals(-99, -98, 0)) + { + logTestString("irr::core::equals(s32, s32, 0) failed.\n"); + return false; + } + + // iszero is a specialized equals method + // float tests + if(!irr::core::iszero(.0f)) + { + logTestString("irr::core::iszero(f32 (,default)) failed.\n"); + return false; + } + + if(irr::core::iszero(-1.0f)) + { + logTestString("irr::core::iszero(f32 (,default)) failed.\n"); + return false; + } + + if(!irr::core::iszero(1.0f, 1.0f)) + { + logTestString("irr::core::iszero(f32, f32) failed.\n"); + return false; + } + + // double tests + if(!irr::core::iszero(0.0)) + { + logTestString("irr::core::iszero(f64 (,default)) failed.\n"); + return false; + } + + if(irr::core::iszero(-1.0)) + { + logTestString("irr::core::iszero(f64 (,default)) failed.\n"); + return false; + } + + if(!irr::core::iszero(-2.0, 2.0)) + { + logTestString("irr::core::iszero(f64, f64) failed.\n"); + return false; + } + + // int tests + if(!irr::core::iszero(0)) + { + logTestString("irr::core::iszero(s32 (,default)) failed.\n"); + return false; + } + + if(irr::core::iszero(-1)) + { + logTestString("irr::core::iszero(s32 (,default)) failed.\n"); + return false; + } + + if(!irr::core::iszero(1, 1)) + { + logTestString("irr::core::iszero(s32, s32) failed.\n"); + return false; + } + + + return true; +} + diff --git a/tests/line2dIntersectWith.cpp b/tests/line2dIntersectWith.cpp index 4946373b..a0a1ea80 100644 --- a/tests/line2dIntersectWith.cpp +++ b/tests/line2dIntersectWith.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Colin MacDonald +// Copyright (C) 2008-2009 Colin MacDonald // No rights reserved: this software is in the public domain. #include "testUtils.h" @@ -8,9 +8,9 @@ using namespace irr; using namespace core; -static bool testLines(line2df const & line1, - line2df const & line2, - bool expectedHit, +static bool testLines(line2df const & line1, + line2df const & line2, + bool expectedHit, const vector2df & expectedIntersection) { bool gotExpectedResult = true; @@ -224,5 +224,5 @@ bool line2dIntersectWith(void) logTestString("\nFAIL!\n"); return allExpected; -} +} diff --git a/tests/main.cpp b/tests/main.cpp index 483c5809..1c03fe92 100644 --- a/tests/main.cpp +++ b/tests/main.cpp @@ -1,32 +1,29 @@ -// This is the entry point for the Irrlicht test suite. -#define _CRT_SECURE_NO_WARNINGS +// Copyright (C) 2008-2009 Colin MacDonald and Christian Stehno +// No rights reserved: this software is in the public domain. -#include "testUtils.h" -#include -#include -#include +// This is the entry point for the Irrlicht test suite. // This is an MSVC pragma to link against the Irrlicht library. // Other builds must link against it in the project files. #if defined(_MSC_VER) #pragma comment(lib, "Irrlicht.lib") +#define _CRT_SECURE_NO_WARNINGS 1 #endif // _MSC_VER -/* Each test must have the same signature. Test should (but are not - * required to) live in a .cpp file of the same name. There is no - * need to #include anything since the test entry points can be - * declared as extern before calling them. - */ -#define RUN_TEST(testEntryPoint)\ - extern bool testEntryPoint(void);\ - logTestString("\nStarting test '" #testEntryPoint "'\n");\ - if(!testEntryPoint()) \ - {\ - (void)printf("\n\n\n******** Test failure ********\nTest '" #testEntryPoint "' failed\n"\ - "******** Test failure ********\n\nPress return to continue\n");\ - (void)getc(stdin);\ - fails++;\ - } +#include "testUtils.h" +#include +#include +#include +#include + +typedef struct _STestDefinition +{ + //! The test entry point function + bool(*testSignature)(void); + + //! A descriptive name for the test + const char * testName; +} STestDefinition; //! This is the main entry point for the Irrlicht test suite. /** \return The number of test that failed, i.e. 0 is success. */ @@ -42,50 +39,56 @@ int main(int argumentCount, char * arguments[]) return 9999; } - extern bool disambiguateTextures(void); - extern bool softwareDevice(void); - extern bool exports(void); - extern bool testVector3d(void); - extern bool testVector2d(void); - extern bool planeMatrix(void); - extern bool fast_atof(void); - extern bool line2dIntersectWith(void); - extern bool drawPixel(void); - extern bool md2Animation(void); - extern bool b3dAnimation(void); - extern bool guiDisabledMenu(void); - extern bool collisionResponseAnimator(void); - extern bool sceneCollisionManager(void); - typedef struct _STest - { - bool(*testSignature)(void); - const char * testName; - } STest; + #define TEST(x)\ + {\ + extern bool x(void);\ + STestDefinition newTest;\ + newTest.testSignature = x;\ + newTest.testName = #x;\ + tests.push_back(newTest);\ + } - #define TEST(x) { x, #x } + // Use an STL vector so that we don't rely on Irrlicht. + std::vector tests; - static const STest tests[] = - { - // Note that to interactively debug a test, you will generally want to move it - // (temporarily) to the beginning of the list, since each test runs in its own - // process. - TEST(disambiguateTextures), // Normally you should run this first, since it validates the working directory. - TEST(sceneCollisionManager), - TEST(collisionResponseAnimator), - TEST(exports), - TEST(testVector3d), - TEST(testVector2d), - TEST(planeMatrix), - TEST(fast_atof), - TEST(line2dIntersectWith), - TEST(drawPixel), - TEST(md2Animation), - TEST(guiDisabledMenu), - TEST(softwareDevice), - TEST(b3dAnimation) - }; - static const unsigned int numberOfTests = sizeof tests / sizeof tests[0]; + // Note that to interactively debug a test, you will generally want to move it + // (temporarily) to the beginning of the list, since each test runs in its own + // process. + TEST(disambiguateTextures); // Normally you should run this first, since it validates the working directory. + TEST(exports); + TEST(sceneCollisionManager); + TEST(testVector3d); + TEST(testVector2d); + TEST(planeMatrix); + TEST(fast_atof); + TEST(line2dIntersectWith); + TEST(testDimension2d); + TEST(drawPixel); + TEST(md2Animation); + TEST(guiDisabledMenu); + TEST(softwareDevice); + TEST(b3dAnimation); + TEST(textureRenderStates); + TEST(terrainSceneNode); + TEST(burningsVideo); + TEST(makeColorKeyTexture); + TEST(cursorSetVisible); + TEST(transparentAlphaChannelRef); + TEST(drawRectOutline); + + // Tests available on 1.6+ + TEST(collisionResponseAnimator); + TEST(irrCoreEquals); + TEST(makeColorKeyTexture); + TEST(matrixOps); + TEST(sceneNodeAnimator); + TEST(vectorPositionDimension2d); + TEST(writeImageToFile); + TEST(flyCircleAnimator); + TEST(relativeTransformations); + + const unsigned int numberOfTests = tests.size(); unsigned int testToRun = 0; unsigned int fails = 0; @@ -106,23 +109,35 @@ int main(int argumentCount, char * arguments[]) fails = (unsigned int)atoi(arguments[2]); logTestString("\nStarting test %d, '%s'\n", - testToRun, tests[testToRun].testName); + testToRun + 1, tests[testToRun].testName); bool success = tests[testToRun].testSignature(); if(!success) { - logTestString("\n\n\n******** Test failure ********\nTest %d '%s' failed\n"\ + logTestString("\n******** Test failure ********\nTest %d '%s' failed\n"\ "******** Test failure ********\n", - testToRun, tests[testToRun].testName); + testToRun + 1, tests[testToRun].testName); fails++; } testToRun++; - - if(testToRun == numberOfTests) + if(testToRun < numberOfTests) { - logTestString("\nTests finished. %d test%s failed.\n", fails, 1 == fails ? "" : "s"); + closeTestLog(); + char runNextTest[256]; + (void)sprintf(runNextTest, "\"%s\" %d %d", arguments[0], testToRun, fails); + fails = system(runNextTest); // Spawn the next test in a new process. + } + + if(1 == testToRun) + { + (void)openTestLog(false); + const int passed = numberOfTests - fails; + + logTestString("\nTests finished. %d test%s of %d passed.\n", + passed, 1 == passed ? "" : "s", numberOfTests); + if(0 == fails) { time_t rawtime; @@ -138,13 +153,7 @@ int main(int argumentCount, char * arguments[]) } } closeTestLog(); - } - else - { - closeTestLog(); - char runNextTest[256]; - (void)sprintf(runNextTest, "%s %d %d", arguments[0], testToRun, fails); - fails = system(runNextTest); + (void)system("tests.log"); } return fails; diff --git a/tests/makeColorKeyTexture.cpp b/tests/makeColorKeyTexture.cpp new file mode 100644 index 00000000..b33a47e2 --- /dev/null +++ b/tests/makeColorKeyTexture.cpp @@ -0,0 +1,72 @@ +// Copyright (C) 2008 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "irrlicht.h" +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; + +/** Test the behaviour of makeColorKeyTexture() using both 16 bit (software) + and 32 bit (Burning) textures, with the new behaviour and the legacy + behaviour. */ +static bool doTestWith(E_DRIVER_TYPE driverType, + bool zeroTexels) +{ + IrrlichtDevice *device = createDevice( driverType, + dimension2d(160, 120), 32); + if (!device) + return false; + + IVideoDriver* driver = device->getVideoDriver(); + ISceneManager * smgr = device->getSceneManager(); + + // Draw a cube background so that we can check that the keying is working. + ISceneNode * cube = smgr->addCubeSceneNode(50.f, 0, -1, vector3df(0, 0, 60)); + cube->setMaterialTexture(0, driver->getTexture("../media/wall.bmp")); + cube->setMaterialFlag(video::EMF_LIGHTING, false); + + ITexture * Texture = device->getVideoDriver()->getTexture("../media/portal2.bmp"); + + device->getVideoDriver()->makeColorKeyTexture(Texture, + position2d(64,64), + zeroTexels); + device->getVideoDriver()->makeColorKeyTexture(Texture, + position2d(64,64), + zeroTexels); + + (void)smgr->addCameraSceneNode(); + + driver->beginScene(true, true, SColor(255,100,101,140)); + smgr->drawAll(); + + driver->draw2DImage(Texture, + position2di(40, 40), + rect(0, 0, Texture->getSize().Width, Texture->getSize().Height), + 0, + SColor(255,255,255,255), + true); + driver->endScene(); + + char screenshotName[256]; + (void)snprintf(screenshotName, 256, "-makeColorKeyTexture-%s.png", + zeroTexels? "old" : "new"); + + bool result = takeScreenshotAndCompareAgainstReference(driver, screenshotName); + + device->drop(); + + return result; +} + +bool makeColorKeyTexture(void) +{ + bool result = doTestWith(EDT_SOFTWARE, false); + result &= doTestWith(EDT_BURNINGSVIDEO, false); + result &= doTestWith(EDT_SOFTWARE, true); + result &= doTestWith(EDT_BURNINGSVIDEO, true); + + return result; +} diff --git a/tests/matrixOps.cpp b/tests/matrixOps.cpp new file mode 100644 index 00000000..6b8a9402 --- /dev/null +++ b/tests/matrixOps.cpp @@ -0,0 +1,49 @@ +// Copyright (C) 2008 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" +#include "irrlicht.h" +#include + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +// Test some matrix ops. +bool matrixOps(void) +{ + matrix4 rotationMatrix; + if (!rotationMatrix.isOrthogonal()) + { + logTestString("irr::core::matrix4::isOrthogonal() failed with Identity.\n"); + return false; + } + + rotationMatrix.setRotationDegrees(vector3df(90, 0, 0)); + if (!rotationMatrix.isOrthogonal()) + { + logTestString("irr::core::matrix4::isOrthogonal() failed with rotation.\n"); + return false; + } + + matrix4 translationMatrix; + translationMatrix.setTranslation(vector3df(0, 3, 0)); + if (translationMatrix.isOrthogonal()) + { + logTestString("irr::core::matrix4::isOrthogonal() failed with translation.\n"); + return false; + } + + matrix4 scaleMatrix; + scaleMatrix.setScale(vector3df(1, 2, 3)); + if (!scaleMatrix.isOrthogonal()) + { + logTestString("irr::core::matrix4::isOrthogonal() failed with scale.\n"); + return false; + } + + return true; +} diff --git a/tests/md2Animation.cpp b/tests/md2Animation.cpp index 6717145b..cd20d267 100644 --- a/tests/md2Animation.cpp +++ b/tests/md2Animation.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Colin MacDonald +// Copyright (C) 2008-2009 Colin MacDonald // No rights reserved: this software is in the public domain. #include "irrlicht.h" @@ -17,11 +17,11 @@ using namespace gui; bool md2Animation(void) { // Use EDT_BURNINGSVIDEO since it is not dependent on (e.g.) OpenGL driver versions. - IrrlichtDevice *device = createDevice( EDT_BURNINGSVIDEO, dimension2d(160, 120), 32); + IrrlichtDevice *device = createDevice( EDT_BURNINGSVIDEO, dimension2d(160, 120), 32); assert(device); if (!device) return false; - + IVideoDriver* driver = device->getVideoDriver(); ISceneManager * smgr = device->getSceneManager(); diff --git a/tests/media/Direct3D 8.1-textureRenderStates.png b/tests/media/Direct3D 8.1-textureRenderStates.png new file mode 100644 index 0000000000000000000000000000000000000000..98282fa1ab04f5f9a038f4c1b9563b53c9c4f4fd GIT binary patch literal 30383 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Μ?bU&9qP_9GbG! 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 literal 0 HcmV?d00001 diff --git a/tests/media/Direct3D 9.0-textureRenderStates.png b/tests/media/Direct3D 9.0-textureRenderStates.png new file mode 100644 index 0000000000000000000000000000000000000000..98282fa1ab04f5f9a038f4c1b9563b53c9c4f4fd GIT binary patch literal 30383 zcmXt9TRhYM{~xJTs*%buwy5SjXHujQbILHxDd(8;oX?fRoDa=0R5B7Da+vd>944nJ zhsn7b_LW$LocZs6@w@o!bF+)>{dm1z&)4(tPIzee;QU#>vmg-Yysi!c#eBbFKEdp) z%+I|KUdkYlFi011&osC|zs<7R!_x2C6;AAI7~P-JY;yk2b4lX{`wueb^Io0Qc`t0j z<@u%i(o2u~kza&lzFj?*ZJ&-ibU0CLP}@2+Vbi$o6Ibx>{qpboPA(JozWcUkl?f9Vcpt@P~gmwV-@odmh_}#+;derZgjeQyEi`zk+N5j=YLAM#I6%$8G zM7w4s?~c%|<)qxP_-zKu-xV42<&8mFYY-#ZcmOOHwfFnzs`~M+z~7_bmZ+`Yb<&-o z`&(Bbe>VDzKAkh)IoLe7c=RmlI9xTkuRL8*yK{cFGh+K+&_eh|@ZHMzwUNjpT29Dr z8aIyn~?+WUsS zWyw{n9F*I2P6LdImj`duBLcR2Ym-UB?t9PF50<=w%>9a%$7BnEFNg2>6!~4}LIg-R z7(-D9ea8t@u`>D8viy;T6~^JAI_7-!wQb)BM#oYA!v0iR)aIWmr z)ZY5UT!aOguwkzzWJI6;Y2DSfh`I#(rE2tn(--3c>|Bic^FUIoOt+bW-QRe5@N0%~ zH-Bq-5l?MQ^!VcTuGfpvu-f|ZVfglX$3(JZd*pU+_lvE-ulJ;=S#$p)Prktf;a1k; z%=u`tS~Bz7rE!n-N%Q6C!Zp`t-s|h;&u$BTTUny{?Tm+5&#lP@j%|*Pj{9}HTqwgy z{@I|p_Ux^%jijcHB=V%tPEmt!QjsK;s8BvM|3q`wQkh-E?!V!j&Yj&6>xJH>*csMO zg{9g2SOj2&%sOHEP)58Xb2tk@! zTA9%Ce-*w05tD1{>&qbx+F`Ef`;(a6gB3?ZH$HlZ+T7Z;F0T2G)@o5g!Mc!bEH?qS z5OJWv$A9aM{w;-`ziUbhJxk64M(W2?BZX^ye`cq5{>`N=sLe)fxJiJ%`nfIcP0$%d z7o-S;=AeV`tC*5r{Wmy(X>+tw$>u=|}cPpZWE9%R+Cd%juRk7#@0qg0$b?HLdfg)THoxjX z%6n3+UKsW@$I*QA)1)`PFZqOvT)QijW}jF2w^{33>CwT+(Tk8H_Rzzh!!yj`vAv!o z6mhWQR=0k1BptOodCahj*x4!EF8q?8TlOco(F(rt{rBG$T0Ck%O$bxbx~524S?TWM z$yxJK8m=h`j|}k;?F`#CTXN9tEHL`;dvmjXdT(v+#nxN}PDihRzaoCJI&y!1d;d@% z`_Ga<Li4Ss|*uGL~yJ0r8ENRWun; zx=r4bzqUOx0!gN)m(d*Ew_4K}X+|_P!Movmsg?%xtFkR}_hGJUab&II_1)HZgM}ZP z4>}KMeL1x6yW{RV2P;e7$8&uP2YcQo!`=1M^9%7jMK6mApO7CXQ$(WM#JAmzTl)VOg1ssjz*D^D4qpV%c-2FiH3_UtbF8RBy92dUwN-R(t&WyR-T-N(bhd z!l0faC~YanXX>%wFRuv<^W|g;ZA(j@I5IlkTR8ZmesF1Z_WS#n_iMF})sMH2ox%K9 z0WdgnbIWMYe&=AP1dkac`C&-})l`~StBUlXS1Y!;aOA=2Y+B?dZEQte+A-0s-BQWL zl|y!RZqD2b>HShDsye{RyOEez@J;O+u+_4vmyEz;?nHzhFRz*Rb(`YujZxdp5s;;Y zh>dv+pQ^dv&;3;1WOyG9vWUVekU<&?0qsF!!4%j&WjU_eu3hqB4fmUeoJ-UA^gNbV zBs7*qf z`WVi?CiAZJE~U_YH|AP+&`S^wXHqr)I7W+5ofr&FDW z?l+)aQP4F;qYt}yR$4BL62}AXQ!HU-SS=u(w<$|t&;D)f{@MkW*V&XQsyp5oHlQ+i zfpj)ST<$gGP09iDgjb?eTaO%;NO_Nt$_yx`hjCq9_rI~b2?bA^fDz}+L z4G`qyf`O^iV;f$HusLUTIUYC(NU3Vl}Z)WoxwO|37jfJ zF{ruJHy^jO(d472y~?Ah-_LU~dQjF9i)RNdhg6*>yA7zsgQ?x=I7wm;7^sV&8__n8 zXpV_BtF2?oS>b0Pj{&_D?I6t9kb=Y|*-5i5^cm%xVib~8LNF}zZM2F9TS)>F1z033 z<{{Ei8|z8o1#y^AvYHL_*kR|ZZVPVPT4}r$Ei`=a0e$Ye1J(dL=boSkbu_DVE-fHtKDAD@L7R$4B+*rG%!5 zoI?{V{*y}2{+yvW(pR;Rk{E31f+z1LuEK3toM>>(v z_jNMPX8KWjb1{xCIxs#OK(e7*b%!LRSW#AdRJra=0vBkbI+s%yB92~Ar(Nn;qQO@X z5~5|?Stym1EPhUy7M!9Yoq2kGziDV_HlT7H8Z-6Z4IosHSOQwox0cKFKJjdkusR9#99`7JeZyTZ8~ zMDp`I?@+0u#Xl!pOzoo?qf1s*z1|N&$OPQoYiSV+CqSScYd=cVPxZ10khmjvqhH+ zTB~N(ez}v*KxP*@QAhwSe&+hU%EQP`iI0ypL5zrnsj*$PrAGh>DLKgPC|pe7Vjahf z&~Xdfd*9d1)c>=0bbkV-(Z=W_X-4}wIW#vTq{^gQ%9uQf8fUKq117Op03MoOS~a8N z@)%%|A-*H|Qg*A(K@{J@VlxN2yPpNzpbIz>3Uld}iFvbh*_8R+t$$vY%LR23L{nK8 zYGTt<<9f^U5N+p_F_-*ORN^latR!6`OPPF2trsI6WdO6p(nF+9o&-52X`>g?X$Rs2!GE_C*J925(gQM=h*ma1n}Y93Z&^ONT=q$+|Ei zA=^2xRQGHh=xbzW4r92P&rvfO3Bww&f2Z|r<1LWlS>_cJYH6^OpwGzu%gD766|Ad% zx576miqM7KoukA3zP>V^#O+9utsX3E#tR5x?02YNOB<}Mrn##`z(m!Wnvu@eCU+u%`FHC&NT+~M#${ud zRJbbr!iaS3X>xACbx;f#uY)$gdM4Yuz&0|YC@R2~d8Z8Bxji$6h$QXs_l0ycm%Q6 zOI(r}@5+CbjpCOcbRbEQmNOM!Oaz8qj2=3l;qJ-K&OuYoLbYv^eDUSkPw|xL6}4*@ zPCxO&0w_%OGFqY#H_EHm`MqGZMT#gQTux9VyL;-mA>_5OM5HeMY(~KbhW`oC>X~@D zcpl57&{QO#kcouNci8-Wpz(G!l<1GGB%l-7^cIosK*YjxSR|DyMs5TN6aVyxza*XPAxDN2>*)~vf zpENHOR2zJ84)Q)i1w}yEZxv~|}wP1(K!!v}975}1T;&_Wh(l=2~ zDk{E1n#e9_jMP0ib7esEOpEnu=sQv{gFyW$boeLA)Nhk=M@?;U0Q7q^6%^M%81mn3;kksy6nL$=*7x4}8Ln_>fr?K~FVnWB(@odI{H7 zv^vUpRe>|i9L0!RNv+HWM7GWZ%fW1%Xigx|;EM2?WFo z(;&pGS0f1Y0fR;SYN23W;CRs$!!9QL+ufgYQ%HDIWB`TVk-AE<)@RpChR{usH(EYx z!|soUV1Xq$(O1>~jk-S@&G-81V2FPxCUhZw0fKVkK>N1JRWB`UAvPoS z(#~Jz0fJtkmK&5{!~$CP;WO&b-KD%wI{gIyoJ8?*2}UQe@K;Sw6ZetTWy1OUJsZ2$ zNI2%)ghmheDZGS~}melkY@XhSa>a->4vqORz_j3zzng6|1SLa(L zC=v-(tEFxZaXcGyb5u+Y>fb!pfP{XtRjc0x5y@Y=0)~^D<|<20;_aofoDJ}J9hSHD zBp1+DS=8UM4=KE;C7D8A-}WhCjS9&ezn~!LmpUcbrCi5_i?y!+g}A|KUM#OMf9n); z*_kNF!+K`%R{copX}LFwbVHoAcLTCB+v~dQlhGfnk(ZZYw{C7#l1?G0O=ByjdK22u ziwA~p)7v{mYku{K)=14R)_xpS)ytgwt$q82gLU?!6fF-t=mXLinZaIIH-GySssux$ zD%0O`FL9rI?)=(Hl2l8L<3*NhBB~@!&e|uymr?91;n#9RW$xqM@=G^%3vhQ|rozdQ zJSZuevL&{)Y77&$!25=?qimr|*ZJdq$JIN=FdL*KiF8hAyxA062seZ+RgM(~VYU$j z6APfR`-*x*q(B*wvA-V=iPISf>@KzQCj0t#JeSCjQlztjk~K;&6;w_#*luPsAIdlBN9dr2h3s|R+U3fUX4T& zymYk%{FGZTBG1s|HETX_)+-b>@#MqE>h3)%FBRC1;E9R`1jQf$0;s)(nPs?md$clT6D^eW# z+6Nnktk8TBZ~uE9Lu4BnZp zI$M^!{y}hHpIqJwTfFL@5v|=eOEZ9ERH(ij0Z6FbLFvw4E%%^XRL`?If`;_bVBM7} z22hF``0fM#b+2bD^m=0H>?`?Ur5X3SsYsN!FFGCW&k^%n^n&yh0~) zh@>XGpJf67<`JSsb!C*e|jvrAM~A#tn)~PPNEV`i8@!bc*jCI zrz$yvFKlo@i@8po0-=&2F$GvyfFb>?Bp_e7XO|) zy&G9KHMBu+`~)X(D;W2`CZVlPXu+1;_~JXRqh=F(vhk1S!-!cy=pW24vWJ1~Gw`6d ztE!AcChj?(66oXQOxI!U*m$-#*m)o%t}z)@$Vh+0p}r?0?+awU>txf%Wy0fp3KW8az0bp^5rnFzwBDD+JLHifW_r(F!;$RP2bW>`-^eUTt4yDn|}3KZfnFQ)TJffhi=&X1%yug2C^lW8%a zkipZG)nd7YF<#gn;)piC@ev9tAy`#B<@J+RT8nLtZ@arVlEOneSv%mZj_$&!3(;_F2uJH-;gR~C|Y^K~%kO0&zZliSap3J?g9 z`RMOF!*^o{yU0;NQKiRdAQQ0W{E^EHC+eeYl%TOi501BlP#aqx|&UJCRqj zwK#n%(Bg025=N0OAMAPfzR4SaY6Tp{&mxGF39 z^&>7Er8&@`hbiKYC}I3zK|n%m7VfTKn$qd6FzJYf4`0u#gKHFg<|i>(0dF_Cf0UJV z>Xmy?v1ok+8Y^suso+@MYGKmcGxqk{EW1n?nZV4nCcWY|fkHLZ1pBNj)<#3yRf@D- z1o~8n+g+!YL#Wg5)Q`Q7!>Xt0v<)(Fv{!xnGkDrNu=S!)(efYA5Np<}Pbz68AXuq{ zIM@A0BET(TF0O$ZXk&*RY_3P=<<)CG&E(p#v&L>V$nq3jH#RWwJpt1M0}8jv7!;=9v-LUV5}4r2@}nT}ErxZO z$xRfA&&Dv5d6l%7Gm?@ zfb9cD+|tZA1=;`8?$A8yXpMe&IP;S6vSW91WvsiK-z7Nm$P{Td4MM4NR7`{xxk6T% zRqyjcTSl?>766g!$weV4Dj+lxQeJ?oFbL%2)D?&RKx5l|p1-IPZ^9rm5^o(6MQRpf z4kREF5S>P!!-p+ygGdq1=m~eT=DA-iC?xD1P)bNfp$2>ZKJW51(emP|f3-O`SGZL= z!PS+Cb5ALA_IJ+7f^b!Cc}XbR(<(zzkS-i*v9`9DmO@~}z{ zlYkH(Vo&al2pD}$rl>v|# z)Zgzu={{-jqYn+NE04jtvvMILfI?2J7NWh~%G;!Mrt0n+3Pdn%VTS_s%H8!>T`K7F zWs7cYy^WA1bA4Iy=W?o>zQwj{?N}i4Q<+i>jRhkDo>z^B*&*$@&CY;m)Bc*)fZkYwLTtV(qv9xIa zNxYc6L6Wk1#RQV~UGr?>-tbVip?-RxbjZ84rd7 z2j4`<-7*2mw#Pb8yqLZDCw0-f{p!GO*i>2`ry1<2phiiSCa=XJPwW}-fbR+pd$vxl2AEZW zVpKl6$-w!C*z=!te38(R{Hkq$w4t1+{hGbUkEwj;(p7lgEVgQSj^+CeXnyI1Wk~gg zNoTc^^rC#DqNLZx+({7Vqf^WK`(bXEG}+-pGp&td0x#7g-qdT$407!uPYd1rUl!nF z2)!Qt86hX!i8%+C5KW=oTI)c_f&R^j#SocmfK|3p$rkWq{{8RevVL*Cw=c4D%IK~D zMxBGcvHR!GAEp$l_-$)-vcxQPWqSH5kfL813)a*Js2z+R&5V()`NmUE8=tC$3ud)A zTTKRx&dho|f>bpg?JRpC$Fy?3Yi0Wh(_l*X-VvVqXIvz@v4DiLuuo?F42v_{+kRP9 zP(ycp08-HU^ms8U5j;bZ)#ducb((Y zd*N7>oSQAG6dBw!bJwE)hY7%lFEr+A7P!7%hm*lBZImZISe+h@X46qaV-w^F;V!K! zS&@i&i4QlLa#5orBVoNuTdU^G_W5(Lxyh}WzMo+c93DPC?c<5TI#$a4+ugOqep0~_ zTPLP@vZ6jmixWX&8YX9f3F3$0nT)@};XBJ`XZfsQ-|5drfjlQ7kyOLOvF{ zCxfdvcF)0~u>%-+6%cn1M#l!f_@3ok08!-hvuuoAHGC{b2z@QwnEOFOmXUmwJw^6(F<3#tNSY*jh|&xX zntMgyIx27|C*ebc`6N!rSFQadej3%G%y}4}aes|zockgE9W@ZV0Dp$U1jqlXA_#?O zHCW2zabmH}<0$FR%nx83Tj|iHeCaZ>$)T zFxBGHTsPFvlB#8d(Pv%iI8m&iL9XQxFF^NRhFc5MgJD9%Rn1Y%b^A#`X?1wx$Ru|J zlksIQTs5FD=chO#A20G4+=NDx8_3!)ms8(RwP4%+D^rs*Pwi+HEBmc$Woc<-5sKOf z4(TQ^(&g+F*=t2F*z$TkCLu7S>>weTA6mbt7>=%Sf@e>UB!CHflZ zlSWBR=|-WlN(yAj)atyW#v@04Af)KQsCGjj&nYKf2T44LRJ8{of5kvz$K+w7nJg+f zrtfeUnu!GG#ir~Vf9f&SGtOWItkzqSCaZ9ClKH~B^2uFm*m)(Jho$z5BUWCzzohiI z*OKvyFH)lGWTH_6G8`3VX%C-l$Pbema{tO2jX;f{%P7Jr_09P}c&uAK0a`pb?gm`` zB=fY6`WT1hBaPM;vIY;@cioIz^mgBNwsSeKSkU~Wvichn zIH+;#$mc=V+-c}S1#0e?a{sV0z0?iL+A~PCmDE}*(9JC>qiwdxF8+`v)HS6(a~#8CHqlruD4 z4h#+_LW4SI)~>0mr{W%gKon826bwJ;il-Nb^?E?}z-{S{+E0I#WJTwnNf31I_`$n& zVswRz_k@nNIul?yrkHXBPZ!sHwr~6>H-OgyHp~H$K(3to=k5szj6AiH|9$ZQ{KpLL>SBsXNYyOD05m1dY&9wuwUB*NcO#lA{8{Y6FgkXta^K80m&z*51J59uu~ zH}Q4nbV^FB{wrJsaW>h65;mp=!(dtR8@IdpYw$74Nc^x!=m1HSLOxJZy zc8CPP+j4<4`v|FdP5Ob(Pk=Cw@$}>#Puex9dOo2p59hqcj4haDl6eZ{7B)Q{3tl+` zBvMkR-#M742Xh!N~p=8YuM${NA zZ927&x!JF7g%*sws(;MU;>?a~&@SWFgAub)we@x?bkP!?H)Go30i@!^dZRHuM{Qm9 zehhJZ#s3Nl*erK?L2dgN@r)L>M5j*C2hu+;`%rS~zj`&+ERM;)8{EmYu+ui4 znC5$?pF~xSDe2Ly%Cb6Bvuuh52BE8OfF+T(%<=o%MMKd2+C_07C9s-1mt3p490rUhn+U{0y3=UthH9kN=qu%%8y%6yW(l* z{=fF1e_rhqb{`iG=aSi>j%Vj>_3waq-7|`v3t!SzV*YEVp?~|y)G9kxPOzXjjKzs0 z-o82+iT-O+v3adkw+jt3-6IzCNML0#Q9W_ppMKFM?7((Jvai4h5|$VKyTki~XfHLF z-TMwxHQG?yo-Z76WkgH{5W_F}B7XX-LI&D;dMna*VN)E&xy1C_^l>wR6ebl+;D-KO z{leo`0D4RCyZdriHAUpXom}aL!WP8^652Th%7;GDkd3=nycOCWBR{+$X=#NeUFl)m zZs+g6S%Sexo_~Te9OWijEU!p-Q&dj8Pd;V_BPX{-}84<|HcQe)eqmw z0WYa<+PLZn8r>ug_dfig$DQH zFl9R)&99Y>({BYF0BfXsGBrfQ6xqLH#94;7{<^fzmA=QH@KqK7n=Nd!>H%3ij^&oH-t&n0G0b(PrhHNJ8=_+o z2H4&qQCH98q15F9PD|l?$?^P`TZ-C2uyiiA50&+{+0HyvG$$+>-sPMdqX%%*jNd5J zSiB^1dhvdYHv7Rq@RHWcN7}@^kpCt{?Ls5IRGs8Y&^he2JD7C;FKz!KGp@HSEu98O zAdr)9c)KWd1vx;hl?l?0o+T`il$gOs`LQD@qp8T0<320d{O1FRPF}Tzvb)&4=6l!=IwgcJiB7+k15JOs$5=bDF+&;sc@~aC=YOV9Q=AKs zH#(m>X{q~zeh7U2yj`4-jo~wYWRWfG-_v>_V==uR$4sD*RTnJjyJD|%Fzx`p>qZLn z9kJ(q{i;9=oXkh8HcaT~Wa>B1LU7@?OWW{bfpYvMfu)#aDmxwzM|@LEy~*%|4P&nR zNT!QBWmVHvyhroH37t7)WFVbyFBtN$dYhe z)%u&OL*V;LOO-0WR;Ys;qSNjc%t}dII!1$y8uXN9FR1hQ#xO5OTod~#DyH+n#wr|Q zAeNO|M@ZqAMQG}*ICxd8T0i0DXu9?vb`nAjy^{j%dR;)1nxxu^tzVfB2$>vTVbaGN=+Ies~RvhbG-(+;j1`oICYc)b;UxWO~3?kA{slnOCC& zVrIw;T^CNN9?5hWF4(-PxgHA&M#P-+Ax-P*b}?Q`f5z)zTlyKQrTT5kogq^XI3otO z>}9z4o=!kwz%F@LSK4kC^T=x4XU(f}cJVcr^0-T%d4laQd^G1^P;0=P0DRwm99N^o z8IsV!Zp$hof&1{EO#QgTnoH?3X7Hms?>3=2+Z_L2l5|Jr%$0=}KRvizoJSMJQ}lL) z{z#CZ92RiU@yoDY^^7axbmkUc`ZPK40O2sC`?i;dH$O-!yZAG-c<5_Pla9SUj8{&_ z=(d5}E$3v>k`5v3Nl3K94KiLwsqPk8$L!i))*q_kM6y5Bl*~i-08Zw4#ZR52m%OqF zv$r7g+%XtjKMJV2{L04FG33k>E4iE#Yk&XC7aMUmIm?I3xUP!8*ctlFUi;BI1atM| zIAL9DxB9|1_{1fVT8i%IAe%7gQ@_58JUMGrlP3k9o~cl^(f*~E?`FD>9O&E6xn*l( zw<<|`0ZPM^YtCj;u*hyPZ0S_*^-R*G>DhonICX#UYh32kRS@WwO47lPl!-!rFMl(t z6zwmZTrg9MaFl>3E{7BqG?IB9v6VD3I+9`fv`X$uC974b>nBLrNm{2q;4Rg{wMb|! z;hRVT%HFm~(J@(}YT)CqIJS2XIb2n29{+nq4A)g&K5H(_VZZv`h&!#X%(cP*SPEAi z9?aCEA`6}k%`WbGP*gZOyib_S_kSB)(p6-IIlN&`k*3sI!!eOW$M(CDS`us_7fdOZ zY%JgXl>`k-?t*?tOzuh%>!&{m9`@U`OzEvm-(j)PAx3s-;EnDNatYmC}|f*EsZ)#bmW2 zi3L1Cp0+sE23fl3+6ww`+dElH#O;D}BtRH#%0e~ywsN@J6iEyJeCi~}`l77^CcQ_cQ_H3534cP~>R^K2sC zuR!lpM$5IO8_<=q*gL9|bCpufykBNwjwA+A!^GoDGXJ$0iXD1toCYncD7%6!v5lDO z{i+;Iup^=TD}U7hLut&QV>8gn=KZP9z?bho*8=Z_;7)kURE!Vrx&%aEp2SdOILe(s!cEDBvmROeu3U;H zn9I)Q(oZ_~{svf(7Y>ganNf{c8D@xdwZ+#O|CmRW2#&^7;LTvdsG$^IL`2rkWiL@6 z2&TpVY_cwL7x|7TG7HX%lHrs5O_|g!##E#`y$&Pi&N!Cr$ol$*eE2$y;jA0vA(GG- zx#;9&yM)FLW4Woh)pXW{3vO_E6rP=81tZJWPGg2e?dFZxqaj2q)45b?_r+^t-wUKk z@O1dHS}N$j0{*y;2JN1or!QijpYOQSW`J#%NSgf?YH>#9)B1qFOR_QV9fPsYTYv)Z z16^2u?pMzrQn5OFelgbS5!;sL^Fl)E5y3*;qwde)ehiK%_10K&@UDZSfz%YHB5OcJ z)^6FJB}00wIsp&<_Se4~<6Pm@lKb_{Qm7^ZHZkoyYJrs$Otlb2AhhYnFW&{NW;j_< zx_{Jqg_OTrpTbd=Rb;>4Jag(mge8+@hU?MC_f8qyB6tGiOT(tuhx9|-nXhrMjdWK= z-pcyBfteP>4n!80wpacIw^Esf?M>YIvEN})r$E{3P}h@f2KBU^>{>^s468asXcM}td+pvRyr>gR)*zzg>f*7|7HnbXFe zVz1s=QCw2(jaBK%%EF^E9Pj|KX+d4TJKR9rn<+*L+%U}*-t~F`mg$o9M1LfNE5q3; zFC3Pol1B6SBv{){^RuAy${;_5RIIPj_`^cN!^Ks+XPD0S!c7+r$dn1@*XH4aqoo%+uqJj(}FtqHNm4iTTAAWrDeO5)lp=pRi^z_ zxhGVN#KS4?#$09clIUB`HpF+@1P#4gD@!$R0Nz_jXLp}iqc`bJ z!%gU4atYvswtO?#@`s89zIQ+p70)5-X9fZQMbNLf@1gAz7{>NK?Z_uJ$2sDz5b4St zl-e7jAl~Br;pQEydqIE7-qxQGd7x)c3H#G@qg+um&}QMeBj>}DbmmPBez>Sv)(tDg zv^Rox{>3j8x3_uD>{ZDXXPP}eh2t{5N>c9on8P!P1UAlA$-aPU$ z^3g>d@P0R9Mt?qz2roZY|Z=4`8DXw`nglkZhv#IqbD$$a3#rPr66bl&X? zCV-j=f-jPNXB3~?6&djBVTZeil}8)S=d?jG((FSi%qWM8TS)7>h8ru^AM zmM-NqR1LPHki!GL)dNlle||r}R*&L5Xq9X;k9N5*|61OBGC#b{wmRz1)hK(FGTyJh zzgwS<*PL`9;KJNW7QQ?H8yh95m<1uq-10X++%|gKd!gd;Fxq75j+4@}_TJC#lL0Z@ zj{4?%ljOh3L68q;~sY=Vq z3Q8sp8#+lvNljkgF8h{yQ0GgW{ zpB(^@|K16=k_f0Tpa|_vWBmGGBziDo&CI}S%-4YSCncv6PNctsfI;~A(`p7WbilwqA}kJX;FV4L?M2GpMWm^ z%W;C-6+)w3VK!Ks$&?F9ib?9NsVBC9dissNRdrqAokCb&9<*q`JM`}IojClXX##ym)5$KReCPfY~LJoNQ%%4Hj`_`xrCO- zD_H=SP&O&_5#Oo8<$_^O(O_vnWqD;6%rq<3x6?w3@(I2I1vIqmF)eB*Eplh8I`ZH< zF1AH#^)OOhq5R6G=j8RwT?I7kpX?eivyYp%nsW)s6YOb!E3CP{9oF1G)8e)24%;!V z&%k|DxycSgJc9lR$v64QBI9j|vD!F=kAC~=^yLuSNuq*5d3WLB!vtkIm*d%*t0%AD znC_N^To3I2j5#6tuo57&aYDh$B5tT4UnS|mf(EU{H6I5Z*$4a*oot=Vg}#@(pw*gOKpt0i#H3u+UVTrFVbCa@Dz2` zNbU#8GSeJa(i0rm=lAV-z#pFuZw1mix3`bHfXkfA0mD{D|JL}g8BA@&+cP!~+C zVk-8blc#^W5Pw@5{(=}!s3>u?W-R2@axxm?!k(_FL2HBbMP7{#3CQr7x|t~mk~e0G zN)=XV)4Sc9k7~Q-Yx+sy{vtcUAQ*v?xl=tu_m|2+sQ?Z(cUb>^LIFNP{=yD>w%Ax z1HG#ah|pJwTn?}o?|Q!Gsb}^N{u)pVxNY#SM*dymCl_6(-6%?|AnViZ4!tk8Prv$N zVLX2VD&Vr<*K`T$fGkIEd<4;Fm;5A&!Hl+`E2GTBEM6t}zQ@I@L7kjBwU3VM>F>xqCX*9P*iX&NH9+%R}g8I`e?l$9RrVgor)&QpA`!0O&}AqTgs zw_PPJtSS)48>!JN1yalHN+Dv=31@F<2WzAmuyQRJ(rS87q=L5zccq??nR7TQgSEclFQt;^-(+f3kV*&RLlrT)&w=Vhl=8X)27-Bdr^JnIu9S!0pT z#+v2U+PQK~jxz%3;#LNN?_ z8u^`44h+NpKx&w)sGumm+U!NA?0R*+Q=In4(5=R!X^(q>;7SDYmVB9QuW!UH0AQjs zV5q6NB)V^Ltl^vMJ=C6B-+{R%yCm|z3WD!__tB%-h+~g#=1=2UT{z}0LbHj;;RMIn z2$smrKf_%*)`jLMrhz(R#l2)PQ&rpJ9M|DAo89Q#YSG%vF*DaXnR zEmmsRr5HAMYglKHhyTU6mOFn(P6l*@a^6zCJ2fIAg{2+{2*XE+1rS|v-rAOP2N_3V z{)>P6A4NbP(+?i^or#Uo%ERrgp1gNbR7*s@89Qj0jzPkpsbX@*a!7T@Mj*2+F?Y)Q5nlY!HQ%Qymm^~ z!g4*=LlND6XU&`jb#AlzeBvoSvG{oSi@bz-9O!!Gqp5; z|7t$Nf{b3Dye7&{*`Gs|1e_2~^VUoid51J?^ug@gZV}n`lBzGy=Tzb9mXs zS&bik7IdYrb(8yyeF>T7GdvNr4=>Q?1V4WMmJU3dy!Sa>B0rB>SFFd?~m!48Z1fP=nRsI#Xs|&M^2*F=<@$2hv)( z3>M)fp}kZNasAps4&C%b+HDhSexGM^d7X#{0A(I5AbJfjrvuxkf>*oW4z~Ljg za;n*B$j_PM0$_mAHE9mOMmJ52|8*e~-fJ@y|;nJ>{(y9yD zzC4A=Mx7Uwl@2zyJ?yLhAF9_q-3>)~6x5JuGK|0s8)p71zc?V90C!s>7+Q^5wB!^= z%*&VNZ*GR$=X!_^^L+{}9C7UbPbnN`tC)ZsYQp4u7E@tz8xHIlpxUQE#MtCNWzC1$ zof0+@VpHc*7d|AALe26#6qkcwsHa;(k&9VC)vyWwTjiDbk4e!M1TmcrU3QXKIZ)(yN5?$a<EIs@!UH~tgi=o6!x`i? z1WB?=UvleoXarWsN)8D1uimKmbi8a(6efeGg>^V!6=n!}A8&YR%0XwaknDTbhXH?d zFw#|m0DrXbw{r>Aat4O3X)>?7&kZ)5bq*h?eltYy^?N#COaj-)+SKt|z@CZK-gCI%vlo=0N7 zrzHSxsQA=o#<}zW67p}``IW8H=We?$X(s_B?$lZ9Tk%iu{acM<0_xW>(^{EiG#zRB zTry!e%=wUwXzKB@4ig}IGgte|&BpTM{gt=gMr>9tgVG+*JoXnc&4OsruLDQN0mV;U zgoc(Z{9y1)HY|EG+;^Ncw)u_Ux8pfF8sYnpaCr zG`Z#(a%GOG!naGew152h%8xESX1!(IL$A|x!!7Cq1rNtOEH;oD7?|9l(sofHByzKz zntr{99^@^>wa^apI3=7nm3y3N^J-I;OY-LHmvWjZ8=V0XK+ng1x37sa^Vdub=C64O zW;ar;Dhau?q0H0?U!i^%&foGm_5$P%(_rXhfh3uCPuP>4Zm66$5h(h9US7};-;wKY z#^K2$nd>m(`z!htP@G|}ta3-Z_;?Q2IsomhzGeDV-Z$BWvs|UU7#tZ`)vHRW<7Tsj zRb0HC{y0ZJP11a_Ef;kUao^JHOGP!E|BS!hE76lU`qA(icMbi!T0H%o4FnIhTkk_< zn93uTHji<;ks3c6DJG+(2KmChgPM97TA^q);WZiGP)yRlI z7Ig4xOBSB9#utdOr1`qtMaZEEamMCn0TRFGSPcezqLgWy`)B`3qE0>m=WWD)Vgi6? z|C1K!OZIy$c!c*X7G{0U!2-NPEp9S8jGM(kOjL(+F`E8~-dC4SqEM2N!(8Jgcn@|d z=RWzi>ka63NQ~YD1cS;Y_`2*!1y<$sQppPsM{?RRB;Tu<4m&I+?1145PvhfHJ=2-N z>4k%4DLiB>{9x7ltIK`2ylyyX)MtcrjKItD%2tIz|MH}~j1#T5y4#zUc9U9C686@o zI|0I9!8c984H0m@dlN>v01{r({#>To?>a^2-zGywNU zOrmN-SaUcthN}~sGKt~Medx)XK+`(j$M%U0Z>NaIeFi_6+zpA|BgG%@XUsC`t-o5@ zp=YsW8&;v$d#Fbf5;ea;`~-;2YsRfBqQs;g;kEx>+JboG5(;WkJrE*&NeMwrG{Sx3&#FzTQ0Qv3a zjDM6Y1*1uwf!{Xd6FMw6h5p&z-vI*cNkh0Q3J0#7$$6CR!U$uweFc={;b>t7GV~b* zt<7I3%bn|*K#(9L;;MPld&iql-`@1Zx`AH$2<67>m)2DTh2#&0vGKn< z9hs81e~JxHiJ;W0?i+UI=!x+2Ti{niE+1r_t~{85AN@O^Eh82Q3~O-{3hh%``K49S zzrTrBI&FSKV)#yx6dNliJ~}+;eR}Er34*)^=$2fjTlz-HW!KV-vM^+#A1c8l3Ex%+ z@UE>|83o(0JtvZm_!387Hl-{yO{}68KbuvU4_Y)29t!L$dxrRIJ%PSyXw;N1IS}o8 zY8XNs<(cR-y8$pchVxi?;0G$LjrpTZjGZ)~g#7yR)$@S5&lrW= zY`%%*j-($QpK~V6uYgq?R10&At{N;T1Puv2rLT4PI*bUtrQe6Yk$PA6uO@z< z49=r$9zO0nlB51TK3>?;XAR4&!g$!_`ZQMgQ|5i8KENFxN?tMW+h|lR`MepfSz?#F&Tk^Oyn~W# zLx7i%=Z2OdsXLv=FKfWphri#|3A^o?5t^RMgF1Lfz0&3hZ|L&u8=@?oJ?!cD=+iNQxVX5^om(#I>JrE zHavj$Z+CAum$;Fq+d z%Hs}Wv`j`vL=6@VFUY>VdR^*LzdGZ(zw?=BffUOe-( zBoqMgRZZanNa$x*`wFuEN-u7P5ow^g$tKEr_jYuIQIkZa;;IMQVeMMq7s;qx14Cx|a z;9JS0JRnL^-%sHX4_4DI6{qqN2VxgzatlCBxVsAd<5|n9Y_41%3)Y(@Z@36ZhUstc zW2c~g(eh(iHW-WWDFMJn#TiMaGO4h22i=VTr4fJ7$aw=5#;6kDelCq5<&Nnnx3Y)p zyuUD+*W~o#T9vzRfi&E{W_}-mAhc+l(GH+1%w{|>XJ?FmX1MF#rFq_~(_|U28=C-Q z<#DxJuVd3}u`qi_H7}r>H5+>EZPk`^Kogooji`UVajR#M>J>4^7p^YkZpb-u%jC24 z6Cpdma-(ft-$L0Cnq~?zp7~Yk|90 zf$w&(P2!|32ZD=`ym~`SIwSInz~UavXHL zG)ZY40U-dkYonqxfSytPttqj0>zz7Pj+KhI&c=h~(<)OvKX{odU7JLb+eG zY}PR_PFoY7Zx?PeiCX+Q*|>(K<^))X2;75pSl3^@n80h~q8S6;_!3h8F(v1vY%XEe zPOuL12Z$ZS#RYI~5>A^-ORcZq+wu zdQkX0iGNZ(9USN{53QWvkX`y_k}f6?5qozWP?jsG?`z%F%Q6D|TeSG^*HhjW)0Wdn z9r<8^i_$MJS!1G#c{b1KTPJ_{d`4_ddL0|_Y@S|awldFB2|m6GH6KdPFqvsP_%VLA zMr?SHc?o;7TGvL3;J5sVbW6jef@GIJI{8l?&typsuz!s|A)jvD$fUG3QVvf}Jbx;f zj&ZHKd&ZlYUE-IzHvGAg6EziOyTey;tG0trLbO}-DtAe1CK2~Mlw`;ym1mjtdh`_< zE%f%$gDY7a0HOY=@b=gDYN|hO^}(TjbLMj>D( z%~*av(&hq0-x`j&e8=h=J1GSwXG2i4C&Q8AF+{ z4B8Z-Q^aWZN?ZF7PkGr-F5irO8qbg;p)&=N@nC75)tA=OWe~UrM-jp9Tc8E{@>I;K-ull~VjC8GMVUgn< ze4ipa#>;^b10Z(XYcr7lIWO_qPHVGhV@^rsS5-XwKqKMx(xc*r0rB{MEjd38l&K12 z2Qz4THeV{k&->$TL^Sl5rH9JpSo#Tr2Ew1i>Gp@AqTd=={`LN@VfRA7rrtsixmc~}wR>CL zR~LhDo?O0KG=?vlY+1jGn`xqHDN#P1PRG--j+Ugtw+`N82?RK!v`{dGHg}ECXMn2? zzOc-aM?vE&Itd*)(!v%E9rM=>lW04}GH3MvI9hkRh5mD0Dg~pj8LFeforB3}-pP|L&}(ye2s#Wv#egw%Ub%0=K!k zw>J%@N9ypSO%u%tR?T*4ulbG8XaYTU#;M*reE~;dB(F_SGT~M2H+N+QhnHDkYuig9 zrYRBC!D$6^?<|J)L+}yMHx}LqNoKZ!QU>&*W*zUk6Sp7%5emYy{Md`?;<_}UG4^WP z*H5Nmo_Pd9z+sQ>=pnC@vz&-aZK zi#I*t%%t#i}5V{QUEXTd{u3l^{WzR&^uFj**3Yb#b8M^U^g{u0$!Xk12$@(9BtlQc&gJ!~W}+^kFY)^N`dD z87nGF!g)qY72onS97--ZCo^s1SKn~~Osc=Qb(A;}mlbokYm$W1+JjoaD4mQ7Qm@rR z4;P4lM)YhEKJOE_cZ2Yt;8zUR*rIr@?O#6eF)x$Y_0Cs4nq14`CrjcG$^O%wv6J1X zd$jHVkE;XoUlEre=dH{}fv(dEnmeTS5bJ67O}*M@UsCw|hhU>@yw*mRl1VTkvROPi zr-GTQe|CP0Yqj`j_csmWVQ5mD*dP2U`T?ix*)`rLn&smfkSL*f$S0pXn?FzZvTLcD zIAaAK^U2BKak}=W(%B}QtDY{PRYmtd)v7E14JdA+u2H+DiekNG&;+eax3m0bxZP(7 z=v;`ek9q#@@U8=DWP@ZBc@`{qQ5uui-slID3N%$9-W(O2qJfxy@QD(uKWJ{ z5_$fg!oNcSb;$pm*Y{JgfQP2&=Lg%7fBKG{PGc9=^RP`gcY!U$3s#F|rQ1p>(Ku_ve|8IP!Xbuq^pZ^YD2bJUb=e9y(&U_GFR z<$m7|%V{4~YoU22j{K6WPJS-cy;Lp(-7Z@c`iBE-^v-|ZbY@3V_>`8tFJ;gbX9)0P z9IoC)KDR`})0HeLLX)hjJPSmckvKxjZc17xituX;_Xlm0&b|B3_;uW`{0`AIBLHUt zsbz@=8F-x3#P2G7pwTEI(Ov~!u)XczK-q(QFlUO) zUDEY~4SzNDcBdNFuUqB$6}r3bW?W?-ISgIHLG0nBsb)d}ESInfH97i0b^7i>U`=w` zsKq~g+~7u{ytl}UO5niJQnR!7Lzr4viz%%&$0m`tUs<$K?C9cEU_}t~eDcKszLYr5 zOf0-sipBWSE3Xs)v6IkhL^WE!@n9qXSO4XWf9k%6olS(gS|k+$lYv*|WYKw>M+-x_ zT!an@^Ark-5+wj@wzC39vlqXBZzO^{-=9F zi|6UE`E;-x7q7(^ykG-sy{KX&fzbyhF-DB}iVDLq{~6w#6a){MrW*S(CvYaqpO<8= zK%N)4A-T1si3d}b{N*(GuXzU=)s-P4+IU+=%D@Ts7)^Le58BoJ`$xq-SE_33 zBv|cUaQb#ghpiv(=RZaEjp%643Mj@mAbI3_Rik*+(ZNma(7EDe2aL83(q*J@=fmj0o$FEYmz4~6yZf+&{4Zvb+y(2M_p9bi(?GW-gxnVCi@mW&r28cW zrwow9{Jxq>EvM$<1wQ(%^u6opf>`-;r%I=5@es&sRFWdHaQ5}wB0aua9d;wVd#Rz+!0sO%a zgYTFQie?wHFM~}k4roX~5JTq7ATDdnxfW7IirpSXgHbmuFSoQOd#XOhbdM%W7V-Gy~1sY#ot$ zy1(m`+UX_VY&Pi6=iAmupIl%+Q~zuj#)!;>k_3Vmd6DCL3$60dH@?!xlc&w{)0G#35> z?SWZbn7N9^b5N zpMHw8e)n8BwskGVTXm!nedkw0o6eXDvoQ<*pEx?D4W?!;z-OYsvob6me^cXUXCvqW zaTq$!AwHXV``cu11$s@Cx&3JPXf^6NNS*AuQTV~;hZOgMG?lv8;QJq1B0x*Pmz_}oO3w+~|G3vl4mKmEKidv%+WHIIvwT~?|I5K?&Xg@k#lB8VKvV%7|u zPR}C0eZo^)WJB2oC$4V@juZH{8Lqxh2CxoH!+7af&Dn712m;q(OD2+bgDyKM&cI44 zFUmcU|5MCe5iI)P$j?m@@?IJUboRW~tGi_m8U1j<&~KNt^}F#XWA$EO;G%{63}w3U z8a@7aIFLU46RhXB>C+n<-F7tnpS$kyZks}wS|=pvvY9Qj<$+%WKU_Ya^ z>g?%uyb|G_cX-=6o<=;~n4~qVgQZOSN zkdgw*_D0Jjby1KDY`M4}TStb58wL+y^x@+hj;r~frr-;$C?WeX7Q zTH$LoJlHi*^&;?mg)z%DcIK6QMV)KZPKP{PWGaY6r3(r02N3res|*%f>>H>@Sy{Yv zjyz(>!47RK;@Zs;BN=-WA7Z%Yvn9J_^#I&P@ljaU-tiA)z%uf^A8sRkzC>96hgcc@ zSiO-JcGx#ZY?W*Tds*JI-*<1BkLGb!3Mlm7ewD zC!>Fe$8T7N*$Mi!*cIpJX#!%74+qt=gZ>Uds2}Hb_Idc;8yAs{taW3fz_D@+8LW~) zcT+|r-T8HhmusJ-6{H&c0cxTKZvgDSSh7(I6=@qi*p|kvAP1s?x_&dthp!Y__Q@uV z_DkE*Dek!V%2_@9>H6f}-fGo!NY{c@HYb;8JIv+ov(x_5gZO{(@du}IQ61V>1hR1m zOCb4Yt|?4^neerWsb z*|H2yqp72JNYs|Nf2k+H-SwhENB)zB%lemNa%r9it zjS-0;p=9aJxyP3Joz#_ zeB8~6zjGZhkTX&d34N^PxlMrZ(?8~RcNtJ~8F8rFbJy*j6{NK2g0Iy$Ndgb~lH-1L z{Sp%0wA5@k-=f-LZ&1WAYcW2)G9V4t%8*!3Qf2b@o!bd*Oo4 z?7@-L(e3?&&_pETNbfB#_rLHxV(0ghqi1C`IrWvU9-SGcxZF{Y1r6}M-Fv&CUblW6 zhlRQGd-tVt&UHDMHcCB<{b1n7nDy+H+?0_bQpA(X#Sectd^z`#B+$_HThn$9Hv7DA z`w0#Cy>QB=D`)oEb_nXJ(i&+7lR z?%+yZB=z+i{*A$-IgMqi;$mWKg@1-CMyjv|7?-$65zYss$bJ#l@%-+`K>_^v;Cox+ zaR1hYsc78Za;o$C8P|N@3)cQQc>mtetchW=BrLXOyFX~BzxCq%sJ(PS`1tVpc8`m0&yQPI& za?MD#Cc@-U?X8Z77Xq#d#G2X1$I4XoE?mbNUFUAX&UlPsA2f+m>3pANnw$tPog5uU zQZ^2XDYm&xU}t6?;5&Y~ZtiF(NwVr+0=`Hy*&Kdk zDy_HELhal;8Ero#=8mH7JOUU!F+q*!92#drmLbn+=m)yVI!PbKj#9EN0bR)fd2+Mk zqLa(#-hV7_Ltv3e+Km*Ui>bww|9k3#PFEKXlzL+jBe?ya{mUnh>=i6s))={R5hZ}L zhBx@%&;}a5{9y#OfXbjnYWY`unEO-ic7;Hfk_Yy7cW-QjED`5+DH_0W)e<$=l z>d}>0<=XcPy`&>V+>j6@H`}V*oK}d9iS98$Np>O-Lqap~j)j1VIub~QIR`GdViAIZ z+0R5>cv4GA$GM9Oj6YlPSeWhD-Ye`3faX$gP5vV_NWfWUETLj=5}C;BXKzIrcI$8q zL~qkz0SGzVH*W2Oozs)PV~$7HvVI(F2XiDaOgumkJL_lg7|op77S>)cN7PgVI@YK1@M2#ngaEK>=(ObT5I*QP=*lTA%ie4<7)th)3 zx)=c(5&{C*#gQYio}u`+X+C#82j^+%d0QZ3Olosm8|?k`2k;1c0~MVNnP;;LI>)}< zy+c#kUefnvz*u65CYkF7mc4uLvuSOt?z=kL_ko?s@c2_(f>EVv?bhvaX!OrbrPG}z zmM)#@Me@Ic$(lg%Ksb)@vbb98t=jl>jn&LF=S4Q!t`;ar+`v+@5&`|^VqMAcW+3D;%cqqeeV5Auo26Ci zZ-o|e9nA(r#>a~%KhG%KQ55uvUA)>#hY@oL^9-tGzeoF+wFyΜ?bU&9qP_9GbG! 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 literal 0 HcmV?d00001 diff --git a/tests/media/Direct3D 9.0-transparentAlphaChannelRef.png b/tests/media/Direct3D 9.0-transparentAlphaChannelRef.png new file mode 100644 index 0000000000000000000000000000000000000000..4f40301fbe68a5e8a1721e72f50694777f6f2e35 GIT binary patch literal 30225 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 literal 0 HcmV?d00001 diff --git a/tests/media/Irrlicht Software Device 1.0-makeColorKeyTexture-new.png b/tests/media/Irrlicht Software Device 1.0-makeColorKeyTexture-new.png new file mode 100644 index 0000000000000000000000000000000000000000..20cc84e00c36d460971375bcc253a7e4ac028620 GIT binary patch literal 13284 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Μ?bU&9qP_9GbG! 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 literal 0 HcmV?d00001 diff --git a/tests/media/burnings video 0.39b-ambient-lighting.png b/tests/media/burnings video 0.39b-ambient-lighting.png new file mode 100644 index 0000000000000000000000000000000000000000..a49b3071e27b5e8cc5f6564cc3ad3316ce541b2c GIT binary patch literal 391 zcmeAS@N?(olHy`uVBq!ia0vp^3xK$Sg9%9fI*@0EaktG3V`FN8T0(0awRq z4>+Y4C$>Ih54VW$n>}++h~|%z-t&JOAG`75RyzNK{VaXL7Jd&b8Xr@_*pd9LLHz#j zdA1Lamd@L({^wB>MaGfsny~-7HvRCQ{B14eEGUeUR&TNiQOIXL@y=DHpGe-!1vtFO4Xhp(jfutCk9 z{by_+=jCk6FZTa2|Ksn%^4;l${q=_)-(lXN*Z7#FPuRlmfdzz-XH%WD*T#3lW4kxs z_t*E{Ei}A2&E87BV#mq5n=7K$md$UUfA8M2`475~HNkZcDaMYEzdwHb_v!J(zyC6~ z&PwAIH|ION;pV=-MZf@fYsVk__TizJi-kc literal 0 HcmV?d00001 diff --git a/tests/media/burnings video 0.39b-flyCircleAnimator.png b/tests/media/burnings video 0.39b-flyCircleAnimator.png new file mode 100644 index 0000000000000000000000000000000000000000..7ce78dc52b77ecaae8abb99de02383fd3280730f GIT binary patch literal 2577 zcma);X*3&%8iu18lnPpHkTBFzOBJoXq;|$GwicJ9cCo8ktAtS^L{&T1T9PS7Yw6fy zFBPh`u}kf>RBRDq3$FQdf6Te(p8Mnbz8~**-e2!|&Wo`$Hw3Xm*Z}|l$mkb6tBYHB zG2xdlUF_p_e^mg0ZPG|j+a^43bA}w?*qctGB5V(CN@4JB_H|;8kSLFP)s3bvg_*#U z=PqZf(e_C63_v};EBo!Ch!pWvmAnB;$g-OMi!-l5Ks87$a4~qkYq=fMhvv!ruL6y0|C4E;o@wAu9@muM zrP&aUszl<4?;2W2mZW(M(UiF;@VnrcOR8`w#-5R-=7=Dp`FBj2trNWxy-D!7CxbMR zb+JjS8mn>;+$?y>%nK$Dzfh>{RP<73TpF?tpPjpl*SkkO)s|b)q zH6<%!?XpX?pDgXy2!>-L22bMs4??Qq3A&6CPt}u4lcb6Ite0(|l6Ov${_*|&qhc$q z6z>y*MAuy$F~7crRUr%T>~OY^V}-MNb?m@Z1pk|y9L%qBKB4QeAFo@b>DjxILoQt< z($bwg3+ieA#v;9`chPU`t1br~Uc209VnId|itL)OyLD_9-82LP*?@5AbG2FsrDwV; zr34GrDrYd*B6%FRKG^A!(kt)`Z|Ai4JNw~{OEb1NW=E+SYnJYicQ#HlgI~r+Ly>oV zIG)tfqz4F`FvL$&!Ow(3#3G^JWxasb3jIQbDn*;^9!W0}ye!M`{f|f>Uejtxh3db2 z|A5e9R{OnS^1|;0nQz@JO9gwF+F+H3E-RvndvZa!y8tvO7Cnl3q-!Is7Iz7524Y9< ztB`+XC3At}kxwhtD#t7&HHXvxzg+z@a9s4Bfx)SDBu;`GzQEm&f5wOSNG$<9nYW{o zh_GVL49`6c6_mJ4seW}KG~enKu-;Rt72i2}bJ_!Ol1eu zV7{saMrD->PX{$`&lHu24jMWg{Jy%4;*V@BU2YljvxEcr?Kv6eARdj!xoZ)LZL_ii z>}RNp87sy@VwI@|7oQ}afRAK32E3By(w2sRk+v-Y8GJOgv&~(vh#)JAeD*EE z9S)gw452)#Ta?w`Vvt(6lNL3z+N7?k(cZ@+5W|*N7?YM6M_aEx3HJ}N@3XmC%nYxk z^XCgRz}T_H+TwcJGf3i3#ag^sE_Gdh=8zg*^O-SKgFuD7XtMQtQ;`Z2M(W0o+6Tu9 zMN&bLn1ySVFUIB)D_5{#?pcX^wqx8XK`e5t{%L%WkKUtL?(=(RUw~AbN zLE@(V+EDhAT4-6NIM8pau-&&4WOgzuI3gV;rz#Gh$*x+8ukqUDBGUTXzyQ`<*6iHz zb{)m_^U#?d$lr2o4s*gwDY&9T)zeYP@U+e4RERR{Z|gVFdEVSTBIy3+9476Db68|V zlROhKGDZn#8MDX+KEmMsC&K<2wf{gbs>(1l%Tit~&NVot6wK`6!P2XlQ=`VkJvp36 z7`g~u(Nbxk4fc(eCCFoPk1xKU`foCIj6UAFwx3Pc*ye4v-cejTG4Q+_#4L3 zquilTB+Jtz7Mu_-W0dxB)zk6$1g#-GS7*S7m>LNclV;;zJ|FY(fysC9>}NZNo<4Lu zbDw}|PJXH*MW04mX-e;%=qvF0Oq!a#jCmLA#I++w>Jcm4fSu6G_Q+1B^VxV@}C`D_vgh%F(~8_HS_h}Ip%|5 zyr)T0E@9Yn~+uR zLq_ydMv5C9e`_dM*o6f$=Mh>z?em3Yye|__F)POxznVi&jMLdGY)kIW+U}9tQ$b zr*t-nIBbur;Y2E3zzmPm-^LHHR4sJv#t2(_QO?SAW2DYviBkX_w!3LShB$s zn(-jt&rlxwE3#V;b;|=Kz_)^m7%D0RPBE*BsDXT${JJq)Q0N8>_z1mzR!Bbat%}c(I9w6W zk7n|9J!j{Eqj^AENFeCwg4vaM{(ORf)p{VYf z;*yenK91CUSCFivjIzU z0~+cQlySSo{K-+a9tl9|ouXWg2=L;1Ls(E1{G%TiZZE=dowKq#u>nh`Gi+`&MTK(2N)CbOToM39~RE$HiLh&I5X9*Lv(O>eVUN Y-Z%Z_#FN*p7gY~nq;IZQp@WS3H8AK&im?##~Y&hEW?pL3pbp1bic^wjTBKB5Ew0QWRCAcnWcPq$kjIq~iO zU%RIa0Kf&%ggiG6L~r4?t9g18c>@5AAurc(4GKROhrFRZ0mq&rGk=9nZZO~g5SzAz(xoi~u4vmuH0tae*Wk`ZQ+Z6irPQtjwIXx#0nYTBfarEZ0?Xv3Z=EKb{ z$41Be&2d!~h*L52(%Fk}zU`-_8FEo>7k;_gc5$qD-Eea_dYY$2&&QuXI=WF6aa`WD zF}HfTy4+)zwY)JGM;bgcfmz)4J+5yJJAd73>u@~RAHw|aC~m&c_`3M!j8oXli$>hf zj2FZ+KvRs&dslgN`+c=*rv%pz)d1p8BXuCCf{us3_V5jp8&SpV_qe;bXLlM!dTn0o!Z@G0R3j{go; z$Jx04UBlbTXX+Y?iUxon644s;&uM7V{Po(A(4EVJ+jTJ`;*ii5a&>gkiu2L3_%;3S z!_DN){>i_3rs~$9zKnj=K}7fVX>qZUrC!hSM)jZb%iHTCPO+nILAO_J#O*dr#O$2} z+#S6*4Q_jni#spm!aiK$x*rNbs}L<=57v z<~Aae$I@+AG^BjO#jC!pEgy#~w?_%I8Fe>{ah&02S8xv;vRbgm$wov=P;jPblJGHh zpyjv{=2`DCQ_TkR;Ka9)2`OG)H}ow3zDgtaBCOutjUQMGg{>6<&wYceswN4?WkqH6 z9)pqii*@}x^ur=jn{+2aBEm>Geq&^MQ=>KsY}z645?@g99C*DG&&R$;BQ@-`jM# zGuKme44)74O2SMuG&K0*piRHlIWxZl-oooF%Qc9*2C0!er}&Uv3>=95SK1IRv(j8y zCbVkU_uOy?3SK9y9=x_T#+-(?+8X|6bDs-(eemyg(Sj(OYdHWTeJy_0{pYcHe0=|G zPxsE{YTPkTT|MEvzaC?!5V3>t)54UJNB!)uvz_-Hg1nZoB{Dqp$E=-P9$fdY5BGHC zLl00PyZ%;IbHTfj2?Y(4B7|Te(8n%X(n-AW_yC|iCzB>l1@wJRr4j<^2I_S0(6sB& z#*v7NQ!PL@cOHkQyoC0Q9{S3`+^sMfhhSlwD%}vWnru4}uQhLYex?#vzBP0Ea~Z*& z-C?iw<=IgVg2j44@;-Y^EP=?LSp{?Ie=pHFM0`+KY1xmnw`7F%H#zCKV+Zmv#< zmLsk;;&if*ZL&epT4dczaACc8dC_~Semhj5EoZn+3K||Bj<2snwy-4;EXPC3Df9a$ z47D)zw|%>2*BaUjstdMBCs{=^y05$MmQ9CPF&mCI*Wr(vO`*irby!q%aFtH2hZTqy zva!1X63Ap6c48Oh*E6C%?%YJapO21`@ znK*nB$spcAAo!ERjkGvs5BV73#gkI(1CRRAog4vpjd(R@i-)h?0&BJ z+{5MT2lp#}xMYd7Ff)k^Hfx`gX116VTAvNsE%Ub$$q@h6$RbW8YI5pHvqWlmS~+cD z$UxL`dY1=26I@Kv3j`HfhG?;HiTlZjALEzb&6xUuF#dGqWu?ufC!S^A1f1COx~#Rk zSaZU$rPldsoSk5CF=uP25s^DK{WayR0~Gu~voL$z5Jqsv6sbX)nBaDkJ&;kHD11*p(fUA1HD0}r)8DyDToZAt8G%+_fm&qv3=ra^#lP%k4 zsAXZf+c}VGs0aCr>&QW93BxE^4&SDg{3i<|=oEDCtnJi!LLW)|diKnZeKRfE9e_`7M*_Pu6hNx4 zX&j=}J7Dr8B|A3bj?zF5%H+bd+znofsYeYwByD^81+y`|e@ z!Mqmfg>}tHW8ZWhuH@`e1%XfMcc}Yl{)-#kIRA2Z9E=OVcn%HNN1;UBcA+pB*d>KD z(t?fag_k@j^TCsTU?;8)4{KrB)qj$R_G17-rMGcJu9(v2CS4m7mV?$jg~$nic{{v9 z_+>eKS5dgX8adMZ>~AAeyE_KLrfg^e3_iWSYOaL1fpcx=@nbp%2S?q2dP^&>X`#aJ zHiL47-7EdRjp+H=l!I!))vtmMD8-@a*_&T7eMNV;D1()suy8yPC6bX))&z&k%ns1TEjN1t4WsZOAeI;p43x4MiFm$~p86F% z;jgP1Twcyf4|!?RV2OP;foW}NL1?&tL{(1qulo9od&~?7tujqHSfr!VveS_$S5W`P z8FKV<3pq6O%!BmuXmOI0*7>3*;;-W6-oNw1RbNoy5q_*?#gI^6NvIaw;eyhO)qJ(Y zp7ZAOP}|R#(r@4rd5`JjUlTYs#K3zqVY8pOyc3 zxpNhlkpbt7IG)tk*C(vC!{-g#$1jgZi-)VKF#bSGnjQqif5y@aBbhRWrH`h@_-j(E z6e5ufY+&AYOLxy7K<-o@ekffw3zfOdDs?_S%T1a_vRnwbdEw^%Ses7B6)DCUV+ zVZ2QaV}qTQQ1g37$>m8Jwrpa-rEN5qvskp-jGV1uS32Di4i z6A^uj0zeR_aSjTY?3|Ccij20Dh9Bhnm#=zr(Wb3He%a0m6;{B&HRS8o0KtCcm0P5A z4m%a&&M_UlH$P1#(!-r1aWhS;JaJtHmYBM=MlpB| z$JRSU@@cc=p;EsZlN|LA0nxy4$qdK4L;aS=hZ!QnA|n0!Rz@Ft3Mo^?T`%o6O z@RYG}$OyH=^F8~N**`j6W~%L*dSDSB<#A!q@kD$)U|ivs_%BI1k>FjML0uEp*;)C* zF-w&|cu_{i1E@p#=zgXl!`k8b@mIEtuBiB0#?@+%@}>?VN5HWfOzYtQK*8BU%c661 zviT1nd@ZTEVBjUp%6+||0XgDeVQdmYHT`5~Js9^Rtqc_%!zik-i4%7sv9-;$NadFF z2*wyz_Kfy#cn3d|N4m8y6MOnQ{Rp;kdgQC64Yn3B6SvWdSK?iNxhA-^mPUB~l@UOs z2N9cqtRO_Y$;av#zjg6C6BB7X4v-Nalh9GM1`l8nE9mG^`v7rW5DM12dUTWuX_it4 zgs>KT3H~W*ESO(?MKg%zO8^2v4^o&qJ|<^|7$tn@bk4M(61Qj8pAHrQm%C|E*prDF zphG+9$@t@5)z#tC(oi4K?&Yt8LS86+pp>D0D&A8ehh#vuA`sLgZT@kks5^ypv!m65 zo>9-*@*Q@1yg;sO6$tXpf(U+ zEx`gPbk=glA{-hZZL<5HMT`NH0`G&8_?6^s$qh6*J z&+B;C8B;hnGqI9NB@t#2P=fV00z7gfQ8KhJ-1I1)x%-tzc=cECe0`DTAiH=rd9u|m z#-onRBe#agJ5XyQP%i5;d>n6rB`-#s=$fPzEbnJ(Pv9-xJ>4dbM-XcU)b zjPr~XAoVHe6wf}CYA6gSEkhtvQLzX=y~UtRFfXdU&(h0UGxOcbbem+_s*OW)<)r20 zi`Lr=WWp-_wT&6U%KamNZ?}^4>7lH36~!2Uj+h(hxG?WtoWJVeM)-a z3ue>DNds4`A%-9_1$1Rb0_qLW!+8;;(=SZnm8-Wym@;Zuy9a8ay0GQ*w`2?#?+bmKIUU^i2a&* zA&Q4B9zzQ1m^H7FQ*$xDHYbAl(~(+wy%b#kflp1X2=u^MMLnQqx6Yv8`l`1KT2J2w zOY`i?zS4hY;3`n20KJG0?nlZO7QwjuNbI443?hIPw6^fTtO*PG1rwK8DiomA3l=G4 z8aE~U>$kgJy8Yh&TZp(Gyzv9)P5RH&W5)Xi2LIKYH~`3NNIp%#pk>pR+Msbu3!V}* zk|%d`4)L{^Ie53V?Rw|%5r7Ju*9H^&#OGEu_LaG3Hdipdl+;Jt; z)X)()ZtE-MC)ppBS(}Y5TSG7J$0LeeQOkD=>JkyR{ihA0qR$yN(_F>QUyn*N?-jzf zCqf7~)Mh;f^1=gi{yw@6$#BhknO>Hgo9jCS1iw%#81V)5EQ8p_&qJjS@!WT;8a!~e zB0k@_B+{LU08lz2VIA0zvQ7adS(AE}g`U0$P2XyAKZ8MSM+Zb{uHMw@#i|Z5AHIV| zAb+NiEe$z=?Xtm~?${F>v+oI72>s$5FgDb)$lxk7WLT`f<;xy3Ku+eb!kH}MRdu+K zn{S@1&VYPzt)TYHrGb_ScXvrZ5MWtek?52A2fzcaQ4S+A8h!{9RU~gQ8f^rk`bK9o z6pPXw9Ly0|A2D$+=Xz&9IcMBECI_xTTGxA+Y!@Q&b&M$5DL#;!2k=#;m{FaypCt{y z!M07TMa)YPTYLP3B(?eOf44%A!MLT@oDNTi%^;z^2uWN~J7LjU7a4I8anrCHaWi8( z$@7YosxgMXGA7>CM3b2IL`7K?f;?ncH82X?qVbbfA5$#JY8p4q%gbxquimm;P+xNcr2N36A0KA{)tXW+<)#lkdG-e>^- zmfh0t{_)wdV1j5lh9RYZ2UPb6jim1&!?@bN6GbAx@#I+URkR`T&pAM25awgNrcBur zqoF^7W&E?iOrW@*``ya%0l7d)fKEZ#3VEl=!lDnavRNF-^DZ|tV2K*d_mhE=GTSQm zA(WBjwu?eH{gikJqiWHm1MqB()392J;d#vVR~O z*XsbC3<)}v=y2OSue((!VML!PR+5@cfVC5{r)WcrEY}o-pV5Vzih-SD-X=QF%LaK zix@<60Q4P~$zX`ty*3Te1TGVRMjyi+pF+shtAb~l<}s*;_da6{3UvTY*lhK>ynN4W zgvLah-0NUNh&sb+K@8RRQk=S!n+6~rtL!GbjKv*1E}vh(wCtznw(~ny)3I8yv|i@ zX(WlUn%TT%dYGo5)RncAhV~WQmmd>r*=t490OD?6ezQe^b1)I@w~w^&2iM#4qwslL z%f)*C>d5#kW_-fZhNj1~95yd?pWg9+BFutx!5d6-gg4Lh5b>^^s7jd#JKcW}6*eH` zrv)0nUq<8DZlsl^-QBAE7ndEtU(M3Dg0>LYM3TIurx=S4<)eG5oEYO!=2jFlO1-ja zYBa>V&c!?Xxy;kML4YCA+unjEqdztuXf7+3*@RNp4cz@={eV<_7o%z^h!BTMZ)a`{ z*&osLEMrf1@ohJI(h;YpH>(jhabBQ>wO)`W*hgU{e-4Re5M#{CP4~xTmTGJW{o`m) z1w4|3LgSn}3tznz)92623`vpm?WcV)B@kLo7(%;5JvQUSVOzz|QX~gmV z15U2_X^1!@xxtCGyG;WO>e&a`6u9Mb(a{iKJ~`jh=4wN&{>5J=vEK)335y%;osTaF z=bfo~Ju1Rf^s(QK4v{>ov9q*sU;fxH`+;!dNQT(#`xH0DFwi$_(d(G(CN&z{O!Ai# zI+B~KWTFB5Z%_@Uw`0k+@3s|D7FOD^(dc;P6M^bs-cvknoC=@>nM$6`(BY6}1k(*6 zXzQ)~0A-hUxzD8*e3JXpzUwVhL7+_jRJ#KU{d3emoyWm6yi6=i(bMH)L8)&4SnK@+ zb?3?i7JE)=_wXYW)O5aa-h{07VCSjfigEYo27I#d8xpM|Y(~lsw3Iia%JPzmn=uBC z^xRKCLUBfY@|!Y#L%7@ciemp6BxWS(?C3a*($&Q>7+5gFcX7w{C>2A)Z5!4FNUIJ0 za%0L^I-lS#6i4DWu_L~p!4__=S0=Rn3W__;?7k=jH=R_%`uCN%#6`6|vb%WK1@1{5 zX7bk6FQ?MR-O`%!Uu8^C!xVZ2M9)pmoj=$55R0v-fo4 zRuh)$OfVU`WX(*FIGY~k)Y&3m3GgrKe_cG^rTvB zfIw#lX6DC|F|<^~wk|NP{8*TYa!*J08Tt-k>RnHnq2iPH#T`0deO|G1XZePDRcHUX%CfALE<;K!3mP(L zR0w8#v9nWo;QZ{;!GfkcXksadhbMR!2<8|h3q0j8L;F2jXV9hgd_*T$*xl(}0>gOs zYy`f-F@ifN_!vxdVKA?%55L(Iqwk)EH(7_C#FS>$>oM`j9^-Fi@#kWM#4nQNNL9nl zxmn%1XaPf|)R^1X2fH*>%D>~X5>7yfrtv`EF_1H)zt+IjnP!)*-D)@h&rR)KnhHXl zq)U|OtqkAnLExnf9F#bahS2eG_P(RzShpUll^k>i=jJ|d@$e{j*8@jR@qGX5EthHO z;gHL{9REq((o3qDTs`91fZV1!iWKelI3NG032UkD?CU4F9WPg`E`CojI+Efxad}ix zUdEH6AfxQB4S_ym-6CqA)3&%ZK^WKsBkh9+g&y|FVBBc6A2{6A0k4;|yl&`PBz*zW z_F`pR54BhGju#xWyk&8MJzX2y+k(C0#5!)fHX#WT&LFpd4j%eH^&ZT1w^@pgdD555 zVI^o5gEj;4Hfjz@+ELO3A9cuEBwreB8Bes(D42XC zH5>CkUOKDr?1Gho$#|$81zF(%KBprl*Jl)}{asS)SuUF|N6#Tim^C>p`AkAiy~H$r zNasKwuP}qmKx_4GRA}+sS}*IuRc%y!pQo(9lMSJR2(+JemC;*zTf+@Cw^0b@gabL-#ia@ zWjVh8P`nB>ZYNlNX;BM#u;j_U;H(LGStgajqa?+^7y0C{E3Eeed(7j0n-YnMwa<$G zrnl`#-^5{vAAi?$tuLVi%MCFfbBSRn_Id-HnD$6gjDFbJj@*Legf?a-P~cYcUdp$w z_J>ER0=0YgJgoe*LLB$A*+`43wtFkTyk$Wr5k3zRJ_qjO7<{>5o_MaAS@HWG*Ln-UZ}vErqC3{~pnG zXYr;Jb3FfuO?%H7jNZ~aX)u~Y{Y&0?6~v-&b^ZEn2@C6gtmn_?%Xy1B&QS74UF_FA z)hp=K6?Dd}*3;PpdE0V4QQ@uyVtz>a%W@l5>~s$Hytb1GIFhJyH($#h&pAjiNb+Kc zkYqg31YD*>va4xeZF}T$YoZpUR+36qIzs6g0uD0imiY~EO!QnvOm`G(eY?Wt^i0ag z+0%U${Int&HeUaKEkHa($0XAaG@}+){_Uw6&1SJAw3i!wrOnR0@vM-Qdw4nTR3UKe zB@g$C;f1}y+6Km)fR(`Xv-elX6W4G7Tc=iWH zx7OyHyKcJr508Bn@)q4k|g3TbQZ-oq|-s;6XhkUtF*C8BO{%ipyh6P>-dP%(0w`rz~1 zJ{V~Bpk{quj_X6!>(kdV3iJ`c7n;4Z!Kbd>QYymQn7VRdkeeV;vZ2<&17ZtV$9D#~ z3cd~1fcDo7)s_$uraR#+ta}c|nt@q=szexfV_Zob#JT{|J+G%?nr!*r?)t+?<|-sY zr~NW%lgSp|eh+wG?{v_Zrl^hKv{l=% z$~HV=DU9EnS;~q|Tt{caXLSg_Z1Qay5M4g_QhV~JxzB3R@FR%CdiU8>n?l?2kkzpA zg{bPgUYC^J0X5gd%F?unJp8xFaf5th$`gK z%carRFLt&ttWBk-|5m`p!sLJKngET@;sfe!xJdk#7(cn23MUJt{n#b>mWf?0`HW(e z<^xJ#(_`tC)KEk=r;)FplxVMaaV1l;jBah0n?R*{BdfM8?PDzWtQ2ULxb4FDwag&6 zL&7I$Hd6)u^4cg#{SF$!AWo#;v%I{;MnSF})VyyppEc|C%(;fKjrb!8!cQoJ{(a4tf)@sC4M&W}f#38Hi2Kjx3rM|~SubY3bY zXUICjr^EL4Dq5rtvXLVj8?SAu z*87i-kH??;mxFkv*CFeNRxfGQ|9f5i>)#ZxOzxv^@UI+04h8==FLTR4hsO$P(U}D- zTlgVS-;w>_3U5xCpqW}<=IDMSY<6Gq)4w`hTiNO2oZpg_N9j>XM9dsy)B$J4;m?a!c)}1J!h43d*hcsx^aySg%Xs9vqX2T zVxI3bxS$(el5ahQI==iA7v_x@|KNT3;pL?_N#o{fGp;qa!Q;?1h5LOg_bA@756o8> z?W+|Mcb4aWKMOBhAiD}@#3#-IdcxT=bxhG6alTt`T72{`crx>w8m7eFN}GkjRV0Al zh;l$`Grj7RPg@@<=gO^os0#_@Un7JCN-Z>Ce=C{Df%RHb{_J1JcttRH-|DNwRbK1; zx8ka4cD9=YohW@rt+>w^Z80)47IZgnB+rQMnb6@UhSR^Uu6SgyfOOjXJx1}R@1Aem z9(i!R`f`y}x&HkueDi!xusIR$c@XEG`DgYstn1&r-qY3yDiry9CB5a!9ri8_Jlc@}~J3@@2k?lXalc@!l% zTil0p=5x5*`$7&92A)6f86AQSI_&>ddzA=dO-|cB34-o8Lg1q~{qzu#cU3|VSB}9y z0KiVnr-xw~o~|YL0{mL`m*aRHfj*P+1H6%%)J~H4l;J&}`qD-TC!c=?TSub5e@nji zV@jhMb?sy`8T2gczIZmEBBe;ZB=^C$Eyix+L-q4%4&94MmB zlIF>C4}|AW@9VXa^?up%p&K$-0w=6S%6d%cD@BA#KLq}<*g2=551@N}ns9a_L6J#4 z$-$OrWVzLtH?zF!-aNB)hLhbywTt`t$I`^^Q;b6*luYkf?kBwgjaHrJ8jGQ7l zw{Xu>g_HnT7N5A7mv=B(bLnph>JZ*JCH&(tR^7ynuO7vVd_)i};t zZ?6PIo|C9tO!DWxm7hkg&ELh|AEXUb?MQrYlC=;`ddy0-rpFa9>5v<$q#dV-*6oX3 zhk}6&REA0NL{>)Q11Kdzv;Xn(zH8VD|8?9O+-JKj(+q@|09CWm=ufV>4`-FtPPY0a z-c>t;PWP#0aEuQ#xFf$##O4;u=`S?^dAUL>DSQ3(x! zZLm&H(LRr$-{hmIxgDds;yadq1LwDHy&HWBEKVDqc{SJIs6)TB5favxXcN|T zDaw!%xlq&9_xuudZN^=oZ8NIQBr0B zA_F22S)McLeo`jmG;oLXsx#nh4_3@OlKpMKFT>kg%{=y#!r{_p*evfK9*?E)Etg;RlRFSt<=ogW3DbmVQR9#r8cxtwyLz`V zrHEbCFX?{wfYIju5SNc|=X)EDZ&p}qS@^O-KuX|EZ+_D2F9!e5gdeTLqRPyCM#H|kfZ4HB9E+?$>dc9 zpxmO^qG^WsHTA7q{=(6bEe2V9oU8SI!}E0S2Ye*LczCM|X9wq8^I?Sy)rcbj*;1w_ zoFB+vOlBV=tO3agq*Ng5M(lEqZgk$)<1D0Uq?2d`yewFY4ym=P%+n0BY&D0fs1wi|v;T z0zU6Jy|Wn+-^%)#Dg!;004QvC#Jm!7D|#^RAvlL`BBPXM^S-zqMD5r@|9Xzm-ubgc zzFd*^H>=1U`239e-j6Hle>q+>h>f0%MtOzBMYUJr7YF|~ot`UI)}^DXTtZ~?82wft za*x-UE~1)3#&#~vTjA+{30uEB)6~=HjK254-6k=zL^`Uu@fnY;+jRZ$_l^h1DL<*W zgMf@wDZ>HW9MW)XEw!v%ai9IefE%US@@D}T)DEdX1u{R}f3+I}YdrU&jtT64l!(s& zb1p>%zKz757GCAwCS^T!6B9i{{yX6cZQpab%Ph58Z6_x_(nvh8H=#GU@-ZpIvX*YS zA`qIHBgS&)lmfaX*pQ`=?Iw`m&fDNizn|=Y=S5z4&7ZPmUVOnUTPutb=PUo>+m%5w z*6QMs1VRZzUz8Jysxb&BUXK#QeBlKNc0Tw$uu` zFY8{nRYy&A70>14H8ZZetKJqO=9Bz?^hj%nPR9WcnCO20m73aT(d{TSIOYfu&^-xE zS7HtA4*a5$6{;mouMsA`D?P81_HD{bI&@FZ7f-qE=_Ki*^dfUjB_8!NsKrZBz527i zU$TmZ@U0;)62~Arpca-+A{b8&EyI;>;9^_dx86JCYxY^JxQpfNzM*uev4~@GQK#myPF#edscbixZ1fhg^=Ac5keklMgz~H0RFSVw2{a8-v}$ zENCVPs)%4hZ;s=418H#_$@7QNAu4VAz?1v+8!^PJJ7sc!9fZ2~#eUAx4n0#q%u@(B z@@VeUzw0#iz>(Gpy~a@JAATTUaX>?l#_@FL+m0CW`KQJp$d}Y6vUib1K#D7UM_jFb{ zf>ApQGxja0Zg|kHa2`ZP7Ab^kFc-i(tZn|n@pQ>$ed0nR7#3iId}{9qjnT?>>W%eq z&RE`Rfq%_ar9JOU16Cx%<*6=ZEWdD&S=d;CsAetaCJ3sAQ2IuG&EE>m7&DXXkgB7p zH1P~)JRw)LF~LJX!Y#OeO7u>_UuqXE()d8oqqSmluNSj%JUglnH$AxxWa$3@@DPbD z1oT^DYweLkcM!y;dAbxSO}9p~ifqrd3j3%>j6~ zlBILGEayN|E!x?gi><=XJs0xS9Z6(JG3)3Mztg2LPQ3>wmA7TjJyN%-3{Kji9xq+) zkLzas#Uz{39?LB$U#N|JAD7swVxmYqBlTV5ZlT55(C5Cd;Qm4DVy<&xy+zc^#>3I5 zw0KnN3x**b(Eg(5^_{C9jMID6x+8#d?`}$YI)0~9^V#VZeyBPz0^~oVRteYXb1*#F zX)qwF|FUm&^J#ZY4p@xklHn7&7q`mYMc)Q|^RG*wx%|gS14NX-V0F_>@)y%&HKtyS z{OJMeos0id@qvgGYPuloic1vMAAy-cWM)5&>Vdf_*5yq^-Q?o$jVUwNd~w$}5+30t z7QYSrbZY~~%91RO2n%w*nf)EQ!}rSkshsdZB=7?AgOt8E1Z&aYe|mb_8^1?0C3(Lg zjx&`_h9q-SkLkPG1p|OX=JnfAgCMt*+~6rl!Yj-g+E_JnR%jhTikYgiaGmF>^U$I1^1tIj#%h24 ztc+69K_$;#l-Oopdnf-8wXeM>E&pKaHGBVI5by-GSNczCQ(t3X*J&PrUAqvED$2;2 z0wy1_C7IJkp4c|nw3EiAWb5MjfDLhyjqti}e)bQq|Jr=W83Gg_Y5E->S-qz0S4RIW zU+H}qmK8Bi_sh&TG17lvoM7t#d9 zb(v-tsDQLra=dqac3&N{FEroO=*Ly%&n!mF(ovDM-{T|qNRMiog|dC?dIhAOe%?s_ zph(afY7N;Dos1ln>nqAnOM#Y)F^F^~kU;bCZq0P39LGvJsjCp~qx9|s>>X<9UC(E*qLy`3eU!NG>FFd-<-6F;6B#2`Y?1ITsy#?c zn#y^RDTGWv+7+6k8j}#{Gxh3edT+RQKCt?BNHR*pog~DaQEYO#NWJ1H9JAfz>- zylaBiG1V^~lN+falhuRch`9En)V~0zoR>;Sn1BqzMD=m%q9$JNpfBEZw`|mxn#D1g zHzucLC&s$;jNA(otW<@6MIqP>`o!<-yq_YHv@h7{{)60MqX;ehrAYEqtMo_#rn^M$ zk+jVM?0AtLD-h3PFGG=Ib$oC5nF}F_=bTw4%;e}<(W$Lb@S(ogQ^0`wPxl)y_sJ1% z&47=?%lO-x;ot!MI(hq;I~B=iniWdbbf4%uH3XHE1(TC`Uw)-KcypiXn)(UPD{YPX z{r8-sbE7sU=kE|9!(hQ79DT~TlpxIT%SJ`T&x-dlKKS|bBugntKIiwOiRx0h&J0gK zj+Jy2qN0Wzx|qmWW7;2bpYGr@v&wp6B6U1I-OF^QhC(xYpDy#HM{ynS5kLuWCbUW? zK$(k4m9zXsFK@1|zpCi3CX`q?fM~3s{aq_FDS{aAh{!c3<}2?=Wz&J*oy(;!SoGoY zRS3lQ8|wK`lf-|$R!&UHk;FFYkP7YQ{Vn4%FAH7gLH};c2HA4K&NmJxfEwGJ=~{s3 z-l{yrC#g2ZM_Hhdq#m=ODe5NFqHgs?_;6h`R=4 zLOcPg5bEi5qnx(+-;M%~YwP1JUmO6Kd?W0H{8 z`0K%{o1v>KZ2fjJ2{2Eu2g#5jNzI&{4wmq6kE|SZ?(e3yFL5ltv3qv`pp1RfRr4~V zaeT&cs0bGD-n5uH{Z~cB@f}eyE|nq;)=ubKlR!SF7xfEtPmLH$oM8`VezJCdjTadp zO=-mQ0>*yiW_klYW0Z%UlJotzOV90fGU^V2!gO>Wqf`o#zcZ!$9wRd;K^C#Oa^W>A zR)zF)-u0Dj%nDmqzsaBQ+cOvLeb;xQy-?O7b5EsjBp~j3DfPD4P?=mWAptUwk_oAG zW&H@vYQw!YFmdIs=oY|6MK zN0m~IiTX!PD|xIa{3=>hc;OCsulwmOH-k}IBGY@kPp$+Zc~2k<_{yqPPN#}U^aT}w z9C^Pc5xTi$8bd^WuR2QrN_-$OK{?529#1w{NLZ#>{RoS5H<(!KH`odvY@+)Wxp&SN zoTaw(V${}axQC7vknqh%j~y~#(G3b{H!jTlRrkVy-Y@=Za+#!Uvx;pNnLu*vpSNZa zNdR-=0hA8KH|Bn7>TbwuhDRh4QBr_pe`9U@kP~HPM@sY0nV;DjVbn9_<=RG0KkC=% zQb;_j@=>uGqXMHKy=7>Y;b^Rn2H;VN|C2(#n3NaYhIe8f0s{fApI`-iwo*iKL1RSB z;=8&znv-9O-zog(_6(Uig*MFQ5BwKOl=s6&Yr|Wn0IAJC{UEzk`OjAx4W{Hj?=y{K zGIbx&*vOdm{L36n%5j6;>mGt})psxW{Y-peWF#(t0rniw14^_yJB}+Tte#9V(Shw* zOYXJAx43mW_h)#_T3a8UJj+s^G#aHRYiaf{oTyxPOJ26s3sKw5+;_S0;|z4?RT;Pc zqxAF5;C)}nTf_=j+8M=^+Rl>&EC1Fw;~4c|qmmF2-ZnJ8<%^lP=Oof37g9Ip#uhia zv$+3t{-X1^`SUn@)1I832>fEm5!xL^S4;PK@QqEZrGD;M>d**B<`p4$!u9UtpwIEv zdqOBBvGI#9`n*xDrrHIM4^$si$}7L5jFL+E_f`b!J?ABL<=oPkWOo(pLb=V?O{3C1 zV>TD4l`W(ny}euP_THl>@A~xd+xnU(=4=I7rH;&pALj=i(rfC{{~V)Bvo!3lhw)Si zdxN0BNL2BC)8~=G<~ijhl4K}xx0v;dg}G%(RUi9ys6swH>{;unE zY9(o)3)7UKSFOLBZp*&s=zvYt>if#CbiNxYRc^o%)gFMp1mZ1?N>u>%?3CJ?-@p5j|!o^8{%v$w5mqt}{1 zE8?~6kdZ7S@j7HO{x8<HB}=lZ;1evo|PS+wx@mA=mcHp4SWXKkxXecKb28ww}$Xd3L?c(S4WX?iOBBUW_4p{F{&54UW2oY`>? zY@K)^EB`*eyw5#o*l@mZ`1)`B*s!fnjyJs`y!vr*d^@6K?se;ZaEy`?cCKsRTL}O- zNE}26_`f;wmKm#hQ@;E4t)2o-mC#|byXGeq=lvJ0TtVsRN3D0aiJM| zs!H1TRG~#Pb(_$Jy~506TP}`0L+(!tzn1s6YHdlpGCAu~ytt|_-sYWedFM7V^>*98 zF_=ZfuDd^Df6b%?hx=1sMSKiR_aAr`6j)J6V*>M`V%! zPG?=!{=_)+RE!>}JO6@|LIVMIX(vkI;WzN#os`i1t{PEN72CLJ2C*$i1iPtV*bn;{ zFWlZN&bDPUeyt&&t@7Q=XMN7~KI$2d%=XIl;L+0ZiF+H)M0{}i1QN6T7O*(qda(<1 zqy#@9gFQ3)oQ+K)Imx&@FJ9j89(ekWhSJEy6v9K6`ccHmeDT-e9n@np&l3C9*Azo5 zHscpt-_QN}($-<3w=*f%P*YLz-@O)0e4IoF(&dKFxmuSZU0~FHF1C5f7@{N>-a_yGqISRB zopp1=ezETF1OPyt@xT89$d?})RjO&1TZ*)3HlB$-`W!J2=;r|Oa49N5U`jg$`?z`Xq*X?zfPWte68V-^s zRkP3#F_zNz%-@FSKt46$dOy`@kt%1yI{U{DZeoPh_Pq1gVXkqwT-<&=8+2!8fWFXu zu@$A(A;)^f>HO<@H3SSw z`vl;uvf~bWsacjZ0_Na)Z3v$oWTk0J(KmnYyNl-6m`= zYC^YPwu?zUp9B)fYa0dtrV-VK3 z&lQ?i*g`z_$4iaYPi?Lh&S&p_y(S2Agt0&YpB+VKZ}87(EdTR(8pm-Q$6=J5iD~6L z48RHxOZl!9sbgfN`oB1x8iP=EW>f?3C!pGL?PzsPy)iYD@j&S)5FryprpVY52K2xR zJEq7KiHHLrnq)m4(sYu;ZhHTA+`XT2%K!BD|BT@K+X8cFoAx{3`j?!f*}%(>iZJdhA!;2e(oW_QosMe48k>P6%xq)D6BgI+K*5e0y0 z8XVo2Mms#@<35i^IqoDx>@UOhM=|G4-rk62(IhsBPJ{#ytxS^HY<1S9=DD%IVO4XUU?N7zS*DbXWKxS_DeIUeDW^2b zc+%-)r-QT`md-+pIVlSK!{2=e3BUPQpM2|Yzg^TvbQ&~`IvnK9XT#?|8DD>Pdi-KK z>`zHf2pGAq6Duf|M3XsE2XbkSF8YbpM9o57)ill=lvP(`Pkym}*K-BjggB)srA&x` zMoeAX$EF!hoF#)!V#)w!mQ}sc#LOWq41iE`*bk*Q8>^aKI1QaH1h3Um+4@E)IC3o0 zKIS|;s3u~GEEtl3*X})5F*B=UMPiV%PSa@PNe;X8_>Qk`n|4FThYSeqhA*yBl78!N z{t>{2gQQ8?4I9`r=xL{i$9#ND(@9UKaYzqCei-F3$uY@EZOWPuFi-;kWX{KZTW=sIj>gPn*85CVtLZA=w?X2(Re ztd80}o(#0|@3@y$GqPGtuMaJ!Yd#c2^$gL&OeaMsxSfTu)9(#*=noen8EwE zEmRQO1}2|5H zuKkCqzE}ia(&C~z&#y&mzr7rXNRRwM`Hniz&HJQm&Mk?oc-~v?l{kJK%p`#ojcKl#O50<0L$1Xi|e=8 zlyzWjrqqt74iSdE{^-B<*Dsr!yO=XI8#?atahHh=z=oro_BkcHe?0+!WZU1Tv&hY=C3_lU&l640H__qZqPKn{Ip5!Zk;lOh z5mi(r=l$*&LSQCSVFCp3f+d!ljutyp!pK6;I6LJU4?}GtLG`b-Q&8XSv~_ceZ-p5H z%Iv(Ufrw^AHj7~E%?D`cIeaD*wd{ZP;r?O&*z|puvq`pb(D9^qztO(=Y(ylp99!zP z_~x_W@R%Oo<^B77*kwc@#;ikIQ?kX6o)uob zS^#9Ah6bjJgvJI1CJm5F^koFkr*OD?^$O7>r|re|c-*TR6m)xN+IE_T5Q3i#6RKpQ zxam4kUA2Mzgy%i>3Rq}ypWt#luU%C!=ifj*c-CIOSC*u!)Cme?Toi;LxX*T{B{rcl zQzi;(c|ZP~v5ld(R-ccb`uCeB8-lH>ETY zInBzD^py3amJD*)0aB)qz(5@xrk0jOsmQgq&!2|JRtdqDyaSL{7&UfKqn5Esfah!Q zrr)GAolZwU-1L3l_ordt5SrLBBcc(qs;C4;3o-PYO$b3tplh=YT`@UYnXW3pJYKh! z=C`bCSg@*!xpS(;$~g$BTp!Ml0Z}cBl^z3C#y}!sYO)MTPJ|)y#^K7U7isGAq$-;q z{KtJ7jRG>EnO!}^cb|`s@6vG8X`Ck6PqG&s5eXrb^w*N;q?SG1H&C&pn$)tE0fo7^ z;g-wIm@HymJv=s9SM33yhR}e3=0vnLMSebH=Y5DxAl`JnsW3SMIS^Uf#2Bw)jG#)W z%+z(8CN{)WFE@Okinw}Sz3e;&zdXSjB`;OYMTM6_tgWqpnYmdLP0mJUAeH!!eS9>@ zA;I1|hW;)kQOlxZn_t|&Nk9A12@Hswm0R|YISumg{*ZOdI!tm987JL~X2QS}M^VvH zX6crqpNeJG0@MPVbDu?h>wsvfSFFUmuJbM4*OtpUGpm7p8DykMi2{=~;bnWPX2Up+ zr&HHnbesOL-)%N+-}M}*Ya0&XVtWZ-DUE)%v*Kdq7KCa}aZ%bicXCxPxoydM( zVZN}Q`#oF0h&f9P+{A_uzWCxTA%qaN7ng0@nHrKYMw-Gfv0;V?CEI2;1`7+}_u*yI6MaTZ>eBvBJW zo(6mW`12|6{9S~sCY+llTn_mm$w4h;oy0tB9>tPcW^9;RP^<`N5t~%ASds#!tRgX4 z3Rk#DuBz#WDr~lvXz4^$jI9@Mo=@Qr35mkh^^N3d7!G%@?lh&_7dKz|_-mhi`eVzv zZJ5yVG&Vh5T=Y%1IqV;Q?cjvtrSo3kaen+`XUBUPraN=QUs?qTtDpI@5j&8Qeo#na=~XECfO%B ziH)LJY%)t(C$%J&GfWM4OfBe?HLE4nlx^_Hxk6>F4*RRYncz*weNlZHNfj9pWqRYTa}eUTa`NE zIQZelX&Gpe1C_zwz!Z^CP1MpTiLqgFE|nHQ zcf(JId=FrRVGjNQKrD$4lkBSP6$8mSs$~Q;%vq;EEg=DzSQeWq5PBg&TFOr=lRM8B p)xTAPZTDl#>+=~ literal 0 HcmV?d00001 diff --git a/tests/media/burnings video 0.39b-makeColorKeyTexture-old.png b/tests/media/burnings video 0.39b-makeColorKeyTexture-old.png new file mode 100644 index 0000000000000000000000000000000000000000..cd860a851801cb2d2c1a19aeb8a69ae4d5c6c3aa GIT binary patch literal 20933 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 XjEzEi5MgP>00000NkvXXu0mjfI_j)f literal 0 HcmV?d00001 diff --git a/tests/media/burnings video 0.39b-textureRenderStates.png b/tests/media/burnings video 0.39b-textureRenderStates.png new file mode 100644 index 0000000000000000000000000000000000000000..98282fa1ab04f5f9a038f4c1b9563b53c9c4f4fd GIT binary patch literal 30383 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Μ?bU&9qP_9GbG! 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 literal 0 HcmV?d00001 diff --git a/tests/media/burnings video 0.39b-transparentAlphaChannelRef.png b/tests/media/burnings video 0.39b-transparentAlphaChannelRef.png new file mode 100644 index 0000000000000000000000000000000000000000..5ae3ceb7e6af71e62b0c05fea8ac004b50cdfaca GIT binary patch literal 29723 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 E1FG=H*Z=?k literal 0 HcmV?d00001 diff --git a/tests/planeMatrix.cpp b/tests/planeMatrix.cpp index 0086aa71..6343698a 100644 --- a/tests/planeMatrix.cpp +++ b/tests/planeMatrix.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Colin MacDonald +// Copyright (C) 2008-2009 Colin MacDonald // No rights reserved: this software is in the public domain. #include "testUtils.h" @@ -51,7 +51,7 @@ static bool transformPlane(const vector3df & point, const vector3df & normal, static bool drawScaledOctTree(void) { bool result = false; - IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, dimension2d(160, 120), 32); + IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, dimension2d(160, 120), 32); if (!device) return false; diff --git a/tests/sceneCollisionManager.cpp b/tests/sceneCollisionManager.cpp index 7cef8372..0a4f6378 100644 --- a/tests/sceneCollisionManager.cpp +++ b/tests/sceneCollisionManager.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Colin MacDonald +// Copyright (C) 2008-2009 Colin MacDonald // No rights reserved: this software is in the public domain. #include "testUtils.h" @@ -10,35 +10,37 @@ using namespace core; using namespace scene; using namespace video; - -/** Test functionality of the sceneCollisionManager */ -bool sceneCollisionManager(void) +static bool testGetCollisionResultPosition(IrrlichtDevice * device, + ISceneManager * smgr, + ISceneCollisionManager * collMgr) { - IrrlichtDevice * device = irr::createDevice(video::EDT_NULL); - assert(device); - if(!device) - return false; - - ISceneManager * smgr = device->getSceneManager(); - ISceneCollisionManager * collMgr = smgr->getSceneCollisionManager(); - IMeshSceneNode * cubeNode = smgr->addCubeSceneNode(10.f); ITriangleSelector * cubeSelector = smgr->createTriangleSelectorFromBoundingBox(cubeNode); triangle3df triOut; vector3df hitPosition; bool falling; + const ISceneNode* hitNode; - vector3df resultPosition = + vector3df resultPosition = collMgr->getCollisionResultPosition(cubeSelector, - vector3df(0, 50, 0), - vector3df(10, 20, 10), - vector3df(0, -100, 0), - triOut, - hitPosition, - falling); + vector3df(0, 50, 0), + vector3df(10, 20, 10), + vector3df(0, -100, 0), + triOut, + hitPosition, + falling, + hitNode); bool result = true; + + if(hitNode != cubeNode) + { + logTestString("Unexpected collision node\n"); + assert(false); + result = false; + } + if(!equals(resultPosition.Y, 25.f, 0.01f)) { logTestString("Unexpected collision response position\n"); @@ -46,21 +48,29 @@ bool sceneCollisionManager(void) result = false; } - if(!equals(hitPosition.Y, 5.f, 0.01f)) + if(!equals(hitPosition.Y, 5.f, 0.01f)) { logTestString("Unexpected collision position\n"); assert(false); result = false; } - resultPosition = + resultPosition = collMgr->getCollisionResultPosition(cubeSelector, - vector3df(-20, 0, 0), - vector3df(10, 20, 10), - vector3df(100, 0, 0), - triOut, - hitPosition, - falling); + vector3df(-20, 0, 0), + vector3df(10, 20, 10), + vector3df(100, 0, 0), + triOut, + hitPosition, + falling, + hitNode); + + if(hitNode != cubeNode) + { + logTestString("Unexpected collision node\n"); + assert(false); + result = false; + } if(!equals(resultPosition.X, -15.f, 0.01f)) { @@ -69,7 +79,7 @@ bool sceneCollisionManager(void) result = false; } - if(!equals(hitPosition.X, -5.f, 0.01f)) + if(!equals(hitPosition.X, -5.f, 0.01f)) { logTestString("Unexpected collision position\n"); assert(false); @@ -77,8 +87,223 @@ bool sceneCollisionManager(void) } cubeSelector->drop(); - device->drop(); + smgr->clear(); return result; } +// Test that getCollisionPoint() actually uses the closest point, not the closest triangle. +static bool getCollisionPoint_ignoreTriangleVertices(IrrlichtDevice * device, + ISceneManager * smgr, + ISceneCollisionManager * collMgr) +{ + // Create a cube with a Z face at 5, but corners close to 0 + ISceneNode * farSmallCube = smgr->addCubeSceneNode(10, 0, -1, vector3df(0, 0, 10)); + + // Create a cube with a Z face at 0, but corners far from 0 + ISceneNode * nearBigCube = smgr->addCubeSceneNode(100, 0, -1, vector3df(0, 0, 50)); + + IMetaTriangleSelector * meta = smgr->createMetaTriangleSelector(); + + ITriangleSelector * selector = smgr->createTriangleSelectorFromBoundingBox(farSmallCube); + meta->addTriangleSelector(selector); + selector->drop(); + + // We should expect a hit on this cube + selector = smgr->createTriangleSelectorFromBoundingBox(nearBigCube); + meta->addTriangleSelector(selector); + selector->drop(); + + line3df ray(0, 0, -5, 0, 0, 100); + vector3df hitPosition; + triangle3df hitTriangle; + const ISceneNode* hitNode; + + bool collision = collMgr->getCollisionPoint(ray, meta, hitPosition, hitTriangle, hitNode); + + meta->drop(); + + if(hitNode != nearBigCube) + { + logTestString("getCollisionPoint_ignoreTriangleVertices: hit the wrong node.\n"); + return false; + } + + if(!collision) + { + logTestString("getCollisionPoint_ignoreTriangleVertices: didn't get a hit.\n"); + return false; + } + + if(hitPosition != vector3df(0, 0, 0)) + { + logTestString("getCollisionPoint_ignoreTriangleVertices: unexpected hit position %f %f %f.\n", + hitPosition.X, hitPosition.Y, hitPosition.Z ); + return false; + } + + return true; +} + + +static bool testGetSceneNodeFromScreenCoordinatesBB(IrrlichtDevice * device, + ISceneManager * smgr, + ISceneCollisionManager * collMgr) +{ + // Create 3 nodes. The nearest node actually contains the camera. + IMeshSceneNode * cubeNode1 = smgr->addCubeSceneNode(10.f, 0, -1, vector3df(0, 0, 4)); + IMeshSceneNode * cubeNode2 = smgr->addCubeSceneNode(10.f, 0, -1, vector3df(0, 0, 30)); + cubeNode2->setRotation(vector3df(90.f, 90.f, 90.f)); // Just check that rotation doesn't stop us hitting it. + IMeshSceneNode * cubeNode3 = smgr->addCubeSceneNode(10.f, 0, -1, vector3df(0, 0, 40)); + cubeNode3->setRotation(vector3df(180.f, 180.f, 180.f)); // Just check that rotation doesn't stop us hitting it. + + ICameraSceneNode * camera = smgr->addCameraSceneNode(); + device->run(); + smgr->drawAll(); // Get the camera in a good state + + ISceneNode * hitNode = collMgr->getSceneNodeFromScreenCoordinatesBB(position2d(80, 60)); + + // Expect the first node to be hit, since we're starting the check from inside it. + bool result = true; + if(hitNode != cubeNode1) + { + logTestString("Unexpected node hit. Expected cubeNode1.\n"); + result = false; + } + + // Now make cubeNode1 invisible and check that cubeNode2 is hit. + cubeNode1->setVisible(false); + hitNode = collMgr->getSceneNodeFromScreenCoordinatesBB(position2d(80, 60)); + if(hitNode != cubeNode2) + { + logTestString("Unexpected node hit. Expected cubeNode2.\n"); + result = false; + } + + // Make cubeNode1 the parent of cubeNode2. + cubeNode2->setParent(cubeNode1); + + // Check visibility. + bool visible = cubeNode2->isVisible(); + if(!visible) + { + logTestString("cubeNode2 should think that it (in isolation) is visible.\n"); + result = false; + } + + visible = cubeNode2->isTrulyVisible(); + if(visible) + { + logTestString("cubeNode2 should know that it (recursively) is invisible.\n"); + result = false; + } + + // cubeNode2 should now be an invalid target as well, and so the final cube node should be hit. + hitNode = collMgr->getSceneNodeFromScreenCoordinatesBB(position2d(80, 60)); + if(hitNode != cubeNode3) + { + logTestString("Unexpected node hit. Expected cubeNode3.\n"); + result = false; + } + + + // Make cubeNode3 invisible and check that the camera node is hit (since it has a valid bounding box). + cubeNode3->setVisible(false); + hitNode = collMgr->getSceneNodeFromScreenCoordinatesBB(position2d(80, 60)); + if(hitNode != camera) + { + logTestString("Unexpected node hit. Expected the camera node.\n"); + result = false; + } + + // Now verify bitmasking + camera->setID(0xAAAAAAAA); // == 101010101010101010101010101010 + hitNode = collMgr->getSceneNodeFromScreenCoordinatesBB(position2d(80, 60), 0x02); + if(hitNode != camera) + { + logTestString("Unexpected node hit. Expected the camera node.\n"); + result = false; + } + + // Test the 01010101010101010101010101010101 bitmask (0x55555555) + hitNode = collMgr->getSceneNodeFromScreenCoordinatesBB(position2d(80, 60), 0x55555555); + if(hitNode != 0) + { + logTestString("A node was hit when none was expected.\n"); + result = false; + } + + smgr->clear(); + + if(!result) + assert(false); + return result; +} + + +static bool getScaledPickedNodeBB(IrrlichtDevice * device, + ISceneManager * smgr, + ISceneCollisionManager * collMgr) +{ + ISceneNode* farTarget = smgr->addCubeSceneNode(1.f); + farTarget->setScale(vector3df(100.f, 100.f, 10.f)); + farTarget->setPosition(vector3df(0.f, 0.f, 500.f)); + farTarget->updateAbsolutePosition(); + + // Create a node that's slightly further away than the closest node, + // but thinner. Its furthest corner is closer, but the collision + // position is further, so it should not be selected. + ISceneNode* middleTarget = smgr->addCubeSceneNode(10.f); + middleTarget->setPosition(vector3df(0.f, 0.f, 101.f)); + middleTarget->setScale(vector3df(1.f, 1.f, 0.5f)); + middleTarget->updateAbsolutePosition(); + + ISceneNode* nearTarget = smgr->addCubeSceneNode(10.f); + nearTarget->setPosition(vector3df(0.f, 0.f, 100.f)); + nearTarget->updateAbsolutePosition(); + // We'll rotate this node 90 degrees to show that we can hit its side. + nearTarget->setRotation(vector3df(0.f, 90.f, 0.f)); + + line3df ray(0.f, 0.f, 0.f, 0.f, 0.f, 500.f); + + const ISceneNode * const hit = collMgr->getSceneNodeFromRayBB(ray); + + bool result = (hit == nearTarget); + + if(hit == 0) + logTestString("getSceneNodeFromRayBB() didn't hit anything.\n"); + else if(hit == farTarget) + logTestString("getSceneNodeFromRayBB() hit the far (scaled) target.\n"); + else if(hit == middleTarget) + logTestString("getSceneNodeFromRayBB() hit the far (scaled) target.\n"); + + if(!result) + assert(false); + + return result; +} + + +/** Test functionality of the sceneCollisionManager */ +bool sceneCollisionManager(void) +{ + IrrlichtDevice * device = irr::createDevice(video::EDT_NULL, dimension2d(160, 120)); + assert(device); + if(!device) + return false; + + ISceneManager * smgr = device->getSceneManager(); + ISceneCollisionManager * collMgr = smgr->getSceneCollisionManager(); + + bool result = testGetCollisionResultPosition(device, smgr, collMgr); + + result &= testGetSceneNodeFromScreenCoordinatesBB(device, smgr, collMgr); + + result &= getScaledPickedNodeBB(device, smgr, collMgr); + + result &= getCollisionPoint_ignoreTriangleVertices(device, smgr, collMgr); + + device->drop(); + return result; +} + diff --git a/tests/sceneNodeAnimator.cpp b/tests/sceneNodeAnimator.cpp new file mode 100644 index 00000000..85453604 --- /dev/null +++ b/tests/sceneNodeAnimator.cpp @@ -0,0 +1,117 @@ +// Copyright (C) 2008 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" +#include "irrlicht.h" +#include + +using namespace irr; +using namespace core; +using namespace scene; + +/** Test functionality of the ISceneNodeAnimator implementations. */ +bool sceneNodeAnimator(void) +{ + IrrlichtDevice * device = irr::createDevice(video::EDT_NULL, dimension2d(160, 120)); + assert(device); + if(!device) + return false; + + ISceneManager * smgr = device->getSceneManager(); + + // Test the hasFinished() method. + ISceneNodeAnimatorCollisionResponse* collisionResponseAnimator + = smgr->createCollisionResponseAnimator(0, 0); + + ISceneNodeAnimator* deleteAnimator = smgr->createDeleteAnimator(1); + + ISceneNodeAnimator* flyCircleAnimator = smgr->createFlyCircleAnimator(); + + ISceneNodeAnimator* flyStraightAnimator + = smgr->createFlyStraightAnimator(vector3df(0, 0, 0), vector3df(0, 0, 0), 1, false); + + ISceneNodeAnimator* flyStraightAnimatorLooping + = smgr->createFlyStraightAnimator(vector3df(0, 0, 0), vector3df(0, 0, 0), 1, true); + + ISceneNodeAnimator* rotationAnimator = smgr->createRotationAnimator(vector3df(0, 0, 0)); + + array points; + points.push_back(vector3df(0, 0, 0)); + points.push_back(vector3df(0, 0, 0)); + ISceneNodeAnimator* followSplineAnimator = smgr->createFollowSplineAnimator(0, points, 1000.f); + + array textures; + textures.push_back(0); + textures.push_back(0); + + ISceneNodeAnimator* textureAnimator = smgr->createTextureAnimator(textures, 1, false); + ISceneNodeAnimator* textureAnimatorLooping = smgr->createTextureAnimator(textures, 1, true); + + bool result = true; + + ISceneNode * deletedNode = smgr->addEmptySceneNode(); + deletedNode->addAnimator(deleteAnimator); + + ISceneNode * testNode = smgr->addEmptySceneNode(); + testNode->addAnimator(collisionResponseAnimator); + testNode->addAnimator(deleteAnimator); + testNode->addAnimator(flyCircleAnimator); + testNode->addAnimator(flyStraightAnimator); + testNode->addAnimator(flyStraightAnimatorLooping); + testNode->addAnimator(rotationAnimator); + testNode->addAnimator(followSplineAnimator); + testNode->addAnimator(textureAnimator); + testNode->addAnimator(textureAnimatorLooping); + + result &= !collisionResponseAnimator->hasFinished(); + result &= !deleteAnimator->hasFinished(); + result &= !flyCircleAnimator->hasFinished(); + result &= !flyStraightAnimator->hasFinished(); + result &= !flyStraightAnimatorLooping->hasFinished(); + result &= !rotationAnimator->hasFinished(); + result &= !followSplineAnimator->hasFinished(); + result &= !textureAnimator->hasFinished(); + result &= !textureAnimatorLooping->hasFinished(); + + device->run(); + device->sleep(10); + device->run(); + smgr->drawAll(); + + // These animators don't have an endpoint. + result &= !collisionResponseAnimator->hasFinished(); + result &= !flyCircleAnimator->hasFinished(); + result &= !rotationAnimator->hasFinished(); + result &= !followSplineAnimator->hasFinished(); + + // These animators are looping and so can't finish. + result &= !flyStraightAnimatorLooping->hasFinished(); + result &= !textureAnimatorLooping->hasFinished(); + + // These have an endpoint and have reached it. + result &= deleteAnimator->hasFinished(); + result &= flyStraightAnimator->hasFinished(); + result &= textureAnimator->hasFinished(); + + collisionResponseAnimator->drop(); + deleteAnimator->drop(); + flyCircleAnimator->drop(); + flyStraightAnimator->drop(); + flyStraightAnimatorLooping->drop(); + rotationAnimator->drop(); + followSplineAnimator->drop(); + textureAnimator->drop(); + textureAnimatorLooping->drop(); + + device->drop(); + + if(!result) + { + logTestString("One or more animators has a bad hasFinished() state\n."); + assert(false); + } + + return result; +} + + diff --git a/tests/softwareDevice.cpp b/tests/softwareDevice.cpp index 1da9d907..a6dd02fa 100644 --- a/tests/softwareDevice.cpp +++ b/tests/softwareDevice.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Colin MacDonald +// Copyright (C) 2008-2009 Colin MacDonald // No rights reserved: this software is in the public domain. #include "irrlicht.h" @@ -13,7 +13,7 @@ using namespace scene; //! Tests the basic functionality of the software device. bool softwareDevice(void) { - IrrlichtDevice *device = createDevice(video::EDT_SOFTWARE, dimension2d(160, 120), 32); + IrrlichtDevice *device = createDevice(video::EDT_SOFTWARE, dimension2d(160, 120), 32); if (!device) return false; diff --git a/tests/terrainSceneNode.cpp b/tests/terrainSceneNode.cpp new file mode 100644 index 00000000..f3ada45f --- /dev/null +++ b/tests/terrainSceneNode.cpp @@ -0,0 +1,73 @@ + +#include "testUtils.h" +#include "irrlicht.h" +#include +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; + +bool terrainSceneNode(void) +{ + IrrlichtDevice *device = + createDevice(video::EDT_OPENGL, dimension2du(160, 120), 32); + + IVideoDriver* driver = device->getVideoDriver(); + ISceneManager* smgr = device->getSceneManager(); + + ITerrainSceneNode* terrain = smgr->addTerrainSceneNode( + "../media/terrain-heightmap.bmp"); + terrain->setScale(core::vector3df(40.f, .1f, 40.f)); + + terrain->setMaterialFlag(video::EMF_LIGHTING, false); + terrain->setMaterialTexture(0, driver->getTexture("../media/terrain-texture.jpg")); + terrain->setDebugDataVisible(scene::EDS_FULL); + + ICameraSceneNode* camera = smgr->addCameraSceneNode(); + + const core::vector3df center (terrain->getBoundingBox().getCenter()); + camera->setTarget (center); + + // yes, Y is intentionally being set to X here + const core::vector3df above (center.X, center.X, center.Z); + camera->setPosition (above); + camera->setUpVector(vector3df(1.f, 0.f, 0.f)); + camera->setFarValue(above.Y); + + device->run(); + smgr->drawAll(); + + + // This shouldn't cause a recalc + camera->setUpVector(vector3df(1.f, 0.f, .01f).normalize()); + device->run(); + driver->beginScene(true, true, video::SColor(255,100,101,140)); + smgr->drawAll(); + driver->endScene(); + + // Note that this has to be a slightly fuzzier than usual compare to satisfy multiple OpenGL environments + bool result = takeScreenshotAndCompareAgainstReference(driver, "-terrainSceneNode-1.png", 98.3f); + if(!result) + { + logTestString("Small camera up rotation caused bad recalc.\n"); + assert(false); + } + + + // This is big enough to cause a recalc + camera->setUpVector(vector3df(1.f, 0.f, .1f).normalize()); + device->run(); + driver->beginScene(true, true, video::SColor(255,100,101,140)); + smgr->drawAll(); + driver->endScene(); + + result &= takeScreenshotAndCompareAgainstReference(driver, "-terrainSceneNode-2.png", 98.9f); + if(!result) + { + logTestString("Large camera up rotation caused bad recalc.\n"); + assert(false); + } + + device->drop(); + return result; +} diff --git a/tests/testDimension2d.cpp b/tests/testDimension2d.cpp new file mode 100644 index 00000000..c489b148 --- /dev/null +++ b/tests/testDimension2d.cpp @@ -0,0 +1,38 @@ +// Copyright (C) 2008-2009 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "testUtils.h" +#include "irrlicht.h" +#include + +using namespace irr; +using namespace core; + +/** Some very basic testing of dimension2df: + operator+= + operator!= (and thus implicitly operator==) */ +bool testDimension2d(void) +{ + dimension2df dimension(100.f, 100.f); + const dimension2df addDimension(200.f, -200.f); + + (void)(dimension += addDimension); + + if(dimension != dimension2df(300.f, -100.f)) + { + logTestString("dimension2df != produced unexpected result.\n"); + assert(false); + return false; + } + + (void)(dimension -= addDimension); + if(dimension != dimension2df(100.f, 100.f)) + { + logTestString("dimension2df -= produced unexpected result.\n"); + assert(false); + return false; + } + + return true; +} + diff --git a/tests/testUtils.cpp b/tests/testUtils.cpp index 2f1339be..2912d999 100644 --- a/tests/testUtils.cpp +++ b/tests/testUtils.cpp @@ -1,7 +1,10 @@ -// Copyright (C) 2008 Colin MacDonald +// Copyright (C) 2008-2009 Colin MacDonald // No rights reserved: this software is in the public domain. -#define _CRT_SECURE_NO_WARNINGS +#if defined(_MSC_VER) +#define _CRT_SECURE_NO_WARNINGS 1 +#endif // _MSC_VER + #include "testUtils.h" #include #include @@ -41,9 +44,12 @@ bool binaryCompareFiles(const char * fileName1, const char * fileName2) (void)fseek(file1, 0, SEEK_END); (void)fseek(file2, 0, SEEK_END); - if(ftell(file1) != ftell(file2)) + const size_t file1Size = ftell(file1); + const size_t file2Size = ftell(file2); + if(file1Size != file2Size) { - logTestString("binaryCompareFiles: Files are different sizes\n"); + logTestString("binaryCompareFiles: Files are different sizes: %d vs %d\n", + file1Size, file2Size); (void)fclose(file1); (void)fclose(file2); return false; @@ -227,7 +233,10 @@ bool openTestLog(bool startNewLog, const char * filename) void closeTestLog(void) { if(logFile) + { (void)fclose(logFile); + logFile = 0; + } } diff --git a/tests/testUtils.h b/tests/testUtils.h index a103cc23..45585e64 100644 --- a/tests/testUtils.h +++ b/tests/testUtils.h @@ -2,12 +2,16 @@ #ifndef _TEST_UTILS_H_ #define _TEST_UTILS_H_ 1 -#include "irrlicht.h" - #if defined(_WIN32) || defined(_WIN64) || defined(WIN32) || defined(WIN64) || defined(_WIN32_WCE) #define TESTING_ON_WINDOWS +#define DIR_SEP_STRING "\\" +#else +#define DIR_SEP_STRING "/" #endif +#include "irrlicht.h" + + //! Compare two files /** \param fileName1 The first file for comparison. \param fileName1 The second file for comparison. diff --git a/tests/testVector2d.cpp b/tests/testVector2d.cpp index 9450b3d9..f3c921c3 100644 --- a/tests/testVector2d.cpp +++ b/tests/testVector2d.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Colin MacDonald +// Copyright (C) 2008-2009 Colin MacDonald // No rights reserved: this software is in the public domain. #include "testUtils.h" diff --git a/tests/testVector3d.cpp b/tests/testVector3d.cpp index 259d72d7..0cdd5616 100644 --- a/tests/testVector3d.cpp +++ b/tests/testVector3d.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2008 Colin MacDonald +// Copyright (C) 2008-2009 Colin MacDonald // No rights reserved: this software is in the public domain. #include "testUtils.h" @@ -14,7 +14,7 @@ static bool compareVectors(const core::vector3d & compare, { if(compare != with) { - logTestString("\nERROR: vector3d %.16f, %.16f, %.16f != vector3d %.16f, %.16f, %.16f\n", + logTestString("\nERROR: vector3d %.16f, %.16f, %.16f != vector3d %.16f, %.16f, %.16f\n", (f64)compare.X, (f64)compare.Y, (f64)compare.Z, (f64)with.X, (f64)with.Y, (f64)with.Z); assert(compare == with); @@ -50,7 +50,7 @@ static bool doTests() vec.set(10, 10, 10); center.set(5, 5, 10); vec.rotateXYBy(-5, center); - // -5 means rotate clockwise slightly, so expect the X to increase + // -5 means rotate clockwise slightly, so expect the X to increase // slightly and the Y to decrease slightly. COMPARE_VECTORS(vec, vector3d((T)10.416752204197017, (T)9.5451947767204359, 10)); diff --git a/tests/tests-last-passed-at.txt b/tests/tests-last-passed-at.txt index cd372a9c..16e40035 100644 --- a/tests/tests-last-passed-at.txt +++ b/tests/tests-last-passed-at.txt @@ -1,2 +1,2 @@ -Test suite pass at GMT Thu Dec 18 15:24:34 2008 +Test suite pass at GMT Thu Jan 22 18:20:21 2009 diff --git a/tests/tests-readme.txt b/tests/tests-readme.txt index 2f7c996d..c930bfcc 100644 --- a/tests/tests-readme.txt +++ b/tests/tests-readme.txt @@ -1,21 +1,120 @@ Welcome to the Irrlicht test suite. - +=================================== This is composed of a series of tests which exercise basic Irrlicht functionality. These are not strictly unit tests, since there is no stub framework that isolates each method under test. They -do however test small units of functionality and should help to isolate problems or spot regressions. +do however test small units of functionality and should help to isolate problems and spot regressions. -Each test resides in its own source file, and must have an entry point with the signature -bool testName(void); where testName should be the same as the source file name (without the suffix). +You are encouraged to run the tests whenever you make any significant code change, and to add tests +for any new or modified area of code. -Each test runs independently, and is responsible for cleaning up after itself and restoring the -working directory to /tests. +The overall test application will return a count of the number of tests that failed, i.e. 0 is success. +It will also log to tests/tests.log file, and on success will update the tests/tests-last-passed-at.txt +file (which gets committed with code changes as a very basic verification that we're not regressing). -testUtils.cpp provides some functions for creating screenshots and comparing files (including images). -Validation images should go im the /media subdirectory. Since the tests rely on the presence of /media -and /empty/empty subdirectories, the working directory must be the /tests directory, not /bin/$PLATFORM. -This means that you cannot run /bin/$PLATFORM/texts.exe from there. You can however cd to /tests and -run ../bin/$PLATFORM/tests.exe +Working directory +================= +Since the tests rely on the presence of /media and /empty/empty subdirectories, the working directory +must be the /tests directory, not /bin/$PLATFORM. This means that you cannot run /bin/$PLATFORM/texts.exe +from there. You can however cd to /tests and run ../bin/$PLATFORM/tests.exe -The overall test application will return a count of the number of test that failed, i.e. 0 is success. \ No newline at end of file + +Adding a new test +================= +To add a new test, e.g. "myNewTest": + +1) Create tests/myNewTest.cpp. At a minimum, this must contain a function with the signature + bool fnName(void), where fnName is the same as the filename (without the .cpp suffix). + + This function must return true if the tests passes, or false if it fails. In this example, + the function should be: + + bool myNewTest(void) + { + ... + } + +2) Add myNewTest.cpp to the build targets in tests.cbp, tests_vc8.vcproj and tests_vc9.vcproj. These + are all text files that can be edited manually by hand; just copy, paste and modify an existing + source file entry. + +3) In tests/main.cpp, find the list of TEST() macro calls, and add a call to your new test, using the + TEST macro, e.g.: + + TEST(myNewTest); + +4) Run your test, and verify any images that it produces (see "Screenshots"). + +5) Remember to svn add tests/newNewTest.cpp and any new tests/media/ files. + +Your test will be run independently in its own indepedent process. It is responsible for creating any +required resources or Irrlicht interfaces, and for cleaning up after itself and restoring the working +directory to /tests. You do not have to link against Irrlicht.lib; the whole application is already +linked to it. + + +Logging +======= +Please use logTestString() to log any intersting output or fails from your test. This is declared in +tests/testUtils.h. Its output goes to tests/tests.log + + +Screenshots +=========== +testUtils.h/.cpp provides a function to create a screenshot and compare it with a reference image. +This is useful for validating new or changed functionality, and for catching regressions. + +Call the unambiguously named takeScreenshotAndCompareAgainstReference() function to do this. It needs +an IVideoDriver (which it will use to create the first part of the filename) and a unique filename +including an image format suffix, e.g. "-myNewTest.png". You should use .png as a suffix unless you +have a very specific need to use another format. Please avoid using .jpg as image compression can +introduce artifacts and false fails. + +Optionally, you can specify the amount of match that is required between the produced screenshot and +the reference image. While the images should match exactly, we have found that OpenGL implementations +can vary significantly across test machines, so a default 99% match (of total colour values across all +pixels) is assumed. You may have to go as low as 98% for some images, but please try to err on the side +of strictness until we can determine that your test image needs to be fuzzier on other peoples' machines. + +If takeScreenshotAndCompareAgainstReference() can't find an existing reference image, it will create +one from the screenshot. In effect, this means that you have to run your test once (expecting it to +fail) in order to produce the initial reference images. The new images are created in tests/results +with filename: + +driverName-filename.suffix + +e.g. OpenGL-myNewTest.png (note that the OpenGL driver elides the actual OpenGL version number from +the filename, as this tends to differ between machines and installations). + +You should check these new images carefully to ensure that they show exactly what you expect. Please +do not just assume that they do, as validating bad behaviour is worse than not validating it at all! + +If the images do appear exactly as you expect, move them to the tests/media directory, and re-run the +tests. They should now pass. Remember to svn add any new media files! + + +What to do when the tests fail +============================== +DON'T PANIC! + +This is a Good Thing. Failing tests challenge our assumptions and help us to make Irrlicht more robust. + +First, check your working directory. The tests need to be run from the tests/ directory, not a /bin +subdirectory. You can do this using the working directory in your debugger, or on the command line by +running the tests executable (wherever it is build) from the tests/ directory. + +If you need to debug a test, first move it temporarily to the start of the list of TEST() macros. This +is because each test runs in its own process, so only the first test will have the debugger attached. + +If the fail is due to a bitmap difference, carefully compare the bitmaps, and the amount of failure. The +OpenGL device does tend to produce differences. You should not just automatically make a test fuzzier, +but if you can rule out any real issue in the code, it can be valid to accept OpenGL image matches as low +as 98%. Other devices should not require this amount of fuzziness! + +If you can't figure out the reason for the failure (or better yet, if you can, and think the tests and/or +Irrlicht need updated), then please do raise the issue in the bug forum: + +http://irrlicht.sourceforge.net/phpBB2/viewforum.php?f=7 + +We do want to hear about fails, and will thank you for finding them. \ No newline at end of file diff --git a/tests/tests.cbp b/tests/tests.cbp index a03b1615..86d6f85a 100644 --- a/tests/tests.cbp +++ b/tests/tests.cbp @@ -38,21 +38,36 @@ + + + + + + + + + + + + + + + diff --git a/tests/tests_vc8.vcproj b/tests/tests_vc8.vcproj index 4afd1517..23a2eb18 100644 --- a/tests/tests_vc8.vcproj +++ b/tests/tests_vc8.vcproj @@ -173,10 +173,18 @@ RelativePath=".\b3dAnimation.cpp" > + + + + @@ -185,6 +193,10 @@ RelativePath=".\drawPixel.cpp" > + + @@ -193,10 +205,18 @@ RelativePath=".\fast_atof.cpp" > + + + + @@ -205,6 +225,14 @@ RelativePath=".\main.cpp" > + + + + @@ -213,14 +241,30 @@ RelativePath=".\planeMatrix.cpp" > + + + + + + + + @@ -233,6 +277,22 @@ RelativePath=".\testVector3d.cpp" > + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + diff --git a/tests/textureRenderStates.cpp b/tests/textureRenderStates.cpp new file mode 100644 index 00000000..8688da21 --- /dev/null +++ b/tests/textureRenderStates.cpp @@ -0,0 +1,61 @@ +// Copyright (C) 2008-2009 Christian Stehno, Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "irrlicht.h" +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +//! Tests interleaved loading and rendering of textures +/** The test loads a texture, renders it using draw2dimage, loads another + texture and renders the first one again. Due to the texture cache this + can lead to rendering of the second texture in second place. */ +static bool runTestWithDriver(E_DRIVER_TYPE driverType) +{ + IrrlichtDevice *device = createDevice( driverType, dimension2d(160, 120), 32); + if (!device) + return true; // Treat a failure to create a driver as benign; this saves a lot of #ifdefs + + IVideoDriver* driver = device->getVideoDriver(); + ISceneManager * smgr = device->getSceneManager(); + + ITexture* tex1 = driver->getTexture("../media/wall.bmp"); + + (void)smgr->addCameraSceneNode(); + + driver->beginScene(true, true, SColor(255,100,101,140)); + driver->draw2DImage(tex1, position2di(0,0)); + driver->endScene(); + + driver->getTexture("../media/tools.png"); + + driver->beginScene(true, true, SColor(255,100,101,140)); + driver->draw2DImage(tex1, position2di(0,0)); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-textureRenderStates.png", 100); + + device->drop(); + + return result; +} + + +bool textureRenderStates(void) +{ + bool passed = true; + + passed &= runTestWithDriver(EDT_SOFTWARE); + passed &= runTestWithDriver(EDT_BURNINGSVIDEO); + passed &= runTestWithDriver(EDT_DIRECT3D9); + passed &= runTestWithDriver(EDT_DIRECT3D8); + passed &= runTestWithDriver(EDT_OPENGL); + + return passed; +} + diff --git a/tests/transparentAlphaChannelRef.cpp b/tests/transparentAlphaChannelRef.cpp new file mode 100644 index 00000000..78cc75e3 --- /dev/null +++ b/tests/transparentAlphaChannelRef.cpp @@ -0,0 +1,61 @@ +// Copyright (C) 2008-2009 Christian Stehno, Colin MacDonald +// No rights reserved: this software is in the public domain. + +#include "irrlicht.h" +#include "testUtils.h" + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; + + +//! Check that EMT_TRANSPARENT_ALPHA_CHANNEL_REF works as expected +bool testWithDriver(video::E_DRIVER_TYPE driverType) +{ + IrrlichtDevice* device = createDevice(driverType, core::dimension2d(160, 120), 32); + if(!device) + return true; + + video::IVideoDriver* driver = device->getVideoDriver(); + scene::ISceneManager* smgr = device->getSceneManager(); + + driver->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true); + + ISceneNode * backCube = smgr->addCubeSceneNode(); + backCube->setPosition(vector3df(0, 0, 10)); + backCube->setScale(vector3df(5, 5, 1)); + backCube->setMaterialTexture(0, driver->getTexture("../media/wall.bmp")); + backCube->setMaterialType(video::EMT_SOLID ); //solid.....? + backCube->setMaterialFlag(video::EMF_LIGHTING, false); + + ISceneNode * frontCube = smgr->addCubeSceneNode(); + frontCube->setMaterialTexture(0, driver->getTexture("../media/help.png")); + frontCube->setMaterialType(video::EMT_TRANSPARENT_ALPHA_CHANNEL_REF ); //solid.....? + frontCube->setMaterialFlag(video::EMF_LIGHTING, false); + + (void)smgr->addCameraSceneNode(0, vector3df(0, 0, -15)); + + driver->beginScene(true, true, video::SColor(255,113,113,133)); + smgr->drawAll(); + driver->endScene(); + + bool result = takeScreenshotAndCompareAgainstReference(driver, "-transparentAlphaChannelRef.png", 99.88f); + + device->drop(); + + return result; +} + + +bool transparentAlphaChannelRef(void) +{ + bool result = testWithDriver(EDT_DIRECT3D9); + + // FIXME Rogerborg 8-January-2009. Burning's video currently produces unexpected results, + // blending using the full alpha value instead of using a boolean mask. This test is being + // added now anyway to help verify the fix when it's done; it should just require an + // update of the reference image. + result &= testWithDriver(EDT_BURNINGSVIDEO); + return result; +} diff --git a/tests/vectorPositionDimension2d.cpp b/tests/vectorPositionDimension2d.cpp new file mode 100644 index 00000000..ecdbda1a --- /dev/null +++ b/tests/vectorPositionDimension2d.cpp @@ -0,0 +1,73 @@ +// Copyright (C) 2008 Colin MacDonald +// No rights reserved: this software is in the public domain. + +/** This test verifies that position2d and vector2d are interchangeable, + and that they can convert from dimension2d */ + +#include "testUtils.h" +#include "irrlicht.h" +#include + +using namespace irr; +using namespace core; + + +template +static bool doTest(void) +{ + bool result = true; + + DIMENSION dimension((T)99.9, (T)99.9); + VECTOR vector(dimension); + POSITION position(vector); + DIMENSION dimension2(vector); + + result &= (vector == position); + result &= (vector == dimension); // The conversion should be explicit. + result &= (dimension2 == position); + result &= (position == POSITION((T)99.9, (T)99.9)); + + dimension = (T)2 * position; + result &= (dimension == VECTOR(2 * (T)99.9, 2 * (T)99.9)); + + dimension /= (T)2; + result &= (dimension == POSITION((T)99.9, (T)99.9)); + + dimension += vector; + result &= (dimension == VECTOR(2 * (T)99.9, 2 * (T)99.9)); + + dimension -= position; + result &= (dimension == POSITION((T)99.9, (T)99.9)); + + position = dimension; + result &= (position == VECTOR((T)99.9, (T)99.9)); + + vector += position; + result &= (vector == POSITION(2 * (T)99.9, 2 * (T)99.9)); + + vector -= position; + result &= (vector == dimension); + + position *= (T)3.5; + result &= (position == VECTOR((T)3.5 * (T)99.9, (T)3.5 * (T)99.9)); + + vector += dimension; + result &= (vector == VECTOR(2 * (T)99.9, 2 * (T)99.9)); + + return result; +} + +bool vectorPositionDimension2d(void) +{ + bool result = true; + + result &= doTest(); + result &= doTest(); + result &= doTest, vector2d, position2d, f64>(); + + if(!result) + assert(false); + + return result; +} + diff --git a/tests/writeImageToFile.cpp b/tests/writeImageToFile.cpp new file mode 100644 index 00000000..b9f63eb3 --- /dev/null +++ b/tests/writeImageToFile.cpp @@ -0,0 +1,132 @@ +// Copyright (C) 2009 Colin MacDonald +// No rights reserved: this software is in the public domain. + +#if defined(_MSC_VER) +#define _CRT_SECURE_NO_WARNINGS 1 +#endif // _MSC_VER + +#include "irrlicht.h" +#include "testUtils.h" +#include + +using namespace irr; +using namespace core; +using namespace scene; +using namespace video; +using namespace io; +using namespace gui; + +//! Tests IVideoDriver::writeImageToFile() using IWriteFile +bool writeImageToFile(void) +{ + IrrlichtDevice *device = createDevice( EDT_BURNINGSVIDEO, dimension2d(160, 120), 32); + if (!device) + return true; // Treat a failure to create a driver as benign; this saves a lot of #ifdefs + + IVideoDriver* driver = device->getVideoDriver(); + ISceneManager * smgr = device->getSceneManager(); + + // Draw a cube background so that we can check that the pixels' alpha is working. + ISceneNode * cube = smgr->addCubeSceneNode(50.f, 0, -1, vector3df(0, 0, 60)); + cube->setMaterialTexture(0, driver->getTexture("../media/wall.bmp")); + cube->setMaterialFlag(video::EMF_LIGHTING, false); + (void)smgr->addCameraSceneNode(); + + driver->beginScene(true, true, SColor(255,100,101,140)); + smgr->drawAll(); + + // Test for benign handling of offscreen pixel values as well as onscreen ones. + for(s32 x = -10; x < 170; ++x) + { + s32 y = 120 * x / 160; + driver->drawPixel((u32)x, (u32)y, SColor(255, 255 * x / 640, 255 * (640 - x) / 640, 0)); + y = 120 - y; + driver->drawPixel((u32)x, (u32)y, SColor(255 * x / 640, 0, 255, 255)); + } + + driver->endScene(); + + bool result = false; + IWriteFile * writtenFile = 0; + IWriteFile * memoryFile = 0; + const char * writtenFilename = 0; + const u32 BUFFER_SIZE = 160 * 120 * 4; + c8 * buffer = 0; + const char * referenceFilename = 0; + + irr::video::IImage * screenshot = driver->createScreenShot(); + if(!screenshot) + { + logTestString("Failed to take screenshot\n"); + assert(false); + goto cleanup; + } + + const video::ECOLOR_FORMAT format = screenshot->getColorFormat(); + if(format != video::ECF_R8G8B8) + { + irr::video::IImage * fixedScreenshot = driver->createImage(video::ECF_R8G8B8, screenshot); + screenshot->drop(); + + if(!fixedScreenshot) + { + logTestString("Failed to convert screenshot to ECF_A8R8G8B8\n"); + assert(false); + goto cleanup; + } + + screenshot = fixedScreenshot; + } + + buffer = new c8[BUFFER_SIZE]; + writtenFilename = "results" DIR_SEP_STRING "burnings video 0.39b-drawPixel.png"; + memoryFile = device->getFileSystem()->createMemoryWriteFile(buffer, BUFFER_SIZE, writtenFilename, false); + if(!driver->writeImageToFile(screenshot, memoryFile)) + { + logTestString("Failed to write png to memory file\n"); + assert(false); + goto cleanup; + } + + writtenFile = device->getFileSystem()->createAndWriteFile(memoryFile->getFileName()); + if(!writtenFile) + { + logTestString("Can't open %s for writing.\n", writtenFilename); + assert(false); + goto cleanup; + } + + if(memoryFile->getPos() != writtenFile->write(buffer, memoryFile->getPos())) + { + logTestString("Error while writing to %s.\n", writtenFilename); + assert(false); + goto cleanup; + } + + writtenFile->drop(); + writtenFile = 0; + + referenceFilename = "media" DIR_SEP_STRING "burnings video 0.39b-drawPixel.png"; + if(!binaryCompareFiles(writtenFilename, referenceFilename)) + { + logTestString("File written from memory is not the same as the reference file.\n"); + assert(false); + goto cleanup; + } + + result = true; + +cleanup: + if(writtenFile) + writtenFile->drop(); + + if(memoryFile) + memoryFile->drop(); + + delete [] buffer; + + device->drop(); + + return result; +} + diff --git a/tools/GUIEditor/CGUIEditFactory.h b/tools/GUIEditor/CGUIEditFactory.h index 0f854146..ea55e526 100644 --- a/tools/GUIEditor/CGUIEditFactory.h +++ b/tools/GUIEditor/CGUIEditFactory.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/tools/GUIEditor/CGUIEditWorkspace.cpp b/tools/GUIEditor/CGUIEditWorkspace.cpp index ede497b4..7d19b730 100644 --- a/tools/GUIEditor/CGUIEditWorkspace.cpp +++ b/tools/GUIEditor/CGUIEditWorkspace.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Gaz Davidson +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Gaz Davidson // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h @@ -860,13 +860,11 @@ void CGUIEditWorkspace::PasteXMLToSelectedElement() // rewind file memWrite->seek(0, false); - io::IXMLReader* xmlReader = (io::IXMLReader*) Environment->getFileSystem()->createXMLReader(memWrite); - // read xml - Environment->readGUIElement(xmlReader, SelectedElement); + Environment->loadGUI(memWrite, SelectedElement); - // drop the xml reader - xmlReader->drop(); + // reset focus + Environment->setFocus(this); // drop the read file memWrite->drop(); diff --git a/tools/GUIEditor/CGUIEditWorkspace.h b/tools/GUIEditor/CGUIEditWorkspace.h index 21ce5279..a9ae40dc 100644 --- a/tools/GUIEditor/CGUIEditWorkspace.h +++ b/tools/GUIEditor/CGUIEditWorkspace.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Gaz Davidson +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Gaz Davidson // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/tools/GUIEditor/CGUIPanel.cpp b/tools/GUIEditor/CGUIPanel.cpp index 17a7ceab..9f981a14 100644 --- a/tools/GUIEditor/CGUIPanel.cpp +++ b/tools/GUIEditor/CGUIPanel.cpp @@ -1,4 +1,4 @@ -// Copyright 2006-2008 Asger Feldthaus +// Copyright 2006-2009 Asger Feldthaus // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/tools/GUIEditor/CGUIPanel.h b/tools/GUIEditor/CGUIPanel.h index ba5c2071..6cba4a47 100644 --- a/tools/GUIEditor/CGUIPanel.h +++ b/tools/GUIEditor/CGUIPanel.h @@ -1,4 +1,4 @@ -// Copyright 2006-2008 Asger Feldthaus +// Copyright 2006-2009 Asger Feldthaus // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/tools/GUIEditor/CGUITextureCacheBrowser.cpp b/tools/GUIEditor/CGUITextureCacheBrowser.cpp index ba46eff8..bc4c6028 100644 --- a/tools/GUIEditor/CGUITextureCacheBrowser.cpp +++ b/tools/GUIEditor/CGUITextureCacheBrowser.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Gaz Davidson +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Gaz Davidson // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/tools/GUIEditor/CGUITextureCacheBrowser.h b/tools/GUIEditor/CGUITextureCacheBrowser.h index 530ff988..a4e331eb 100644 --- a/tools/GUIEditor/CGUITextureCacheBrowser.h +++ b/tools/GUIEditor/CGUITextureCacheBrowser.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt / Gaz Davidson +// Copyright (C) 2002-2009 Nikolaus Gebhardt / Gaz Davidson // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/tools/GUIEditor/CMemoryReadWriteFile.cpp b/tools/GUIEditor/CMemoryReadWriteFile.cpp index b13d699e..54857d41 100644 --- a/tools/GUIEditor/CMemoryReadWriteFile.cpp +++ b/tools/GUIEditor/CMemoryReadWriteFile.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/tools/GUIEditor/CMemoryReadWriteFile.h b/tools/GUIEditor/CMemoryReadWriteFile.h index 1fa51b4b..ba8a5dc1 100644 --- a/tools/GUIEditor/CMemoryReadWriteFile.h +++ b/tools/GUIEditor/CMemoryReadWriteFile.h @@ -1,4 +1,4 @@ -// Copyright (C) 2002-2008 Nikolaus Gebhardt +// Copyright (C) 2002-2009 Nikolaus Gebhardt // This file is part of the "Irrlicht Engine". // For conditions of distribution and use, see copyright notice in irrlicht.h diff --git a/tools/IrrFontTool/newFontTool/CFontTool.cpp b/tools/IrrFontTool/newFontTool/CFontTool.cpp index d1c92adf..4b0e77dc 100644 --- a/tools/IrrFontTool/newFontTool/CFontTool.cpp +++ b/tools/IrrFontTool/newFontTool/CFontTool.cpp @@ -608,7 +608,7 @@ inline u32 getTextureSizeFromSurfaceSize(u32 size) texHeight = lastTextureHeight; /* The texture that holds this "page" of characters */ - currentImages[currentImage] = Device->getVideoDriver()->createImage(video::ECF_A8R8G8B8, core::dimension2d(textureWidth, texHeight)); + currentImages[currentImage] = Device->getVideoDriver()->createImage(video::ECF_A8R8G8B8, core::dimension2du(textureWidth, texHeight)); currentImages[currentImage]->fill(video::SColor(alpha ? 0 : 255,0,0,0)); for (core::map::Iterator it = CharMap.getIterator(); !it.atEnd(); it++) diff --git a/tools/IrrFontTool/newFontTool/CVectorFontTool.h b/tools/IrrFontTool/newFontTool/CVectorFontTool.h index 3250dd11..1095104d 100644 --- a/tools/IrrFontTool/newFontTool/CVectorFontTool.h +++ b/tools/IrrFontTool/newFontTool/CVectorFontTool.h @@ -1,6 +1,6 @@ /* - Vector font tool - Gaz Davidson December 2006 + Vector font tool - Gaz Davidson December 2006-2009 I noticed bitmap fonts were taking massive amounts of video memory at reasonable sizes, so I decided to make a vector font. I always wanted to try converting pixels to triangles... diff --git a/tools/IrrFontTool/newFontTool/irrFontTool_v8.vcproj b/tools/IrrFontTool/newFontTool/irrFontTool_v8.vcproj index acc3b45f..fcb71a19 100644 --- a/tools/IrrFontTool/newFontTool/irrFontTool_v8.vcproj +++ b/tools/IrrFontTool/newFontTool/irrFontTool_v8.vcproj @@ -101,6 +101,7 @@ ConfigurationType="1" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" CharacterSet="2" + WholeProgramOptimization="1" > - \ No newline at end of file + diff --git a/tools/IrrFontTool/newFontTool/irrFontTool_v9.vcproj b/tools/IrrFontTool/newFontTool/irrFontTool_v9.vcproj index b4b69b09..528dc662 100644 --- a/tools/IrrFontTool/newFontTool/irrFontTool_v9.vcproj +++ b/tools/IrrFontTool/newFontTool/irrFontTool_v9.vcproj @@ -101,6 +101,7 @@ ConfigurationType="1" InheritedPropertySheets="$(VCInstallDir)VCProjectDefaults\UpgradeFromVC71.vsprops" CharacterSet="2" + WholeProgramOptimization="1" > getFont(\"Myfont.xml\");\n\n" L"That's all, have fun :-)"; - -#ifdef _IRR_WINDOWS - wchar_t *completeText = L"Font created" -#else - wchar_t *completeText = L"Font created\n\n" - L"Please note that anti-aliasing under X11 is controlled by the system " - L"configuration, so if your system is set to use anti-aliasing, then so " - L"will any fonts you create with FontTool"; -#endif + +#ifdef _IRR_WINDOWS + wchar_t *completeText = L"Font created" +#else + wchar_t *completeText = L"Font created\n\n" + L"Please note that anti-aliasing under X11 is controlled by the system " + L"configuration, so if your system is set to use anti-aliasing, then so " + L"will any fonts you create with FontTool"; +#endif enum MYGUI { @@ -258,9 +258,9 @@ public: { VecTool = new CVectorFontTool(FontTool); } - - /* Message box letting the user know the process is complete */ - env->addMessageBox(L"Create", completeText); + + /* Message box letting the user know the process is complete */ + env->addMessageBox(L"Create", completeText); return true; } @@ -458,7 +458,7 @@ void createGUI(IrrlichtDevice* device, CFontTool* fc) int main() { - IrrlichtDevice* device =createDevice(video::EDT_OPENGL, core::dimension2d(800, 600)); + IrrlichtDevice* device =createDevice(video::EDT_OPENGL, core::dimension2du(800, 600)); video::IVideoDriver* driver = device->getVideoDriver(); scene::ISceneManager* smgr = device->getSceneManager(); gui::IGUIEnvironment *env = device->getGUIEnvironment();

The Irrlicht Engine